Revenue local dev mesh seed feedback
Position
Revenue supports synthetic fixtures as the localhost default. Localhost should not point at production commercial data by accident, and Revenue should treat any sanitized production snapshot as a separate, explicitly gated workflow for narrow reconciliation cases only.
The Revenue local mesh should prove money-state transitions without using real names, contact fields, lesson schedules, payment details, customer notes, provider tokens, or business-sensitive snapshots. The fixtures can be fake, but they need to preserve contract shape, state sequencing, id prefixes, provider-reference fields, and dispatcher envelope behavior.
Revenue seed needs
Revenue needs a synthetic organization and tenant posture, including the single-tenant org_sguild default, fake provider-account configuration, and fake Square or manual provider references that are clearly not production references.
Revenue needs fake Persons by person_id only. Revenue should not seed canonical Person fields locally because Platform owns Person identity. The local fixture should include at least one payer or guardian person, one participant person when needed by reservation payloads, and one person with no prior lock so the first credit.locked path emits the customer.handoff sidecar.
Revenue needs fake credit accounts, orders, order items, promotion redemptions where discount flows are being exercised, credit ledger entries, credit reservations, lessons or lesson references, refunds, refund items, provider accounts, order externals, refund externals, external actions, webhook event rows, idempotency records, and empty dispatcher producer and inbox tables. The reservation set should cover RESERVED, LOCKED, CONSUMED, RELEASED, VOIDED, and FORFEITED, plus funding states PENDING_FUNDING, FUNDED, REFUNDING, REFUNDED, and NOT_APPLICABLE.
For end-to-end validation, the minimum story should be: fake intake or sales action results in a Platform Person, Revenue creates an order and credits, Revenue creates and funds a reservation, Delivery attaches or creates the lesson hold, Revenue locks the reservation, Revenue emits customer.handoff on the first lock for that person, Delivery later emits lesson delivery, Revenue consumes the credit, and refund or release paths can be exercised against the same fake graph.
Inputs from other domains
From Platform, Revenue needs fake identity responses for the seeded person_id values, service JWT or a local auth stub posture, and the local dispatcher fanout configuration. The fake identity payloads need to be stable enough that Revenue can call Platform by person_id without storing canonical identity fields.
From Sales, Revenue needs synthetic order or reservation initiation payloads that preserve the current commercial fields: person reference, offering or offer item context, lesson window, participant, service area, lesson type, credit quantity, price, currency, and idempotency key.
From Delivery, Revenue needs synthetic delivery.lesson-hold.created and lesson.delivered events tied to the Revenue reservation and lesson identifiers. The lesson.delivered event should include enough payload to run the credit consumption path and prove the local inbox dedup row maps to the downstream ledger mutation.
From Growth and Coaching, Revenue does not need direct seed ownership for the first Revenue validation pass. Revenue only needs their upstream and downstream effects represented through Platform Person, Sales commercial initiation, Delivery lesson state, and dispatcher fanout proof.
Dispatcher surface
Revenue producer events that make the mesh useful are order.created, order.updated, credit.purchased, credit.reserved, credit.funded, credit.locked, customer.handoff, credit.consumed, credit.released v2, credit.forfeited, payment.received, payment.failed, refund.initiated, refund.completed, reservation.funded, reservation.refunding, and reservation.refunded.
For local validation, credit.released v1 should not be part of the default mesh. It is deprecated; the default should exercise v2 with the reason-code partition visible.
Revenue consumer events are delivery.lesson-hold.created and lesson.delivered. If Platform wants the mesh to prove Revenue's own reconciliation subscriber for credit.consumed, that should be an explicit second-pass case rather than the first local operator-valid path.
Revenue agrees with Platform's dispatcher rule: a producer-local dispatcher_event row is not enough. The Revenue pass condition should include the Revenue transaction commit, the producer-local event row, fanout delivery to the expected local consumer, the consumer inbox dedup row, and the expected consumer projection or ledger side effect.
Cron routes
Revenue's scheduled routes in vercel.json are /api/cron/reservation-job and /api/cron/idempotency-cleanup.
/api/cron/reservation-job is meaningful when the seed includes funded and pending-funding reservations with attached lesson windows near the lock threshold, credit accounts, order or ledger context, and first-lock marker state. This tick can mutate reservation status, ledger entries, and dispatcher output, so it should require an explicit operator action.
/api/cron/idempotency-cleanup is safe against synthetic fixtures when the seed includes expired and unexpired mutating API idempotency records. It should still require the local cron secret, but its expected effect is bounded cleanup.
Revenue also has /api/cron/lesson-completion-reconciliation in the repo even though it is not currently listed in vercel.json. The local mesh should either surface it as a manual utility route or Platform and Revenue should decide separately whether it belongs in Vercel cron. It is meaningful when the seed includes completed lesson rows or a delivered-lesson dispatcher path that should produce credit consumption.
Local setup constraints
Revenue should run on port 3005 in the mesh. The current npm run dev script does not pin a port, so the orchestration helper should invoke Revenue with an explicit port or Revenue should add a mesh-specific dev command later.
Prisma is on the Prisma 7 shape. Runtime queries use DATABASE_URL through the PrismaPg adapter, and Prisma CLI commands use DIRECT_URL when present through prisma.config.ts. Both URLs need a ?schema=revenue query parameter for the app schema, and test commands force ?schema=revenue_test through scripts/with-revenue-test-env.mjs.
Revenue's current foot-gun is that .env.local is absent in some local checkouts, so Next and Prisma can fall back to .env. The mesh spec should require a local or explicitly named dev database in .env.local, and should treat production DSNs in localhost as an opt-in production-read mode, not the default. The same rule should apply to Square, Airtable, JWT, dispatcher, and cron secrets.
Dispatcher is also a known setup constraint. Revenue's wrapper can no-op unless a real transport is installed at startup. A local operator-valid mesh therefore needs DISPATCHER_BUS_ENABLED=true, a concrete local transport, local producer DSNs, local inbox URLs, and shared local HMAC secrets. DISPATCHER_DEBUG=true is useful for observing would-be emits during setup, but debug logging is not proof of fanout.
Snapshot exceptions
Revenue has no objection to synthetic fixtures as the default. The only cases that may need a separate sanitized-snapshot workflow are reconciliation cases where the bug depends on historical provider drift, duplicate webhook delivery history, imported Airtable legacy IDs, legacy Square status oddities, rounding edge cases across old order items and refund items, or a specific production incident timeline.
Those cases should not be part of ordinary localhost startup. They should be named, time-boxed, stripped of customer identity and notes, and run against an explicitly labeled dev database with sandbox or inert provider credentials.
References
2026-05-22-platform-local-dev-mesh-seed-data-proposal2026-05-19-revenue-localhost-reservation-dispatcher-positionadrs/ADR-0009-dispatcher-cross-process-transport.mdcoordination/domains/revenue.mdrevenue/vercel.jsonrevenue/lib/dispatcher.README.md