* docs: development docs match the codebase; add-a-provider playbook - architecture.md: rewritten as a ~110-line map verified against the code (processes, layout, data model from the migrations, graphs, model calls, background jobs); links the accurate topic pages - testing.md, api-reference.md, code-standards.md: rewritten from the real suite, the /api prefix and Bearer auth, and the actual error-handling pattern (no longer contradicts AGENTS.md) - change-playbooks.md: new "Add an AI provider" playbook (registry + the four hand-maintained copies + tests + docs, checked against #1443/#1444); fixes async nodes, command registration, polling paths, locale steps (LanguageToggle, satisfies TranslationShape), colocated frontend tests - development-setup.md is the single setup page (deps, .env with localhost SURREAL_URL, DB -> API -> worker -> frontend, real log lines, /health); quick-start.md and README.dev.md point to it - contributing.md: Conventional Commits, CHANGELOG rule, pre-PR checks that match CI; PR template gains ruff format and frontend checks - AGENTS files agree with the docs (provider edits, routers vs services, async nodes, checkpoint path, ADR-013, stop_on); api/AGENTS.md is a plain link instead of a Claude-only @ import - ADR index explains ADR-010 (reserved for #1332) and number-at-merge; GitHub-compatible encryption anchor; small credentials/security fixes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: address review (CI commands, async source creation, paths, ADR-010, language toggle) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
4.8 KiB
Frontend Rules (frontend/)
Normative rules for working on the Next.js frontend. Architecture and flow walkthroughs live in docs/7-DEVELOPMENT/frontend.md — this file is only what you must know before changing code. Project-wide rules are in the root AGENTS.md.
Commands (run inside frontend/)
- Dev server:
npm run dev(port 3000; API must be up at 5055 first) - Lint:
npm run lint(eslint src/) - Tests:
npm run test(vitest run) · coverage:npm run test:coverage - Build:
npm run build
Hard rules
- i18n is mandatory: every UI string goes through
t('section.key')and the key must exist in all locales undersrc/lib/locales/(currently 14; en-US is the reference). Missing keys fall back to en-US silently — keep locales in sync. Each non-en-US locale ends withsatisfies TranslationShape(type derived from en-US), so a missing/extra key failstsc; the parity test (src/lib/locales/index.test.ts) checks the same at runtime. Adding a whole language also touchessrc/lib/utils/date-locale.ts;src/components/common/LanguageToggle.tsxrenders thelanguageslist, so it needs no edit (see the i18n playbook). - Styling goes through design tokens (ADR-011): use semantic utilities (
text-destructive,bg-warn-tint,text-teal,text-type-video, …) defined insrc/app/globals.css— never raw Tailwind palette classes (text-red-600,bg-amber-50) and never hand-writtendark:color twins (tokens re-resolve per theme). The laws: fern acts, teal is the AI voice, red only destroys, warn is clay, color never washes a reading surface./dev/design(dev-only route) renders every token and primitive in both themes — it's the visual reference, and screen-level PRs must not change it. - All requests go through
apiClient(src/lib/api/client.ts); never create a second axios instance. Auth token is auto-added from localStorage keyauth-storage. - Data fetching uses TanStack Query hooks in
src/lib/hooks/withQUERY_KEYS; mutations invalidate caches and show toasts (sonner). Follow the existing hook shape. - FormData requests: nested objects/arrays must be
JSON.stringify-ed before appending; the interceptor strips Content-Type so the browser sets the multipart boundary — don't re-add it. - No automatic request retry — handle failures in the consuming code (podcast retry is an explicit endpoint/hook, not a client retry).
Gotchas
- Zustand stores with
persist: checkhasHydratedbefore rendering persisted state (SSR hydration mismatch), and keep each store'snamekey unique (localStorage collision). NEXT_PUBLIC_API_TIMEOUT_MS: default 600000 (10 min) for slow LLM calls;0disables the timeout.- SSE (
useAsk): incomplete lines stay in the buffer between reads; incomplete JSON is silently skipped — don't "simplify" the buffer handling. useSourceStatuspolls every 2s while status isrunning/queued/new.- Cache invalidation is deliberately broad (e.g.
['sources']hits all source queries) — a simplicity/perf trade-off, be precise only when it matters. - Dark mode requires the
darkclass on the document root, not justprefers-color-scheme. It's hand-rolled: the zustandtheme-store(persisted astheme-storage) sets the class viaThemeProvider— no next-themes. - Dialogs don't auto-reset form state (parent clears it) and auto-focus the first input (layout shift risk with conditional inputs). Fixed overlays use
z-50. - Provider nesting order in
app/layout.tsxmatters: ErrorBoundary → ThemeProvider → QueryProvider → I18nProvider → ConnectionGuard → Toaster. ErrorBoundary is a class component and uses the rawenUSlocale object (no hooks). i18nruns withuseSuspense: false(no SSR for translations).
Deep dives
frontend architecture · credentials system · change playbooks (i18n / frontend-only changes) · code standards
This is NOT the Next.js you know
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ (resolved from this file's directory; in monorepos the next package may not be visible from the repo root) before writing any code. Heed deprecation notices.
This block is written and re-added by next dev — verify at node_modules/next/dist/server/lib/generate-agent-files.js. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.