# Per-module integration axes (the embed lookup)

**Audience: AI coding agents.** Look target module up here BEFORE wiring. Do every marked axis; skip blanks. Axis legend (full detail in `SKILL.md` Step 1):
**A** siblings (peer `@platform-modules/*`) · **B** db (drizzle `pgTable` schema, host runs migration) · **C** stores (host-injected interface, real DB-backed impl) · **D** provider (SDK peer behind adapter) · **E** endpoint (web-standard `Request`→`Response` to mount) · **F** react (`-react` island/provider).

> **Risk order — embed low first.** Leaf (no axes) = near-zero risk; **B (db migration) and E (auth/webhook endpoint) riskiest** (live schema / trust boundary). Test loop on leaf before db/provider module. **Swap-parity target** = prior-app code the embed replaces — assert module output equals it.

| Module | Axes | Peers (A) | DB schema (B) | Stores (C) | Provider (D) | Endpoint (E) | Swap-parity target |
|---|---|---|---|---|---|---|---|
| **util** | — | — | — | — | — | — | prior-app `crypto.ts`/`tokens.ts`/`encryption.ts` |
| **seo** | — | — | — | — | — | — | prior-app jsonld + sitemap escaper |
| **i18n** | (E) | — | — | — | — | `./routing` locale negotiation (opt) | prior-app locale router / `Accept-Language` parse |
| **i18n-react** | F | react | — | — | — | — | prior-app React locale context |
| **realtime-react** | F | react | — | — | — | — | prior-app presence/channel hook |
| **tax** | (A) | db (opt) | — | — | — | — | prior-app IL-VAT schedule + `resolveVatRate` |
| **mail** | D | — | — | — | resend / ses / postmark / brevo | — | prior-app transactional-email send |
| **ai** | D | — | — | — | openai-compat / anthropic (fetch, no SDK) | — | prior-app LLM-call wrapper + fallback |
| **uploads** | D + leaf | aws4fetch | — | — | r2-binding / presign-s3compat | — | prior-app image validators (magic-bytes/dims/size) |
| **search** | A | db | host-owned tables (no own schema) | — | — | — | prior-app FTS query path |
| **ledger** ★ | A + B | db | `ledgerSchema` | — | — | — | prior-app credit-ledger append/balance |
| **helpdesk** | A + B | db | `helpdeskSchema` | — | — | — | prior-app support-message store |
| **tenancy** | A + B + C | db | `triadSchema` | `TenancyStore` | — | — | prior-app rbac + tenant isolation |
| **jobs** | A + B + D | db | outbox / poll tables | `IdempotencyStore` | cf-queues binding | — | prior-app outbox/queue runner |
| **notifications** | A + C + D | db, mail | — (host tables) | `PreferenceStore`, `DedupStore` | `./email` / `./webpush` channels | — | prior-app notify + preference resolve |
| **marketing** | A + C + D | db, mail | — (host tables) | `ComplianceStore`, `SelfManagedStore` | `./self-managed` / `./brevo` | — | prior-app campaign-send + suppression |
| **billing** | A + C + D + E | db, jobs, ledger, tax | — (uses ledger's) | `IdempotencyStore` | stripe / sumit | webhook `ingestWebhook` | prior-app charge + webhook ingest |
| **auth** | A + B + C + D + E | db, mail, util | `customAuthSchema` / `betterAuthSchema` | `OtpStore` | better-auth (engine-better-auth only) | session / OAuth handlers | prior-app raw-WebCrypto sessions · prior-app better-auth |
| **db** | (foundation) | drizzle, neon, postgres, pglite | the type contract itself | — | driver adapter per host PG | — | host's existing drizzle client |
| **realtime** | Step-0 gate | workers-types | core is **types-only**; `/server` (DO/Queue) real | — | — | DO fetch handler | — (don't embed the types-only core) |

## Reading the matrix

- **`(X)` parenthesised** = optional / partial (e.g. `tax` takes db handle only for persisted-rate variant; `./rates-table` alone = pure leaf).
- **"host-owned tables"** (search, notifications, marketing) = module needs `Database` handle but ships **no** `pgTable` — reads/writes *host's* tables. Host's existing schema = contract; no module migration, but host columns module expects must exist.
- **★ ledger** money-grade — its B-axis migration + append idempotency are hard-floor; embed only after leaf + plain db module (helpdesk) proven loop.
- Module with **multiple axes** embedded axis-by-axis in `SKILL.md` Step 3 order (B → C → D → E), each verified before next.