- NestJS backend: auth, restaurants, orders, drivers, payments, tracking, reviews, zones, admin, email - Next.js 14 frontend: landing, restaurants, checkout, tracking, dashboards, onboarding - Expo mobile app: driver orders and earnings screens - PostgreSQL + PostGIS schema with seed data - Docker Compose for local dev (Postgres, Redis, OSRM) - MapLibre GL + OpenStreetMap integration - Stripe subscription and payment processing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Vibe — Fair-Trade Delivery Platform
Flat-fee food delivery for the Greater Toronto Area. No commissions. No exploitation. Restaurants keep 100% of profits.
Quick Start
# 1. Copy env and fill in your keys
cp .env.example .env
# 2. Start PostgreSQL/PostGIS + Redis
npm run docker:up
# 3. Install all dependencies
npm install
# 4. Start backend + frontend
npm run dev
Backend: http://localhost:3001
Frontend: http://localhost:3000
PgAdmin: http://localhost:5050 (after docker-compose --profile dev up)
Project Structure
The_Vibe/
├── packages/
│ ├── database/
│ │ ├── schema.sql # Full PostgreSQL + PostGIS schema
│ │ └── seed.sql # GTA zones + dev data
│ ├── backend/ # NestJS API (port 3001)
│ │ └── src/
│ │ ├── modules/
│ │ │ ├── auth/ # JWT auth, roles guard
│ │ │ ├── drivers/ # Sessions, break-even algorithm
│ │ │ ├── restaurants/ # Menu, savings dashboard
│ │ │ ├── orders/ # Full order lifecycle
│ │ │ ├── payments/ # Stripe subscriptions + daily fee
│ │ │ ├── tracking/ # Socket.IO real-time gateway
│ │ │ ├── zones/ # GTA PostGIS geofencing
│ │ │ ├── menu/ # Menu CRUD
│ │ │ └── admin/ # Platform analytics
│ │ └── database/ # pg Pool + transaction helper
│ └── web/ # Next.js 14 frontend (port 3000)
│ └── src/
│ ├── app/
│ │ ├── page.tsx # Landing page
│ │ ├── restaurants/page.tsx # Browse + map
│ │ ├── orders/[id]/track/ # Real-time order tracking
│ │ ├── driver/dashboard/ # Break-even dashboard
│ │ ├── restaurant/dashboard/ # Savings dashboard
│ │ └── admin/page.tsx # Platform admin
│ ├── components/
│ │ └── map/MapView.tsx # MapLibre GL JS
│ ├── hooks/
│ │ └── useDriverTracking.ts # GPS + Socket.IO
│ └── lib/
│ ├── api.ts # Axios client
│ └── osrm.ts # OSRM routing client
└── docker-compose.yml
Pricing Model
| Stakeholder | Model | Amount |
|---|---|---|
| Restaurant | Monthly subscription | $500/month |
| Restaurant | Per-order fee | $0.10/order |
| Restaurant | CC processing (Stripe) | 2.9% + $0.30 |
| Driver | Daily access fee | $20/day |
| Driver | Delivery fee | $5 per delivery (kept 100%) |
| Driver | Tips | 100% kept |
| Customer | Delivery fee | $5 flat |
| Customer | Hidden fees | $0 |
Driver Break-Even
- 4 deliveries × $5 = $20 → break even
- Every delivery after #4 = pure profit
- Tips never counted against break-even
Restaurant Savings Example (100 orders/day)
- UberEats at 30% on $35 avg: $31,500/month
- The Vibe: $500 + $300 + CC ≈ $3,400/month
- Savings: ~$28,000/month
API Endpoints
Auth
POST /api/v1/auth/register
POST /api/v1/auth/login
GET /api/v1/auth/me
Restaurants
GET /api/v1/restaurants?lng=&lat=&radius=&cuisine=
GET /api/v1/restaurants/savings-calculator?orders=&avgValue=
GET /api/v1/restaurants/:slug
POST /api/v1/restaurants (restaurant_owner)
GET /api/v1/restaurants/dashboard/savings (restaurant_owner)
Orders
POST /api/v1/orders (customer)
GET /api/v1/orders/mine (customer)
GET /api/v1/orders/:id
PATCH /api/v1/orders/:id/confirm (restaurant_owner)
PATCH /api/v1/orders/:id/ready (restaurant_owner)
PATCH /api/v1/orders/:id/pickup (driver)
PATCH /api/v1/orders/:id/delivered (driver)
Drivers
GET /api/v1/drivers/me/session
POST /api/v1/drivers/me/session/start
POST /api/v1/drivers/me/session/end
PATCH /api/v1/drivers/me/location
GET /api/v1/drivers/nearby?lng=&lat=
Payments (Stripe)
POST /api/v1/payments/restaurant/subscribe
POST /api/v1/payments/driver/daily-fee
POST /api/v1/payments/driver/payment-method
POST /api/v1/payments/orders/:orderId/intent
POST /api/v1/payments/webhook
Zones (GTA Geofencing)
GET /api/v1/zones
GET /api/v1/zones/geojson # GeoJSON FeatureCollection
GET /api/v1/zones/check?lng=&lat=
Admin
GET /api/v1/admin/stats
GET /api/v1/admin/revenue?days=30
GET /api/v1/admin/restaurants
GET /api/v1/admin/drivers
PATCH /api/v1/admin/drivers/:id/approve
Map Stack
- MapLibre GL JS — open-source map renderer (browser)
- OpenStreetMap tiles via MapTiler (free tier)
- OSRM — self-hosted routing engine (ontario-latest.osm.pbf)
- PostGIS — geofencing, spatial queries, driver proximity
GTA Zones (active at launch)
- Downtown Toronto (priority 10)
- Liberty Village (priority 9)
- North York (priority 8)
- Scarborough (priority 7)
- Mississauga (priority 6)
Real-Time Architecture
Driver App Socket.IO Gateway Customer App
│ │ │
├─ emit driver:location ──► │
│ ├─ emit driver:moved ────►│
│ │ │
│ ◄── emit join:order ──────┤
│ │ │
│ Orders Service │
│ ◄── order:new ────────────┤
│ ├─ emit to restaurant room │
Driver location updates every 5 seconds via WebSocket.
DB breadcrumbs written to delivery_tracking table.
Environment Variables Required
See .env.example for full list. Key ones:
DATABASE_URL— PostgreSQL + PostGIS connection stringSTRIPE_SECRET_KEY— Stripe API keySTRIPE_RESTAURANT_PRICE_ID— $500/month Price ID in StripeJWT_SECRET— random secret, min 32 charsNEXT_PUBLIC_MAPTILER_KEY— free MapTiler account for OSM tiles
Performance Targets
| Metric | Target |
|---|---|
| Restaurants | 1,000+ |
| Active drivers | 5,000 |
| Orders/day | 50,000 |
| Location updates/sec | ~50,000 (drivers × 0.2hz) |
| DB connections | max 20 (pg pool) |
Scale path: Redis adapter for Socket.IO → horizontal Node scaling → Postgres read replicas.
Description
Languages
TypeScript
97.8%
Shell
1.4%
JavaScript
0.7%
CSS
0.1%