Skip to content

How to get the stack running locally

Source: g2labs-in/billuu-docs@7780d43 · content/start/how-to-get-running.md · updated 2026-09-26

What you end up with

Four processes. Two you run with Node, two you run with Docker.

PieceRepoCommandAddress
APIbrewlabs-billu-backendnpm run devhttp://localhost:8000
Web appbrewlabs-billu-frontendnpm run devhttp://localhost:5173
PostgreSQL 15none, a containerdocker runlocalhost:5432
Redis 7none, a containerdocker runlocalhost:6379

Redis is optional. The browser flow works without it.

Steps 3 to 8 were run end to end against the current main of the backend and the current new_design_implentation of the frontend, on Linux with Node 25 and Docker 29. Where another document describes a step that does not work, this page says so and gives the command that does.

Prerequisites

ThingVersionWhere that is pinned
Node.js20.github/workflows/ci.yml uses node-version: '20', Dockerfile.dev uses node:20-alpine
Node.js22 or newerCONTRIBUTING.md setup section
npmships with Nodenpm ci reads package-lock.json in both repos
Docker with Composerecentonly for Postgres and Redis
gitanyaccess to both g2labs-in repos

Nothing enforces the Node version. Neither repo has an .nvmrc and neither package.json declares engines. Use 20 to match CI, or 22 or newer to match CONTRIBUTING.md. Install it with nvm or mise if your machine defaults to something newer.

Ports 8000, 5173, 5432 and 6379 must be free.

Step 1. Clone the two repos side by side

Terminal window
mkdir -p ~/code && cd ~/code
git clone https://github.com/g2labs-in/brewlabs-billu-backend.git
git clone https://github.com/g2labs-in/brewlabs-billu-frontend.git
git clone https://github.com/g2labs-in/brewlabs-billu-admin.git breww-admin

Use the SSH URLs (git@github.com:g2labs-in/...) if your key is set up.

The backend stays on main. The frontend does not.

Terminal window
cd brewlabs-billu-frontend
git checkout new_design_implentation
cd ..

new_design_implentation is the frontend branch the work is on. It is 18 commits ahead of the frontend’s main, it is the branch that carries the frontend CI workflow, and docs/LOCAL_SETUP.md in the backend repo names it as the branch to test against.

Step 2. Install dependencies

Terminal window
cd ~/code/brewlabs-billu-backend && npm ci
cd ~/code/brewlabs-billu-frontend && npm ci

npm ci wipes and reinstalls node_modules from the lockfile. The two trees are roughly 225 MB and 860 MB.

Step 3. Start Postgres and Redis

CONTRIBUTING.md and README.md both tell you to run docker compose up -d postgres redis from the backend repo. That command fails.

$ docker compose up -d postgres redis
no such service: postgres

The backend’s own docker-compose.yml declares api, db, pgbouncer and redis. There is no postgres service. The db service also publishes no host port, so an API running on your host cannot connect to it even if you start it. That file describes the deployed stack, not a local dependency.

Two commands that do work.

Terminal window
docker run -d --name billu-postgres -p 5432:5432 \
-e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=brewwlabs postgres:15-alpine
docker run -d --name billu-redis -p 6379:6379 redis:7-alpine

Postgres prints rejecting connections while it initialises and then accepting connections. Check it with:

Terminal window
docker exec billu-postgres pg_isready -U postgres -d brewwlabs

The user, password, port and database name above match .env.example exactly, so step 4 needs no database edits. POSTGRES_USER is not set, which gives you postgres.

The workspace directory that holds the clones has a second option. It carries a Makefile, a docker-compose.yml and a .env.example of its own, and docker compose up -d postgres redis works there. Be aware of two things. Those three files are not in any repo, so a fresh clone will not have them. That postgres service creates a database named control_plane, so you have to point DATABASE_URL and CONTROL_PLANE_DATABASE_URL at localhost:5432/control_plane instead of brewwlabs.

Step 4. Create the backend environment file

Terminal window
cd ~/code/brewlabs-billu-backend
cp .env.example .env

.gitignore tracks .env.example and ignores .env and .env.*. Never commit a real file.

Four things in .env matter for a local run.

VariableValueWhy
DATABASE_URLpostgresql://postgres:postgres@localhost:5432/brewwlabsalready the value in .env.example, and the value the container in step 3 accepts
CONTROL_PLANE_DATABASE_URLthe same valuethe control plane lives in the public schema of the same database
ENCRYPTION_KEY64 hex charactersmissing from .env.example. Step 5 fails without it
JWT_SECRET, REFRESH_TOKEN_SECRETany string locallytoken signing

The exact failure without ENCRYPTION_KEY:

❌ Missing environment variables: ENCRYPTION_KEY

src/scripts/initialize_control_plane.js requires it and checks the format. Use the dev-only key that .env.example already carries for CONTROL_PLANE_KMS_KEY:

ENCRYPTION_KEY=62e9e04562382067c920181ba498f5978ed9b9687903957e8e900981d137cd95

Leave the optional integrations empty. Razorpay, Cloudinary, Firebase, WhatsApp, email and Google OAuth have no local values, and the features that need them fail on their own. NODE_ENV=development, PORT=8000 and FRONTEND_URL=http://localhost:5173 are already in .env.example and should stay as they are.

Two details about how the file is read.

  • app.js loads .env at the top and then forces NODE_ENV=production if it is unset. Keep NODE_ENV in the file.
  • A few scripts load .env.local instead, for example src/scripts/check-associations.js and src/scripts/resetPassword.js. Create .env.local only if you run those.

The frontend needs no environment file. vite.config.js proxies /api to process.env.VITE_API_PROXY_TARGET or to http://localhost:8000.

Step 5. Create the schema and seed data

Terminal window
npm run migrate:control-plane
npm run seed:control-plane
node src/scripts/init-database.js --wipe
CommandRunsResult
npm run migrate:control-planesrc/scripts/initialize_control_plane.jscreates the public control plane tables, about 2 seconds
npm run seed:control-planesrc/scripts/create-superadmin.jscreates admin@brewwlabs.com with password Admin@123456
node src/scripts/init-database.js --wipesrc/scripts/init-database.jscreates the demo tenant, 10 products, 6 variants, 15 orders, and the login below

The demo login, printed by the seed script:

RoleEmailPassword
Tenant ownerdemo@brewlabs.comDemo@123
Super adminadmin@brewwlabs.comAdmin@123456

init-database.js also creates the control plane tables when they are missing, so on an empty database that one command is enough for the demo tenant. It does not create a super admin. Keep npm run seed:control-plane in the sequence if you want the admin account.

--wipe drops and rebuilds the demo tenant schema. Point it only at your own database. docs/LOCAL_SETUP.md warns about --wipe because that guide runs against the shared Supabase test instance. The warning does not apply to the local container from step 3.

The super admin is not a login for the web app. src/App.jsx signs out any session with role === "SUPER_ADMIN".

Step 6. Start the backend

Terminal window
npm run dev

That is nodemon --inspect=0.0.0.0:9229 --exec 'npm run start', which runs node app.js. npm start runs the same thing without nodemon.

The entry point is app.js at the repo root. package.json says "main": "src/app.js" and that entry is wrong.

Confirm the API and its database:

Terminal window
curl -s localhost:8000/health
{"success":true,"message":"Success","data":{"db":"ok","redis":"down","timestamp":"...","uptime":8.6,"environment":"development","version":"3.1.0-security-audit-cors-fixed","updatedAt":"2026-04-04 23:05","trustProxy":"enabled"}}

db must be ok. redis is down until step 8, and that is the expected value with the example .env.

Step 7. Start the frontend and log in

Terminal window
cd ~/code/brewlabs-billu-frontend
npm run dev

Vite serves http://localhost:5173 and proxies /api to the backend, so there is no CORS setup to do and no env file to write.

Open http://localhost:5173. The app lands on /auth. Log in with demo@brewlabs.com and Demo@123. You should land on the dashboard with the seeded outlet, showing today’s revenue, active orders and table occupancy.

Two checks that need no browser:

Terminal window
curl -s localhost:5173 | grep -o "<title>.*</title>"

That prints <title>BrewwLabs</title>.

Terminal window
curl -s -X POST localhost:8000/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"identifier":"demo@brewlabs.com","password":"Demo@123"}'

That returns {"success":true,"message":"Success","data":{"user":{...},"organization":{...}}}.

The login field on the screen and in the API is identifier, and it accepts an email or a phone number. The panel type comes from the token, not from a request header, so a scripted call needs no x-panel-type header. src/core/middleware/tokenVerification.js derives it from the role, and src/config/corsConfig.js allows the header for the browser client, which sends it.

Step 8. Optional, turn Redis on

Redis is off by default. src/config/redis.js treats it as disabled unless REDIS_ENABLED is exactly the string true, and .env.example does not set it. In that state the cache layer is an in-process mock and the BullMQ workers do not start.

With the container from step 3 running, add these to .env:

REDIS_ENABLED=true
REDIS_URL=redis://localhost:6379

Restart the backend. /health then reports "redis":"ok".

Step 9. Optional, run everything in containers

The workspace directory that holds the clones has a Makefile that drives the whole stack and the two repos together through docker-compose.yml.

TargetDoes
make initcopies .env.example to .env, then builds images
make updocker compose up -d
make up-logsstarts in the foreground and follows the logs
make downstops everything
make psshows the containers
make logs, make logs-backend, make logs-frontend, make logs-db, make logs-redisfollow logs
make restart-backend, make restart-frontendrestarts one service
make shell-backend, make shell-frontend, make shell-dbshells into a container
make migratenpm run migrate:control-plane inside the backend container
make migrate-statusnpm run df:check-migrations
make seednpm run seed:control-plane
make db-reset, make db-backup, make db-restore FILE=...database maintenance
make test, make test-unit, make test-integration, make test-securityJest suites, see the warning below
make lint, make lint-fixeslint, see the warning below
make healthpings the four services
make clean, make clean-allremoves Docker resources

Two caveats. make init copies .env.example to .env at the workspace root, which is a different file from the backend’s .env, and the root file points DATABASE_URL at the postgres service name. That compose file also mounts brewlabs-billu-backend/migrations into the Postgres data directory for first boot initialisation, and main has no tracked migrations/ directory, so the first boot applies no schema. Run make migrate after make up. And make health looks for a status field that /health does not return, so the backend line reports UNREACHABLE while the API is healthy. Use curl localhost:8000/health.

Confirm it worked

CheckCommandExpected
Database containerdocker exec billu-postgres pg_isready -U postgres -d brewwlabsaccepting connections
Schema and seednpm run df:health in the backendruns src/scripts/data-first-cli.js health and prints a health table for the database
API healthcurl -s localhost:8000/health"db":"ok"
Web appcurl -s -o /dev/null -w '%{http_code}\n' localhost:5173200
Loginstep 7, in a browserthe dashboard, with seeded orders

Troubleshooting

SymptomCauseFix
❌ Missing environment variables: ENCRYPTION_KEY from npm run migrate:control-plane.env.example has no ENCRYPTION_KEYadd a 64 hex character ENCRYPTION_KEY to .env, step 4
no such service: postgres from docker compose up -d postgres redisthe backend compose file has db, not postgresuse the docker run commands in step 3, or run compose from the workspace root
"db":"down" in /healththe API cannot reach Postgrescheck the container is up and DATABASE_URL names localhost:5432/brewwlabs
"redis":"down" in /healthRedis is disabled by defaultexpected. Set REDIS_ENABLED=true, step 8
Login fails with a network error in the browserthe API is not running, or a local frontend env file sets VITE_API_BASE_URL, which src/auth/authService.js and several components readstart the backend, and remove VITE_API_BASE_URL from any local frontend env file. The dev server proxies /api to localhost:8000 on its own
EADDRINUSE on 8000 or 5173something else holds the portfind it with ss -ltnp | grep 8000 and stop it
npm run lint fails in the backendeslint is not a dependency of the backendknown gap, recorded in CONTRIBUTING.md. Use npm run check:syntax
npm run test:unit, test:integration, test:security or test:regression failsthose scripts point at a tests/ directory that is not in the repouse the smoke chain instead, in the working agreements page
Refusing to run: DATABASE_URL host is "unset", not localhost from a smoke scriptthe smoke harness reads the environment, not .env, and refuses anything that is not localexport DATABASE_URL first, for example export DATABASE_URL=postgresql://postgres:postgres@localhost:5432/brewwlabs
The superadmin cannot log into the web appthe web app is the tenant paneluse demo@brewlabs.com, the superadmin is for the admin API
Red errors about audit_logs in the backend log right after a logina database seeded by init-database.js --wipe is missing columns the audit model writesthe login still succeeds and the API answers 200. The failed write is the audit row
Node version complaints during npm cithe shell is on a different Nodenvm use 20, then npm ci again

Sources

  • brewlabs-billu-backend/CONTRIBUTING.md
  • brewlabs-billu-backend/README.md
  • brewlabs-billu-backend/AGENTS.md
  • brewlabs-billu-backend/docs/LOCAL_SETUP.md
  • brewlabs-billu-backend/package.json
  • brewlabs-billu-backend/.env.example
  • brewlabs-billu-backend/.gitignore
  • brewlabs-billu-backend/app.js
  • brewlabs-billu-backend/docker-compose.yml
  • brewlabs-billu-backend/Dockerfile.dev
  • brewlabs-billu-backend/src/config/redis.js
  • brewlabs-billu-backend/src/config/corsConfig.js
  • brewlabs-billu-backend/src/core/middleware/tokenVerification.js
  • brewlabs-billu-backend/src/scripts/initialize_control_plane.js
  • brewlabs-billu-backend/src/scripts/create-superadmin.js
  • brewlabs-billu-backend/src/scripts/init-database.js
  • brewlabs-billu-backend/scripts/test-api-smoke.js
  • brewlabs-billu-backend/scripts/lib/smoke-harness.js
  • brewlabs-billu-backend/scripts/test-bootstrap.js
  • brewlabs-billu-backend/.github/workflows/ci.yml
  • brewlabs-billu-frontend/LOCAL_SETUP.md
  • brewlabs-billu-frontend/package.json
  • brewlabs-billu-frontend/vite.config.js
  • brewlabs-billu-frontend/playwright.config.js
  • brewlabs-billu-frontend/src/App.jsx
  • brewlabs-billu-frontend/src/auth/authService.js
  • brewlabs-billu-frontend/Dockerfile.dev
  • workspace root Makefile
  • workspace root docker-compose.yml
  • workspace root .env.example