Contributing
The long-form documentation lives in docs/ and is published at
https://orochibraru.com/opencount. This file is the short version: what you
need to get a change landed.
- docs/development.md: setup, scripts, hooks, conventions, releases
- docs/architecture.md: how the app is put together
- docs/testing.md: the unit suite and the rules its runner enforces
CLAUDE.md: every convention, each one a hard rule, for people and AI agents alikeTODO.md: the backlog
#Requirements
- mise, which pins Bun, Go, Tesseract and Poppler. Or Bun alone, with Tesseract and Poppler installed yourself if you touch receipt reading.
- Docker, to build the image.
#Setup
mise run bootstrap # bun install, then .env with a fresh AUTH_SECRET
bun run dev # dev server on :5173, worker includedWithout mise: bun install, copy .env.example to .env and set AUTH_SECRET
(openssl rand -base64 32).
The dev server migrates ./data/opencount.sqlite and starts the worker under
watch. Delete the file to start over from a fresh instance; the setup code is in
the dev server's output.
Installing dependencies wires the git hooks through prek: pre-commit runs the
fixers and checks, commit-msg enforces Conventional Commits, pre-push runs
the type check, the import-cycle check and the unit tests.
#The commands
bun run dev # Vite dev server on :5173, with the worker
bun run build # build/server and build/worker
bun run start # run the compiled server, which spawns the worker
bun run check # svelte-check (fails on warnings) and tsc
bun run lint # every prek hook over every file
bun run format # bun fmt, Markdown included
bun run circular # fails on an import cycle
bun run test # unit tests
bun run test:integration # HTTP flows against the built server
bun run test:e2e # Playwright against the built server
bun run db:generate # a migration from the schema
mise run verify # every hook at the commit and push stages, as CI runs themThe package manager is bun. Never npx or npm.
#The container
compose.yaml builds the image from your checkout and runs it on port 3000,
with AUTH_SECRET and ORIGIN from .env:
docker compose up --buildIt is for checking the real container before a PR. Self-hosters use
compose.prod.yaml, which pulls the published image; keep the two in step.
#Screenshots
mise run screenshots # every screen into docs/images/
mise run showcase # the README hero, docs/images/feature.webpDesktop shots are dark theme at 1440 by 900, phone shots light theme at 390 by 844. Rerun them when a change moves a screen, and commit the images with it.
#Before you open a PR
bun run check,bun run lintandbun run testpass on the whole repo, with zero warnings.- A schema change comes with its generated migration. Committed migrations are append-only: fix a bad one with a new one.
- A new environment variable is declared in
src/env.tswith a schema and a description, and documented in docs/configuration.md. - A user-facing change updates the page of
docs/that describes it. - Every screen still works at 375px wide.
- Conventional Commit title. Squash merges turn it into the commit releaser
reads, and
fix,featand the rest all ship in the next canary.
This guide lives in the project repo: edit it there, and this page follows within a day.