Skip to content

docs: align documentation with code + add a doc-drift CI guard#151

Open
aliceout wants to merge 11 commits into
mainfrom
claude/amazing-hamilton-f1ghyc
Open

docs: align documentation with code + add a doc-drift CI guard#151
aliceout wants to merge 11 commits into
mainfrom
claude/amazing-hamilton-f1ghyc

Conversation

@aliceout

Copy link
Copy Markdown
Owner

Contexte

Revue complète de toute la documentation (docs en ligne nodea.app/docs, docs docs/, et commentaires de code) pour vérifier l'alignement doc ↔ code dans les deux sens, repérer les doublons, et réduire les sources de vérité.

Verdict : le code était la référence correcte dans ~tous les écarts — aucun bug de code, aucune régression de sécurité. Tout était de la dérive documentaire (~50 écarts). Ironie : la source de vérité crypto déclarée (tech.md) était la plus fausse (buildAAD inexistant, formule de guard à une passe au lieu de deux), alors que Database.md/Architecture.md décrivaient le code correctement.

Ce qui change (11 commits thématiques)

Commit Portée
docs(security) tech.md : vrais builders AAD (factor-wrap.ts), formule de guard à deux passes, catalogue des 35 rate-limiters
docs(architecture,db) routes /{collection}/records, collections.ts, schéma splité, SameSite=Strict, 8 slices, 13 tables, colonnes device_label_*
docs(adr) notes Update (client = 15 fichiers/~71 fns ; slice composer supprimé → 8)
fix(comments) refs mortes (docs/roadmap/health.md ×4, security-audit.md, modules_list.tsx)
docs(diagrams) chemins d'endpoints auth corrigés dans 3 diagrammes
docs(modules) payloads snake→camelCase, enums/champs réels, bannière « Habits dormant »
docs(public) variables self-host (ADDRESS/SMTP_PASS), ports, commande e2e, 17 namespaces
build(docs) garde-fou CI check-docs.mjs + Node 24 (engines + .nvmrc)
docs(auth) Auth-Spec + 7 flows : modèle cookie, endpoints en 2 temps, champs, codes d'erreur, rate limits
docs(api) 27 en-têtes de fichiers (routes)
docs(shared,db) 15 en-têtes schémas + 3 en-têtes DDL

Doublons réduits (« moins de sources = moins de risques »)

  • Faits crypto (AAD, guard) re-pointés vers une source unique (le code).
  • Matrices de re-auth des docs de flow remplacées par des renvois à Auth-Spec §6.
  • Toutes les références de chemin mortes éliminées.

Proposition implémentée : un garde-fou anti-dérive

scripts/check-docs.mjs (câblé dans ci.yml, lançable via pnpm check:docs) fait échouer le build si une doc cite un chemin de dépôt inexistant ou si un compteur (slices / namespaces / tables d'entrée) diverge du code. Il a déjà attrapé 11 refs mortes supplémentaires corrigées dans cette PR.

À noter

  • Commits « Unverified » : l'environnement éphémère n'avait pas de clé de signature privée (seulement un .pub vide) — l'identité (Claude <noreply@anthropic.com>) est correcte, seule la signature manque.
  • Suivi optionnel non inclus (refacto invasive) : dédoublonner Auth-Spec §8/§9 (~120 lignes répétées avec les docs de flow) — à faire délibérément.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CpnWVGG39KuHDA6paXsqY6


Generated by Claude Code

claude added 11 commits June 20, 2026 16:59
- AAD: replace the non-existent buildAAD(parts[]) length-prefixed model
  with the real factor-wrap.ts string builders (nodea:v1\x1f<id>\x1f<tag>)
- guard: document the two-pass scoped-HMAC derivation, not a single HMAC
- collections registry path: collections/registry.ts -> collections.ts
- rate-limit catalog: rebuild exhaustively from the 35 rateLimit() sites
  (add /records, change-email, recover-kek/verify, modules-config,
  user-preferences; fix mfa/bypass + passkey + login/reset paths)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpnWVGG39KuHDA6paXsqY6
… code

Architecture.md:
- routes: /{collection}+collection-factory.ts -> unified /records+records.ts
- collections registry path -> src/collections.ts (COLLECTIONS array)
- schema path -> db/schema/<domain>.ts barrel
- cookie SameSite=Lax -> Strict (matches auth/cookies.ts + SEC-08)
- store slice list -> the 8 real slices (drop mobileMenuOpen/composer)
- guard derivation -> two-pass scoped HMAC; otplib 13.4.0 -> 13.4.1
- HRT: note hrt_suppliers_entries carries the hrt_products payload
- drop brittle hard test counts

Database.md:
- 9 entry tables -> 13; factory in schema/entries.ts; collections.ts
- guard formula -> two-pass; schema path -> db/schema/<domain>.ts
- sessions: add device_label_cipher/_iv, mark ip_hash/user_agent deprecated

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpnWVGG39KuHDA6paXsqY6
- ADR-0007: client is now 15 files / ~71 functions, not 14; decision stands
- ADR-0013: the composer slice was removed; the store has 8 slices now

Respects ADR immutability via dated Update sections (same convention as
ADR-0016), rather than rewriting the historical decisions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpnWVGG39KuHDA6paXsqY6
- drop dead pointers to untracked docs/roadmap/health.md (x4),
  docs/security-audit.md and docs/Operations.md
- modules_list.tsx -> modules-registry.tsx (module-ids, Navigation)
- store header: nine -> eight slice creators
- Navigation: module comes from the flow slice, not a :moduleId URL

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpnWVGG39KuHDA6paXsqY6
- MfaBypass: POST /mfa-bypass/request -> /auth/mfa/bypass/request
- OpaqueFlow: /login/finish returns { needsMfa, id }; wrap blobs come
  from a follow-up GET /auth/me/crypto (not inlined)
- SteppedMfa: /auth/mfa/totp -> /verify; /auth/mfa/passkey -> {start,finish}

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpnWVGG39KuHDA6paXsqY6
- snake_case payload blocks -> camelCase (wire format, ADR-0012) across
  Mood, Goals, Journal, Library, Review, Habits
- Mood: moodScore is string-only; moodEmoji legacy/optional
- Goals: add completedAt/updatedAt; document legacy status aliases
- Journal: type literal journal.entry; export key modules.journal[]
- Library: drop non-existent page_count/current_page; fix dead refs
  (cache.ts path, MarkdownEditor, records.ts); add collection field
- Review: camelCase envelope; document top-level closing + updatedAt
- Habits: dormant-status banner (#98); French category enum
- registry: HRT comment now names all four collections

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpnWVGG39KuHDA6paXsqY6
- self-host: WEB_BASE_URL -> ADDRESS (required); SMTP_PASSWORD -> SMTP_PASS;
  OPEN_REGISTRATION is a DB/admin setting, not env; web port 8080;
  add COOKIE_SECURE + DATA_DIR
- README: dev:web port 8089; soften hard test counts
- Internationalisation: 14 -> 17 namespaces (+ habits/hrt/library)
- fork: four packages incl. e2e; e2e command 'e2e' not 'test';
  colour tokens live in dirk.css (--color-k-accent)
- CONTRIBUTING: e2e command fix; SECURITY: drop non-existent infra/
- CLAUDE.md: monorepo line lists packages/e2e

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpnWVGG39KuHDA6paXsqY6
- scripts/check-docs.mjs: fail CI on dead repo-path references in docs
  and on slice/namespace/entry-table count drift; wired into ci.yml
- engines: node >=24, pnpm >=10; add .nvmrc; CI Node 22 -> 24
  (matches both Dockerfiles + @types/node)
- fix residual dead refs: tech.md cron.ts, ADR-0011 Operations.md note

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpnWVGG39KuHDA6paXsqY6
- cookie model: single nodea_session (SameSite=Strict), kind-discriminated
  (drop the 4 __Host- cookies + loadSession draft)
- middleware table: the real five; no loadSession/requireRegisterSession/migrate
- 2-step endpoints: reauth, reset (start/finish); inline MFA finalization
  (no /auth/mfa/finalize); passkey MFA = /mfa/passkey/{start,finish}
- single /auth/mfa/totp/verify handles TOTP + backup (no verify-backup)
- recovery /finish: 5 camelCase fields, blobs nulled; regenerate path
- self-delete: DELETE /auth/me (no confirmation_phrase)
- change-password/start body: { registrationRequest } only
- register errors as reason sub-fields; UV anti-enumeration note
- AAD builders + hash_mismatch log line; schema file map; rate-limit table
- add passkey rename + session device-label routes; §6 pointers (de-dup)
- fix dead path refs (cron.ts, src/test, packages/e2e/tests, passkey/)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpnWVGG39KuHDA6paXsqY6
Every >50 LOC file in packages/api/src/routes/ now opens with the
mandated 3-part header (what / where / non-obvious invariants) — the
routes layer was at 0% coverage. Captures per file: endpoints + mount,
gating middleware, rate-limit buckets, and the security-relevant
invariants (guard-exempt 1:1 tables, invite atomicity, inline MFA
finalization, anti-enumeration, destructive vs non-destructive recovery).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpnWVGG39KuHDA6paXsqY6
- packages/shared/src/schemas/*.ts (>50 LOC): file-level overview above
  the existing per-symbol docs — role, front+back single source, wire
  conventions (camelCase/ADR-0012), EntryView omits guard, COLLECTION_NAMES
- packages/api/src/db/schema/{users,auth,admin}.ts: top overview listing
  every table in the file + its FK-cascade posture (entries.ts/enums.ts
  already carried file-level blocks; modules.ts is sub-50-LOC, exempt)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpnWVGG39KuHDA6paXsqY6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants