# Meezi — Docker (full platform)

Run all services with one command.

## Services

| Service | Description | Default Port |
|---------|-------------|-------------|
| **postgres** | PostgreSQL 16 database | 5434 (host) |
| **redis** | Redis 7 (session, rate-limit, refresh tokens) | 6381 (host) |
| **api** | Main ASP.NET Core 10 API | 5080 |
| **admin-api** | Admin ASP.NET Core 10 API | 5081 |
| **web** | Customer-facing Next.js dashboard | 3101 |
| **website** | Marketing / landing website | 3010 |
| **admin-web** | Admin panel Next.js | 3102 |

---

## Quick start — full stack (all 7 services)

```powershell
cd F:\Projects\Meezi
copy .env.example .env
docker compose -f docker-compose.full.yml up -d --build
```

## Quick start — core stack only (dashboard + API)

```powershell
docker compose up -d --build
```

## Quick start — with admin panel

```powershell
docker compose -f docker-compose.yml -f docker-compose.admin.yml up -d --build
```

---

## Default URLs

| Service | URL |
|---------|-----|
| Dashboard (customer) | http://localhost:**3101**/fa/login |
| Marketing website | http://localhost:**3010**/fa |
| Admin panel | http://localhost:**3102**/fa/admin/login |
| Main API Swagger | http://localhost:**5080**/swagger |
| Admin API Swagger | http://localhost:**5081**/swagger |
| Health (main API) | http://localhost:**5080**/health |
| Health (admin API) | http://localhost:**5081**/health |
| Hangfire (main API) | http://localhost:**5080**/hangfire |

Demo login: `09121234567` — OTP appears in API logs (`docker compose logs -f api`).

---

## Ports (change in `.env`)

| Variable | Default | Purpose |
|----------|---------|---------|
| `WEB_PORT` | 3101 | Next.js dashboard |
| `WEBSITE_PORT` | 3010 | Marketing website |
| `ADMIN_WEB_PORT` | 3102 | Admin panel |
| `API_PORT` | 5080 | Main ASP.NET API |
| `ADMIN_API_PORT` | 5081 | Admin ASP.NET API |
| `POSTGRES_PORT` | 5434 | Postgres on host |
| `REDIS_PORT` | 6381 | Redis on host |

If a port is taken, edit `.env`:
```powershell
copy .env.example .env
# Edit .env — change WEB_PORT, WEBSITE_PORT, etc.
docker compose -f docker-compose.full.yml up -d --build
```

---

## Build args and API URLs

`NEXT_PUBLIC_API_URL` — what the **browser** uses to call the Main API. Must be a host URL (not `api:8080`).

`MEEZI_API_URL` — what the **website server** uses for internal SSR calls. Uses the Docker service name `http://api:8080`.

```powershell
# Rebuild only the website after changing NEXT_PUBLIC_SITE_URL:
docker compose -f docker-compose.full.yml up -d --build website
```

---

## Useful commands

```powershell
# Status
docker compose -f docker-compose.full.yml ps

# Logs
docker compose -f docker-compose.full.yml logs -f api
docker compose -f docker-compose.full.yml logs -f website
docker compose -f docker-compose.full.yml logs -f web

# Stop everything
docker compose -f docker-compose.full.yml down

# Stop and remove volumes (wipes DB!)
docker compose -f docker-compose.full.yml down -v

# Rebuild a single service
docker compose -f docker-compose.full.yml up -d --build website
docker compose -f docker-compose.full.yml up -d --build api
```

---

## Printer setup (inside Docker)

The Meezi API sends print jobs directly from the **browser dashboard** — the API itself does not talk to printers. This means:

- Your thermal printer only needs to be on the **same WiFi/LAN** as the browser running the dashboard
- **No Docker-specific configuration needed** for printers
- See the full guide at: http://localhost:3010/fa/printer-guide

---

## Dev without Docker

Still works:
```powershell
docker compose up -d postgres redis
# then in separate terminals:
dotnet run --project src/Meezi.API
dotnet run --project src/Meezi.Admin.API
cd web/website && npm run dev   # port 3010
cd web/dashboard && npm run dev # port 3000 → maps to 3101
cd web/admin && npm run dev     # port 3102
```

---

## Sprint 10 — billing & integrations (dev)

**ZarinPal (mock):** leave `ZarinPal:MerchantId` empty. In dashboard **تنظیمات** → upgrade Pro/Business → redirected through mock pay URL back to `/fa/settings?billing=success`.

**Snappfood webhook** (demo café vendor `demo_vendor`):

```powershell
$body = '{"orderId":"sf-001","vendorId":"demo_vendor","customerName":"Test","customerPhone":"09121111111","total":150000,"items":[{"name":"لاته","quantity":1,"unitPrice":150000}]}'
$hmac = [System.BitConverter]::ToString((New-Object System.Security.Cryptography.HMACSHA256([Text.Encoding]::UTF8.GetBytes("meezi-dev-snappfood-secret"))).ComputeHash([Text.Encoding]::UTF8.GetBytes($body))).Replace("-","").ToLower()
Invoke-RestMethod -Method Post -Uri "http://localhost:5080/api/webhooks/snappfood" -Body $body -ContentType "application/json" -Headers @{ "X-Snappfood-Signature" = $hmac }
```

**Taraz:** Settings → «ارسال به تاراز» (logs only until `Taraz:Username` is set).

**Hangfire:** renewal reminder job runs daily — dashboard at `http://localhost:5080/hangfire` (dev).

---

## Tables & QR

- Dashboard: `/fa/tables` — floor plan, add table, print QR (PNG)
- Dev QR URL in codes: `http://localhost:3101/q/{qrCode}` (see `App__QrPublicBaseUrl`)
- Scan `demo_table_01` in Flutter or open manual entry on QR screen

---

## Production env (Arvan)

See [DEPLOY.md](DEPLOY.md). Key additional website vars:

```env
NEXT_PUBLIC_SITE_URL=https://meezi.ir
MEEZI_API_URL=http://api:8080
```

---

## Menu images (Food-101)

- Manifest: `data/menu-image-manifest.json`
- API upserts images on dev seed via `EnsureMenuImagesAsync`
- Optional import: `dotnet run --project tools/MenuImageImporter -- --food101 <path-to-food-101/images>`
