This monorepo uses Bun workspaces. Each package lives in packages/<name> with source under src/. Build outputs flow to dist/ and must never be edited manually. Shared tooling lives at the root (tsconfig.json, biome.json, vitest.config.ts, bun.lock); review cross-package impact before changing these files.
- Use the root
package.jsoncatalogto pin shared dependency versions. Packages reference catalog entries with the"catalog:"protocol. - Add new shared dependencies to the root catalog before consuming them in individual packages. This keeps versions centralized and avoids drift across workspaces.
- Always run
bun installfrom the repository root so that catalog resolutions and the sharedbun.lockstay in sync. - When publishing npm packages, ensure you build or pack with Bun (
bun pm pack/bun publish) so catalog references collapse to concrete semver ranges.
bun install— Sync dependencies and respect the lockfile used in CI.bun run build— Run the TypeScript project references build, emitting artifacts to everydist/folder.bun run lint— Execute Biome formatter and linter in a single pass (onlypackages/*/src/**is scanned viafiles.includes).bun testorbun run test— Execute Bun's built-in test runner across the workspace (seepackages/db/src/index.test.tsfor examples).bun run changeset— Draft release notes and version bumps via Changesets.bun run clean— Remove build artifacts and reinstall dependencies (does not delete untracked source files).
TypeScript runs with strict enabled; avoid implicit any and replace as casts with dedicated type guards or the satisfies operator where appropriate. Prefer unknown for external inputs. Use kebab-case for package folders, PascalCase for types and enums, and camelCase for variables and functions. Always commit the formatter output produced by bun run lint.
All source comments, test names, and test descriptions must be written in English.
Use Bun's built-in test runner. Co-locate tests as *.test.ts files or inside __tests__/. Name suites with behavior-focused sentences so failures highlight intent. For new features, cover both success paths and the most representative error paths. Run bun test (and bun run build when touching types) before opening a PR.
Write imperative commit summaries under 50 characters (e.g., Add chat session schema) and include context, impact, and test notes in the body when needed. PR descriptions must capture purpose, key changes, test evidence, linked issues, and screenshots or logs for user-facing updates. Attach the latest .changeset/ entry whenever a release is required.
Never commit secrets; surface runtime configuration via factories that accept environment values. Version changes must follow SemVer, with breaking updates declared in Changesets. Verify releases by checking the generated changelog and confirming publication for each package on npm. Enable secret scanning and push protection in CI (e.g., gitleaks), and require npm 2FA + provenance for publishing.
- Maintain a single dependency direction (
routes → queries → services → repositories) so that upper layers stay ignorant of lower-level details. routesshould delegate exclusively toqueries, translate their results into HTTP responses, and decide status codes. Avoid placing business logic here.queriescompose the necessaryservicesandrepositoriesper use case. Inject dependencies through factories so tests can swap in mocks easily.servicesmay depend onrepositories, but repositories must never depend on services. Extract complex domain logic into dedicated modules and keep the service layer thin.repositoriesencapsulate external SDK, SQL, or KV access and return plain or domain-specific types (string,Date, structured objects) to callers.- Separate authentication and authorization concerns inside
packages/auth. Place runtime-specific adapters underauthentication/(header.ts,supabase.ts, shared utilities, anderrors.ts) and domain policies underauthorization/(e.g.,policies/chat.tsexposingcanAccessChat). Policies can declare repository interfaces and receive concrete implementations via dependency injection. - Supabase JWT verification is handled by
createSupabaseAuthentication, which fetches the JWKS from.well-known/jwks.json; only extend this provider via dedicated modules so JWKS caching and claim validation remain centralized. - Process authenticated requests in the order
Route Handler → Authentication → Queries → Authorization → Services/Repositories, passing the authenticated actor into queries before evaluating policies.