Data Ownership
Who owns what data. Services access other services' data through APIs, never the database directly.
Ownership Map
| Data | Owner | Storage | Others access via |
|---|---|---|---|
| Events (proposals, approvals, executions) | Event Store API | PostgreSQL events table |
GET /events, POST /events |
| Patterns (merchant → account mappings) | Event Store API | PostgreSQL patterns table |
Embedded in event responses |
| Cost snapshots (usage data) | Cost API | Cost API's own storage | GET /usage/* |
| Conversations (Discord thread history) | Book-E | In-memory / Postgres | Not shared |
| Bank transactions | Folio (external) | Folio's systems | Accounting API → Folio API |
| Accounting records | Fiken (external) | Fiken's systems | Accounting API → Fiken API |
| Character config | Git | ConfigMap on k8s | Mounted in Book-E pod |
The Rule
Each piece of data has exactly one owner. Other services read it through the owner's API.
Wrong
Review-E reads the events table directly via SQL
Right
Review-E calls GET /events?status=PROPOSED via the Event Store API
Database Access
Only the Event Store API has Postgres credentials. All other services go through HTTP APIs.
graph LR
B[Book-E] -->|HTTP| ES[Event Store API]
R[Review-E] -->|HTTP| ES
A[Accounting API] -->|HTTP called by| ES
C[Cost API] -->|HTTP called by| ES
ES -->|SQL| DB[(PostgreSQL)]
M[Metabase] -->|SQL read-only| DB
Systems of Record
Data we store is secondary. The systems of record are external:
| Data | System of Record | We store |
|---|---|---|
| Bank transactions | Folio | Events referencing Folio event IDs |
| Accounting entries | Fiken | Events referencing Fiken purchase/entry IDs |
| Receipts/invoices | Folio attachments | Events with file URLs, not the files |
| AI usage | Anthropic/Google/Cloudflare | Periodic cost snapshots |
We never duplicate financial data. Our events reference external IDs.