Skip to content

Yum Backend API

Yum is the central REST API for the SMACKZ platform. It handles menus, orders, authentication, pages, loyalty, image uploads, and all data mutations. Every client application (Admin, Websites, Mobile, KDS) communicates with Yum.

Tech Stack

Component Technology
Runtime Node.js (>= 20.18.1, recommended 22.x LTS)
Framework Fastify v5
Language TypeScript
Database PostgreSQL 14 via Drizzle ORM
Validation Zod
Auth Firebase Admin SDK + JWT
Email Resend.com
Images Cloudflare R2 (direct upload via signed URLs)
Cache Redis (ioredis) -- optional, degrades gracefully
Docs Swagger UI at /docs

Project Structure

api/
├── controllers/     # Request handlers
├── db/models/       # Drizzle ORM entities (database tables)
├── decorators/      # Firebase auth decorator
├── routes/          # API endpoint definitions
├── schema/          # Zod validation schemas
├── services/        # Business logic
├── repositories/    # Data access layer
├── utils/           # Helpers (time, email, images)
├── lib/             # Shared libraries (Redis, etc.)
├── plugin/          # Fastify plugins (Swagger, auth)
├── scripts/         # Admin & utility scripts
└── index.ts         # Entry point

Getting Started

git clone <repo-url> && cd yum
npm install
cp .env.dev .env
npm run dev

The server starts at http://localhost:8080 with hot reload. Swagger UI is available at http://localhost:8080/docs.

Common Commands

Command Purpose
npm run dev Start dev server with hot reload
npm run build Build TypeScript to dist/
npm run ts.check TypeScript type check
npm run lint:check ESLint check
npm test Run test suite (Jest)
npm run db:push Sync Drizzle models to database
npm run db:studio Open Drizzle Studio (DB browser)
npm run admin:menu Interactive admin tools menu

Key API Domains

Domain Base Path Description
Auth /api/v1/auth/ Login, register, Firebase config, token refresh
Restaurants /api/v1/restaurants/ CRUD, working hours, settings
Menus /api/v1/restaurants/{id}/menus/ Menus, sections, items, serving sizes
Orders /api/v1/restaurants/{id}/orders/ Order lifecycle
Pages /api/v1/restaurants/{id}/pages/ Dynamic pages and sections
Images /api/v1/restaurants/{id}/images/ Signed upload URLs, confirmation
Cart /api/v1/users/{id}/restaurants/{id}/cart/ Shopping cart
Loyalty External smackz-loyalty service Points, offers, tiers

Authentication

Yum supports two auth modes:

  • Web (Admin) -- Email/password via Firebase Identity Platform. login_source: web header always uses platform Firebase.
  • Mobile -- Phone OTP via Firebase Phone Auth. Each restaurant can have its own Firebase project.

The loginSource === "web" check ensures SuperAdmin users always authenticate against platform Firebase, regardless of which restaurant they are managing.

Dynamic Pages

Restaurants have configurable pages (homepage, about, contact) with ordered sections. Each section has a content type (text, chefs_favorites, featured_menu, reviews, etc.) and a view type (grid, list, carousel, row). Page and section properties are stored as JSONB, so adding new display properties never requires database migrations.

Image Pipeline

Images are uploaded directly to Cloudflare R2 via signed URLs. The flow is: generate signed URL, client uploads directly to R2, then confirms the upload with Yum. This keeps image traffic off the API server. Images can optionally be processed through Cloudflare Images for WebP/AVIF conversion.

CDN Caching

Public read-only GET endpoints are cached at Cloudflare's edge (PoPs). The Fastify onSend hook in api/plugin/cache.ts sets Cache-Control: public, max-age=60, s-maxage=3600, stale-while-revalidate=30 for matching routes; mutations trigger fire-and-forget purge calls via the Cloudflare Purge-by-URL API so the next request fetches fresh data.

Bucket TTL Examples
Global assets 24h fonts, themes, layouts
Restaurant static 1h menus, items, pages
Computed 5min crowd favorites, pickup availability

Purge scope is minimal -- editing a menu item only purges menus + menu-items + mapped-menu-items URLs. Configuration in api/utils/cacheConfig.ts (28 regex patterns); purge wrapper in cachePurgeHelper.ts. Disabled in local dev when CLOUDFLARE_API_TOKEN is absent. See yum/docs/CLOUDFLARE_CACHING.md.

Pre-commit Coverage Gate

.husky/pre-commit runs four checks in order: npm run lint:check, npm run ts.check, npm run build, then scripts/precommit-coverage-gate.js. The coverage gate enforces 100% on staged source files (lines, branches, functions, statements) measured against the unit test suite only. It lists staged files (git diff --cached --diff-filter=ACMR), classifies them, resolves related unit tests via Jest's static graph + filename convention, and runs them with testcontainers disabled. Typical wall-clock: <10s for one staged file, ~20--30s for five. See yum/docs/PRECOMMIT_COVERAGE.md.

Location-Scoped Settings

As of 2026-04, several per-branch settings (diningOptions, parkingOptions, deliveryProvider, working hours, holidays, token counters) live on locations rather than restaurants. Routes that target a single entity (CRUD-by-ID) do not include locationId; only list/query routes do. See Restaurants & Locations and yum/docs/LOCATION_SCOPED_SETTINGS.md.

Fastify v5 Async Handler Discipline

Fastify v5 expects async route handlers to return reply after reply.send(...). Omitting the return causes a "double-send" race where Fastify calls reply.send(undefined) after the handler resolves, crashing the server with ERR_HTTP_HEADERS_SENT on subsequent requests. The first request often masks the bug because the Zod serializer compilation is slow enough to write headers before the race window. Always return reply.send(...) (or return reply.status(n).send(...)) in async handlers. See yum/docs/FASTIFY_V5_DOUBLE_SEND_ISSUE.md.

Export/Import

Yum includes services for exporting and importing restaurant data:

  • menuExportImport -- Menus, sections, items, and mappings
  • restaurantExportImport -- Restaurant configuration
  • userExportImport -- User accounts
  • orderExportImport -- Order history
  • unifiedExport -- Combined export

Key Files

  • yum/CLAUDE.md -- Detailed backend guidelines and doc index
  • yum/api/routes/ -- All route definitions
  • yum/api/db/models/ -- Drizzle ORM table definitions
  • yum/api/schema/ -- Zod validation schemas
  • yum/drizzle.config.ts -- Drizzle configuration
  • yum/docs/DATABASE_SCHEMA.md -- Full database schema reference
  • yum/docs/NOTIFICATIONS.md / NOTIFICATION_COVERAGE.md -- See Notifications
  • yum/docs/DELIVERY_ADMIN_GUIDE.md / DELIVERY_CONSUMER_GUIDE.md -- See Delivery
  • yum/docs/LOCATION_SCOPED_SETTINGS.md -- 2026-04 location migration reference
  • yum/docs/CLOUDFLARE_CACHING.md -- CDN caching configuration
  • yum/docs/PRECOMMIT_COVERAGE.md -- Pre-commit coverage gate
  • yum/docs/ROUTE_LOCATION_AUDIT.md -- Route locationId policy
  • yum/docs/FASTIFY_V5_DOUBLE_SEND_ISSUE.md -- Fastify v5 async handler discipline
  • yum/docs/FRONTEND_MIGRATION_GUIDE.md -- Identity Platform + location-scoped settings frontend migration