Data Model
All control-plane state lives in one DynamoDB table:
agent-runner-<env>. It is PAY_PER_REQUEST, KMS-encrypted, with PITR and
DynamoDB Streams enabled.
Single-table design
| Entity | PK | SK | GSI1 PK | GSI1 SK |
|---|---|---|---|---|
| Tenant | TENANT#<id> | META | SLUG#<slug> | TENANT |
| User | USER#<sub> | META | TENANT#<tenant_id> | USER#<sub> |
| Grant | TENANT#<id> | GRANT#<sub> | — | — |
| API Key | TENANT#<id> | KEY#<prefix8> | — | — |
| Model Catalog | MODELS | MODEL#<model_id> | — | — |
| Billing Rollup | TENANT#<id> | BILLING#<YYYY-MM>#<model>#<region> | — | — |
| Free Credit | TENANT#<id> | CREDIT#FREE | — | — |
| Audit Entry | TENANT#<id> | AUDIT#<ts>#<uuid> | — | — |
Access patterns
- Resolve tenant by slug — the proxy reads the Host header slug and
queries GSI1 on
SLUG#<slug>. Cached in-memory for 60 seconds. - List a tenant’s grants / keys — query
PK=TENANT#<id>with the appropriate SK prefix. - Fetch the whole model catalog — all catalog entries share
PK=MODELS, so one Query (SK begins_with MODEL#) returns everything. - Billing rollups — atomic
UpdateItem ADDon per-month, per-model, per-region counter rows.
The Stripe customer is stored on the owner’s USER#<sub> META row,
not on the tenant. One owner sharing multiple workspaces shares one
Stripe customer; each workspace has its own stripe_subscription_id on
its TENANT#<id> META row.
For full attribute schemas and additional access patterns, see
specs/ARCHITECTURE.md in the repository.
Last updated on