Contribution¶
How to add and change code and tests.
Adding a route¶
To add a new endpoint inside an existing feature (e.g. auth, admin, rbac, invitations):
- Router — In the feature's
*.router.ts, add the route and wrap the handler withSharedHelpers.handleIfError(Controller.method). - Controller — In the feature's
*.controller.ts, add a static method that: - Calls the feature validator to parse
req.body/req.query - Calls the feature service
- Sends the response with
SharedHelpers.sendResponse(res, status, message, isSuccess, data) - Validator — In the feature's
*.validator.ts, add a Zod schema and parse function for the new input. - Service — In the feature's
*.service.ts, add the business logic; use models and shared helpers as needed; throwSharedErrors.*on failure. - OpenAPI — If the route is part of the public API, register it in the feature's
*.openapi.ts(seeauth.openapi.ts,rbac.openapi.ts,invitations.openapi.tsandlib/openapi.ts).
Follow the existing patterns in that feature (e.g. emailPassword controller/service) and CONVENTIONS.md for response shape and errors.
Adding an auth method¶
To add a new auth strategy (e.g. magic link, social login):
- New folder under
src/auth/— e.g.src/auth/magicLink/with: magicLink.router.ts— Routes (e.g. send-link, verify-token)magicLink.controller.ts— HandlersmagicLink.service.ts— Business logic; integrate with Better Auth / session as needed-
magicLink.validator.ts— Request validation -
Strategy ID — In the new service, define a static
AUTH_STRATEGY_ID(e.g.'magic-link'). This is the URL segment under/api/auth/. -
Mount in auth router — In
src/auth/auth.router.ts: import magicLinkRouter from './magicLink/magicLink.router';import MagicLinkService from './magicLink/magicLink.service';- Add:
authRouter.use('/' + MagicLinkService.AUTH_STRATEGY_ID, magicLinkRouter); -
If the strategy is optional per app, use
AuthMiddleware.requireStrategyForApp(MagicLinkService.AUTH_STRATEGY_ID)on the router (see emailPassword.router.ts). -
Auth app config — If only some apps use this strategy, add or update a config in
src/authApps/(e.g.*.config.ts) so the auth app'sstrategiesinclude the new ID. -
OpenAPI — Register the new paths in
auth.openapi.ts(or a dedicatedmagicLink.openapi.tsif you split).
Use emailPassword, emailOtp, and smsOtp under src/auth/ as reference for structure and how they're mounted.
Adding tests¶
Integration tests are config-driven: each suite loads a JSON config and the runner executes HTTP and DB steps, then asserts responses.
Add a new suite¶
- Config file — Create
tests/configs/<area>.<feature>.json(e.g.tests/configs/auth.magicLink.json). Structure: suiteId— Short name for the describe blockflows— Reusable sequences of steps (HTTP and/or dbRead, dbWrite, dbInsert); each flow hasflowIdandsteps-
tests— Each test hastestId,request,expectedResponse, and optionalpreflowIds(flows to run first; captured values can be used in the test request via{{flow.flowId.key}}) -
Suite file — Create
tests/suites/<area>.<feature>.integration.test.ts: beforeAll(() => TestHelpers.beforeAll());afterAll(() => TestHelpers.afterAll());-
runConfigSuite('tests/configs/<area>.<feature>.json'); -
Request —
requesthasmethod,path, optionalheaders,body,query. Paths and body can use{{flow.flowId.key}}to inject values captured in a preflow. -
Expected response —
expectedResponsehasstatusand optionalbody,headers. Top-level keys inbodymust match exactly. Fordatayou can use__keys(list of keys that must exist and be non-empty strings) and__arrayKeys(keys that must be arrays); seetests/types/testConfig.types.ts. -
Flows — Steps can be
type: 'http'(default),dbRead,dbWrite,dbInsert. Usecaptureto store response or document values for later steps (e.g.$body.data.token,$.codefor a dbRead doc). Dates indbInsertsupport__nowand__now+MS.
See TESTS.md for config format details and examples in existing configs.
Test thresholds and coverage¶
Running tests¶
From repo root:
npm run test:integration --workspace=jadu-auth-be
From be/:
npm run test:integration
With coverage (enforced on pre-push when be/ changes):
npm run test:integration --workspace=jadu-auth-be -- --coverage
Thresholds¶
Coverage is enforced at 98% for lines, functions, branches, and statements (see vitest.config.integration.ts). The same run is used by the pre-push hook (Lefthook) when you push changes under be/.
Excluded from coverage¶
The following are excluded so that thresholds reflect meaningful code:
| Pattern | Reason |
|---|---|
**/*.openapi.ts |
OpenAPI spec glue; no runtime logic |
src/index.ts |
Entry point; exercised by integration tests via the app |
src/**/*.config.ts |
Config objects; validated at load |
src/**/*.types.ts |
Type definitions only |
src/lib/jwt.ts |
Compatibility shim; production uses Better Auth |
src/models/**/*.ts |
Data-access; exercised indirectly via services |
To change thresholds or exclusions, edit be/vitest.config.integration.ts.