Data model
The proposed data model. This is a draft for discussion with the partner — field names and relations are refined during implementation in DirectusDirectusAn open-source headless platform on top of PostgreSQL: provides the data model, REST/GraphQL API, authentication, RBAC and a ready-made admin UI without writing code..
Key idea — brand_id everywhere
Almost every business table carries brand_id (directly or via a relation). TenantTenantA logically isolated customer in a multi-tenant system. In Ghost Kitchen a tenant is a brand: its data is separated from others by `brand_id` and access rules.
isolation is built on it: access policies filter rows by the user's brand.
ER diagram (draft)
Notes on key entities
brand— the tenantTenantA logically isolated customer in a multi-tenant system. In Ghost Kitchen a tenant is a brand: its data is separated from others by `brand_id` and access rules..domain,theme(colors/logo),settings(currency, language, checkout policy).kitchen— a brand's location. Delivery zones and time slots live here (not in a paid plugin).menu_item— a menu itemMenu itemAn individual dish or product in a brand's menu available for ordering. May have modifiers and an associated SKU. at the brand level;skulinks to accounting.kitchen_menu_item— publishing an item at a specific kitchen with optional local price/availability (stop-list).modifier_group/modifier— modifiersModifierAn option that alters a menu item: add-on, size, doneness, ingredient removal. May affect the price. (size, add-ons) withmin/maxselection rules.order/order_item/order_item_modifier— the order as a snapshot: prices are frozen at order time (unit_price_cents) so later menu changes don't alter history.payment— the payment in MollieMollieA European payment provider. Accepts payments (cards, iDEAL, Apple/Google Pay, etc.) and reports payment status via webhooks.;provider_payment_idfor reconciliation and webhook idempotencyIdempotencyThe property of an operation yielding the same result when repeated. Protects against duplicate orders/payments when a webhook is redelivered or a request is retried..customer— a single customer at the platform level (cross-brand analytics and loyalty).user_role— the user × role × scope (brand/kitchen) link for RBACRBACRole-Based Access Control — access management based on roles. Permissions are granted to a role (Company Admin, Brand Admin, Restaurant Manager) rather than to each user individually..
Money and time
- All amounts are in the minor currency unit (
*_cents, integers) to avoid losing cents to floating point. - All timestamps are in UTC; the UI converts them to the kitchen's time zone.
:::warning Open questions
- Is separate inventory/stock tracking needed, or is a kitchen stop-list enough?
- Delivery addresses/zones — free text, a geocoder, or zone polygons?
- Are promo codes/loyalty needed in the MVP or in phase 2? :::