Fooodo / Docs

Fooodo architecture

How Fooodo is built — the two-service split of menu app and payment service, the company/restaurant/table multi-tenancy model, the POS-agnostic connector contract, and where UVS sits.

Fooodo runs as two cooperating services plus an external POS, reached through a POS-agnostic connector contract. This page is the system map: how the pieces connect, why they're split, and how multi-tenancy works.

The two services

Menu apporders · admin · POS sync
Payment serviceMollie · tips · donations
Molliepayment provider
R-KeeperPOS · system of record
Service topology
  • Menu app. Customer-facing flow (QR → browse → order), the operator admin panel, and all POS connector traffic.
  • Payment service. Separate service behind a token-authenticated API. Owns Mollie integration, webhook routing, donation routing, and tip routing. Has its own internal admin.
  • POS connector. Whichever POS the restaurant runs. Fooodo treats it as the system of record for the menu and as the kitchen's source of truth for orders. R-Keeper is the live reference connector today; other POS connectors are scoped per-customer — the connector contract itself is POS-agnostic.

The two Fooodo services talk over an authenticated HTTP API; there is no shared database, no shared queue, and no shared deployment. They can be deployed independently.

Why split the payment service

Three reasons:

  1. Compliance scope stays small. Card data only ever touches the payment service; the menu app receives a checkout URL and a callback. PCI scope is bounded to one codebase.
  2. The payment service is reusable. It was designed to serve multiple Fooodo surfaces over time, not just the current menu app. New products consume it without re-implementing payment plumbing.
  3. Failure isolation. If Mollie has a regional outage, the menu app stays up; orders queue in the "ready to be paid" state and reconcile when the payment service recovers.

Multi-tenancy

Every record in the menu app is scoped through this hierarchy:

  1. Company
    tenant boundary · brand · billing
  2. Restaurant
    POS config · hours · default flow
  3. Table
    QR code · per-table flow override
  4. Order
    items · payments · tips · donations
Multi-tenancy hierarchy
  • Company is the tenant boundary. Currently one active company in production (Čili Pizza), but tenant separation is enforced everywhere — adding a second chain doesn't require a separate deployment.
  • Restaurant admins can only manage their own restaurant — the role system enforces this at the policy layer.
  • Every QR code resolves to a specific table at a specific restaurant. There is no shared "scan to order" code; Fooodo always knows which seat an order is for. This is what makes Pay-Later, table-side bill split, and seat-level analytics possible.

Where UVS sits

UVS is the order and operations core inside the menu app — the central event stream that records everything the platform writes (orders, payments, table state, kitchen tickets) before propagating to consumers (the active POS connector, the payment service, future modules).

For integrators this matters concretely: modules don't talk to each other directly, and the contract is POS-agnostic. A connector for a new POS doesn't touch the kitchen flow or the payment service — it speaks the UVS contract, and inherits payments, multi-tenancy, and reporting for free. R-Keeper is one implementation of that contract; the contract itself is the system. The contract is documented in the integration repo, which partners receive during onboarding.

Stack at a glance

ComponentShape
Menu appPHP backend, React frontend, PostgreSQL, Redis-backed job queue
Payment serviceIndependent PHP service with its own database and admin
Payment providerMollie (Card, Apple Pay, Google Pay)
POS connectorR-Keeper (live); other POS connectors scoped per-customer
Marketing siteNext.js + next-intl + Fumadocs (this site)

Specific framework versions are intentionally omitted from this public surface — partners building POS connectors get the version pinning during onboarding alongside the integration repo.

What lives where

  • Menu management, orders, tables, customer-facing flow → menu app.
  • Card data, refunds, payment methods, tips, donations → payment service.
  • Menu source of truth, kitchen tickets, reports → your POS (R-Keeper today, other connectors as they ship).
  • Marketing copy, public docs, AI assistant, MCP server → this site.

If you are integrating with Fooodo, the API surface you care about is the menu app's external API. The payment service is internal — the menu app proxies to it.

On this page