Codebase patterns for agents
High-signal rules for where code belongs and how to keep types and boundaries clean in this monorepo.
Repository shape
| Path | Role |
|---|---|
apps/web/ | React SPA (Vite), Cloudflare Pages–oriented |
apps/worker/ | Hono API on Cloudflare Workers, Drizzle + Postgres |
apps/docs/ | Documentation site (if present in workspace) |
docs/ | Human and agent-oriented documentation (ADRs, frontend guides) |
Shared npm/pnpm workspace rules live at the repo root; prefer workspace dependencies over ad-hoc relative imports across apps/.
Domain separation (frontend)
- Route ownership is expressed under
apps/web/src/domains/— e.g.shared/,hod/,developer/,employee/,technician/,admin/,auth/. - Shared pages (profile, settings, system tools) usually live under
domains/shared/pages/and are wired through the router with permission-aware shells. - Role-specific dashboards and flows live under the matching
domains/<role>/tree; avoid importing role-only pages from another role’s tree. - Cross-cutting UI:
apps/web/src/components/,layouts/,context/.
See also: ../frontend/architecture/domains.md and ../frontend/features/shared-vs-role-pages.md.
Backend (workers)
- Routes under
apps/worker/src/routes/compose Hono handlers; keep them thin and delegate to services. - Services under
apps/worker/src/lib/services/own business logic, DB access (Drizzle), cache, and integration with Durable Objects where applicable. - Types for API and domain models belong in
apps/worker/src/types/(and friends), then reused or mirrored on the web side when the client needs them (apps/web/src/types/). - IDs — Prefer centralized generators in
apps/worker/src/lib/services/id/(e.g.forMaintenance()) instead of ad-hoc UUIDs when that is the project convention.
Type safety
- Avoid
anyfor persisted or API-bound data; extend interfaces and Zod schemas where validation exists. - When adding a new endpoint, define or extend response types and use them in the client service layer (
apps/web/src/lib/services/). - i18n — Prefer typed or namespaced keys (see
apps/web/src/i18n/keys.tsand locale JSON) over raw strings in UI. - SEO (web) — The SPA sets meta via
apps/web/src/components/seo/RouteSeo.tsxusingapps/web/src/lib/seo/routeRegistry.ts.- For a new page/route: add a route pattern +
routeIdinrouteRegistry.ts, then addapps/web/locales/en.jsonstrings underseo.routes.<routeId>.{title,description}. - If the title/description depends on runtime/dynamic data (e.g. user name): render
apps/web/src/components/seo/PageSeo.tsxin that page and addseo.routes.<routeId>.dynamicTitle/dynamicDescriptionkeys (or whatever keys the page uses). - After updating SEO strings: run
pnpm locales:sync, thenpnpm locales:validate:quality(parity / English-identical report).
- For a new page/route: add a route pattern +
Internal services and logging
- Use the real public methods on
InternalLoggerService(and related services) — e.g.logSecurityEvent,suspicious,logMaintenance— with the correct argument order and stringrequestIdparameters. Do not call private cache methods from feature services unless that is the established pattern in that file.
Configuration and env
- Workers use Wrangler and typed
Envbindings; new bindings belong in wrangler config andEnvtypes. - Do not commit secrets; use
.dev.vars/ platform secrets as documented in project guides.
Documentation
- Substantial architectural choices should reference or add an ADR under
docs/architecture/decisions/. - User-facing feature documentation may go under
docs/frontend/or product docs as appropriate.