ADR-0205 : Navin Enterprise AI Notes & Knowledge Workspace, espace de notes et de connaissances au-dessus du Control Plane
- Statut : proposé (2026-11-05)
- Décideurs : équipe plateforme Navin Enterprise AI, mission brief 03 (
agent_uses_cases/tel_note_meeting/03_NAVIN_NOTES_IA_EQUIVALENT_NOTION.md) - Références : ADR-0176 (modèle UC-00 dont les modules génériques sont copiés), ADR-0180 (socle frontend partagé, non
utilisé ici, voir décision 1), ADR-0174 (fournisseur de mémoire), conventions du produit
navin-enterprise-notes/CONVENTIONS.md, paquet OPAeai.notes(deploy/policies/opa/notes.rego, testsnotes_test.rego, clénotesdedeploy/policies/opa/data.json), fragment OpenFGAdeploy/policies/openfga/products/notes.fga(+notes.tests.fga.yaml,notes.tuples.yaml), gabarit Managernavin-notes-agent(navin-manager/agent-templates/navin-notes-agent.yaml,published: false,navin-enterprise-notes/navin-integration/template/manifest.yaml).
Contexte
Le brief 03 demande un espace de travail de notes et de connaissances pour les équipes d'un locataire : pages en blocs avec sous-pages, bases de données à propriétés typées (relations, rollups, formules), vues, formulaires, wikis vérifiés, tâches, coédition temps réel avec historique, recherche permissionnée, automatisations, import/export, partage (invités, liens publics, sites) et un assistant IA qui propose sans jamais décider. La cible fonctionnelle est la parité avec les usages d'un outil de type Notion ; rien de propriétaire n'est copié : ni code, ni format interne, ni marque, seul le format d'export documenté est lu par l'import. Les permissions doivent être vérifiées par le serveur sur chaque lecture, résultat de recherche, synchronisation WebSocket, export, embed, rollup et traitement en arrière-plan ; un agent n'a jamais plus de droits que l'utilisateur qu'il sert ; le contenu sous legal hold n'est ni exporté ni supprimé.
Décision
- Produit séparé
navin-enterprise-notes/(id produitnotes, secteurcross_industry) avec son propre frontend Next.js 16 + React 19 + MUI 9 au lieu du shell partagé de l'ADR-0180 : un éditeur de blocs CRDT, des vues de bases de données et un graphe de connaissances ne se décrivent pas par unproduct.manifest.jsonpiloté par le shell ; le produit n'a donc pas de manifeste de produit à la racine et le contratagent-product-manifestreste réservé aux agents sectoriels. Le BFF (OIDC, sessions Redis, CSRF, proxy/api/notes) est copié de UC-00 et adapté. - Backend FastAPI
navin_notes(hatchling, Python 3.12, mêmes épingles que UC-00) avec PostgreSQL comme source de vérité : schémanotes, tables préfixéesnotes_,tenant_idetproject_idsur chaque table, RLS activée et forcée vianotes.current_tenant()/notes.current_project(), rôlesnavin_notes_migrate(DDL) etnavin_notes_app(sans BYPASSRLS), Alembic à révisions nommées. Les fichiers restent dans le stockage objet du Control Plane, l'index sémantique dans Qdrant/Cognee via le Control Plane : jamais un second index du contenu. - Coédition par CRDT Yjs : le document vivant d'une page est un document Yjs servi par un processus
realtimedédié (pycrdt-websocket, protocoley-websocket), persisté dansnotes_crdt_documentset matérialisé en blocsnotes_blocks. Le serveur délivre un jeton de salle court (60 s) après vérification OpenFGA, ferme toute mise à jour d'un clientview/comment(code 4403), borne la taille des mises à jour et du document, et révoque les sessions à la perte d'un droit. L'identité ne vient jamais du navigateur. - Formules des bases de données : un DSL propre (lexer, parser, typage, évaluation pure, limites de profondeur et de
coût) compilé et testé avant sauvegarde ; jamais
eval, jamais d'exécution de code libre ; les sorties CSV neutralisent l'injection de formule tableur. - Autorisation en deux couches via le Control Plane : OpenFGA pour les relations (
notes_instance,notes_workspace,notes_teamspace,notes_page,notes_database,notes_form,notes_automation,notes_file, héritagecan_*de parent en enfant,public: [user:*]écrit uniquement par le service de partage) et OPAeai.notespour les décisions au-dessus des relations : partage public (classification, réglage d'instance), invités (domaine autorisé), export (legal hold, invité, format), sites (administrateur, domaine approuvé), automatisations (hôte de webhook, domaine e-mail, lancement d'agent approuvé), écriture d'agent (délégation d'un utilisateur, jamais au-delà de sa permission,dry_rund'abord au-dessus du seuil), application IA en masse (approbation au-dessus du seuil), suppression définitive (legal hold, rétention), import Notion (consentement enregistré), import de réunion (jeton de permission source), changement de rétention (tenant_admin). Fail closed, raisons triées, chaque décision auditée. - Le LLM ne décide ni n'exécute : toute sortie IA est une proposition (
notes_ai_edit_proposals) avec aperçu et diff, acceptée explicitement par un humain, idempotente, annulable ; le contenu des pages donné au modèle est une donnée non fiable, et les appels d'outils proposés sont vérifiés contre les permissions de l'appelant avant exécution. - Intégration Manager par six composants
runtime, migrate, backend, worker, realtime, web(stratégiededicated, servicenavin-notes-agent), ports de développement web 3489, API 8488, realtime 8489, Redis 6409. Le gabarit resteprepared/published: false; les artefacts sontpendingtant qu'ils ne sont pas construits. - Hors périmètre de la version 0.1.0 : empaquetage natif bureau ou mobile, SCIM, import Notion au-delà du format
d'export documenté (Markdown/CSV/HTML zippé), parité hors ligne complète (seul un cache local
y-indexeddbpurgé à la déconnexion ou à la perte d'accès est livré).
Conséquences
- Un frontend propre coûte un socle BFF/i18n/thème dupliqué depuis UC-00 et maintenu dans le produit ; en échange l'éditeur, les vues et la collaboration ne sont pas contraints par le shell.
- Le processus
realtimeest un composant de plus à superviser (santé, métriques, sauvegarde des documents CRDT) ; la cohérence PostgreSQL + snapshots CRDT est vérifiée par le test de restauration. - Toute nouvelle action sensible passe par une relation
can_*et une décisioneai.notes; une action absente de la politique est refusée (unknown_action). - Le gabarit reste absent du catalogue tant qu'aucune validation explicite n'est donnée ; les connecteurs réels (réunions, calendrier, CRM) restent à brancher via le Control Plane.
Alternatives étudiées
- Lexical (Meta) comme éditeur : écarté au profit de Tiptap/ProseMirror, dont l'intégration Yjs (
y-prosemirror), les schémas de nœuds stricts et l'écosystème d'extensions (tables, mentions, mathématiques) sont plus mûrs pour un modèle de blocs validé côté serveur. - Hocuspocus (serveur Node de collaboration) : écarté pour garder un seul langage côté serveur (Python) et appliquer
les permissions, la persistance et la révocation dans le même code que l'API ;
pycrdt-websocketfournit le même protocoley-websocket. - Modèle EAV sans contraintes pour les propriétés des bases de données : écarté ; les propriétés sont en
jsonbvalidé contre le schéma de la base (types, options, relations) avec index ciblés, et les montants en chaînes décimales. - Tailwind / shadcn pour l'interface : écartés, MUI 9 est le seul kit (cohérence avec la plateforme, RTL, a11y), sans second système de styles.
Liens
- Brief :
agent_uses_cases/tel_note_meeting/03_NAVIN_NOTES_IA_EQUIVALENT_NOTION.md(sections 2, 19, 30, 35) - Conventions :
navin-enterprise-notes/CONVENTIONS.md - Politiques :
deploy/policies/openfga/products/notes.fga,deploy/policies/opa/notes.rego - Gabarit :
navin-enterprise-notes/navin-integration/template/manifest.yaml,navin-manager/agent-templates/navin-notes-agent.yaml - Version anglaise :
docs/architecture/ADRs/en/ADR-0205-navin-enterprise-notes-agent.md