Skip to content

System overview

Source: g2labs-in/billuu-docs@7780d43 · content/architecture/system-overview.md · updated 2026-09-26

What Billuu is

Billuu is a multi-tenant restaurant POS by BrewLabs. One backend deployment serves every customer. Each customer’s business data sits in its own PostgreSQL schema inside one shared database, so onboarding a customer needs no new server. The rules that make that safe are on the Multi-tenancy page.

Production is one Azure virtual machine for the API, Netlify for the browser apps, Supabase for PostgreSQL, and Cloudflare in front of everything.

Applications

Every deployable in the workspace, with the stack its own package.json declares.

ApplicationCodeStackRuns onJob
Backend APIbrewlabs-billu-backendNode.js 20, Express 4, Sequelize 6, Socket.IO, BullMQ, ioredisAzure VM billuu-app as the Docker Swarm service billuu-backend-poxd1a, port 8000Serves every /api/* request
Staff POS and back officebrewlabs-billu-frontendReact 18, Vite 6, Tailwind, Redux Toolkit, TanStack Query, socket.io-clientNetlify, and a Cloudflare Worker named billuu-pos reached at billing.billuu.comOrders, tables, kitchen view, menu, inventory, reports
Super admin panelbreww-admin, repo g2labs-in/brewlabs-billu-adminReact 19, Vite 6, Tailwind, Redux Toolkit, MUI, rechartsCloudflare Worker named billuu-admin, live at superadmin.billuu.com behind a Cloudflare Access email gateTenants, subscriptions, plans, platform administrators, and the platform screens behind /dashboard. Most of those screens have no backend and say so
Marketing sitebilluu_landingPageNext.js 14, Tailwind, three.jsNot in the current production inventoryPublic landing page
CRM servicebrewlabs-billu-crmExpress 4, Sequelize 6, node-telegram-bot-api, node-cronNot in the current production inventoryCustomer, segment, and campaign records, plus a Telegram bot
Docs sitebilluu-docsAstro Starlight, Pagefind, Bun buildNo DNS record in the infra repo. site is set to https://doc.billuu.com in billuu-docs/astro/astro.config.mjsThis documentation

Three of these have no production entry in the infra inventory, so do not assume they are running. brewlabs-billu-crm has no Dockerfile and no entry in /home/codejack/code/linode/CONTEXT.md. The landing page repo ships billuu_landingPage/netlify.toml with the Next.js Netlify plugin, while the infra notes call the site undeployed and name Cloudflare Pages as the intended home. billuu-docs has no hostname in the Cloudflare record set.

The frontend repo carries stale hostnames. brewlabs-billu-frontend/vercel.json rewrites /api/:path* to https://pos-backend-6afs.onrender.com, and brewlabs-billu-frontend/.env.example sets VITE_API_BASE_URL to https://billu.3dpnow.com/api. Neither is the production API hostname today. The infra repo is authoritative for hostnames.

The super admin panel is the one application whose live URL does not serve its own repo. The domain answers with a build of commit 4611679 from the branch testing-phase-with-auth-21-feb-2026, and the panel branch has an unrelated history. The Super admin panel section of this site covers that, and the API gap behind it.

Where production runs

The resource group is billuu-prod. The VM billuu-app is a Standard_B2ls_v2 with 4 GB of RAM, a 64 GB disk, and the static IP 20.235.64.99, in the centralindia region.

HostnameServesProxied by Cloudflare
testing.billuu.comThe backend API through Traefikyes
dokploy.billuu.comThe Dokploy panel, behind Cloudflare Accessyes
billuu.com, wwwNetlifyno
billing.billuu.comNetlifyno
order.billuu.comNetlify, the customer ordering app that QR codes point atno
main.billuu.comThe VM, unused, kept for parityno

The backend container is built from the stabilize-phase-1-2 branch and listens on port 8000. Redis 8 runs on the same host as billuu-redis-engwdt with no published port. Dokploy owns the Traefik dynamic configuration under /etc/dokploy/traefik/dynamic/, so never hand-edit those files.

Port 443 on the VM answers Cloudflare edge addresses and Tailscale and drops everything else. The filter is enforced by /usr/local/bin/billuu-firewall.sh through the DOCKER-USER chain. Port 80 stays open to the world because Let’s Encrypt validates over HTTP from its own addresses.

Request path

flowchart TD
Browser["Browser"]
Edge["Cloudflare edge"]
Netlify["Netlify sites"]
Traefik["Traefik on billuu-app"]
Backend["Backend container on port 8000"]
Redis["Redis 8 on the same host"]
Pooler["Supabase pooler in Mumbai"]
Postgres["PostgreSQL, public and tenant schemas"]
Browser --> Edge
Edge -->|"DNS only hostnames"| Netlify
Edge -->|"proxied hostnames"| Traefik
Traefik --> Backend
Backend --> Redis
Backend --> Pooler
Pooler --> Postgres

The path in words, for an API call:

  1. The browser reaches the Cloudflare edge, which holds DNS, TLS, the WAF, and a rate limit of 40 requests per 10 seconds per IP on /api/auth.
  2. Cloudflare forwards to the VM. Traefik terminates TLS with a Let’s Encrypt certificate and routes to the container on port 8000.
  3. brewlabs-billu-backend/app.js runs the global middleware: dynamic CORS, helmet, compression, JSON parsing with a 10 MB limit, standardResponseMiddleware, profilerMiddleware, and a 60 second request timeout from REQUEST_TIMEOUT_MS.
  4. applyMultiTenantMiddlewareChains(app) in src/architecture/databaseMiddlewareChain.js mounts each route group with its own chain. Tenant routes get UnifiedAuthMiddleware.authenticate, then UnifiedTenantMiddleware.setupTenantContext, then modelsSafetyLayer. Public routes for auth, onboarding, QR, sessions, and the customer app get the shorter publicChain.
  5. The handler calls req.dbContext.executeInTenant or req.dbContext.readInTenant, which setupTenantContext installs on the request.
  6. src/core/database/databaseExecutor.js picks the schema, wraps the call in a transaction for writes, and hands the handler a set of models bound to that schema. Sequelize writes schema-qualified table names, so the SQL names the schema explicitly.
  7. PostgreSQL answers through the Supabase pooler. Reads without a transaction go through readWithTenant and never open one.

A GET request on a tenant route is downgraded to readInTenant automatically unless the caller passes forceTransaction.

How the pieces talk

FromToMechanism
BrowserBackendHTTPS to VITE_API_BASE_URL, with Authorization: Bearer <jwt> and the headers x-panel-type, x-outlet-id, and x-organization-id set in brewlabs-billu-frontend/src/https/axiosWrapper.js
BrowserBackendSocket.IO over the same HTTP server for order and alert events, set up in src/infrastructure/websocket/socketService.js
BackendPostgreSQLOne Sequelize instance for every schema, created in src/config/unified_database.js
BackendRedisCache, rate limiting, and BullMQ queues through ioredis, configured in src/config/redis.js
BackendRazorpayPayment orders and webhooks in src/controllers/tenant/paymentController.js
BackendCloudinaryImage uploads through src/utils/imageUpload.js
BackendFirebasePush notification delivery through the Admin SDK, configured in src/config/firebase.js
BackendSMTPOTP email through nodemailer in src/auth/otp.service.js
BackendS3-compatible storageE-bill uploads in src/services/ebillService.js
HostGrafana CloudAlloy ships host metrics and container logs, config at monitoring/alloy/config.alloy
Hosthealthchecks.ioBackup and heartbeat jobs ping a dead-man check
UptimeRobotPublic URLsFour external HTTP checks every five minutes

The infra notes list Auth0 as part of backend auth. The code does not bear that out. Authentication is a JWT signed in src/core/auth/tokenService.js from process.env.JWT_SECRET and read back by src/core/auth/unifiedAuthMiddleware.js. Google sign-in comes from passport-google-oauth20, and the Firebase Admin SDK is used for push, not for login. Auth0 appears only in the frontend, as @auth0/auth0-react.

Background work

Four things run without a request.

JobTriggerCode
System metrics refreshEvery 15 minutes, plus once 30 seconds after bootcron.schedule in brewlabs-billu-backend/app.js, running scripts/update_system_metrics.js
Expire unpaid ordersEvery 5 minutescron.schedule in brewlabs-billu-backend/app.js, which scans TenantRegistry for active tenants and updates Order and Payment
FEFO expiry alertsDailystartFefoExpiryAlertCron in src/workers/fefoExpiryAlertCron.js
Notification, onboarding, and snapshot queuesBullMQsrc/workers/notificationWorker.js, src/workers/onboardingWorker.js, src/workers/snapshotWorker.js, started only when Redis is real

Startup is not a no-op. brewlabs-billu-backend/app.js runs bootstrapControlPlane, dataFirstInitializer, runStartupMigrations, runStartupValidation, and a schema heal before it listens. Set SKIP_STARTUP_MIGRATIONS=true to skip the last three.

Where to look next

  • Multi-tenancy for how one process serves every customer.
  • The Platform section of this site for deploys, rollback, and runbooks.
  • /home/codejack/code/linode/CONTEXT.md for the full host, DNS, firewall, and backup inventory. It is the single source of truth for infrastructure.

Sources

  • /home/codejack/code/linode/CONTEXT.md
  • /home/codejack/code/linode/README.md
  • brewlabs-billu-backend/app.js
  • brewlabs-billu-backend/package.json
  • brewlabs-billu-backend/Dockerfile
  • brewlabs-billu-backend/src/architecture/databaseMiddlewareChain.js
  • brewlabs-billu-backend/src/config/corsConfig.js
  • brewlabs-billu-backend/src/config/unified_database.js
  • brewlabs-billu-backend/src/config/control_plane_db.js
  • brewlabs-billu-backend/src/config/redis.js
  • brewlabs-billu-backend/src/config/firebase.js
  • brewlabs-billu-backend/src/config/config.js
  • brewlabs-billu-backend/src/core/database/databaseExecutor.js
  • brewlabs-billu-backend/src/core/tenant/unifiedTenantMiddleware.js
  • brewlabs-billu-backend/src/core/auth/tokenService.js
  • brewlabs-billu-backend/src/core/auth/unifiedAuthMiddleware.js
  • brewlabs-billu-backend/src/infrastructure/websocket/socketService.js
  • brewlabs-billu-frontend/package.json
  • brewlabs-billu-frontend/index.html
  • brewlabs-billu-frontend/vite.config.js
  • brewlabs-billu-frontend/vercel.json
  • brewlabs-billu-frontend/.env.example
  • brewlabs-billu-frontend/src/App.jsx
  • brewlabs-billu-frontend/src/https/axiosWrapper.js
  • brewlabs-billu-crm/package.json
  • brewlabs-billu-crm/src/index.js
  • billuu_landingPage/package.json
  • billuu_landingPage/netlify.toml
  • billuu-docs/docs.manifest.yaml
  • billuu-docs/astro/astro.config.mjs