Platevo

Restaurant Food Ordering & Delivery — Flutter apps + Node.js backend + Next.js admin

Customer appDriver appAdmin panelNestJS API iOS + AndroidEnglish · العربية · EspañolEverything included

1. Overview

Platevo is a complete, single-restaurant / multi-branch food ordering and delivery system. Unlike the market leaders that sell each app separately, everything is included in one package:

Plain-language note: you do not need to be a programmer to run Platevo. This guide gives you copy-paste commands and tells you exactly what to check after each step.

2. Architecture

All three front-ends talk to one Node.js API. A shared TypeScript package defines every data shape once, so the apps, the admin, and the server can never disagree.

Figure 1
Figure 1. How the Flutter apps and the Next.js admin communicate with the NestJS API (REST /api/v1), which owns PostgreSQL and Redis and connects to Stripe, Firebase, and Resend. External integrations are "seams": simulated until you add keys.

3. Quick start

These four steps get the whole system running locally.

# 1. Start the database and cache (Docker)
docker compose up -d

# 2. Install dependencies (pnpm)
pnpm install

# 3. Set up the server environment, then create demo data
cp .env.example server/.env         # edit the CHANGE_ME values
pnpm --filter @platevo/server prisma:migrate
pnpm --filter @platevo/server prisma:seed

# 4. Run the API — Swagger docs at http://localhost:3000/api/docs
pnpm dev:server

Then run the admin panel and the apps:

# Admin panel → http://localhost:3001  (sign in below)
pnpm --filter @platevo/admin dev

# Customer app (demo data, no backend needed)
cd app && flutter run --dart-define=USE_MOCK=true

# Customer app (live, against your API on an Android emulator)
cd app && flutter run --dart-define=API_BASE_URL=http://10.0.2.2:3000/api/v1

# Driver app
cd driver && flutter run --dart-define=USE_MOCK=true
Demo accounts (created by the seed — development only, password Password123!): [email protected] · [email protected] · [email protected].

4. Requirements

ToolVersionUsed for
Node.js20 or newerAPI server, admin panel
pnpm9 or newerinstalling dependencies (monorepo)
Dockerany recentPostgreSQL + Redis in one command
Flutter3.x (Dart 3)customer & driver apps
PostgreSQL16 (via Docker)the database

5. Configuration

All server settings live in server/.env. Copy .env.example and fill in the values. Every integration is simulated until you add its key, so the whole system works end-to-end out of the box.

VariableWhat it doesIf left empty
DATABASE_URLPostgreSQL connectionrequired
JWT_ACCESS_SECRET / JWT_REFRESH_SECRETsign login tokens (use two different 32+ char random strings)required
STRIPE_SECRET_KEY / STRIPE_WEBHOOK_SECRETreal card payments + webhookcard payments are simulated (marked paid, no charge)
FCM_SERVICE_ACCOUNT_JSONFirebase push notificationsnotifications are logged, not sent
RESEND_API_KEYreal email (password reset, marketing)emails are logged instead of sent
GOOGLE_CLIENT_IDS / APPLE_CLIENT_IDS / FACEBOOK_APP_IDsocial loginsocial buttons show "not configured"
Security: if you set STRIPE_SECRET_KEY you must also set STRIPE_WEBHOOK_SECRET — the server refuses to start otherwise, because an unverified webhook could be forged to mark orders paid.

6. The customer app

A premium ordering experience with full right-to-left Arabic support and dark mode. The full flow — browse, customize, cart, checkout, and live tracking:

Prices are never trusted from the phone: the server recomputes every amount (variations, add-ons, delivery fee, coupon, tax) so a tampered app can never set its own price.

7. The admin panel

Everything a restaurant needs to run the day, in the browser.

Figure 8
Figure 8. Dashboard — today’s orders and revenue, a 7-day revenue chart, the action queue, and top dishes.
Figure 9
Figure 9. Live order board — orders flow across status columns; a sound plays on each new order. Assign a driver and advance status from the order card.
Figure 10
Figure 10. Menu management — categories and dishes, each with photos, variations, add-on groups, and per-branch availability.

Other sections: Branches (delivery zones, per-weekday hours with timezone, fee rules), Drivers (accounts + earnings), Customers (lifetime spend), Coupons (percent/fixed with usage limits), Marketing (promo push + email broadcasts), Settings, and an Audit log of every staff action.

8. Make it yours — rebranding

Platevo is built so one change rebrands a whole app. Exact files and lines:

WhatFileChange
Customer app accent colorapp/lib/core/tokens.dartthe accent line (static const Color accent)
Driver app accent colordriver/lib/core/tokens.dartthe accent line
Admin accent coloradmin/app/globals.css--color-accent in the @theme block
App name (customer)app/pubspec.yaml + app/lib/main.dartname: / title:
Restaurant name, currency, logoAdmin → Settingsno code — edit in the panel
API URL the apps callrun flag--dart-define=API_BASE_URL=…
Languages / translationsapp/lib/l10n/app_*.arbedit the English/Arabic/Spanish strings

9. Backing up your production database

Your orders and customers live in PostgreSQL. Back it up regularly — this is the one thing you cannot recreate.

Option A — your hosting panel

Most hosts (DigitalOcean, Railway, RDS, etc.) offer one-click automated database backups in their dashboard. Turn on daily backups — it is the simplest safety net.

Option B — a manual dump (one command)

# Save a full backup to a plain-SQL file (run anywhere with database access):
pg_dump "postgresql://USER:PASSWORD@HOST:5432/platevo" > platevo-backup-$(date +%F).sql

# Restore that plain-SQL file into a fresh database:
psql "postgresql://USER:PASSWORD@HOST:5432/platevo" < platevo-backup-2026-01-01.sql

# Or use PostgreSQL's compressed custom format (smaller, restores in parallel):
pg_dump -Fc "postgresql://USER:PASSWORD@HOST:5432/platevo" > platevo-backup-$(date +%F).dump
pg_restore --clean --if-exists -d "postgresql://USER:PASSWORD@HOST:5432/platevo" platevo-backup-2026-01-01.dump
Automate it: add the pg_dump line to a daily cron job and copy the file to off-server storage (S3, Backblaze, Google Drive). A backup on the same server is not a backup. Test a pg_restore into a throwaway database every so often — an untested backup is a guess.

10. Troubleshooting

SymptomFix
Migration fails with "port 5432 already in use" / "access denied"Another PostgreSQL is already running on your machine. Stop it, or change the ports in docker-compose.yml and the matching DATABASE_URL in server/.env.
Admin shows a white page / 500 after buildingDo not run next build while next dev is running — they share the .next folder. Stop dev, then rm -rf admin/.next and start it again.
App can't reach the API from an Android emulatorUse http://10.0.2.2:3000/api/v1 (not localhost). On a real device use your computer's LAN IP.
Card payment "works" but no money arrivesYou are in simulated mode. Add STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET to server/.env.
Server won't start: "STRIPE_WEBHOOK_SECRET is required"You set a Stripe key without its webhook secret. Add both, or remove both to stay in simulated mode.

11. Changelog

VersionNotes
1.0.0Initial release — customer app, driver app, admin panel, NestJS API, OpenAPI 3.1 + Postman, EN/AR/ES, Stripe/FCM/Resend seams, full test suites.

12. Support

Thank you for choosing Platevo. For help, use the support tab on the item page. Please include your purchase code, what you tried, and the exact error text — it gets you a faster, more precise answer.