AGENTS.md
Rama main · réplica de lectura del repositorio original.
# 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/<feature>/` 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/<domain>/`. `<name>.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. `<name>.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<T>` 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 (`<name>.<topic>.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_<short_name>.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.