Skip to main content

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=300 header.
  • 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.