Moanv
Larderline case study
Larderline

Architecture

Larderline

A solution-architecture summary — how the system is designed, and why. Verified from the source code.

Type of system
Multi-tenant SaaS (recipe costing & allergens)
Users
Independent UK restaurants
Hosting
United Kingdom
Main stack
React + TypeScript, Django REST, PostgreSQL
Status
Live (free + paid plans)
Built for
Moanv's own product

The problem

Costing a menu in a spreadsheet loses money three ways: scaled recipes drift because volume-to-weight conversions treat grated and diced the same; ingredient prices go stale; and the allergen matrix is a Word doc that's out of date the moment a supplier changes — a £5,000-plus risk under Natasha's Law.

How it fits together

Users

Restaurant owners & chefs

Front end

React 18 + TypeScript (Vite, MUI)

Tenant boundary

Backend / API

Django + DRF (Gunicorn, nginx)

Database

PostgreSQL

One shared database; every row carries an owner, and team sharing expands a user to their team's IDs at query time.

External services

  • Stripe — billing
  • Microsoft Graph — email
  • AI providers (bring-your-own-key)
  • Listmonk — marketing email
  • Chatwoot — support
Owners and chefs use a React single-page app that talks to a Django REST API backed by PostgreSQL. Every row is owned by a user, and team access is resolved per query. Stripe handles billing, Microsoft Graph sends email, and users can bring their own AI key for recipe generation.

Tech stack

Front end

  • React 18, TypeScript, Vite, MUI
  • TanStack Query, Recharts
  • jsPDF / html2canvas (client PDF)

Backend

  • Python 3.11, Django 4.2, Django REST Framework
  • Gunicorn (systemd)
  • reportlab / pypdf (server-side PDF)

Database

  • PostgreSQL

Hosting

  • United Kingdom
  • Single Ubuntu VPS, nginx, systemd, deployed via Azure DevOps over SSH

Third-party

  • Stripe (billing)
  • Microsoft Graph (email)
  • Listmonk (marketing email)
  • Chatwoot (support)
  • AI providers — bring-your-own-key

Key design decisions

Never let the model say a dish is free from an allergen

Why: The allergen tool forces all 14 UK allergen keys onto every dish and collapses anything missing or unrecognised to ‘check’ — never to a negative. A build test fails if banned words like ‘free from’ reach the output.

Trade-off: The tool is deliberately conservative: it says ‘check’ rather than reassure.

A density-aware scaling engine

Why: Volume-to-weight differs by preparation — grated carrot is 55g per 100ml, diced is 115g. A lookup of 147 densities and 59 prep forms keeps a scaled recipe true from 2 to 200 portions.

Trade-off: The density data has to be maintained.

Role hierarchy plus a permission matrix

Why: owner / head_chef / chef / viewer mapped to resources and HTTP verbs, enforced by DRF permission classes.

Trade-off: More permission design up front.

Field-level encryption for users' own AI keys

Why: Bring-your-own-key credentials are encrypted (Fernet/AES) before storage, so the database alone doesn't yield them.

Trade-off: Encryption is keyed from the app secret, which must be protected.

Security & data protection

  • Hosted in the United Kingdom.
  • TLS 1.2/1.3 with HSTS, nosniff, X-Frame-Options DENY and X-XSS-Protection at nginx.
  • JWT authentication (email + password) plus Google and Microsoft sign-in; email verification and password reset.
  • Role-based access (owner / head_chef / chef / viewer) via a permission matrix.
  • Users' own AI keys encrypted at rest (Fernet / AES).
  • Rate limits (per-user daily, newsletter, demo and allergen tools) plus honeypot fields on public forms.
  • An activity log records who did what to which resource.
  • Secrets live in the environment only; production refuses to boot without its key and database password.

Built to hold up

Performance
A React single-page app with a Django API and server-side PDF generation.
Availability
A single UK VPS, systemd-managed.
Scalability
Owner-scoped tenancy on shared PostgreSQL; server-side plan limits on recipes, AI, scaling, ingredients and seats.

What we'd do next

  • Improve mobile load time so it's quick on the pass, not just on a laptop.
  • Add supplier price feeds so ingredient costs update themselves.
  • Broaden allergen and costing exports to more delivery platforms.