System Overview
Whole-platform map for Eziseller (EziSeller). Audience: new dev with Node/React experience, no Eziseller context. Every other KB page links back here.
1. Overview
Eziseller (EziSeller) is a multi-channel e-commerce order management platform for small and mid-size merchants in India. A single merchant ("store") can receive orders from a manual dashboard, a public catalog checkout, WhatsApp Business conversations, or Instagram DMs — all of which funnel into one unified Order pipeline with invoicing (GST), inventory, and Shiprocket-backed fulfillment. The platform is built as a split deployment: a Next.js 14 App Router frontend on Vercel and a standalone Express/TypeScript API on Azure App Service, with a shared PostgreSQL database accessed via Prisma. Subscriptions (Razorpay) gate features, and the super-admin portal sits on top of the same API with impersonation support.
2. Architecture
CORS on the API is locked to FRONTEND_URL (backend/server.ts:L61-L64), so browsers never talk to Azure directly in production — they go through Vercel's rewrite. Meta webhooks are the one inbound exception and land on an unauthenticated /webhooks/meta path (backend/server.ts:L130).
3. Data model
Fifty-plus Prisma models organized in clusters. See schema.prisma for the full list.
Model groups: auth/tenancy (User, Store — schema.prisma:L20-L110), catalog (Product, ProductVariant — L316-L400), orders (Order, DraftOrder, OrderItem, Fulfillment — L401-L630), shipping (ShippingProvider, Shipment — L673-L810), messaging (WhatsApp/Instagram credentials, templates, message logs — L814-L1210), billing (Plan, UserSubscription, SubscriptionPayment — L1367-L1490), notifications and audit (L1314-L1570).
4. Key flows
4.1 Request lifecycle (/api/*)
The rewrite rule is in next.config.js:L10-L17. The maintenance-mode short-circuit and the middleware stack are in backend/server.ts:L71-L91.
4.2 Cross-system: WhatsApp order → invoice → shipping label
5. Lifecycle / state machine
6. Key files
- backend/server.ts:L48-L131 — Express bootstrap, CORS, maintenance gate, full route table (35+ mounts)
- backend/server.ts:L160-L232 — graceful shutdown, notification queue (30s), subscription cron
- next.config.js:L10-L17 —
/api/*proxy to backend - src/middleware.ts:L1-L36 — frontend maintenance redirect
- backend/prisma/schema.prisma — single source of truth for all models
- backend/routes/auth.ts:L69 — in-memory refresh token store (see gotcha below)
- backend/middleware/ —
auth.ts,rbac.ts,subscription.ts,validation.ts(applied per-route, not globally) - .github/workflows/backend-deploy.yml — CI/CD to Azure (backend only; frontend auto-deploys on Vercel)
- package.json:L5-L20 — dev/build/db scripts for both halves of the monorepo
7. Env vars & config
Two boundaries: root .env.local for frontend (only NEXT_PUBLIC_* values ship to the browser) and backend/.env for the API. See .env.example for the full list.
| Var | Scope | Purpose | What breaks |
|---|---|---|---|
NEXT_PUBLIC_API_URL | FE | Target of /api/* rewrite | All API calls 404 in prod |
FRONTEND_URL | BE | CORS allowlist | Browser requests blocked |
DATABASE_URL | BE | Postgres connection string | Server crashes on boot |
JWT_SECRET | BE | Signs access + refresh tokens | All sessions invalid |
MAINTENANCE_MODE | BE | Blocks /api/* with 503 | — |
NEXT_PUBLIC_MAINTENANCE_MODE | FE | Redirects all pages to /maintenance | — |
CLOUDINARY_* | BE | Image + PDF storage | Uploads fail |
WHATSAPP_*, INSTAGRAM_* | BE | Meta Graph API creds (global fallback; per-user creds stored in DB) | Webhook verify fails |
RAZORPAY_* | BE | Subscription billing | Checkout + webhook break |
8. Gotchas & troubleshooting
- Issue: Users are logged out after every backend deploy → Cause: refresh tokens live in an in-process
Set(backend/routes/auth.ts:L69), which resets on restart → Fix: users re-login; long-term, move to DB or Redis. - Issue: Frontend spams
/api/auth/refresh→ Cause: access tokens expire in 1 minute; every stale request triggers a refresh. This is intentional but surprising in dev. - Issue: A brute-force attack on
/api/ordersisn't rate-limited → Cause:express-rate-limitis only wired intoauth.ts(backend/routes/auth.ts:L26-L54), not globally. Relies on Azure's front-door limits. - Issue: Maintenance mode only partly works → Cause: it's two independent toggles —
MAINTENANCE_MODE(backend 503s) andNEXT_PUBLIC_MAINTENANCE_MODE(frontend redirect). Flip both together. - Issue: Staff user can't see data → Cause: multi-tenancy uses
User.ownerId; queries must scope by owner. OWNER has a 1:1 Store; STAFF inherits viaownerId. - Issue: Meta webhook 401s → Cause: CORS isn't the problem —
/webhooks/metais mounted without/apiprefix (backend/server.ts:L130) to satisfy Meta's signature checks. Don't move it under/api/*.
9. Extension points
- New order channel: add a route under
backend/routes/, funnel intoDraftOrder(notOrderdirectly) so the merchant can review. Reuselib/draft-order-service.tsandlib/ai-parser.ts. - New external integration: put the client in
backend/lib/, credentials per-user in a new Prisma model (pattern:WhatsAppUserCredentials,InstagramUserCredentials), webhook route underbackend/routes/. - New gated feature: add plan flag to
Planmodel, enforce withmiddleware/subscription.tson the route. - New background job: add to
backend/schedulers/(cron) orbackend/jobs/(one-shot); wire intoserver.tsshutdown hooks.
10. Related docs
- auth/authentication.md — JWT + refresh token details
- auth/rbac.md — OWNER/STAFF/SUPER_ADMIN model
- auth/subscription-gating.md — plan enforcement
- orders/order-lifecycle.md — Order state machine in depth
- webhooks/webhooks-overview.md — inbound webhook topology
- messaging/messaging-overview.md — WhatsApp + Instagram shared plumbing
- ops/deployment.md — Azure + Vercel CI/CD specifics
- ops/cron-and-jobs.md — subscription + notification schedulers