Restaurant Food Ordering & Delivery — Flutter apps + Node.js backend + Next.js admin
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:
/api/v1 with a committed OpenAPI 3.1 contract and Postman collection.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.
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.
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
Password123!):
[email protected] · [email protected] · [email protected].| Tool | Version | Used for |
|---|---|---|
| Node.js | 20 or newer | API server, admin panel |
| pnpm | 9 or newer | installing dependencies (monorepo) |
| Docker | any recent | PostgreSQL + Redis in one command |
| Flutter | 3.x (Dart 3) | customer & driver apps |
| PostgreSQL | 16 (via Docker) | the database |
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.
| Variable | What it does | If left empty |
|---|---|---|
DATABASE_URL | PostgreSQL connection | required |
JWT_ACCESS_SECRET / JWT_REFRESH_SECRET | sign login tokens (use two different 32+ char random strings) | required |
STRIPE_SECRET_KEY / STRIPE_WEBHOOK_SECRET | real card payments + webhook | card payments are simulated (marked paid, no charge) |
FCM_SERVICE_ACCOUNT_JSON | Firebase push notifications | notifications are logged, not sent |
RESEND_API_KEY | real email (password reset, marketing) | emails are logged instead of sent |
GOOGLE_CLIENT_IDS / APPLE_CLIENT_IDS / FACEBOOK_APP_ID | social login | social buttons show "not configured" |
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.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.
Everything a restaurant needs to run the day, in the browser.
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.
Platevo is built so one change rebrands a whole app. Exact files and lines:
| What | File | Change |
|---|---|---|
| Customer app accent color | app/lib/core/tokens.dart | the accent line (static const Color accent) |
| Driver app accent color | driver/lib/core/tokens.dart | the accent line |
| Admin accent color | admin/app/globals.css | --color-accent in the @theme block |
| App name (customer) | app/pubspec.yaml + app/lib/main.dart | name: / title: |
| Restaurant name, currency, logo | Admin → Settings | no code — edit in the panel |
| API URL the apps call | run flag | --dart-define=API_BASE_URL=… |
| Languages / translations | app/lib/l10n/app_*.arb | edit the English/Arabic/Spanish strings |
Your orders and customers live in PostgreSQL. Back it up regularly — this is the one thing you cannot recreate.
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.
# 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
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.| Symptom | Fix |
|---|---|
| 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 building | Do 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 emulator | Use 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 arrives | You 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. |
| Version | Notes |
|---|---|
| 1.0.0 | Initial release — customer app, driver app, admin panel, NestJS API, OpenAPI 3.1 + Postman, EN/AR/ES, Stripe/FCM/Resend seams, full test suites. |
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.