Architectural Constraints
CAP Theorem Position
Vespertene Shop is AP — Available and Partition tolerant. Consistency is eventual, not strict.
Rationale: A digital goods store prioritises completing purchases over strict consistency. A customer who pays should always get their download link, even if a secondary read replica is stale by a few seconds.
Practical Implications
- Read-your-own-writes consistency on account pages via cache-busting (
revalidatePath) — not relying on replica lag - Download token redemption is the ONE exception — atomic increment + guard in a single DB transaction
- Cart state is client-managed (Medusa JS SDK + cookie) — cart loss on network partition is acceptable; cart data is not orders
- Stripe webhook idempotency: deduplicate on Stripe event ID before creating download links — prevents double fulfilment on retry
Consistency Boundaries
| Operation | Consistency required | Implementation |
|---|---|---|
| Download token redemption | Strong (atomic) | Single DB transaction with row lock |
| Order creation on webhook | Idempotent | Upsert on Stripe event ID |
| Product page reads | Eventual (stale-while-revalidate) | Next.js cache, max-age=300 |
| Account/order history | Read-your-own-writes | revalidatePath on mutation |
| Cart state | Client-local | Medusa JS SDK + cookie |
Scalability Constraints (Phase 1)
- Single Fly.io instance — no horizontal scaling needed at Phase 1
- PgBouncer via Supabase for connection pooling (max 20 connections on free tier)
- Cloudflare R2 for file delivery — offloads all bandwidth from the server
- Phase 2: add Redis for Medusa event bus and caching when moving to Railway