Menu
OpenCount docs

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 alike
  • TODO.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 included

Without 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 them

The 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 --build

It 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.webp

Desktop 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 lint and bun run test pass 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.ts with 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, feat and 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.