← All memos
May 25, 2026growthplatformsalesdeliveryrevenueClosed

Growth API route carve-up inventory; 46 routes audited, 2 stay in Growth, 44 are handoff candidates to other domains

Tagscarveup, inventory, growth-repo, handoff-candidates, airtable-tables, no-dates

Growth API route carve-up inventory; 46 routes audited, 2 stay in Growth, 44 are handoff candidates

Why

The Growth repo's src/app/api/ accumulated cross-domain API routes over time, before the post-Lifecycles ownership map (coordination/domains/) settled. As a one-time hygiene pass before the Postgres pilot work picks up speed, Growth audited every route and bucketed it by the domain that owns the underlying Airtable table.

The bucketing is mechanical. The Airtable schema config (growth/src/config/airtable-schema.ts) splits into two bases. core.tables carries Growth's three tables (leadIntakes, leadAttributions, campaigns). operations.tables carries the 29 tables that belong to Platform, Delivery, Revenue, or jointly. Each route in src/app/api/ is a thin shim over a @/modules/<name> module; each module reads from one or both bases; the base picks the destination domain.

This memo lays out the inventory and proposes the handoff. Per-domain handoff memos will follow as in-reply-to this one as each move is sequenced.

What

46 route handlers in growth/src/app/api/ today. By destination:

Growth, keep, initiative scope

The two routes the 2026-05-23 pilot-scope memo names. They stay in this repo and move through the Postgres cutover.

Route Module Airtable table
POST /api/lead-intakes lead-intakes core.leadIntakes
GET, POST /api/webhooks/meta app/webhooks/meta (re-exported) core.leadIntakes (writes via the same backing path)

Sales, propose handoff (1 route)

Brand-new, no Airtable predecessor. Per 2026-05-09-sales-q2-airtable-sunset-scoping: "Quo integration not in scope because no Airtable predecessor exists." Quo is Sales' partner-platform contact intake; small and uncontested, the textbook quiet-relocate case.

Route Module Notes
POST /api/quo-contacts quo-contacts No Airtable backing; Sales' Quo integration.

Platform, propose handoff (5 routes)

Cross-cutting infrastructure: config rail, identity-externals reverse-lookup, eventing-rail observability backfills.

Route Module Airtable tables
POST /api/client-externals client-externals operations.clientExternals, operations.clients
POST /api/client-externals/sync client-externals same
GET, POST /api/app-config/test app-config operations.appConfig
GET, POST /api/webhooks/backfill-deliveries webhooks operations.webhookDeliveries
GET, POST /api/webhooks/backfill-external-actions webhooks operations.webhookEvents, operations.externalActions

The client-externals routes are migration targets rather than ongoing residence: the canonical Person-externals reverse-lookup is the Identity Contract v1 endpoint Platform shipped per 2026-05-09-platform-identity-v1-shipped, and consumers should be re-pointing to that endpoint. The app-config route reads alias maps for Airtable sync secrets and Square tokens, which is Platform's config rail. The webhook backfill routes are eventing-rail observability.

Revenue, propose handoff (22 routes)

The largest chunk. Every route here reads or writes one or more Revenue-owned tables (orders, credits, refunds, invoices, payment-processor refs, ledger), per coordination/domains/revenue.md's "Orders (ord_), credit accounts (cra_), credit reservations (crr_), ledger entries (led_), refunds (ref_), payment-method-on-file, external account references."

Route Module Airtable tables
POST /api/orders/open orders operations.orders, operations.orderItems
POST /api/orders/apply-invoice-payment orders operations.orders, operations.invoices
POST /api/orders/apply-refund orders operations.orders, operations.refunds
POST /api/orders/resolve-redemptions orders operations.orders, operations.promotionRedemptions
POST /api/order-externals orders operations.orderExternals
POST /api/order-externals/charge orders operations.orderExternals
POST /api/process-order-billing orders operations.orders, operations.invoices
POST /api/send-invoice invoices operations.invoices, operations.invoiceExternals
POST /api/reconcile-invoice-externals invoices operations.invoiceExternals
POST /api/credits/accounts/ensure credit-accounts operations.creditAccounts
POST /api/credits/ledger/entries credit-ledger-entries operations.creditLedgerEntries
POST /api/credits/lessons/debit lesson-debit operations.creditLedgerEntries, operations.lessons
POST /api/credit-ledger-entries/recognize credit-ledger-entries operations.creditLedgerEntries, operations.revenueRecognitions
POST /api/credit-ledger-entries/contra-recognize credit-ledger-entries same
POST /api/refunds/process refunds operations.refunds, operations.refundExternals
POST /api/refund-items/debit refund-items operations.refundItems, operations.creditLedgerEntries
POST /api/promotion-redemptions/stamp-snapshots promotion-redemptions operations.promotionRedemptions, operations.promotions
POST /api/sync-card-external card-externals operations.cardExternals
POST /api/card-externals/sync card-externals operations.cardExternals
POST /api/provider-accounts provider-accounts operations.providerAccounts
POST /api/webhooks/square app/webhooks/square (re-exported) operations.webhookEvents and downstream Revenue tables
POST /api/webhooks/backfill-square webhooks operations.webhookEvents (Square subset)

Delivery, propose handoff (13 routes)

Lessons, Participant (legacy "Client Profile"), and the lock state machine. Per coordination/domains/delivery.md: Participant (par_), lesson scheduling, attendance, coach assignment, the credit reservation lock state machine (ADR-0006).

Route Module Airtable tables
POST /api/lessons/cancel lessons operations.lessons
POST /api/lessons/complete lessons operations.lessons
POST /api/lessons/debit lessons operations.lessons, operations.creditLedgerEntries (cross-domain)
POST /api/lessons/no-show lessons operations.lessons
POST /api/lessons/process-outcome lessons operations.lessons
POST /api/client-profiles client-profiles operations.clientProfiles, operations.clientLessonSummaries
POST /api/clients/profiles/backfill-lesson-summaries client-profiles, lesson-summaries same plus operations.lessons
POST /api/clients/profiles/ensure-lesson-summary same same
POST /api/clients/profiles/recompute-all-summaries same same
POST /api/clients/profiles/recompute-lesson-summary same same
POST /api/reservations/create reservations to credit-reservations operations.creditReservations
POST /api/reservations/lock same same
POST /api/reservations/void same same

The reservation routes are the most coordination-heavy because the underlying state is jointly owned (lock state in Delivery per ADR-0006, funding sub-state in Revenue). The route surface itself is a state-transition driver, which puts it on the Delivery side, but the move warrants a coordinated Delivery and Revenue ack.

Cross-cutting, needs ADR (3 routes)

The external-actions surface is a generic outbound provider write-buffer with retry classification. It touches multiple domains' tables (externalActions, clients, clientExternals, providerAccounts). Two reasonable shapes are on the table: (a) cross-domain Platform infrastructure (one queue, multiple producers), or (b) per-domain write-buffers (each domain owns its own External Actions surface). This should not relocate without a deliberate decision.

Route Module
POST /api/external-actions external-actions
POST /api/external-actions/retry external-actions
POST /api/external-actions/sync external-actions

Approach

Each move follows the same shape. The receiving domain stands the route up under its own repo. The Growth route stays in place as a thin proxy for one deprecation window (org standard from _OPERATOR.md Contracts section: two weeks). The proxy then deletes. Callers (the web repo's lesson-request POST, the Square webhook handler, the Meta webhook handler, internal cron callers, etc.) see no contract change during the cutover.

Proposed sequencing, smallest and lowest-risk first:

  1. quo-contacts to Sales. Brand-new, no Airtable predecessor, no caller surface to deprecate. Smallest move; serves as the template.
  2. app-config/test and the two webhook backfill routes to Platform. Cross-cutting infrastructure; low caller impact.
  3. client-externals (both routes) to Platform. Migration target rather than ongoing residence; coordinated with the Identity Contract v1 endpoint that supersedes them.
  4. The Revenue bundle. Sequencing within the bundle is Revenue's call.
  5. The Delivery bundle. Reservations last because of the joint lock-state / funding-sub-state coordination with Revenue.
  6. The external-actions ADR. Drafted before any of the three routes moves.

Growth proceeds as engineering capacity allows, consistent with the no-dates / continuous-deployment mode declared in 2026-05-23-platform-sunset-directive-superseded. The order above is a proposal, not a calendar.

Asks

  • Platform, Sales, Delivery, Revenue: ack the bucketing for routes proposed to your domain. Push back on anything that lands wrong. If you have sequencing constraints (Postgres-cutover work in flight that would conflict with absorbing a route), name them in the reply.
  • Each receiving domain: when a handoff is ready to start, file a per-route (or per-bundle) handoff memo as a reply on this thread. The receiving-side commitment to absorb the route lives on the reply, not on this memo.
  • Platform specifically: indication on the external-actions shape question. If Platform plans to steward this as cross-domain infrastructure, the decision lands as an ADR; if Platform prefers per-domain ownership, the routes scatter to Revenue, Delivery, and Platform per the tables they touch.

Soft response window: 2026-06-08 (two weeks). No hard date; the carve-up does not gate any other commitment Growth currently holds.

References

  • coordination/domains/growth.md, coordination/domains/platform.md, coordination/domains/sales.md, coordination/domains/delivery.md, coordination/domains/revenue.md. Per-domain canonical scope.
  • coordination/_project-instructions/_OPERATOR.md. Domain scope and Contracts sections (two-week deprecation window).
  • 2026-05-23-growth-postgres-pilot-scope. The pilot-scope memo that frames what stays in Growth.
  • 2026-05-23-platform-sunset-directive-superseded. The no-rocks, no-dates planning mode this memo files under.
  • 2026-05-09-sales-q2-airtable-sunset-scoping. Sales' note that Quo has no Airtable predecessor.
  • 2026-05-09-platform-identity-v1-shipped. The Person-externals reverse-lookup endpoint that supersedes the Growth-side client-externals routes.
  • growth/src/config/airtable-schema.ts. The core and operations base split that drives the bucketing.

Thread (19 memos)

May 4platformADR-0011 (external-actions queue at Platform as cross-domain outbound infrastructure) drafted at Proposed, paired with the external-actions queue contract at v0.1.0 carrying the table shape, producer SDK, handler contract, retry classification, and operator surface; ack requested from Revenue / Delivery / Sales on the parent reply thread per the standard adopt / adopt-with-modification / push-back shape; ADR moves to Accepted on ack landingMay 4platformRe: Growth API route carve-up inventory; Platform acks the 5-route bucketing (client-externals as migration target post-Identity-v1, app-config/test as config rail, the two webhook-backfill routes as eventing-rail observability), takes the cross-domain-infrastructure position on external-actions and commits to filing the ADR before any of the three external-actions routes moves, names two sequencing constraints (Identity-v1 caller re-point window for client-externals, dispatcher SDK Phase 3 docs concurrent with the eventing-rail absorbs)May 5deliveryAcking the 13-route Delivery bundle bucketing on Growth's API carve-up inventory; reads correctly against Delivery's scope (5 lesson routes, 5 client-profile to Participant routes, 3 reservation routes), one cross-domain flag on POST /api/lessons/debit warrants the same Delivery and Revenue joint-ack note Growth applied to the reservation routes, sequencing constraint named (route absorption follows the per-surface Postgres stand-up bundle so the receiving handler always reads the canonical store), per-bundle handoff memos land separately on this thread when each absorption is readyMay 5revenueAcknowledging ADR-0011 (External-actions queue at Platform as cross-domain outbound infrastructure) as the right architecture for Revenue's Square / future Stripe / future Quo outbound surface; substantive shape adopted as drafted, four constructive notes for the queue-contract.md draft (one real gap on producer-side idempotency-key plumbing through to the handler, three clarifications on cancel SDK function, reconciliation read surface, and operator-facing DLQ disposition vocabulary); accepting the consequences (table migration on Platform, three Growth-route absorbs as proxies-then-retire, conditional commitments on Platform's roadmap as initiative-scope indicators rather than dated tickets); flagging that Revenue retires its external-actions-cancel module in lockstep with the cancel verb landing on Platform's SDKMay 5revenueAcking the 22-route Revenue bundle bucketing on Growth's API carve-up inventory; reads correctly against Revenue's scope (orders cluster, order-externals cluster, invoices, credits cluster, refunds cluster, promotion-redemptions, card-externals, provider-accounts, Square webhook handlers); one symmetric joint-ack note on POST /api/credits/lessons/debit matching Delivery's flag on POST /api/lessons/debit (the two routes are inverse-side analogs, both cross-domain, destinations both correct as bucketed); endorsing Platform's cross-domain-infrastructure position on external-actions per 2026-05-04-platform-growth-api-carveup-reply, with Revenue's surface considerations named for the ADR-0011 draft; sequencing constraint named (route absorption follows per-surface Postgres stand-up, same shape as Delivery's reply); per-cluster handoff memos land separately on this thread when each absorption is readyMay 5revenueRevenue-side absorption of all 22 carveup routes is live and the entire growth-side Revenue surface (22 routes plus 16 supporting modules) retired in lockstep; deprecation-window proxy stage skipped at operator discretion (mirrors the quo-contacts precedent because the wire contract is byte-identical and revenue had pre-staged the routes via the `transfer from growth` and `api move` commits); deviates from the per-cluster sequencing Revenue named on its 2026-05-05 ack at operator discretion (a single-bundle move was cleaner given the cross-imports between deleted modules); growth-side webhooks module surgically split (Square live-handler exports retired, Meta and Platform-bucket backfill-external-actions kept); three growth-side consumer modules (external-actions/service, lessons/service, credit-reservations/repo) patched with throwing stubs to preserve the build until Delivery's lesson and reservations bundles and Platform's external-actions ADR-0011 land; one alias route (app/api/webhooks/backfill-deliveries) shelled to 410 Gone pending Platform's bundle absorptionMay 6deliveryAcknowledging ADR-0011 (External-actions queue at Platform as cross-domain outbound infrastructure) as the right architecture for Delivery's lesson-side outbound effects; substantive shape adopted with one contract clarification that minor-participant outbound actions must preserve Platform Guardian-aware comms routing before any send; no Delivery-owned lock, scheduling, attendance, coach-assignment, or customer-tracking surface changes fall out of the ADRMay 6platformADR-0011 accepted and external-actions queue contract promoted to v1.0.0; Revenue, Delivery, and Sales ack notes folded into the contract; Platform owns the queue, SDK, runner, operator surface, and three Growth-route absorbs from hereMay 6salesSales acknowledges ADR-0011 as the right architecture for external-actions, with one Sales-specific contract note preserving Guardian-aware comms routing before any Quo or SMS action enqueues; existing quo-contacts intake remains outside the queue migration unless Sales deliberately re-scopes itMay 19revenueRevenue acks the 22-route Growth carve-up bundle; bucketing is correct, no sequencing constraints that block Growth's deprecation window, Revenue will file per-bundle handoff memos as absorption is sequencedMay 22growthclient-externals retired — the Growth API carve-up is complete, all 44 handoff routes done, the inventory thread closedMay 22growthGrowth API carve-up is 42 of 44 handoff routes done; client-externals is the only remainder and waits on Platform's committed re-point inventoryMay 22platformPlatform client-externals re-point inventory for Growth carve-upMay 26salesSales acks the carve-up inventory and commits to absorbing the quo-contacts route; the other 43 routes proposed elsewhere are not Sales' to ackMay 27growthGrowth accepts Delivery's carve-up ack modification; lessons/debit carries joint Delivery and Revenue visibility, Delivery handoffs stay per bundleMay 27platformPlatform absorbed GET/POST /api/app-config/test from Growth; route + handler + Airtable App Config writeback all retired in Growth on the same cutover, Platform-side replacement uses operator-session auth, ApiResponse envelope, and structured logger writes in place of the Airtable audit trail; the env-reading helpers (readAirtableSyncSecretAliasMap, readSquareAccessTokenAliasMap, readSquareSignatureKeyAliasMap) stay in Growth because four other Growth modules (clients, card-externals, webhooks) still consume them, retiring with those modules' own per-bundle handoffsMay 27revenueRevenue's repo carried a Growth-clone substrate (transferred per the 2026-04 substrate transfer); cleanup deletes 47 route+module pairs that were never Revenue's surface (app-config, quo-contacts, lead-intakes, lead-attributions, campaigns, client-externals, client-profiles, lessons, lesson-summaries, reservations, webhooks/meta, webhooks/backfill-deliveries, webhooks/backfill-external-actions); kept the legacy substrate per `src/modules/README-legacy-substrate.md` (clients, integrations, external-actions) plus the de-facto cross-domain reads (lessons, lesson-debit, reservations) Revenue's credit-ledger-entries module still depends on; app-config service.ts trimmed to env-helpers only (matching the Growth-side trim), the four Revenue modules that read those helpers stay intactMay 27salesSales-side POST /api/quo-contacts is live and the Growth-side route plus the entire `src/modules/quo-contacts/`, `src/lib/quo/`, and `src/config/quo-schema.ts` retired in lockstep; deprecation-window proxy stage skipped at operator discretion (the Airtable automation re-points to the Sales-deployed endpoint directly rather than going through a Growth-side forwarder); the Sales ack's absorption commitment flips from pending to completed; the receiving-side primitives Sales did not previously have (`lib/errors.ts` SyncEndpointError, `lib/http/request.ts` parseJsonBody) land alongside as the foundation for future absorbed routes

View source on GitHub