Arc OS — Architecture
Vue d'ensemble
Arc OS remplace 11 321 lignes d'infrastructure Python/JS sur mesure par des outils natifs Claude Code. L'agent IA est le backend.
Architecture système (Phase 52.1)
graph TB
User[👤 Navigateur utilisateur :18888]
TG[📱 Telegram]
Local[💻 IDE local]
subgraph "Edge"
Nginx[Nginx :18888<br/>basic-auth + deny-list]
FE[React CRM + Phaser<br/>conteneur frontend]
end
subgraph "Master Bot Bun :19210 — 127.0.0.1 uniquement"
ApiSrv[api-server.ts<br/>196 LOC]
Routes[master-bot/routes/<br/>auth · internal · cli · websocket]
Router[shared/routes/router.ts<br/>373 LOC dispatcher]
subgraph "19 modules domaine — Phase 48"
D1[auth · projects · workers]
D2[skills · sage · chat]
D3[wiki · files · onboarding]
D4[billing · invites · analytics]
D5[+ 7 autres]
end
end
subgraph "Bots fédérés"
Master[Master Bot<br/>orchestrateur]
Child[Child Bots<br/>par projet]
Claude[claude -p CLI]
end
subgraph "Couche intelligence"
Eval[Binary Evals]
Ctx[Context Router top-5]
Learn[Learnings inject]
Karp[Karpathy nightly loop]
end
NB[NotebookLM Bridge<br/>FastAPI :19213 localhost]
Google[(Google NotebookLM)]
DB[(SQLite WAL<br/>30+ tables<br/>migrations 001-035)]
Vault[(AES-256-GCM Vault<br/>config/vault.json)]
Bridge[Local Bridge CLI<br/>relais WebSocket]
User -->|HTTPS| Nginx
Nginx --> FE
Nginx -->|/api/crm/*| ApiSrv
Nginx -->|/api/sse/*| ApiSrv
Nginx -->|/ws/terminal| ApiSrv
ApiSrv --> Routes
Routes --> Router
Router --> D1 & D2 & D3 & D4 & D5
TG --> Master
TG --> Child
Master -.spawns via tmux.-> Child
Child --> Claude
Claude --> Eval & Ctx & Learn
Router -.queries.-> NB
Child -.auto-sync.-> NB
NB --> Google
Router --> DB
Router --> Vault
Child --> Vault
Local --> Bridge
Bridge -.ws relay.-> ApiSrv
Karp -.nightly.-> DB
Faits clés :
- 70+ endpoints REST (Phase 52.1) répartis dans 19 modules domaine sous
shared/routes/ - Bind 127.0.0.1 — Bun n'est jamais exposé en externe ; nginx proxie via le loopback
- Isolation multi-tenant —
canAccessProject(registry, chatId, project)sur chaque route protégée - Zero-Knowledge E2EE (Phase 45) — WebCrypto PBKDF2 + clé maître AES-256-GCM en
sessionStorage
LEGACY (v1) :
User → Telegram Bot (Python 111 Ko) → HybridEngine → command_queue.json
→ bridge_processor.sh → Claude → command_responses.json
→ FastAPI EventBus → WebSocket → Phaser UI
V2 (NATIVE-FIRST) :
User → Canal Telegram officiel → Session Claude Code
↓ ↓
reply/edit_message Agent Teams (TaskCreate/SendMessage)
↓
Écriture état → fichiers JSON
↓
Arc OS Bridge MCP → HTTP/SSE → Phaser UI
Réduction : 11 321 lignes → ~3 700 lignes (67 % de moins)
Composants
1. Session Claude Code (Le cerveau)
La session Claude Code remplace :
- Backend FastAPI (15 services)
- HybridEngine (39 Ko)
- bridge_processor.sh (19,6 Ko)
- response_watcher.py (14 Ko)
- event_bus.py
- supply_chain.py (13 Ko)
Toute l'orchestration se fait nativement via Agent Teams.
2. Arc OS Bridge MCP Server (Adaptateur d'état)
Serveur MCP TypeScript (Bun) qui fait le pont entre l'état Claude Code et le frontend.
Outils MCP (côté Claude Code) :
| Outil | Direction | Description |
|---|---|---|
get_office_state |
lecture | Lit state/office-state.json |
update_agent_state |
écriture | Met à jour position, statut, bulle d'un agent |
get_tasks |
lecture | Lit les fichiers de tâches Agent Teams |
get_knowledge |
lecture | Lit l'index de connaissance |
HTTP API (côté frontend) :
| Endpoint | Méthode | Description |
|---|---|---|
/api/state |
GET | État complet du bureau |
/api/tasks |
GET | Liste des tâches |
/api/knowledge |
GET | Index de connaissance |
/api/events |
GET | Flux SSE |
3. Frontend Phaser (Couche visuelle)
Phaser 3.80 + Vite. Se connecte au serveur MCP via HTTP/SSE.
Différence clé par rapport à v1 : pas de WebSocket — remplacé par SSE depuis le serveur MCP. Pas d'UI de saisie de commandes — Telegram est l'interface de contrôle.
4. Interface de commande Telegram (Couche UI tactique — Phase 21.0)
Telegram est le panneau de contrôle principal de tout Arc OS. Deux niveaux de bots :
Master Bot (@citadel_ceo_bot) :
- Clavier de réponse persistant :
Мої Проєкти/Новий Проєкт/Watchdog/Web UI - Cartes de projet inline par enfant : Restart, Delete, View MANIFEST, Active Skills
- Boutons CRM URL : Project, Tasks, Files, Settings (liens stub vers le frontend)
- Routeur de requêtes de callback pour toutes les actions inline
- Flux de confirmation de suppression : clavier inline → YES/CANCEL → édition du message
- Enregistrement
setMyCommandsau démarrage
Child Bots (@cv2_pt_bot, etc.) :
- Chaque réponse Claude reçoit des boutons inline sur le dernier bloc :
STOP(SIGKILL) /PAUSE(SIGSTOP) /RESUME(SIGCONT) — contrôle du sous-processusBTW— met en file d'attente du contexte supplémentaire pour le prochain appel ClaudeFix It— génère automatiquement un prompt de correction depuis la dernière réponse bot
- Bouton de label skills affichant les compétences chargées du projet
- Routeur de requêtes de callback pour toutes les actions signal/contexte
Intégration CRM (développement) :
CRM_BASE_URL = http://62.171.128.248:18888 (dev)
https://crm.citadel.v2 (prod futur)
Tous les layouts de clavier sont définis dans shared/ui_templates.ts — source unique pour les changements UI.
Protocole de données callback : action:target (max 64 octets)
- Master :
restart:pt,delete:pt,confirm_del:pt,cancel_del:pt,manifest:pt,skills:pt - Child :
stop,pause,resume,btw,fixit,skills_info
Flux de données
1. L'utilisateur envoie "/status" via Telegram
2. La session Claude Code reçoit via le canal Telegram
3. Rick lit state/office-state.json + TaskList()
4. Rick répond via Telegram (edit_message pour les mises à jour en direct)
5. Rick appelle update_agent_state() via MCP
6. Le serveur MCP écrit dans state/office-state.json
7. Le file watcher détecte le changement → pousse un événement SSE
8. Le frontend reçoit SSE → met à jour les sprites d'agents
Gestion de l'état
Tout l'état réside dans des fichiers JSON sous state/ :
| Fichier | Schéma | Mis à jour par | Lu par |
|---|---|---|---|
office-state.json |
Positions agents, statut, bulles | Claude (via MCP) | Frontend (via HTTP) |
knowledge.json |
Métadonnées de fichiers indexés | Agent Squanchy | Frontend, Beth |
reports/*.json |
Sorties d'analyse | Beth, Summer | Frontend |
Les tâches Agent Teams sont gérées nativement par Claude Code dans ~/.claude/tasks/citadel-v2/.
Agents (6)
| Agent | Rôle | Modèle | Activation |
|---|---|---|---|
| Rick | CEO/Orchestrateur | opus-4.6 | Toujours actif (chef d'équipe) |
| Morty | SRE/Monitoring | haiku-4.5 | Vérifications santé, cron |
| Summer | Mémoire/Revue | sonnet-4.5 | Revue de code, sécurité |
| Jerry | Maintenance | haiku-4.5 | Nettoyage, docs |
| Squanchy | Archiviste | haiku-4.5 | Indexation de fichiers |
| Beth | Analyste | sonnet-4.5 | Recherche, analyse |
Chaîne d'approvisionnement
CEO → Rick (décompose) → Agent Team (exécute)
→ Revue croisée (Summer valide)
→ Rick (synthétise)
→ CEO (résultat final)
Appliquée via :
- Blueprints : Configurations de département définissant les rôles d'agents
- Skills : Expertise chargée dynamiquement
- Protocole HANDOFF : Passage de contexte structuré entre agents
Stack technologique
| Couche | v1 | v2 |
|---|---|---|
| Backend | FastAPI + Python 3.12 | Session Claude Code |
| Base de données | SQLite (8 tables) | Fichiers JSON + Agent Teams |
| Messagerie | WebSocket + EventBus | Agent Teams SendMessage |
| État | SQLite + pont JSON | Fichiers JSON (state/) |
| Frontend | Phaser 3.86 + WebSocket | Phaser 3.80 + SSE |
| Telegram | Bot personnalisé (111 Ko) | Canal officiel plugin |
| Bridge | bash + jq (19,6 Ko) | Supprimé |
| MCP | Aucun | Arc OS Bridge (TypeScript) |
| Déploiement | Docker Compose | Docker Compose |
Hooks de cycle de vie
Les hooks Claude Code (~/.claude/settings.json) synchronisent automatiquement l'état des agents :
Événement SubagentStop → subagent-stop.sh → office-state.json (agent=idle)
↓
StateManager (fs.watch) → SSE → Phaser UI
Événement Stop → session-end.sh → latest_wrapup.txt + tous agents=idle
Scripts : scripts/citadel-hooks/subagent-stop.sh, scripts/citadel-hooks/session-end.sh
Champs clés : subagentName (SubagentStop), stopReason (Stop), cwd (les deux).
NotebookLM Bridge (Phase 36.3)
Recherche sémantique réelle via Google NotebookLM, remplaçant les uploads manuels de fichiers :
Cloud PM Chat → Bun Master Bot (:19210)
│
executeAskNotebooklm()
│
HTTP → FastAPI Bridge (:19213, localhost uniquement)
│
notebooklm-py async client
│
Google NotebookLM (recherche sémantique gratuite)
Fallback : recherche par mots-clés locale (code existant)
- Un notebook par projet — mapping stocké dans
notebook_mapping.json - Auto-sync — fermeture/ouverture de ticket + mise à jour wiki → POST fire-and-forget vers
/sync - SyncWorker —
asyncio.Queue(200), délai 2s, backoff exponentiel (3 essais) - Cache de requêtes — LRU, TTL 5 min, max 100 entrées
- systemd —
citadel-notebooklm-bridge.service, redémarrage automatique, localhost uniquement - Auth — Cookies Google dans
/root/.notebooklm/storage_state.json
L'export basé sur fichiers legacy (/citadel-wrapup, /citadel-recall) reste fonctionnel en fallback.
Politique de routage des données et tâches
Système à trois niveaux. Chaque niveau a un objectif strict. Mélanger les niveaux = chaos.
┌─────────────────────────────────────────────────────────────────┐
│ NIVEAU 1 : Mémoire de travail (Chaud) │
│ office-state.json + state/tasks/ │
│ CLI : /citadel-task, /citadel-status │
│ │
│ Tâches agents quotidiennes. Vit pendant la session. Disparaît │
│ après. Tâche terminée → /citadel-wrapup → Niveau 3. │
├─────────────────────────────────────────────────────────────────┤
│ NIVEAU 2 : Backlog stratégique (Tiède) │
│ GitHub Issues (repos Claude-CEO + citadel-v2) │
│ │
│ Epics uniquement : Phase 20, Phase 21, bugs globaux. │
│ Pas de tâches quotidiennes. Pas de tickets "fix typo". │
│ Un ticket = une initiative plurisemaines ou un défaut critique.│
├─────────────────────────────────────────────────────────────────┤
│ NIVEAU 3 : Mémoire long terme (Froid) │
│ docs/library-export/ → Google Drive → NotebookLM │
│ CLI : /citadel-wrapup, /citadel-recall │
│ │
│ Encyclopédie. Résultats de session, décisions archi, RAG. │
│ Archive en lecture seule. Pas de tâches actives. │
└─────────────────────────────────────────────────────────────────┘
Règles de routage
| Type de données | Niveau | Exemple |
|---|---|---|
| "Corriger le script de déploiement" | 1 — Mémoire de travail | /citadel-task "Fix deploy script" |
| "Phase 20 : SaaS multi-tenant" | 2 — GitHub Issues | gh issue create --title "Phase 20: ..." |
| "Résumé session : hooks implémentés" | 3 — Library | /citadel-wrapup → NotebookLM |
| "Décision archi : choix SSE plutôt que WS" | 3 — Library | Archivé dans wrapup après session |
| "Bug : SSE se coupe sur le VPS" | 2 — GitHub Issues | Seulement si inter-session / bloquant |
| "Rick travaille sur les hooks" | 1 — Mémoire de travail | Statut agent office-state.json |
Cycle de vie
CEO donne une tâche → Niveau 1 (l'agent travaille dessus)
↓ terminée
/citadel-wrapup → Niveau 3 (archivée)
↓ si stratégique
gh issue create → Niveau 2 (suivi long terme)
Anti-patterns (NE PAS FAIRE)
- Ne pas créer de GitHub Issues pour les tâches quotidiennes ("fix typo", "update config")
- Ne pas stocker le statut de tâches actives dans library-export/
- Ne pas utiliser office-state.json pour des décisions long terme ou des notes d'architecture
- Ne pas dupliquer : une tâche vit dans exactement un niveau à la fois
Infrastructure (Phase 20.5)
Logging structuré (shared/logger.ts)
Format JSONL, sortie double (fichier + console), découpage quotidien par catégorie.
/var/log/citadel/
├── master/
│ ├── system-2026-04-02.log ← cycle de vie, config, santé
│ ├── dialog-2026-04-02.log ← (non utilisé par master)
│ └── error-2026-04-02.log ← erreurs (aussi dans system)
├── citadel-v2/
│ ├── system-2026-04-02.log
│ ├── dialog-2026-04-02.log ← messages user ↔ Claude
│ └── error-2026-04-02.log
└── <project-name>/ ← par projet embarqué
Rotation des logs : config/logrotate-citadel.conf → /etc/logrotate.d/citadel (quotidien, rétention 7 jours).
Vault de secrets (shared/vault.ts)
Stockage chiffré AES-256-GCM pour les tokens de bots.
Source clé : env SECRET_ENCRYPTION_KEY → fichier config/vault-key → auto-généré
Stockage : config/vault.json (écritures atomiques : tmp + mv)
Cache : En mémoire après initVault() — pas d'I/O disque par getSecret()
Fallback : getSecret("FOO") → cache vault → process.env.FOO
Nommage : child:<project-name>:token
Le token propre du Master reste dans .env (le vault se charge dans le processus master).
Watchdog auto-réparant (master-bot/watchdog.ts)
Moniteur en arrière-plan pour les child bots. S'exécute dans le processus du master bot.
Toutes les 30s : vérification santé HTTP → /api/child/health (timeout 5s)
Sain → reset des échecs
Non sain → incrément des échecs
3+ échecs + backoff écoulé → redémarrage auto (kill tmux → démarrage nouveau avec token vault)
Backoff : 30s → 1 min → 5 min → 15 min → 60 min (cap)
10 échecs consécutifs → désactivation permanente + notification CEO
État persisté dans config/watchdog-state.json (survit au redémarrage du master).
Notifications CEO via Telegram : premier redémarrage, échec de redémarrage, désactivation permanente.
Commande /watchdog : statut en temps réel de tous les enfants.
Protocole de suppression de projet (Phase 20.4 + 21.0)
/remove_project <name> → triple confirmation → nettoyage complet :
1. Kill de la session tmux : child-<name>
2. Kill massif des fantômes : ps aux | grep child-<name> → kill -9 tous les PIDs
3. Vérification du port : ss -tlnp | grep :<port> → forcer libération si occupé
4. Retrait de bot_registry.json + rechargement en mémoire
5. Suppression de /opt/repos/<name>/ (sécurité : chemin doit être sous /opt/repos/, min 3 segments)
6. Suppression de /var/log/citadel/<name>/
Noms protégés : citadel-v2, citadel, claude-ceo, claude-CEO — suppression bloquée.
Problème de processus fantôme (leçon apprise) : après un kill tmux, des processus bun orphelins peuvent garder les ports. Le kill massif + vérification de port empêche les "bots fantômes" qui répondent aux vérifications santé mais ignorent Telegram.
Gestion des skills (Phase 21.0)
Les child bots chargent les skills depuis deux sources au démarrage, dédupliquées via Set :
Source 1 : MANIFEST.md (JSON)
→ manifest.skills[] (matchés pendant l'onboarding)
→ manifest.library_skills[] (fichiers .md de bibliothèque matchés)
Source 2 : répertoire skills/
→ fichiers *.md → nom de fichier sans extension
Fusion : Set<string>(manifest.skills + manifest.library_skills + skills/*.md)
Exemple (projet PT) : 5 depuis manifest + 7 depuis skills/ = 12 skills uniques.
Les skills apparaissent comme :
- Bouton de label inline sur les réponses child :
🏷️ odoo-expert, docker-ops, ... - Callback
skills_info: toast avec la liste complète - Commande
/skillsdans master : liste le contenu du répertoire skills
Sécurité (Phase 42 — Audit Sentinel 2026-04-23, 4 passes, 13 patches)
Vue d'ensemble complète : SECURITY.md. Rapport d'audit : security/audit-2026-04-23.md.
Secrets et stockage :
- Pas de credentials dans le repo ; les fichiers d'état ne contiennent pas de secrets
- Tokens de bots dans le vault chiffré (
config/vault.json, AES-256-GCM). FallbackgetSecret()versprocess.env - Clé de chiffrement auto-générée dans
config/vault-key(chmod 600).vault.json,vault-key,watchdog-state.json,data/citadel.db*dans le gitignore
Auth :
- JWT HMAC-SHA256, TTL 24h, comparaison de signature
crypto.timingSafeEqual - OAuth Google + GitHub avec token CSRF (10 min, usage unique)
- Email/mot de passe avec vérification requise avant connexion (TTL 24h), réinitialisation de mot de passe (TTL 30 min), envoyé via Resend
- Extraction du token —
extractChatId()lit le header Bearer OU le query?token=(pour EventSource navigateur), correspondant exactement àcrmAuthMiddleware
Multi-tenancy (Phase 42) :
- Garde
canAccessProject(registry, chatId, project)sur chaque route protégée - CEO (
ceo_chat_id) et DBuser.role === 'admin'voient tout ; autres filtrés par correspondanceowner_id(DB SSOT) - Routes SSE, terminal WebSocket,
/api/cli/*,/api/mcp/*,/api/crm/projects/:name/*toutes gardées /ws/terminal/:name?mode=interactivenécessite CEO ou admin
Périmètre réseau :
- Bun bind
127.0.0.1:19210uniquement — nginx proxie via loopback /api/internal/*rejette toute requête portant des headers proxy (X-Forwarded-For,X-Real-IP,Forwarded) comme canari de mauvaise config nginx- Allowlist SSRF sur
handleScoutAnalyze— HTTPS + correspondance exacte de hostname +redirect:"manual"(bloque le contournement par chaîne de redirections) - UFW bloque
:19210,:19213,:19200en externe
Sécurité entrées/chemins :
- Regex
isValidProjectName()à chaque point d'entrée (incl. endpoints internes) safePath()sur tous les chemins de fichiers contrôlés par l'utilisateur —handleSaveSkilltrouvé + patché Phase 42.6- Liste de refus nginx :
/.*,/(state|scripts|config|data|knowledge-base|issues|skills|blueprints|mcp-server)/ - Whitelist CORS (
CRM_ALLOWED_ORIGINS), headers sur les erreurs aussi - Écritures atomiques pour les mutations de registry (
tmp.${pid}+mv) - Déchiffrement du token vault pour le démarrage child : utiliser
bun -eavec node:crypto (PAS Python)
Couverture de régression : scripts/vps-sync.sh exécute 7+ tests smoke post-déploiement après chaque déploiement (bind loopback, traversal de chemins, validation chat/save, canari proxy, SSE ?token=, validation fail-closed, blocage SSRF si CEO_TOKEN défini).
Modules du Master Bot (Phase 25 — Résolution DEBT-1)
Le master bot est organisé en modules ciblés :
master-bot/
├── bot.ts ← Bootstrap : vault, registry, contexte, câblage (106 lignes)
├── context.ts ← Type MasterContext + interfaces domaine
├── api-server.ts ← Bun.serve() — HTTP, WebSocket, SSE, routes CRM
├── tg-api.ts ← Wrapper Telegram Bot API (sendMessage, getUpdates, etc.)
├── child-state.ts ← Lire état child bot, santé, heartbeat, tmux, bridge
├── telegram-commands.ts ← Tous les handlers /commande, handler requête callback, routeur messages
├── telegram.ts ← Boucle de polling légère + réexports pour compat rétrograde
├── watchdog.ts ← Moniteur child bot auto-réparant
└── onboarding.ts ← Assistant interactif de création de projet
bot.ts importe uniquement depuis telegram.ts et api-server.ts. Tous les autres modules sont des détails d'implémentation internes.
Bridge CLI (Phase 25 — Local Gateway)
bridge/
├── bin/citadel-bridge.ts ← Entrée CLI (commander.js) : connect, pull, push, status, disconnect
├── src/
│ ├── auth.ts ← Validation JWT contre CRM
│ ├── config.ts ← Persistance ~/.citadel/bridge.json
│ ├── inject.ts ← Marqueurs CLAUDE.md <!-- CITADEL:START/END -->
│ ├── sync.ts ← Pull skills-bundle + learnings, push learnings locaux
│ └── heartbeat.ts ← Rapporteur d'activité de session
├── package.json
└── tsconfig.json
Endpoints CRM API (50+ au total)
CRM principal (Phase 22)
| Endpoint | Méthode | Objectif |
|---|---|---|
/api/master/health |
GET | Santé Master bot (public) |
/api/crm/projects |
GET | Liste tous les projets + santé en direct |
/api/crm/projects/:name |
GET | Détail du projet |
/api/crm/projects/:name/logs |
GET | Tail des logs JSONL |
/api/crm/projects/:name/files |
GET | Listing répertoire sécurisé |
/api/crm/projects/:name/files/upload |
POST | Upload de fichiers |
/api/crm/projects/:name/files/mkdir |
POST | Créer un dossier |
/api/crm/projects/:name/files/create |
POST | Créer un fichier |
/api/crm/projects/:name/files/delete |
DELETE | Supprimer fichier/dossier |
/api/crm/projects/:name/files/clone |
POST | Cloner un repo git |
/api/crm/projects/:name/files/read |
GET | Lire le contenu d'un fichier |
/api/crm/projects/:name/wiki/tree |
GET | Lister les fichiers .md du wiki |
/api/crm/projects/:name/wiki/file |
GET | Lire le contenu d'un fichier wiki |
/api/crm/projects/:name/skills |
GET | Skills installés |
/api/crm/projects/:name/metrics |
GET | Séries temporelles qualité |
/api/crm/projects/:name/restart |
POST | Redémarrer le child bot |
/api/crm/projects/:name/specs |
GET | Lister les specs |
/api/crm/projects/:name/specs/:id/approve |
POST | Approuver une spec |
/api/crm/projects/:name/specs/:id/reject |
POST | Rejeter une spec |
/api/crm/projects/:name/active-role |
GET/POST | Rôle de l'agent |
/api/crm/projects/:name/message |
POST | Mettre en file un message pour un worker |
/api/crm/projects/:name/workers |
GET/POST | CRUD registry workers |
/api/crm/projects/:name/workers/:id |
PUT/DELETE | Mettre à jour/supprimer un worker |
/api/crm/projects/:name/workers/generate-prompt |
POST | Générer un system prompt via IA |
/api/crm/projects/:name/skills-bundle |
GET | Skills + evals pour bridge |
/api/crm/projects/:name/learnings |
GET/POST | Sync learnings |
/api/sse/logs/:name |
GET | Flux SSE de logs (?category=) |
Tableau de bord & Wiki (Phase 32)
| Endpoint | Méthode | Objectif |
|---|---|---|
/api/crm/projects/:name/wiki/save |
PUT | Sauvegarder/créer une page wiki |
/api/crm/projects/:name/skills/save |
PUT | Sauvegarder un fichier skill |
/api/crm/projects/:name/skills/delete |
DELETE | Supprimer un fichier skill |
Multi-tenant (Phase 33)
| Endpoint | Méthode | Objectif |
|---|---|---|
/api/crm/account/settings |
GET/PUT | Clés API au niveau compte |
/api/crm/projects/create |
POST | Création légère de projet |
/api/crm/onboarding/setup |
POST | Assistant d'onboarding complet |
MCP & CLI (Phase 34)
| Endpoint | Méthode | Objectif |
|---|---|---|
/api/mcp/issues/:project |
POST/GET | CRUD tickets |
/api/mcp/issues/:project/:id |
PUT | Mettre à jour un ticket |
/api/mcp/wiki/:project |
PUT | Sync wiki via MCP |
/api/mcp/roadmap/:project |
GET/PUT | Lecture/sync roadmap |
/api/cli/init/:project/:mode |
GET | Contexte cloud pour CLI |
/api/mcp/skills/:project/:skill |
GET | Récupérer un skill pour MCP |
/api/mcp/report/:project |
POST | Rapport de mission |
/api/mcp/learnings/:project |
GET | Obtenir les learnings pour MCP |
Terminal en direct (Phase 35)
| Endpoint | Méthode | Objectif |
|---|---|---|
/api/crm/projects/:name/terminal/log |
POST | Recevoir JSONL terminal depuis ARC CLI |
Cloud PM & Knowledge (Phase 36)
| Endpoint | Méthode | Objectif |
|---|---|---|
/api/crm/projects/:name/chat |
POST | Proxy chat SSE vers Anthropic API |
/api/crm/projects/:name/skills/generate |
POST | Neural Skill Generator (NotebookLM) |
/api/crm/projects/:name/notebooks |
GET | Notebooks NotebookLM liés |
Auth & OAuth (Phase 37)
| Endpoint | Méthode | Objectif |
|---|---|---|
/api/auth/register |
POST | Inscription email/mot de passe |
/api/auth/login |
POST | Connexion email/mot de passe |
/api/auth/google |
GET | Redirection OAuth Google |
/api/auth/callback/google |
GET | Callback OAuth Google |
/api/auth/github |
GET | Redirection OAuth GitHub |
/api/auth/callback/github |
GET | Callback OAuth GitHub |
/api/auth/providers |
GET | Providers OAuth disponibles |
Notes épinglées (Phase 41.8)
| Endpoint | Méthode | Objectif |
|---|---|---|
/api/crm/projects/:name/pins |
GET | Lister les notes épinglées (plus récentes en premier) |
/api/crm/projects/:name/pins |
POST | Épingler un message worker dans le Context Rail (body : worker_id, body, title optionnel, author) |
/api/crm/projects/:name/pins/:id |
DELETE | Supprimer une note épinglée |
Backend : migration 009 (table pinned_notes), pinnedNoteQueries dans shared/db.ts. Frontend : ContextRail.jsx récupère au montage, écoute l'événement CustomEvent crm-pin-created, DELETE optimiste.
Couche de protection des données (Phase 45)
Chiffrement hybride au repos — fondation crypto côté client + chiffrement côté serveur.
Côté client (navigateur)
frontend/src/crm/crypto/e2ee.ts— Wrapper WebCrypto (214 lignes)- PBKDF2 (100k itérations, SHA-256) → clé maître AES-256-GCM
- Cycle de vie de la clé :
initMasterKey(password)à la connexion →sessionStorage→clearMasterKey()à la déconnexion/401 - Récupération :
generateRecoveryKey()→ format 1Password (XXXX-XXXX-XXXX-XXXX-XXXX)
Côté serveur (Bun + SQLite)
shared/vault.ts—encryptField()/decryptField()via clé vault AES-256-GCM (format préfixev1:)- Clés API : chiffrement à la sauvegarde, déchiffrement au chargement (transparent pour le frontend) —
routes/system.ts - Messages chat : auto-chiffrement INSERT, auto-déchiffrement SELECT —
db.ts+ migration 015 - Clés de récupération : table
recovery_keys(migration 016), 4 endpoints API
Headers de sécurité
- CSP :
default-src 'self'; script-src 'self'sur toutes les réponses CRM X-Frame-Options: DENY,X-Content-Type-Options: nosniff,Referrer-Policy: strict-origin-when-cross-origin
Sanitisation PII
shared/pii-sanitizer.ts— masque emails, clés API (sk-ant-*,sk-*), JWTs, numéros de carte- Appliqué à l'ingestion de logs JSONL terminal (
routes/chat.ts)
Endpoints de clé de récupération
| Endpoint | Méthode | Objectif |
|---|---|---|
/api/crm/account/recovery |
POST | Créer une clé de récupération (stocke la clé maître chiffrée) |
/api/crm/account/recovery |
GET | Lister les clés de récupération actives |
/api/crm/account/recovery |
DELETE | Révoquer des clés de récupération |
/api/crm/account/recovery/restore |
GET | Récupérer la clé maître chiffrée pour la restauration |
Détails sécurité complets : docs/SECURITY.md, docs/architecture/PHASE_45_E2EE.md.