Contributing¶
Thanks for considering contributing to tap. This is a self-hosted project maintained by and for its users — issues, bug reports, and pull requests are all welcome. Participation is governed by the Code of Conduct; found a security issue instead of a regular bug? See SECURITY.md rather than opening a public issue.
Getting set up¶
See the "Local development" section of the
README for backend and frontend setup.
You'll need PostgreSQL and Redis running locally (or use docker compose up postgres redis from
the repo root to run just those two).
Before opening a pull request¶
Backend (cd backend):
ruff check .
ruff format --check .
mypy app
pytest --cov=app
Frontend (cd frontend):
pnpm lint
pnpm format:check
pnpm typecheck
pnpm test
pnpm build
All of the above run in CI (.github/workflows/ci.yml) on every pull request; running them
locally first saves a round-trip.
If pre-commit is installed (pip install pre-commit), run pre-commit install once to get
the fast checks (formatting, linting) automatically on every commit, and
pre-commit install --hook-type commit-msg once to also validate commit message format (see
below) before it's written.
Adding a carrier or tracking method¶
See Adding a provider — this is almost certainly the most common kind of contribution, and has a dedicated walkthrough.
Commit messages and pull requests¶
- Keep pull requests focused; unrelated cleanup makes review harder.
- Write commit messages and PR descriptions around why, not just what — the diff already shows what changed.
- Add or update tests for behavior you add or change. A bug fix without a regression test is easy to reintroduce.
Conventional Commits¶
Every commit message must follow Conventional Commits:
<type>(<scope>): <description>, e.g. fix(providers): handle 17TRACK rate-limit responses.
type is one of feat, fix, docs, style, refactor, perf, test, build, ci,
chore, revert. This isn't just style — merges to main are released automatically by
semantic-release based on these prefixes: a fix cuts a
patch release, a feat a minor release, and a BREAKING CHANGE: footer (or ! after the type)
a major release. Anything else (docs, chore, ci, ...) doesn't trigger a release at all.
pre-commit install --hook-type commit-msg (see above) checks this locally; CI checks it again
on every pull request.
Releases themselves (version, CHANGELOG.md, GitHub Release) are entirely automated by
.github/workflows/release.yml on every push to main — there's nothing to do manually, and
backend/frontend package.json/pyproject.toml versions are intentionally not kept in lockstep
with release tags; the tag and CHANGELOG.md are the source of truth for "what version is this".
Reporting issues¶
Open a GitHub issue with: what you expected, what happened instead, and — for a tracking provider issue — which carrier/provider/tracking number pattern is affected (not the tracking number itself if it identifies a real shipment; a redacted or synthetic example is fine).