|
| 1 | +# Contributing to TimeTrackerAPI |
| 2 | + |
| 3 | +The project mirrors on [GitHub](https://github.com/CryptoJones/TimeTrackerAPI) |
| 4 | +and [Codeberg](https://codeberg.org/CryptoJones/TimeTrackerAPI). PRs and |
| 5 | +issues on either forge are welcome; commits are pushed to both. |
| 6 | + |
| 7 | +For vulnerability reports, see [`SECURITY.md`](SECURITY.md) — those use |
| 8 | +private channels, NOT public issues. |
| 9 | + |
| 10 | +## Quick start |
| 11 | + |
| 12 | +```bash |
| 13 | +git clone https://github.com/CryptoJones/TimeTrackerAPI.git |
| 14 | +cd TimeTrackerAPI |
| 15 | +cp .env.example .env |
| 16 | +# edit DB_PASSWORD in .env (see .env.example for the full env knob list) |
| 17 | + |
| 18 | +npm ci |
| 19 | +docker compose up -d postgres setup # local Postgres + schema bootstrap |
| 20 | +npm run migrate # apply all sequelize migrations |
| 21 | +npm test # unit + api + integration |
| 22 | +npm start # serves on PORT (default 3000) |
| 23 | +``` |
| 24 | + |
| 25 | +`npm test` runs the full vitest suite (45+ files, 479+ cases at this |
| 26 | +writing). The integration suite (`tests/integration/`) auto-skips when |
| 27 | +no Postgres is reachable, so a fresh `npm test` without docker still |
| 28 | +passes the unit + api tiers. |
| 29 | + |
| 30 | +## Before you open a PR |
| 31 | + |
| 32 | +- **`npm run lint`** — eslint flat-config (`no-unused-vars`, `eqeqeq`, |
| 33 | + `no-console`, etc.). CI gates on this. |
| 34 | +- **`npm test`** — the full suite must pass. New features that touch |
| 35 | + controllers / middleware should land with new tests covering the |
| 36 | + happy + 4xx paths. |
| 37 | +- **`npm run audit`** — `npm audit --audit-level=high --omit=dev`. |
| 38 | + CI fails on any high/critical advisory affecting production deps. |
| 39 | +- **OpenAPI:** if you add or change an endpoint, update |
| 40 | + `app/config/openapi.js` (Swagger UI at `/docs` reads from it, and |
| 41 | + the Postman collection is generated from it via |
| 42 | + `openapi-to-postmanv2` — see [README.md](README.md) for the |
| 43 | + one-liner). |
| 44 | +- **CHANGELOG.md:** add a one-paragraph entry under `[Unreleased]` |
| 45 | + describing what changed and (briefly) why. |
| 46 | + |
| 47 | +## Commit style |
| 48 | + |
| 49 | +Conventional-commit-ish: subject begins with `feat:`, `fix:`, `chore:`, |
| 50 | +`refactor:`, `docs:`, `test:`, or `ci:` followed by a scope in parens |
| 51 | +when useful (`feat(api):`, `fix(server):`). Body explains the why, |
| 52 | +not just the what. Multi-paragraph is fine for non-trivial changes. |
| 53 | + |
| 54 | +If you co-author with an AI assistant, add a `Co-Authored-By:` trailer |
| 55 | +naming the model + the tool — keeps attribution honest for downstream |
| 56 | +forks. |
| 57 | + |
| 58 | +## What gets reviewed |
| 59 | + |
| 60 | +- **Auth scoping.** Every new endpoint that touches a domain entity |
| 61 | + must enforce the right `getCompanyId*` helper in |
| 62 | + [`app/middleware/auth.js`](app/middleware/auth.js) — direct, customer, |
| 63 | + job, vendor, or header-scoped. Master vs non-master semantics need |
| 64 | + to be explicit in the controller. |
| 65 | +- **Input validation.** Bodies go through `zod`-strict whitelists |
| 66 | + in [`app/schemas/`](app/schemas). Unknown fields are rejected, not |
| 67 | + silently stripped. |
| 68 | +- **Soft-delete.** Models with an `*Arch` column carry |
| 69 | + `defaultScope: { where: { *Arch: false } }`. Archived rows are |
| 70 | + invisible to reads by default; ops that need to see them must |
| 71 | + `.unscoped()` explicitly. |
| 72 | +- **No raw SQL** when a model call works. The `app/middleware/auth.js` |
| 73 | + P5-M refactor is the precedent: model methods are mockable, |
| 74 | + raw `sequelize.query` is not. |
| 75 | +- **Logger.** Anything that previously called `console.*` outside |
| 76 | + startup should route through `app/config/logger.js` (`log.info`, |
| 77 | + `log.warn`, etc.) — that's what feeds the structured request log, |
| 78 | + redaction layer, and OTEL future. |
| 79 | +- **Tests.** New code lands with tests. The `_setDbForTesting` seam |
| 80 | + on `auth.js` + `idempotency.js` lets HTTP tests drive success |
| 81 | + paths without a real DB; use it instead of integration-only |
| 82 | + coverage when possible. |
| 83 | + |
| 84 | +## What you DON'T need |
| 85 | + |
| 86 | +- A signed CLA. The project is Apache-2.0 and contributions are |
| 87 | + accepted under the same terms. |
| 88 | +- A particular Node version, beyond the engines pin |
| 89 | + (`>=20.0.0`). The CI matrix tests against Node 20 and 22. |
| 90 | +- A particular IDE / editor. Just match the existing whitespace |
| 91 | + conventions (4-space indent in JS, 2-space in YAML). |
| 92 | + |
| 93 | +## Where to start |
| 94 | + |
| 95 | +- Look at issues labelled `good first issue` on either forge. |
| 96 | +- Run the test suite locally and read the test file headers — they |
| 97 | + document the conventions used across the codebase (vi.mock |
| 98 | + caveats, how master-vs-scoped is exercised, etc.). |
| 99 | +- Skim [`CHANGELOG.md`](CHANGELOG.md) — every architectural decision |
| 100 | + has a short rationale paragraph. |
| 101 | + |
| 102 | +Proudly Made in Nebraska. Go Big Red! 🌽 https://xkcd.com/2347/ |
0 commit comments