docs: document cross-stack DynamoDB data contracts (INFRA-138) #79

Merged
amoussa1229 merged 1 commit from INFRA-138-document-dynamo-contracts into main 2026-07-08 20:22:56 +00:00

View file

@ -82,6 +82,22 @@ EventBridge (daily 02:00 UTC)
This bot reads the `purchase-orders` DynamoDB table **read-only** (via the `po-sync` and `wo-po-lookup` Lambdas, both granted `grantReadData`). The table is owned by the `procurement-ingest` repo (`po-ingest` stack), which is the sole authoritative writer. Any change to the `purchase-orders` schema must be coordinated with `procurement-ingest` (owner) and `payments-dashboard` (the other read-only consumer).
## Cross-stack data contracts
This bot does **not own any DynamoDB tables.** It imports five tables owned by other stacks via `Table.fromTableName(...)` (`lib/constructs/bedrock-agent.ts`, `workorder-sync.ts`, `po-sync.ts`) and reads them read-only. Because the tables are imported by name, this stack has no compile-time link to the owner: an owner-side change to a table's name, key schema, attribute names, GSIs, encryption key, or lifecycle policy will **silently break the Bedrock agent (Alex)** at runtime, not at deploy. The CMK grant-gap incident (INFRA-95 / M-3) is precedent: because `grantReadData` on an imported table does not carry KMS permissions, every read failed with `kms:Decrypt AccessDenied` until an explicit grant was added.
Owner-side changes to any of these tables must be coordinated with this repo before they ship. Treat them as cross-repo migrations, not local edits.
| Table | Owner repo / stack | Keys the bot depends on | Attributes the bot reads | Encryption |
|---|---|---|---|---|
| `WorkOrders` | `procurement-ingest` / `WorkorderIngestStack` (`cdk/wo_stack.py`) | PK `work_order_id` (S). `GetItem` by id; full-table `Scan` in `workorder-sync`. | `work_order_id`, `description`, `wo_status`, `customer`, `site_code`, `building`, `address`, `severity`, `priority`, `assigned_to`, `date_reported`, `scheduled_start`, `due_date`, `updated_at` | Shared CMK (`/seahaven/dynamodb/cmk-arn`) |
| `WorkOrderComments` | `procurement-ingest` / `WorkorderIngestStack` (`cdk/wo_stack.py`) | PK `work_order_id` (S), SK `comment_id` (S). `Query` by `work_order_id`. | `work_order_id`, `created_at` (used for sort), `commenter`, `text` | Shared CMK (`/seahaven/dynamodb/cmk-arn`) |
| `purchase-orders` | `procurement-ingest` / `po-ingest` (`cdk/po_stack.py`) | PK `po_number` (S). `GetItem` by number; full-table `Scan` in `po-sync`. | `po_number`, `po_status`, `email_type`, `cancelled_at`, `total_amount`, `currency`, `supplier.name`, `source_system`, `order_date`, `revision_date`, `payment_terms`, `requisition_number`, `department`, `submitted_by`, `on_behalf_of`, `ship_to.{name,address,location_code,attn}`, `line_items[].{description,amount,currency,need_by,category}` | Shared CMK (`/seahaven/dynamodb/cmk-arn`) |
| `verified-sites` | `procurement-ingest` / `po-ingest` (`cdk/po_stack.py`) | PK `siteCode` (S). `GetItem` by code, **and `Query` on GSI `by-state`** for state listings. | `siteCode`, `address`, `fullAddress`, `city`, `state`, `zip`, `latitude`, `longitude`, `notes` | AWS-managed (NOT CMK) |
| `PaymentsDashboard` | `payments-dashboard` / `payments-dashboard` (`template.yaml`) | PK `pk` (S), format `payment#<check_number>`. `GetItem` by pk; full-table `Scan` filtered `begins_with(pk, "payment#")`. | `pk`, `check_number`, `payee`, `amount_usd`, `method`, `status`, `send_payment_on`, `clear_status`, `cleared_date`, `invoice_numbers`, `company_subsidiary`, `bank_reference` | CMK (shared) |
**Known broken contract (verified-sites `by-state` GSI):** `lambda/wo-po-lookup/index.ts` still queries `IndexName: 'by-state'` for state-based site listings, but the owner removed that GSI on 2026-06-03 (procurement-ingest audit M-20, "0 reads in 30d"). State listings (`lookup_site` with a `state` arg) therefore fail at runtime today. Point-lookups by `siteCode` are unaffected. This needs either the GSI restored owner-side or the state-listing path removed from the bot.
## Documentation
The canonical map of Sea Haven's AWS infrastructure lives in Confluence. This project's `seahaven-slack-bot` stack is represented there as a Mermaid subgraph.