Metadata-Version: 2.5
Name: arkitekt-datalayer
Version: 1.0.0
Summary: S3-backed stores for arkitekt services: bookkeeping rows, scoped upload/read grants, quotas and purge
Author-email: jhnnsrs <jhnnsrs@gmail.com>
License-Expression: MIT
License-File: LICENSE
Requires-Python: <4,>=3.12
Requires-Dist: authentikate>=5.1.0
Requires-Dist: boto3>=1.38.9
Requires-Dist: django-polymorphic>=4.11.2
Requires-Dist: django>=5.2
Requires-Dist: duckdb>=1.2.2
Requires-Dist: kante>=2.4.1
Requires-Dist: pydantic<3,>2
Requires-Dist: strawberry-graphql>=0.260
Description-Content-Type: text/markdown

# arkitekt-datalayer

The `datalayer` Django app shared by arkitekt services: S3-backed store rows (media, big file,
zarr, parquet, sparse, fabriks, konnektion), scoped upload and read grants minted as STS
sessions, per-organization/user/upload quotas, and an orphan purge.

Install it as `arkitekt_datalayer`; its app label is `datalayer`, so tables are `datalayer_*`
and models are referenced as `"datalayer.MediaStore"`.

```python
INSTALLED_APPS = [..., "polymorphic", "authentikate", "arkitekt_datalayer"]
DATALAYER = conf.datalayer.model_dump(exclude_none=True) if conf.datalayer else {}
```

Embed `arkitekt_datalayer.configuration.DatalayerSettings` in the service's config model (narrow
the buckets it needs in a subclass). Without a `DATALAYER` setting the app still installs; grants
and writes then raise, naming the missing bucket.

What a service wires itself: the GraphQL mutations it exposes (`arkitekt_datalayer.mutations`,
gated by `load_config().upload_roles`), `scalars.SCALAR_MAP` in its schema config, and the store
types it declares in its hub contract. Deleting data rows should straddle the delete with
`storage.stores_orphaned_by` / `storage.flag_orphaned`; `manage.py purge_orphaned_stores`
collects them after `store_grace_days`.

Tests run against a real postgres and RustFS via dokker: `uv run pytest`.
