# Meezi — Production deployment (Arvan Cloud) ## Prerequisites - Arvan Cloud account (Iran region) - Domain `meezi.ir` DNS pointed to Arvan load balancer - ZarinPal merchant ID (production, sandbox off) - Kavenegar API key - PostgreSQL 16 + Redis managed or VMs ## Services | Service | Suggested host | |---------|----------------| | API | `api.meezi.ir` → ASP.NET container port 8080 | | Dashboard | `app.meezi.ir` or `meezi.ir` → Next.js standalone | | QR landing | `meezi.ir/q/*` → same Next.js app (`/q/[code]` route) | | Postgres | Private network only | | Redis | Private network only | ## Environment variables (API) ``` ConnectionStrings__DefaultConnection=Host=...;Database=meezi;... ConnectionStrings__Redis=... Jwt__Key=<32+ char secret> App__PublicBaseUrl=https://api.meezi.ir App__QrPublicBaseUrl=https://meezi.ir Billing__DashboardBaseUrl=https://app.meezi.ir ZarinPal__MerchantId= ZarinPal__Sandbox=false Kavenegar__ApiKey= Snappfood__WebhookSecret= Taraz__Username= Taraz__Password= Taraz__CertificatePath=/secrets/taraz.pfx RUN_MIGRATIONS=true Cors__Origins__0=https://app.meezi.ir Cors__Origins__1=https://meezi.ir ``` ### ZarinPal / Taraz validation 1. **Sandbox first:** set `ZarinPal__Sandbox=true` and a sandbox merchant; complete subscribe flow; confirm redirect `?billing=success` and JWT refresh on settings. 2. **Production:** set `ZarinPal__Sandbox=false` and production `ZarinPal__MerchantId`; verify callback URL is reachable from ZarinPal. 3. **Taraz:** with real credentials, submit from Settings → تاراز; confirm tracking in API logs (stub logs until full SDK wired). ## Environment variables (Web) ``` NEXT_PUBLIC_API_URL=https://api.meezi.ir ``` ## Routing - Customer QR codes encode `https://meezi.ir/q/{qrCode}` (see `App:QrPublicBaseUrl`). - Next.js route [`web/dashboard/src/app/q/[code]/page.tsx`](web/dashboard/src/app/q/[code]/page.tsx) resolves via public `GET /api/q/{code}`. - Flutter app parses scanned URL and calls the same API. ## Arvan checklist - [ ] Postgres + Redis on private network (no public ports) - [ ] `api_uploads` persistent volume mounted at `/app/uploads` - [ ] `RUN_MIGRATIONS=true` on API deploy only - [ ] Hangfire `/hangfire` behind VPN or basic auth - [ ] CORS origins: dashboard + marketing domain - [ ] `App__QrPublicBaseUrl=https://meezi.ir` - [ ] `Billing__DashboardBaseUrl=https://app.meezi.ir` (locale path added by API) - [ ] TLS on load balancer for `api.*` and `app.*` - [ ] Kavenegar + ZarinPal production keys in Arvan secrets (not in git) ## Deploy steps 1. Build and push Docker images (`docker compose` Dockerfiles in `docker/`). 2. Run EF migrations on API startup (`RUN_MIGRATIONS=true`) once per release. 3. Configure Hangfire dashboard behind auth in production. 4. Smoke test: OTP login, POS terminal register, create order, menu images visible, ZarinPal subscribe (sandbox first). ## CI suggestion - `dotnet build` + `dotnet test` on PR - `npm run build` in `web/dashboard` - Deploy on tag to Arvan registry