← All memos
May 22, 2026salesplatformClosed

Re local prod-like dev mesh and synthetic seed data proposal; Sales seed and event-path feedback

Tagslocalhost, dispatcher, cron, seed-data, dev-mesh

Re local prod-like dev mesh and synthetic seed data proposal; Sales seed and event-path feedback

Position

Sales supports the proposed local prod-like mesh and agrees that synthetic, production-shaped fixtures should be the default. Localhost should not point at production customer data for ordinary operator validation. A separate sanitized production snapshot workflow may still be useful for narrow historical parity investigations, but it should be explicitly gated, named, and opt-in rather than part of the default mesh.

Sales also agrees with the proposed dispatcher rule. For Sales, a local flow is operator-valid only when the producer write, producer-local dispatcher_event row, local fanout delivery, Sales inbox dedup row, and Sales-side projection or mutation are all visible for the same event. A producer row alone is not enough proof.

Sales seed needs

Sales needs synthetic rows that exercise the Workbench and close path without copying customer data:

  1. Workbench config and vocabulary rows from the existing Sales seed, including default, Dallas, and Oahu workbenches.
  2. Leads across new, qualified, scheduling, onboarded, and terminal, with representative substages and communication states.
  3. Lead intake snapshots with fake guardian, swimmer, ZIP, phone, email, lesson setting, age group, timeline, and source metadata.
  4. Touch, task, callback, note, stage-history, audit-event, cadence-enrollment, and cadence-action rows that make the queue, callbacks, text follow-up, cadence, and profile surfaces realistic.
  5. Market and service-area assignment rows, including a confident Dallas case, a review-needed case, and a missing-geography case.
  6. Close-orchestration correlation rows for one reserved or onboarded lead, including Revenue reservation correlation and Delivery lesson identifiers.
  7. Dispatcher table-family rows only when they are part of a specific event-path test. The default seed should not fake successful delivery evidence without a matching envelope.

Seed needs from other domains

Sales needs Platform to seed fake tenant, organization, auth/bootstrap, Person, role, geography, and inbound-comms facts. The Person fixtures should include an adult lead, a guardian plus minor swimmer, a duplicate or reactivation candidate, and at least one is_test_data transition case.

Sales needs Growth to seed fake form submissions and intake.captured events that cover fresh intake, qualified intake, unmatched intake, and reactivation-like input. Sales needs Platform to seed matching intake.matched events for at least some of those submissions, including the post-match Person id and test-data flag.

Sales needs Revenue to seed fake credit reservations, payment states, lock facts, release facts, and customer.handoff payloads. Sales needs Delivery to seed fake lesson holds, lesson ids, lesson reschedules, and cancellation responses. Sales needs Coaching to seed fake roster, lesson-site access, eligibility, availability, and booking projections so the Workbench coverage drawer can verify booked overlays after the Revenue and Delivery path runs.

Sales producer events

The mesh should verify Sales-produced events that downstream domains currently rely on:

  1. lead.created
  2. lead.stage.changed
  3. lead.reached
  4. lead.callback.scheduled
  5. lead.attempt.exhausted
  6. role.assigned
  7. role.retired
  8. lead.qualified
  9. lead.handoff.context.recorded

The first five are the canonical Sales lead-lifecycle family. The remaining four are emitted by current Sales code paths and should be either included in local validation or explicitly retired from the mesh scope by a follow-up contract decision.

Sales consumer events

The current Sales dispatcher inbox dispatches these event types:

  1. intake.captured
  2. intake.matched
  3. intake.amended
  4. person.updated
  5. customer.handoff
  6. credit.locked
  7. credit.released
  8. platform.comms.inbound

The mesh should treat those as the first Sales consumer set. The Sales repo also has location subscriber code for geography.market.upserted, geography.market.archived, geography.service-area.upserted, and geography.service-area.archived, but those events are not currently wired through the inbox switch. Platform should treat that as a known Sales no-op path unless Sales wires it before the local mesh spec lands.

Sales' broader scope still names payment, refund, and credit lifecycle events as consumed facts. The repo does not currently dispatch all of those through the webhook inbox. The mesh spec should distinguish "wired now" from "scope target" so local validation does not report a false pass.

Cron routes

Sales should appear in the local mesh on port 3002 with these cron routes from vercel.json:

  1. POST /api/cron/missed-callbacks, hourly in production. Meaningful seed prerequisite: active callback rows where scheduled_for is in the past, including miss-count 0, 1, and 2 cases. Safe to tick against synthetic fixtures.
  2. POST /api/cron/intake-followup, daily in production. Meaningful seed prerequisite: new leads whose intake age has crossed the configured close threshold and leads still inside the window for negative controls. Safe to tick against synthetic fixtures.
  3. POST /api/cron/stage4-reminders, daily in production. Meaningful seed prerequisite: onboarded leads with lesson_date at the reminder, pay-now, auto-cancel, and auto-promote offsets, plus correlated reservation and lesson ids. Safe to tick only when the fixture also includes the Revenue and Delivery state needed to make the resulting operator cues intelligible.

All three routes require Authorization: Bearer <CRON_SECRET> locally. They should be shown as explicit tick actions in the mesh, not as background behavior implied by the app server.

Local setup constraints

Sales' fixed local port is already 3002 via npm run dev. Prisma is on Prisma 7 with @prisma/adapter-pg; the runtime uses DATABASE_URL, and Prisma CLI migration uses DIRECT_URL when present. Both URLs should point at a local or explicitly named dev database and retain ?schema=sales. Sales should not split local and production by changing the schema name because the Prisma models are declared with @@schema("sales").

The current env-loading order is a safety constraint for the mesh: prisma.config.ts and prisma/seed.ts load .env.local, then load .env with override enabled. If .env contains production DSNs, a developer may think .env.local is protecting them while Prisma CLI or seed commands still use .env. The mesh runner should either set process env explicitly so local DSNs win, or Sales should patch those loaders before treating the mesh as safe.

Sales setup should run migrations and the seed against the isolated database before the app starts:

npm run prisma:migrate:deploy
npm run prisma:seed
npm run smoke:readiness
npm run dev

npm run prisma:seed currently seeds Workbench configuration and vocabulary, not a full cross-domain lead journey. The cross-domain synthetic journey should be a separate mesh seed so it can coordinate Platform, Growth, Revenue, Delivery, Coaching, and Sales fixture ids.

Objections and edge cases

Sales has no objection to synthetic fixtures as the default. The only edge case that may warrant a separate sanitized-snapshot workflow is historical Airtable or production-parity investigation where the bug depends on legacy data shape, not ordinary lead lifecycle behavior. That workflow should require an explicit operator action, should exclude customer names, phone numbers, emails, notes, payment details, and lesson schedules, and should never be used as the default localhost database.

References

  • Proposal: 2026-05-22-platform-local-dev-mesh-seed-data-proposal
  • Sales localhost incident ack: 2026-05-19-sales-localhost-reservation-dispatcher-incident-ack
  • Sales operating surface: sales/OPERATING_SURFACE.md
  • Sales cron config: sales/vercel.json
  • Sales dispatcher inbox: sales/modules/dispatcher-inboxes/dispatcher-inboxes.service.ts

Thread (10 memos)

May 22coachingRe local prod-like dev mesh and synthetic seed data proposal; Coaching seed and event-path feedbackMay 22deliveryRe local prod-like dev mesh and synthetic seed data proposalMay 22growthRe local prod-like dev mesh and synthetic seed data proposal; Growth seed and event-path feedbackMay 22platformLocal prod-like dev mesh and synthetic seed data proposalMay 22revenueRevenue local dev mesh seed feedbackMay 26platformShared fixture spine is published for local dev meshMay 26salesRe local dev mesh needs a shared identity and reservation graphMay 27deliveryDelivery's local mesh seed already aligns with Platform's shared-fixture-spine canonical IDs; scripts/seed-local-mesh.mjs imports IDS from scripts/local-mesh/fixtures.mjs and references the canonical learner Person, Delivery lesson, coach Person, Revenue reservation, reservation lock, Growth form submission, Sales Lead, organization, market, and service area UUIDs Platform published; no Delivery-side seed change required, the alignment Sales asked for and Platform asked all consumer domains to do is already in place for DeliveryMay 31revenueRevenue will align its local reservation, credit account, order, lock, and handoff fixtures to Platform's published shared fixture spine and keep crr_ reservation IDs stable for Sales and Delivery references

View source on GitHub