Skip to content

Self-Hosting

Broccoli runs as one Node.js process against one SQLite file — no managed infrastructure, no platform team required to operate it.

Running it

bash
cd ui
npm install
npm run dev        # Vite on 5173 + Express on 3001, concurrently

Vite proxies /api to the Express server. Configuration comes from a .env file at the repo root — connector credentials (JIRA, GitHub) use lowercase keys (jira_url, jira_token, github_token, …), plus JWT_SECRET, ENCRYPTION_KEY and PORT.

For a production deployment behind a real domain, put nginx (or any reverse proxy) in front of the Node process to terminate TLS, and set REQUIRE_HTTPS=true plus CANONICAL_HOST=<your domain> once your certificate is in place — this turns on the app-side HTTPS redirect, HSTS, and the Secure flag on the session cookie.

Contributing

A few things worth knowing before you touch the codebase:

  • Never write to the database while the server is running. SQLite runs in WAL mode; a second writing process can produce real corruption. Stop the server, back up the database file, then run your script.
  • The database driver is synchronous. There's no await on a query — a slow query blocks the entire process, including every other user's request.
  • Tenancy is enforced in application code, not the database. There's no row-level security underneath — every read must be filtered by an identity derived from the session token, never from an id in the request body. A resource in another tenant should return 404, not 403 — a 403 confirms the resource exists somewhere.
  • There are no frontend tests in this codebase today — changes to top-level routing or layout components are unverified by definition; click through them by hand.

Testing

bash
cd ui
npx tsc --noEmit   # type-check
npm test           # server-side test suite
npm run build      # production build

Deploying

The reference deployment is a single VPS: a systemd timer polls the git remote every couple of minutes, and on a new commit to the main branch backs up the live database, pulls, rebuilds and restarts the service. There is no separate release step — merging is deploying.