Aller au contenu principal

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 OPA eai.notes (deploy/policies/opa/notes.rego, tests notes_test.rego, clé notes de deploy/policies/opa/data.json), fragment OpenFGA deploy/policies/openfga/products/notes.fga (+ notes.tests.fga.yaml, notes.tuples.yaml), gabarit Manager navin-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​

  1. Produit séparé navin-enterprise-notes/ (id produit notes, secteur cross_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 un product.manifest.json piloté par le shell ; le produit n'a donc pas de manifeste de produit à la racine et le contrat agent-product-manifest reste réservé aux agents sectoriels. Le BFF (OIDC, sessions Redis, CSRF, proxy /api/notes) est copié de UC-00 et adapté.
  2. Backend FastAPI navin_notes (hatchling, Python 3.12, mêmes épingles que UC-00) avec PostgreSQL comme source de vérité : schéma notes, tables préfixées notes_, tenant_id et project_id sur chaque table, RLS activée et forcée via notes.current_tenant() / notes.current_project(), rôles navin_notes_migrate (DDL) et navin_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.
  3. Coédition par CRDT Yjs : le document vivant d'une page est un document Yjs servi par un processus realtime dédié (pycrdt-websocket, protocole y-websocket), persisté dans notes_crdt_documents et matérialisé en blocs notes_blocks. Le serveur délivre un jeton de salle court (60 s) après vérification OpenFGA, ferme toute mise à jour d'un client view/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.
  4. 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.
  5. 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éritage can_* de parent en enfant, public: [user:*] écrit uniquement par le service de partage) et OPA eai.notes pour 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_run d'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.
  6. 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.
  7. Intégration Manager par six composants runtime, migrate, backend, worker, realtime, web (stratégie dedicated, service navin-notes-agent), ports de développement web 3489, API 8488, realtime 8489, Redis 6409. Le gabarit reste prepared / published: false ; les artefacts sont pending tant qu'ils ne sont pas construits.
  8. 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-indexeddb purgé à 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 realtime est 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écision eai.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-websocket fournit le même protocole y-websocket.
  • Modèle EAV sans contraintes pour les propriétés des bases de données : écarté ; les propriétés sont en jsonb validé 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