at.Applied Theology DOCUMENTATION Back to site
Platform

Databases & files

Choose the store based on access patterns and recovery requirements. There is no need to use every datastore in one app.

Choose a store

Data Default home Why
Application documents, relationships, accounting RDS PostgreSQL Transactions, joins, flexible queries, shared migrations
Owner-scoped settings with predictable key access Optional DynamoDB Explicit keys, conditional updates, managed scale
Audio, video, images, large exports S3 Direct uploads, multipart transfer, signed downloads
Temporary files and local generation output kit.data_dir Convenient local workspace; requires care when scaling

Arena and the shared platform already use RDS. DynamoDB is an additional abstraction, not a replacement for the SQL store.

PostgreSQL documents

store = kit.store.for_owner(user.id)
record_id = await store.put("notes", {"title": "First note"})
record = await store.get("notes", record_id)
recent = await store.list("notes", limit=20, offset=0)
await store.delete("notes", record_id)

put is an insert-or-replace operation. list supports bounded pagination and top-level JSON filters with where. Its response includes record IDs. For relational constraints, joins, or multi-record transactions, use explicit SQLAlchemy tables and reviewed migrations.

Custom table names should start with the app slug. Production runtime roles have data permissions, not schema-creation privileges.

Optional DynamoDB

Provision a table for the app, declare kv in its manifest, and bind verified identity:

from at.kv import Conflict

kv = kit.kv.for_owner(user.id)
created = await kv.put("preferences", "theme", {"color": "blue"})
updated = await kv.put(
    "preferences", "theme", {"color": "green"},
    expected_version=created["version"],
)
page = await kv.query("preferences", prefix="th", limit=20)

Without expected_version, writes are create-only. A stale version raises Conflict. Reads are strongly consistent. Prefix queries return a signed cursor; follow it until absent, including after an empty page.

Values are JSON objects capped at 300 KiB. Large payloads belong in S3. Optional expiry is enforced by the adapter before DynamoDB's asynchronous TTL cleanup. There are no scans, arbitrary SQL-style filters, or silent fallback to PostgreSQL.

The Infrastructure Demo is a working reference. DynamoDB operator notes cover provisioning, throughput limits, and point-in-time recovery.

S3 upload workflow

Call kit.enable_files() to expose the shared file API. Endpoints are relative to the app:

Endpoint Purpose
POST /api/files/uploads Reserve an upload with filename, size, and content type
POST /api/files/{id}/parts/{part} Obtain a signed URL for an upload part
GET /api/files/{id}/parts Inspect uploaded parts for resume
POST /api/files/{id}/complete Validate and finalize the object
GET /api/files List the authenticated owner's catalog
GET /api/files/{id}/url Get a short-lived download URL
DELETE /api/files/{id} Cancel an upload or delete an owned file

The browser sends file bytes directly to S3. The platform owns metadata, authorization, and quota reservations. Pending uploads count toward quota so parallel reservations cannot bypass it. Default owner limits are 100 GiB and 1,000 files per app; configuration can change them.

The Media Library demonstrates the complete workflow. Arena has a separate artifact API and implementation; do not assume endpoint shapes are interchangeable.

Recovery and cleanup

The source media bucket is versioned. New media versions replicate to a separate private recovery bucket, and source deletion does not propagate there. Application credentials cannot delete recovery copies.

This is same-account, same-region recovery, not an immutable cross-account vault. Recovery current versions have no automatic expiry; noncurrent recovery versions retain 90 days. Storage costs grow with media and retained versions.

Hourly maintenance reconciles uploads older than two days: it recovers completed S3 objects whose catalog update failed, or releases unused reservations. It does not expire completed user files. SQL catalog data is protected separately by nightly backups and RDS recovery.