Skip to content

Working agreements

Source: g2labs-in/billuu-docs@9f1dcd7 · content/team/working-agreements.md · updated 2026-09-16

Where the rules live

CONTRIBUTING.md in brewlabs-billu-backend is the source for everything on this page. Read it before your first pull request. AGENTS.md in the same repo is the short version for coding agents, and README.md points at both.

The frontend repo has no CONTRIBUTING.md and no pull request template. It has one CI workflow and nothing else in .github/.

Repos and people

RepoWhat it isWhere the work happens
g2labs-in/brewlabs-billu-backendExpress API, Sequelize, PostgreSQLmain
g2labs-in/brewlabs-billu-frontendReact web appnew_design_implentation, because main is 18 commits behind it
g2labs-in/billuu_landingPageNext.js marketing sitetracked in the same issue flow

Three people maintain the code.

PersonHandleOwns
Abhilash@anonymousabhi13Backend and frontend, the API contract, the schema, the order path. The only repo admin
Aakash@Aakash-choukseyInfrastructure and CI, the build, the deploy, repo configuration
Anshul@geekyyanshulFull stack, working through the backlog

Ask on the issue, not in a direct message, so the answer stays on the record.

Branches

Trunk based. main is production. Branch from main, never push to main, and keep unrelated changes out of the branch.

PrefixUse
feat/<issue>-<slug>new behaviour
fix/<issue>-<slug>a bug from an issue
chore/<issue>-<slug>tooling, dependencies, cleanup, no behaviour change
hotfix/<issue>-<slug>production is broken now, merge back the same day

The issue number is part of the branch name. Real branches in the backend repo look like chore/16-point-at-the-queue and feat/8-client-order-id.

Commits

Conventional Commits, matching the history.

fix(orders): accept a client supplied order id
feat(inventory): record stock movements against the ledger
chore(ci): run lint before the smoke chain

Scope is the area of the codebase. One logical change per commit. The body explains why, and names the evidence for anything the message claims. Commit subjects in the real history carry the pull request number as well, for example chore(repo): untrack the env files and write down how we work here (#14).

Issues

Issues live in GitHub Issues, in the repo the work belongs to. AGENTS.md states this and names the label namespaces type/, area/, priority/ and size/.

Open an issue from a form. Blank issues are disabled in the backend repo. Each form asks for the fields that make the work checkable.

FormLabel it appliesRequired fields
Tasktype/taskcontext, what to build, acceptance criteria, how to verify, depends on, area, size
Bugtype/bugwhat happened, what should have happened, steps to reproduce, request, evidence, severity
Featuretype/featurethe problem, proposed behaviour, acceptance criteria, how we will verify it

The area/ values on the forms are area/api, area/db, area/auth, area/orders, area/inventory and area/infra. The size/ values are size/s, size/m and size/l, where s is about a day and l is a week or more.

Before you pick something up, read the pinned queue issue. It is the ordered list of what is next across both repos, so it answers “frontend or backend first” without a meeting.

There is a stale document to be aware of. docs/agents/issue-tracker.md still describes the older process, one markdown file per issue under .scratch/<feature-slug>/ with a Status: line. AGENTS.md says the tracker is GitHub Issues now and that .scratch/ is history. The old files are still in the repo at .scratch/simplify/issues/.

Triage labels

The five canonical role labels live in docs/agents/triage-labels.md. In this tracker they keep their default names.

LabelMeaning
needs-triagea maintainer has to evaluate the issue
needs-infowaiting on the reporter
ready-for-agentfully specified, ready for an agent to pick up
ready-for-humanneeds a human to implement it
wontfixwill not be actioned

Pull requests

Fill in the template. .github/pull_request_template.md asks for the user visible change, the evidence, and the risk line. None of those are optional.

SectionWhat goes in it
Closes #the issue the PR closes
What changes for the userone short paragraph. What an outlet, an operator or the next engineer notices
How to verifythe commands you ran and what they printed. A claim without output is not evidence, and the template shows the shape it wants
Riskcheckboxes for schema changes, order and payment and identity changes, API contract changes, new environment variables, and tenant data access
Reviewer noteswhere you want a second look, and what you already ruled out

Keep the PR reviewable in one sitting. Squash merge, and the branch is deleted on merge.

Review and merge

One approval from someone who is not the author. Who must give it depends on the change.

ChangeApproval must come from
Schema, migrations, orders, payments, auth, permissionsAbhilash or Aakash. Anshul reviews these and asks questions, he does not clear them alone
Docs, CI, configurationAakash merges those himself
Everything elseany one of the three, other than the author

CODEOWNERS requests the right reviewers automatically. It covers /src/architecture/, /src/utils/databaseExecutor.js, /migrations/, /src/modules/orders/, /models/ and /control_plane_models/ for both Abhilash and Aakash, and /.github/, /Dockerfile, /docker-compose.yml and /nginx.conf for Aakash alone.

Never merge your own PR into main, and never merge a red check to fix it after.

Nothing on the server enforces any of this. CONTRIBUTING.md records why, the org is on the free plan and the repo is private, so the repo has no branch protection, no required checks and no required reviews. CODEOWNERS requests reviewers and blocks nothing. A missing lock is not permission.

When main is broken, revert first and understand second. git revert <sha> on a branch, open the PR, merge it. Production deploys from main, so a red main is a deploy you cannot make.

CI gates

The backend workflow is brewlabs-billu-backend/.github/workflows/ci.yml. It runs on every push and every pull request, and it has three jobs.

The checks job, displayed as Syntax:

OrderStep
1actions/checkout@v4
2actions/setup-node@v4, Node 20, npm cache
3npm ci
4npm run check:syntax
5npm run check:secrets, step name “No credentials in tracked files”

The integration job, displayed as Bootstrap + API smoke, with a postgres:15-alpine service and the test environment variables set at job level:

OrderStep
1actions/checkout@v4
2actions/setup-node@v4, Node 20, npm cache
3npm ci
4npm run test:bootstrap
5npm run test:smoke
6npm run test:admin
7npm run test:inventory
8npm run test:accounting
9npm run test:staff

The e2e job, displayed as Frontend E2E. It declares needs: integration, so it waits for that job, and it runs only when the repository variable E2E_ENABLED is true.

OrderStep
1actions/checkout@v4
2actions/setup-node@v4, Node 20, npm cache
3npm ci
4checkout g2labs-in/brewlabs-billu-frontend into frontend/, using the E2E_FRONTEND_TOKEN secret
5npm ci in frontend/
6npx playwright install --with-deps chromium in frontend/
7node src/scripts/init-database.js --wipe
8start node app.js in the background, then poll http://127.0.0.1:8000/health until it answers
9npm run test:e2e -- --project=chromium in frontend/
10upload frontend/playwright-report/ as an artifact, on failure only

checks and integration start at the same time. e2e is the only job with a dependency.

The frontend workflow is brewlabs-billu-frontend/.github/workflows/ci.yml. One job, displayed as Build, on every push and pull request.

OrderStep
1actions/checkout@v4
2actions/setup-node@v4, Node 20, npm cache
3npm ci
4npm run build
5npm run lint, step name “Lint”

That file exists only on new_design_implentation. The frontend main has no workflow.

There is no deploy workflow on either main. The workspace checkouts on older branches still carry .github/workflows/deploy.yml. It runs lint, unit, integration and security tests on Node 18, pushes an image to ghcr.io and deploys over SSH. Do not read it as the current pipeline. Deployment is Dokploy, see below.

Checks you can run before you push

Terminal window
npm run check:syntax # parse every source file
npm run check:secrets # fail when a credential is tracked, or sits in a tracked file
npm run test:smoke # API smoke test, needs a local database

If you touched the schema, the order path, inventory or payments, run the smoke chain locally before you push. The chain is test:bootstrap, test:smoke, test:admin, test:inventory, test:accounting, test:staff, in that order. The five smoke scripts share scripts/lib/smoke-harness.js, which reads DATABASE_URL from the environment and refuses to run against anything that is not localhost. Export it first. npm run test:smoke passes against a local database in about 13 seconds.

Three groups of declared scripts cannot run today.

ScriptWhy it fails
npm run lint, npm run lint:fixeslint is not a dependency. README.md lists npm run lint under Checks anyway
npm run test:unit, test:integration, test:security, test:regressionthey point at a tests/ directory that is not in the repo
npm run test:automation, test:automation:fix, test:onboarding, test:dbthey point at tests/automation/runTests.js. The file is at src/tests/automation/runTests.js

CONTRIBUTING.md says this plainly. Until those scripts are repaired, the smoke chain is the gate.

One more path to know before you ship a schema change. CONTRIBUTING.md and CODEOWNERS both name migrations/ at the repo root. That directory is not tracked on main. The runner and the tenant migrations live in src/migrations/, and the numbered tenant migrations are in src/migrations/tenant/.

Deploy

Dokploy watches the backend repo on the billuu-app VM and injects the environment. Set variables in Dokploy, never in a tracked file. The production database is external, so a deploy does not move data.

If your change needs a migration, run it deliberately and say so in the pull request.

The infrastructure notes live in g2labs-in/linode-infra.

When you are stuck

Ask on the issue. Blocked for more than half a day, say so on the issue and take the next one.

Sources

  • brewlabs-billu-backend/CONTRIBUTING.md
  • brewlabs-billu-backend/README.md
  • brewlabs-billu-backend/AGENTS.md
  • brewlabs-billu-backend/package.json
  • brewlabs-billu-backend/docs/agents/issue-tracker.md
  • brewlabs-billu-backend/docs/agents/triage-labels.md
  • brewlabs-billu-backend/docs/agents/domain.md
  • brewlabs-billu-backend/.github/CODEOWNERS
  • brewlabs-billu-backend/.github/pull_request_template.md
  • brewlabs-billu-backend/.github/ISSUE_TEMPLATE/config.yml
  • brewlabs-billu-backend/.github/ISSUE_TEMPLATE/task.yml
  • brewlabs-billu-backend/.github/ISSUE_TEMPLATE/bug_report.yml
  • brewlabs-billu-backend/.github/ISSUE_TEMPLATE/feature_request.yml
  • brewlabs-billu-backend/.github/workflows/ci.yml
  • brewlabs-billu-backend/.github/workflows/deploy.yml
  • brewlabs-billu-backend/src/migrations/, src/migrations/tenant/ directory listings
  • brewlabs-billu-frontend/.github/workflows/ci.yml
  • brewlabs-billu-frontend/package.json
  • workspace root docs/agents/issue-tracker.md
  • backend git history on main, origin/main and origin/chore/16-point-at-the-queue for branch, commit and PR numbering examples