Multi-Tenant Routing & Isolation
Flour n Sugar treats each baker/store as an independent tenant from day one, ensuring strict data boundaries while running on a unified, high-performance web infrastructure.
Architectural Patterns
Incoming Request
│
├───> Path: /api/*, /admin/*, /locations/*, /categories/*
│ └── Served by Central Marketplace / System Handlers
│
└───> Path: /:storeSlug (e.g., /webake)
│
├── 1. Middleware Checks Reserved Slugs (api, admin, etc.)
├── 2. Query Store by Slug (Prisma cache layer)
├── 3. If Store is Published -> Hydrate Tenant Storefront Page
├── 4. If Store is Unpublished -> Render "Under Construction"
└── 5. If Store Not Found -> Render Branded 404 with Discovery Suggestions
Data Isolation Strategy
Data isolation is enforced at the database and application authorization layers:
1. Tenant Membership
A user can belong to multiple stores. Platform authority and store authority are deliberately separate:
model Store {
id String @id @default(uuid())
slug String @unique
name String
members StoreMember[]
products Product[]
}
model StoreMember {
userId String
storeId String
role StoreRole // OWNER, MANAGER, BAKER, STAFF, DELIVERY, ACCOUNTANT
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
store Store @relation(fields: [storeId], references: [id], onDelete: Cascade)
@@unique([userId, storeId])
}
2. Authorization Boundary Enforcement
- Public Reads: Public visitors can only query stores where
status == "PUBLISHED". - Role-scoped writes: Mutations verify the active user's membership and the required store role; platform moderation uses the separate
PlatformRole. - Cross-tenant guard: A user may access or mutate a store resource only through a membership for that store. Authorization tests must cover attempts against another store's resources.
Caching & Revalidation Strategy
Because baker menus do not change every second, public storefront pages benefit from Incremental Static Regeneration (ISR):
- Initial Render: Pre-rendered at edge or on first request.
- Cache Revalidation: Cached with an
s-maxage=60, stale-while-revalidate=300header. - On-Demand Cache Purge: When a baker updates a product price or toggles an item out of stock in their dashboard, the API triggers an instant revalidation tag for
store-[slug], ensuring instant updates without waiting for cache TTLs.