# Repository Instructions ## Scope These instructions apply to the entire repository. Keep changes focused, preserve unrelated work in the tree, and follow the more detailed guidance in `CONTRIBUTING.md` and `docs/` when working in a documented subsystem. The repository requires Node.js 22.19 or newer and contains three applications: - `frontend/`: Next.js web application. - `backend/`: Express API, document processing, database access, and LLM integration. - `word-addin/`: Microsoft Word task-pane add-in. The root `e2e/` directory contains the web application's Playwright tests. ## UI and Design Read `docs/design-system.md` before making a non-trivial UI change. It is the source of truth for tokens, spacing, surfaces, primitives, and accessibility. Informational labels and statuses should normally be plain text rather than decorative pill badges unless a pill is specifically requested. This does not apply to established interactive pill controls such as `PillButton`, `TabPillButton`, and `OptionPill`. Keep ordinary account identifiers and their permission/status text fully visible. Do not truncate a normal-length email or hide its status to make a compact card fit. Put independent information on separate lines, allow long unbroken values to wrap, and let controls or cards reflow based on available container width. Verify both realistic and unusually long content at narrow widths; match loading states to the same layout. See the content-fitting rules in `docs/design-system.md`. Before creating UI markup, search these locations in order: 1. `frontend/src/app/components/ui/` contains reusable web primitives such as buttons, inputs, dropdowns, search, empty states, and liquid-glass surfaces. 2. `packages/ui/` (imported as `@mike/ui`) contains framework-light components rendered by both the web app and Word add-in. Files use the `XxxUI.tsx` convention and are exported from `packages/ui/src/index.ts`, with thin web adapters or re-exports in `frontend/src/app/components/ui/` where appropriate. Code here may import `@mike/client` but never an application (`frontend/src/app/`, `word-addin/src/`). 3. `frontend/src/app/components/shared/` contains web-app building blocks that understand the application shell, including `PageHeader`, `TablePrimitive`, `TableToolbar`, `FileDirectory`, and side panels. 4. `frontend/src/app/components/modals/` and `frontend/src/app/components/popups/` contain the established modal, confirmation, and warning patterns. 5. `frontend/src/app/components//` contains feature-specific web components. Keep one-off feature behavior here instead of turning it into a primitive prematurely. For add-in-only work, low-level controls live in `word-addin/src/shared/ui/` and reusable task-pane compositions live in `word-addin/src/taskpane/components/primitives/`. If a component must render in both the web app and add-in, prefer `packages/ui/`. Export a new file from `packages/ui/src/index.ts`; both targets already scan the package for Tailwind classes. The web app is configured for shadcn's `new-york` style in `frontend/components.json`. If no existing primitive fits a non-trivial interaction, add the shadcn component from the `frontend/` directory so it lands in `src/app/components/ui/`. Do not add a new UI dependency when an existing primitive or Tailwind can solve the problem. Design changes should follow the existing liquid-glass theme, use borders sparingly, and use Lucide icons. Prefer the tokens and shared class constants in `frontend/src/app/globals.css` and `frontend/src/app/components/ui/liquid-surface.ts` over raw palette values, custom hex colors, or copied shadow strings. When changing layout or spacing, update the corresponding loading state at the same time. Table skeleton helpers (`SkeletonLine` and `SkeletonDot`) live in `frontend/src/app/components/shared/TablePrimitive.tsx`; the shared full-screen gate is `frontend/src/app/components/shared/FullScreenLoader.tsx`. Many feature loading states are colocated with their component, so search for `animate-pulse`, `SkeletonLine`, and `SkeletonDot` in the affected feature. Preserve the accessibility baseline: - Every interactive element needs a visible focus indicator. - Icon-only buttons need an accessible name, normally `aria-label`. - Non-submit buttons inside forms need `type="button"`. - Selection and toggle state must be represented with the appropriate ARIA attribute, not color alone. - Use a native checkbox with `TABLE_CHECKBOX_CLASS` from `TablePrimitive.tsx` for standalone checkbox inputs. `CheckSquare` is the directory/picker row selection visual and is decorative by default. ## Frontend Structure - Route and page components live in `frontend/src/app/`. - Shared domain types live in `frontend/src/app/components/shared/types.ts`. - Calls to the Express backend belong in `frontend/src/app/lib/mikeApi.ts` so authentication, API error parsing, and request behavior stay consistent. - Reusable client behavior belongs in `frontend/src/app/hooks/` or `frontend/src/app/lib/`, with a colocated `*.test.ts` or `*.test.tsx` file. Behavior the Word add-in also needs (error classification and toasts, the model catalog, upload sessions, response excerpts, Sentry event hygiene) lives in `packages/client/`, imported as `@mike/client`, and must stay framework-free. Its public surface is `packages/client/src/index.ts`; its tests are colocated and run with the frontend's Vitest. - Use the `@/` alias for imports rooted at `frontend/src/`. - Production frontend code must not import anything outside `frontend/` except through a `paths` alias in `frontend/tsconfig.json` whose target `frontend/Dockerfile` copies into the image. Test files may import shared fixtures and add-in sources because `frontend/tsconfig.build.json` keeps them out of `next build`; `frontend/src/__tests__/architecture.test.ts` enforces both rules. Do not expose raw backend, database, provider, or stack errors in the UI. Classify a thrown value once with `describeError` and show it with `notifyError` (both from `frontend/src/app/lib/userFacingError.ts`), which draws a `WarningPopup` that offers "Retry" only when a retry is honest and "Contact support" only for failures the user cannot fix. Auth sentences come from the single table in `frontend/src/app/lib/authMessages.ts`. See "Reporting failures" in `docs/design-system.md` for where each kind of failure is shown. ## Backend Structure - Read `docs/backend-architecture.md` before adding or moving backend code. It is the source of truth for the module layout, the layering rules, and the test that enforces them. - `backend/src/app.ts` configures Express, middleware, rate limits, and mounts one router per module. - HTTP handlers and their domain logic live in `backend/src/modules//`. `.routes.ts` is the HTTP layer: it parses params/query/body, calls the service, and maps typed results onto status codes and JSON; it never queries the database. `.service.ts` is the module's facade (named re-exports only, exactly one per module) and, for small modules, the implementation. Service code takes an explicit `db: Db` (from `backend/src/lib/supabase.ts`) plus request-derived primitives, returns typed results (`ServiceResult` from `backend/src/lib/serviceResult.ts` for new code), and never touches `req`/`res`. SSE streaming loops are the one deliberate exception and stay in the routes file. - Large modules split the service into topic files (`..ts`) behind the facade. Import a module from outside (another module, a worker, a job, `app.ts`) only through that facade. Within a module, import sibling implementations directly, never through its own facade. - `backend/src/application/` owns cross-domain account, purge and export workflows. Routes and the job registry may call it; domain implementations and facades must not import or re-export it. Application services call domain facades, accept explicit inputs and never depend on Express. - `backend/src/lib/` is the shared kernel: infrastructure and cross-domain primitives. It must not import from `backend/src/modules/` or `application/`, and neither may `backend/src/middleware/`. There is no `backend/src/routes/` directory; a new HTTP surface is a new module. - `backend/src/__tests__/architecture.test.ts` checks these rules on every test run. If it fails, fix the layering rather than the test; allowlist entries need a comment explaining why. `dependencyCycles.test.ts` also parses imports/re-exports, literal dynamic imports, require calls and type references across all four applications, the shared `packages/` sources and every local file they reach. All source cycles fail CI. - Document-version creation, activation, replacement, and deletion belong to `backend/src/modules/documents/`. Call its facade instead of writing version rows or lifecycle RPCs from another module. Callers authorize destination and copy-source scopes independently; the database trigger owns durable cleanup. - Domain job bodies live in their modules; cross-domain workflow adapters live in `application/jobs/`; `backend/src/jobs/registry.ts` composes handlers and failure hooks. Keep queue transport in `lib/dbq/` and `workers/`, and the assistant engine in `modules/chat/engine/`. - Shared serialized API/event declarations live in `packages/contracts/` and are imported with `import type` from `@mike/contracts`. Keep client display state local and update producer/consumer tests when changing a wire payload. - Authentication and other request middleware live in `backend/src/middleware/`. - LLM provider creation is centralized in `backend/src/lib/llm/providers.ts`; shared AI SDK behavior lives alongside it in `backend/src/lib/llm/`. - Backend unit and integration tests live under `backend/src/__tests__/` or beside the relevant module as `*.test.ts`. Keep route handlers thin when logic is reusable. Preserve authorization checks and ownership/project-sharing boundaries on every new query or mutation. Never send internal exception messages to clients: use the helpers in `backend/src/lib/httpError.ts`; logging must use the redaction helpers in `backend/src/lib/safeError.ts`. Intentional validation and permission failures should remain explicit 4xx responses, and a `code` a client is expected to act on must be listed in `CODE_KINDS` in `packages/client/src/userError.ts` (a drift test keeps that table to codes some server really emits). ## Database Migrations `backend/schema.sql` is the complete fresh-install schema. `backend/migrations/` contains incremental changes for existing deployments. For every new migration: 1. Use the filename `YYYYMMDD_NN_.sql`, where the date is the current date and `NN` is the next unused two-digit sequence for that date. Inspect the directory first; never create two migrations with the same date and sequence. Historical filenames do not all follow the current convention. 2. Add `-- Migration date: YYYY-MM-DD` at the top. 3. Make the new migration safe to re-run where possible: use `if exists` / `if not exists`, `create or replace` for functions, drop-before-create for policies and constraints, and guarded data backfills or type changes. 4. Update `backend/schema.sql` with the migration's final database shape in the same change, and add the migration's filename to the `schema_migrations` list at the end of that file (`backend/src/__tests__/migrationLedger.test.ts` checks the list matches the directory). 5. Preserve RLS, grants, ownership, security-definer settings, and explicit `search_path` hardening when changing database objects. Each database records the migrations it has applied in `public.schema_migrations`; `backend/scripts/migrate.sh` (also run by Compose's `db-init`) applies the files it does not list, in filename order, exactly once, each inside a transaction with its ledger row. Do not write `begin` / `commit` in a new migration; if it cannot run in a transaction (for example `create index concurrently`), add a line reading `-- migrate:no-transaction`. Never edit or rename a migration that has shipped: deployments that ran it would not run the new version. Do not assume every historical migration is safely replayable, and do not apply migrations to a remote or production database unless the user explicitly requests it and the target has been confirmed. See `docs/deployment.md` for deployment procedure and `.github/workflows/schema-drift.yml` for the fresh-versus-upgraded schema check. ## Diagnostic identity Sentry operation, error-kind, component, stage and job labels are static source-authored identifiers; adding one needs no central registration. Never interpolate user or dependency data into a diagnostic label, error name or computed function name. Preserve upstream errors as causes, not as labels. Raw messages, request payloads and arbitrary extras remain filtered centrally. The backend diagnostic source-contract test scans all three applications; review forwarded helper parameters and mappings as well. See `docs/observability.md` for the trust model and examples. ## Verification Choose the smallest verification that can catch the regression, and expand it for cross-cutting or high-risk changes. A build is not required after every small edit, but relevant tests are required for risky behavior changes and when specifically requested. Common commands from the repository root: ```bash npm test --prefix backend npm run build --prefix backend npm test --prefix frontend npm run test:coverage --prefix frontend npm run lint --prefix frontend npm run typecheck --prefix frontend npm run build --prefix frontend npm run typecheck --prefix word-addin npm run build --prefix word-addin npm run test:e2e --prefix word-addin npm run test:e2e npm run test:e2e:local npm run test:stack --prefix backend ``` A change to a Dockerfile, a `.dockerignore`, a tsconfig, or an import that crosses an application boundary must be verified by building the affected image from the repository root, for example `docker build -f frontend/Dockerfile .`. The host-side build cannot catch a missing build-context file because every sibling directory exists on the host; `.github/workflows/docker-images.yml` builds all three images on every pull request for the same reason. Use targeted Vitest files while iterating, for example: ```bash npm test --prefix backend -- src/__tests__/integration/tabular.routes.test.ts npm test --prefix frontend -- src/app/components/ui/button.test.tsx ``` The stack and browser suites require their documented local services. Consult `docs/frontend-testing.md`, `docs/e2e-ci.md`, and `docs/safe-local-testing.md` before running them. New behavior should normally have a regression test at the lowest useful layer: unit first, route integration second, and Playwright only when a real browser flow is necessary. When changing dependencies, update the `package-lock.json` belonging to the affected package. Before handing off work, run `git diff --check`, inspect the diff for unrelated changes, and report which verification commands were run. ## Branch Names Name branches after the change they contain, using a descriptive prefix such as `docs/`, `fix/`, `feat/`, `refactor/`, `test/`, or `chore/` (for example, `docs/shorten-readme-telemetry`). Never use `claude/` as a prefix. ## Pull Requests Keep a pull request focused on one feature, bug, or cleanup. Write PR descriptions in Markdown and include: - Summary. - What changed. - Why it changed. - Testing performed. Do not commit secrets, API keys, private documents, `.env` files, build output, or local test artifacts. ## Error reporting principles - Prefer small reporting helpers and clear ownership at the boundary that knows what happened. Reuse existing mechanisms before adding another policy layer. - Preserve original exceptions, causes, useful stack locations, operation/stage context, and request/job correlation. Optimize for actionable user failures. - Mark expected outcomes where they are actually handled. A recognized UI error code, HTTP status, or AbortError name alone does not prove handling or reporting ownership. Keep unowned terminal transport and response-body failures visible. - Keep the final outbound privacy allowlist protecting customer documents, credentials, and identities. Separate privacy enforcement from configurable volume policy; avoid repeat traffic starving new/severe failures. - Preserve the shared Sentry projects' hard ceiling of 50 total events per runtime per day. Match the resolved destination project, including explicitly configured DSNs, and keep quiet resets or issue eviction from replenishing that ceiling. Reserve capacity for new failures and severity escalations before repeats. - Treat console capture as a fallback, not a business-policy engine. Prefer explicit capture of the original Error with static context. - Keep development reporting off by default; avoid accumulating compiler-internal filename filters. - Verify meaningful regressions through final SDK envelopes as well as source-level tests. Test diagnostic usefulness, ownership/deduplication, and privacy. - Prefer focused simplification and root-cause fixes over suppressing symptoms or building new reporting frameworks. See `docs/observability.md` for reporting ownership and transport policy.