Arc OS — Arquitectura
Resumen
Arc OS reemplaza 11.321 líneas de infraestructura personalizada en Python/JS con las herramientas nativas de Claude Code. El agente de IA ES el backend.
Arquitectura del Sistema (Fase 52.1)
graph TB
User[👤 Usuario Browser :18888]
TG[📱 Telegram]
Local[💻 IDE Local]
subgraph "Edge"
Nginx[Nginx :18888<br/>basic-auth + deny-list]
FE[React CRM + Phaser<br/>contenedor frontend]
end
subgraph "Master Bot Bun :19210 — solo 127.0.0.1"
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 Módulos de Dominio — Fase 48"
D1[auth · projects · workers]
D2[skills · sage · chat]
D3[wiki · files · onboarding]
D4[billing · invites · analytics]
D5[+ 7 más]
end
end
subgraph "Bots Federados"
Master[Master Bot<br/>orquestrador]
Child[Child Bots<br/>por proyecto]
Claude[claude -p CLI]
end
subgraph "Capa de Inteligencia"
Eval[Binary Evals]
Ctx[Context Router top-5]
Learn[Inyección de Learnings]
Karp[Karpathy Loop nocturno]
end
NB[NotebookLM Bridge<br/>FastAPI :19213 localhost]
Google[(Google NotebookLM)]
DB[(SQLite WAL<br/>21+ tablas<br/>migraciones 001-021)]
Vault[(AES-256-GCM Vault<br/>config/vault.json)]
Bridge[Local Bridge CLI<br/>relay 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 -.lanza via tmux.-> Child
Child --> Claude
Claude --> Eval & Ctx & Learn
Router -.consulta.-> NB
Child -.auto-sync.-> NB
NB --> Google
Router --> DB
Router --> Vault
Child --> Vault
Local --> Bridge
Bridge -.ws relay.-> ApiSrv
Karp -.nocturno.-> DB
Datos clave:
- 70+ endpoints REST (Fase 52.1) distribuidos en 19 módulos de dominio en
shared/routes/ - Bind en 127.0.0.1 — Bun nunca queda expuesto externamente; nginx actúa como proxy a través del loopback
- Gate de multi-tenancy —
canAccessProject(registry, chatId, project)en cada ruta protegida - Zero-Knowledge E2EE (Fase 45) — WebCrypto PBKDF2 + clave maestra AES-256-GCM en
sessionStorage
LEGACY (v1):
Usuario → Bot Telegram (Python 111KB) → HybridEngine → command_queue.json
→ bridge_processor.sh → Claude → command_responses.json
→ FastAPI EventBus → WebSocket → UI Phaser
V2 (NATIVE-FIRST):
Usuario → Canal Telegram Oficial → Sesión Claude Code
↓ ↓
reply/edit_message Agent Teams (TaskCreate/SendMessage)
↓
Escribe estado → archivos JSON
↓
Arc OS Bridge MCP → HTTP/SSE → UI Phaser
Reducción: 11.321 líneas → ~3.700 líneas (67% menos código)
Componentes
1. Sesión Claude Code (El Cerebro)
La sesión Claude Code reemplaza:
- Backend FastAPI (15 servicios)
- HybridEngine (39KB)
- bridge_processor.sh (19,6KB)
- response_watcher.py (14KB)
- event_bus.py
- supply_chain.py (13KB)
Toda la orquestación ocurre nativamente a través de Agent Teams.
2. Arc OS Bridge MCP Server (Adaptador de Estado)
Servidor MCP TypeScript (Bun) que conecta el estado de Claude Code con el frontend.
MCP Tools (lado Claude Code):
| Tool | Dirección | Descripción |
|---|---|---|
get_office_state |
lectura | Lee state/office-state.json |
update_agent_state |
escritura | Actualiza posición, estado, burbuja del agente |
get_tasks |
lectura | Lee archivos de tareas de Agent Teams |
get_knowledge |
lectura | Lee índice de conocimiento |
HTTP API (lado Frontend):
| Endpoint | Método | Descripción |
|---|---|---|
/api/state |
GET | Estado completo de la oficina |
/api/tasks |
GET | Lista de tareas |
/api/knowledge |
GET | Índice de conocimiento |
/api/events |
GET | Stream SSE |
3. Frontend Phaser (Capa Visual)
Phaser 3.80 + Vite. Se conecta al servidor MCP vía HTTP/SSE.
Diferencia clave respecto a v1: sin WebSocket — reemplazado por SSE del servidor MCP. Sin interfaz de entrada de comandos — Telegram es la interfaz de control.
4. Interfaz de Comandos Telegram (Capa UI Táctica — Fase 21.0)
Telegram es el panel de control principal de todo Arc OS. Dos niveles de bots:
Master Bot (@citadel_ceo_bot):
- Teclado persistente de respuesta:
Мої Проєкти/Новий Проєкт/Watchdog/Web UI - Tarjetas de proyecto inline por hijo: Reiniciar, Eliminar, Ver MANIFEST, Skills Activos
- Botones URL de CRM: Proyecto, Tareas, Archivos, Configuración (enlaces al frontend)
- Router de callback query para todas las acciones inline
- Flujo de confirmación de eliminación: teclado inline → SÍ/CANCELAR → editar mensaje
- Registro de
setMyCommandsal arrancar
Child Bots (@cv2_pt_bot, etc.):
- Cada respuesta de Claude recibe botones inline en el último chunk:
STOP(SIGKILL) /PAUSE(SIGSTOP) /RESUME(SIGCONT) — control de subprocesoBTW— encola contexto adicional para la próxima llamada a ClaudeFix It— genera automáticamente un prompt de corrección desde la última respuesta del bot
- Botón de label de skills mostrando las competencias del proyecto cargadas
- Router de callback query para todas las acciones de señal/contexto
Integración CRM (desarrollo):
CRM_BASE_URL = http://62.171.128.248:18888 (dev)
https://crm.citadel.v2 (prod futuro)
Todos los layouts de teclado definidos en shared/ui_templates.ts — única fuente para cambios de UI.
Protocolo de datos de callback: acción:objetivo (máx. 64 bytes)
- Master:
restart:pt,delete:pt,confirm_del:pt,cancel_del:pt,manifest:pt,skills:pt - Child:
stop,pause,resume,btw,fixit,skills_info
Flujo de Datos
1. Usuario envía "/status" via Telegram
2. La sesión Claude Code lo recibe via Canal Telegram
3. Rick lee state/office-state.json + TaskList()
4. Rick responde via Telegram (edit_message para actualizaciones en vivo)
5. Rick llama a update_agent_state() via MCP
6. El servidor MCP escribe en state/office-state.json
7. El file watcher detecta el cambio → envía evento SSE
8. El frontend recibe SSE → actualiza sprites de agentes
Gestión de Estado
Todo el estado vive en archivos JSON bajo state/:
| Archivo | Esquema | Actualizado por | Leído por |
|---|---|---|---|
office-state.json |
Posiciones, estados, burbujas de agentes | Claude (via MCP) | Frontend (via HTTP) |
knowledge.json |
Metadatos de archivos indexados | Agente Squanchy | Frontend, Beth |
reports/*.json |
Salida de análisis | Beth, Summer | Frontend |
Las tareas de Agent Teams son gestionadas nativamente por Claude Code en ~/.claude/tasks/citadel-v2/.
Agentes (6)
| Agente | Rol | Modelo | Activación |
|---|---|---|---|
| Rick | CEO/Orquestrador | opus-4.6 | Siempre activo (líder del equipo) |
| Morty | SRE/Monitoreo | haiku-4.5 | Health checks, cron |
| Summer | Memoria/Revisión | sonnet-4.5 | Code review, seguridad |
| Jerry | Mantenimiento | haiku-4.5 | Limpieza, docs |
| Squanchy | Archivero | haiku-4.5 | Indexación de archivos |
| Beth | Analista | sonnet-4.5 | Investigación, análisis |
Supply Chain
CEO → Rick (descomponer) → Agent Team (ejecutar)
→ Cross-Review (Summer valida)
→ Rick (sintetizar)
→ CEO (resultado final)
Aplicado a través de:
- Blueprints: Configs de departamento que definen roles de agentes
- Skills: Experiencia cargada dinámicamente
- Protocolo HANDOFF: Transferencia estructurada de contexto entre agentes
Stack Tecnológico
| Capa | v1 | v2 |
|---|---|---|
| Backend | FastAPI + Python 3.12 | Sesión Claude Code |
| Base de datos | SQLite (8 tablas) | Archivos JSON + Agent Teams |
| Mensajería | WebSocket + EventBus | Agent Teams SendMessage |
| Estado | SQLite + JSON bridge | Archivos JSON (state/) |
| Frontend | Phaser 3.86 + WebSocket | Phaser 3.80 + SSE |
| Telegram | Bot personalizado (111KB) | Plugin de Canal Oficial |
| Bridge | bash + jq (19,6KB) | Eliminado |
| MCP | Ninguno | Arc OS Bridge (TypeScript) |
| Deploy | Docker Compose | Docker Compose |
Lifecycle Hooks
Los hooks de Claude Code (~/.claude/settings.json) sincronizan automáticamente el estado del agente:
Evento SubagentStop → subagent-stop.sh → office-state.json (agent=idle)
↓
StateManager (fs.watch) → SSE → UI Phaser
Evento Stop → session-end.sh → latest_wrapup.txt + all agents=idle
Scripts: scripts/citadel-hooks/subagent-stop.sh, scripts/citadel-hooks/session-end.sh
Campos clave: subagentName (SubagentStop), stopReason (Stop), cwd (ambos).
NotebookLM Bridge (Fase 36.3)
Búsqueda semántica real via Google NotebookLM, reemplazando las subidas manuales de archivos:
Cloud PM Chat → Bun Master Bot (:19210)
│
executeAskNotebooklm()
│
HTTP → FastAPI Bridge (:19213, solo localhost)
│
notebooklm-py async client
│
Google NotebookLM (búsqueda semántica gratuita)
Fallback: búsqueda local por palabras clave (código existente)
- Un notebook por proyecto — mapping almacenado en
notebook_mapping.json - Auto-sync — cierre/apertura de issue + actualización de wiki → POST fire-and-forget a
/sync - SyncWorker —
asyncio.Queue(200), retraso 2s, backoff exponencial (3 reintentos) - Caché de consultas — LRU, TTL 5min, máx. 100 entradas
- systemd —
citadel-notebooklm-bridge.service, auto-reinicio, solo localhost - Auth — cookies de Google en
/root/.notebooklm/storage_state.json
La exportación basada en archivos heredada (/citadel-wrapup, /citadel-recall) sigue funcionando como fallback.
Política de Enrutamiento de Datos y Tareas
Sistema de tres niveles. Cada nivel tiene un propósito estricto. Mezclar niveles = caos.
┌─────────────────────────────────────────────────────────────────┐
│ NIVEL 1: Memoria de Trabajo (Caliente) │
│ office-state.json + state/tasks/ │
│ CLI: /citadel-task, /citadel-status │
│ │
│ Tareas diarias de agentes. Vive durante la sesión. Muere tras │
│ ella. Tarea completada → /citadel-wrapup → Nivel 3. │
├─────────────────────────────────────────────────────────────────┤
│ NIVEL 2: Backlog Estratégico (Tibio) │
│ GitHub Issues (repos Claude-CEO + citadel-v2) │
│ │
│ Solo epics: Fase 20, Fase 21, bugs globales. │
│ Sin tareas diarias. Sin issues de "corregir typo". │
│ Un Issue = una iniciativa de varias semanas o defecto crítico. │
├─────────────────────────────────────────────────────────────────┤
│ NIVEL 3: Memoria a Largo Plazo (Frío) │
│ docs/library-export/ → Google Drive → NotebookLM │
│ CLI: /citadel-wrapup, /citadel-recall │
│ │
│ Enciclopedia. Resultados de sesiones, decisiones │
│ arquitectónicas, RAG. Solo lectura. Sin tareas activas. │
└─────────────────────────────────────────────────────────────────┘
Reglas de Enrutamiento
| Tipo de Dato | Nivel | Ejemplo |
|---|---|---|
| "Arreglar script de deploy" | 1 — Memoria de Trabajo | /citadel-task "Arreglar script de deploy" |
| "Fase 20: SaaS Multi-Tenant" | 2 — GitHub Issues | gh issue create --title "Fase 20: ..." |
| "Resumen de sesión: hooks implementados" | 3 — Library | /citadel-wrapup → NotebookLM |
| "Decisión arquitectónica: elegimos SSE sobre WS" | 3 — Library | Archivado en wrapup tras sesión |
| "Bug: SSE se cae en VPS" | 2 — GitHub Issues | Solo si es cross-sesión o bloqueante |
| "Rick está trabajando en hooks" | 1 — Memoria de Trabajo | Estado del agente en office-state.json |
Ciclo de Vida
CEO da tarea → Nivel 1 (agente trabaja en ella)
↓ completada
/citadel-wrapup → Nivel 3 (archivada)
↓ si es estratégica
gh issue create → Nivel 2 (rastreada a largo plazo)
Antipatrones (NO HACER)
- NO crear GitHub Issues para tareas diarias ("corregir typo", "actualizar config")
- NO guardar estado de tareas activas en archivos library-export/
- NO usar office-state.json para decisiones a largo plazo o notas de arquitectura
- NO duplicar: una tarea vive en exactamente un nivel a la vez
Infraestructura (Fase 20.5)
Logging Estructurado (shared/logger.ts)
Formato JSONL, salida dual (archivo + consola), división diaria de archivos por categoría.
/var/log/citadel/
├── master/
│ ├── system-2026-04-02.log ← ciclo de vida, config, health
│ ├── dialog-2026-04-02.log ← (no usado por master)
│ └── error-2026-04-02.log ← errores (también en system)
├── citadel-v2/
│ ├── system-2026-04-02.log
│ ├── dialog-2026-04-02.log ← mensajes usuario ↔ Claude
│ └── error-2026-04-02.log
└── <nombre-proyecto>/ ← por proyecto incorporado
Rotación de logs: config/logrotate-citadel.conf → /etc/logrotate.d/citadel (diario, retención 7 días).
Secrets Vault (shared/vault.ts)
Almacenamiento cifrado AES-256-GCM para tokens de bots.
Fuente de clave: env SECRET_ENCRYPTION_KEY → archivo config/vault-key → autogenerado
Almacenamiento: config/vault.json (escrituras atómicas: tmp + mv)
Caché: En memoria tras initVault() — sin I/O de disco por getSecret()
Fallback: getSecret("FOO") → caché vault → process.env.FOO
Nomenclatura: child:<nombre-proyecto>:token
El token del Master permanece en .env (el vault carga dentro del proceso master).
Watchdog Auto-Curativo (master-bot/watchdog.ts)
Monitor en segundo plano para child bots. Corre dentro del proceso del master bot.
Cada 30s: health check HTTP → /api/child/health (timeout 5s)
Saludable → reiniciar contador de fallos
No saludable → incrementar fallos
3+ fallos + backoff transcurrido → auto-reinicio (matar tmux → iniciar nuevo con token vault)
Backoff: 30s → 1m → 5m → 15m → 60m (tope)
10 fallos consecutivos → desactivar permanentemente + notificar al CEO
Estado persistido en config/watchdog-state.json (sobrevive reinicios del master).
Notificaciones al CEO via Telegram: primer reinicio, fallo de reinicio, desactivación permanente.
Comando /watchdog: estado en tiempo real de todos los hijos.
Protocolo de Eliminación de Proyectos (Fases 20.4 + 21.0)
/remove_project <name> → triple confirmación → limpieza completa:
1. Matar sesión tmux: child-<name>
2. Matar procesos fantasma: ps aux | grep child-<name> → kill -9 todos los PIDs
3. Verificar puerto: ss -tlnp | grep :<port> → forzar liberación si ocupado
4. Eliminar de bot_registry.json + recarga en memoria
5. Eliminar /opt/repos/<name>/ (seguridad: la ruta debe estar bajo /opt/repos/, mín. 3 segmentos)
6. Eliminar /var/log/citadel/<name>/
Nombres protegidos: citadel-v2, citadel, claude-ceo, claude-CEO — eliminación bloqueada.
Problema de procesos fantasma (lección aprendida): tras matar tmux, procesos bun huérfanos pueden ocupar puertos. El kill masivo + verificación de puerto previene "bots fantasma" que responden a health checks pero ignoran Telegram.
Gestión de Skills (Fase 21.0)
Los child bots cargan skills de dos fuentes al arrancar, con deduplicación via Set:
Fuente 1: MANIFEST.md (JSON)
→ manifest.skills[] (coincidentes durante el onboarding)
→ manifest.library_skills[] (archivos .md de library coincidentes)
Fuente 2: directorio skills/
→ archivos *.md → nombre de archivo sin extensión
Merge: Set<string>(manifest.skills + manifest.library_skills + skills/*.md)
Ejemplo (proyecto PT): 5 de manifest + 7 de skills/ = 12 skills únicos.
Los skills aparecen como:
- Label de botón inline en respuestas del hijo:
🏷️ odoo-expert, docker-ops, ... - Callback
skills_info: toast con lista completa - Comando
/skillsen master: lista contenidos del directorio skills
Seguridad (Fase 42 — Auditoría Sentinel 2026-04-23, 4 pasadas, 13 parches)
Resumen completo: SECURITY.md. Informe de auditoría: security/audit-2026-04-23.md.
Secretos y almacenamiento:
- Sin credenciales en el repo; los archivos de estado no contienen secretos
- Tokens de bot en vault cifrado (
config/vault.json, AES-256-GCM). Fallback degetSecret()aprocess.env - Clave de cifrado autogenerada en
config/vault-key(chmod 600).vault.json,vault-key,watchdog-state.json,data/citadel.db*en gitignore
Auth:
- JWT HMAC-SHA256, TTL 24h, comparación de firma con
crypto.timingSafeEqual - OAuth Google + GitHub con estado CSRF (10min, uso único)
- Email/contraseña con verificación requerida antes del login (TTL 24h), restablecimiento de contraseña (TTL 30min), entregado via Resend
- Extracción de token —
extractChatId()lee el header Bearer O el query?token=(para EventSource de browser), coincide exactamente concrmAuthMiddleware
Multi-tenancy (Fase 42):
- Gate
canAccessProject(registry, chatId, project)en cada ruta protegida - El CEO (
ceo_chat_id) y el roladminen DB (user.role === 'admin') ven todo; los demás controlados por coincidencia deowner_id(DB SSOT) - Rutas SSE, terminal WebSocket,
/api/cli/*,/api/mcp/*,/api/crm/projects/:name/*todas controladas /ws/terminal/:name?mode=interactiverequiere CEO o admin
Perímetro de red:
- Bun hace bind solo en
127.0.0.1:19210— nginx actúa como proxy a través del loopback /api/internal/*rechaza cualquier solicitud que lleve headers de proxy (X-Forwarded-For,X-Real-IP,Forwarded) como canary de mala configuración de nginx- Allowlist SSRF en
handleScoutAnalyze— HTTPS + coincidencia exacta de hostname +redirect:"manual"(bloquea bypass de cadena de redirección) - UFW bloquea externamente
:19210,:19213,:19200
Seguridad de entradas y rutas:
- Regex
isValidProjectName()en cada punto de entrada (incluidos endpoints internos) safePath()en todas las rutas de archivos controladas por el usuario —handleSaveSkillencontrado y parcheado en Fase 42.6- Lista de denegación de Nginx:
/.*,/(state|scripts|config|data|knowledge-base|issues|skills|blueprints|mcp-server)/ - Lista blanca de CORS (
CRM_ALLOWED_ORIGINS), headers también en errores - Escrituras atómicas para mutaciones del registro (
tmp.${pid}+mv) - Descifrado de token vault para arranque de hijo: usar
bun -econ node:crypto (NO Python)
Cobertura de regresión: scripts/vps-sync.sh ejecuta 7+ smoke tests post-deploy tras cada deploy (bind loopback, path traversal, validación de chat/save, canary de proxy, SSE ?token=, validación fail-closed, bloqueo SSRF si CEO_TOKEN configurado).
Módulos del Master Bot (Fase 25 — Resolución de DEBT-1)
El master bot está organizado en módulos enfocados:
master-bot/
├── bot.ts ← Bootstrap: vault, registry, context, todo conectado (106 líneas)
├── context.ts ← Tipo MasterContext + interfaces de dominio
├── api-server.ts ← Bun.serve() — HTTP, WebSocket, SSE, rutas CRM
├── tg-api.ts ← Wrapper de Telegram Bot API (sendMessage, getUpdates, etc.)
├── child-state.ts ← Lee estado del child bot, health, heartbeat, tmux, bridge
├── telegram-commands.ts ← Todos los manejadores /comando, manejador de callback query, router de mensajes
├── telegram.ts ← Loop de polling slim + re-exports para compatibilidad hacia atrás
├── watchdog.ts ← Monitor auto-curativo del child bot
└── onboarding.ts ← Asistente interactivo de creación de proyectos
bot.ts importa solo desde telegram.ts y api-server.ts. Todos los demás módulos son detalles de implementación internos.
Bridge CLI (Fase 25 — Local Gateway)
bridge/
├── bin/citadel-bridge.ts ← Entrada CLI (commander.js): connect, pull, push, status, disconnect
├── src/
│ ├── auth.ts ← Validación JWT contra CRM
│ ├── config.ts ← Persistencia ~/.citadel/bridge.json
│ ├── inject.ts ← Marcadores <!-- CITADEL:START/END --> en CLAUDE.md
│ ├── sync.ts ← Pull skills-bundle + learnings, push learnings locales
│ └── heartbeat.ts ← Reportador de actividad de sesión
├── package.json
└── tsconfig.json
Endpoints de CRM API (50+ en total)
CRM Principal (Fase 22)
| Endpoint | Método | Propósito |
|---|---|---|
/api/master/health |
GET | Health del master bot (público) |
/api/crm/projects |
GET | Listar todos los proyectos + health en vivo |
/api/crm/projects/:name |
GET | Detalle del proyecto |
/api/crm/projects/:name/logs |
GET | Tail de logs JSONL |
/api/crm/projects/:name/files |
GET | Listado de directorio seguro |
/api/crm/projects/:name/files/upload |
POST | Subir archivos |
/api/crm/projects/:name/files/mkdir |
POST | Crear carpeta |
/api/crm/projects/:name/files/create |
POST | Crear archivo |
/api/crm/projects/:name/files/delete |
DELETE | Eliminar archivo/carpeta |
/api/crm/projects/:name/files/clone |
POST | Clonar repo git |
/api/crm/projects/:name/files/read |
GET | Leer contenido de archivo |
/api/crm/projects/:name/wiki/tree |
GET | Listar archivos .md de wiki |
/api/crm/projects/:name/wiki/file |
GET | Leer contenido de archivo wiki |
/api/crm/projects/:name/skills |
GET | Skills instalados |
/api/crm/projects/:name/metrics |
GET | Timeseries de calidad |
/api/crm/projects/:name/restart |
POST | Reiniciar child bot |
/api/crm/projects/:name/specs |
GET | Listar specs |
/api/crm/projects/:name/specs/:id/approve |
POST | Aprobar spec |
/api/crm/projects/:name/specs/:id/reject |
POST | Rechazar spec |
/api/crm/projects/:name/active-role |
GET/POST | Rol del agente |
/api/crm/projects/:name/message |
POST | Encolar mensaje al worker |
/api/crm/projects/:name/workers |
GET/POST | CRUD del registro de workers |
/api/crm/projects/:name/workers/:id |
PUT/DELETE | Actualizar/eliminar worker |
/api/crm/projects/:name/workers/generate-prompt |
POST | Generar prompt de sistema con IA |
/api/crm/projects/:name/skills-bundle |
GET | Skills + evals para bridge |
/api/crm/projects/:name/learnings |
GET/POST | Sincronización de learnings |
/api/sse/logs/:name |
GET | Stream SSE de logs (?category=) |
Dashboard y Wiki (Fase 32)
| Endpoint | Método | Propósito |
|---|---|---|
/api/crm/projects/:name/wiki/save |
PUT | Guardar/crear página wiki |
/api/crm/projects/:name/skills/save |
PUT | Guardar archivo de skill |
/api/crm/projects/:name/skills/delete |
DELETE | Eliminar archivo de skill |
Multi-Tenant (Fase 33)
| Endpoint | Método | Propósito |
|---|---|---|
/api/crm/account/settings |
GET/PUT | Claves API a nivel de cuenta |
/api/crm/projects/create |
POST | Creación ligera de proyectos |
/api/crm/onboarding/setup |
POST | Asistente completo de onboarding |
MCP y CLI (Fase 34)
| Endpoint | Método | Propósito |
|---|---|---|
/api/mcp/issues/:project |
POST/GET | CRUD de issues |
/api/mcp/issues/:project/:id |
PUT | Actualizar issue |
/api/mcp/wiki/:project |
PUT | Sincronización de wiki via MCP |
/api/mcp/roadmap/:project |
GET/PUT | Lectura/sincronización de roadmap |
/api/cli/init/:project/:mode |
GET | Contexto cloud para CLI |
/api/mcp/skills/:project/:skill |
GET | Obtener skill para MCP |
/api/mcp/report/:project |
POST | Informe de misión |
/api/mcp/learnings/:project |
GET | Obtener learnings para MCP |
Terminal en Vivo (Fase 35)
| Endpoint | Método | Propósito |
|---|---|---|
/api/crm/projects/:name/terminal/log |
POST | Recibir JSONL de terminal desde ARC CLI |
Cloud PM y Conocimiento (Fase 36)
| Endpoint | Método | Propósito |
|---|---|---|
/api/crm/projects/:name/chat |
POST | Proxy de chat SSE a API de Anthropic |
/api/crm/projects/:name/skills/generate |
POST | Generador Neural de Skills (NotebookLM) |
/api/crm/projects/:name/notebooks |
GET | Notebooks NotebookLM vinculados |
Auth y OAuth (Fase 37)
| Endpoint | Método | Propósito |
|---|---|---|
/api/auth/register |
POST | Registro con email/contraseña |
/api/auth/login |
POST | Login con email/contraseña |
/api/auth/google |
GET | Redirección OAuth Google |
/api/auth/callback/google |
GET | Callback OAuth Google |
/api/auth/github |
GET | Redirección OAuth GitHub |
/api/auth/callback/github |
GET | Callback OAuth GitHub |
/api/auth/providers |
GET | Proveedores OAuth disponibles |
Notas Fijadas (Fase 41.8)
| Endpoint | Método | Propósito |
|---|---|---|
/api/crm/projects/:name/pins |
GET | Listar notas fijadas (más recientes primero) |
/api/crm/projects/:name/pins |
POST | Fijar un mensaje de worker al Context Rail (body: worker_id, body, title opcional, author) |
/api/crm/projects/:name/pins/:id |
DELETE | Eliminar pin |
Backend: migración 009 (tabla pinned_notes), pinnedNoteQueries en shared/db.ts. Frontend: ContextRail.jsx carga al montar, escucha el evento personalizado crm-pin-created, DELETE optimista.
Capa de Protección de Datos (Fase 45)
Cifrado híbrido en reposo — base de criptografía del lado del cliente + cifrado en reposo del lado del servidor.
Lado del Cliente (Browser)
frontend/src/crm/crypto/e2ee.ts— wrapper WebCrypto (214 líneas)- PBKDF2 (100k iteraciones, SHA-256) → clave maestra AES-256-GCM
- Ciclo de vida de la clave:
initMasterKey(password)en login →sessionStorage→clearMasterKey()en logout/401 - Recuperación:
generateRecoveryKey()→ formato 1Password (XXXX-XXXX-XXXX-XXXX-XXXX)
Lado del Servidor (Bun + SQLite)
shared/vault.ts—encryptField()/decryptField()usando clave vault AES-256-GCM (formato prefijov1:)- Claves API: cifrar al guardar, descifrar al cargar (transparente para el frontend) —
routes/system.ts - Mensajes de chat: auto-cifrado en INSERT, auto-descifrado en SELECT —
db.ts+ migración 015 - Claves de recuperación: tabla
recovery_keys(migración 016), 4 endpoints API
Headers de Seguridad
- CSP:
default-src 'self'; script-src 'self'en todas las respuestas CRM X-Frame-Options: DENY,X-Content-Type-Options: nosniff,Referrer-Policy: strict-origin-when-cross-origin
Sanitización de PII
shared/pii-sanitizer.ts— redacta emails, claves API (sk-ant-*,sk-*), JWTs, números de tarjeta- Aplicado al ingest de logs JSONL de terminal (
routes/chat.ts)
Endpoints de Clave de Recuperación
| Endpoint | Método | Propósito |
|---|---|---|
/api/crm/account/recovery |
POST | Crear clave de recuperación (almacena clave maestra cifrada) |
/api/crm/account/recovery |
GET | Listar claves de recuperación activas |
/api/crm/account/recovery |
DELETE | Revocar clave(s) de recuperación |
/api/crm/account/recovery/restore |
GET | Recuperar clave maestra cifrada para recuperación |
Detalles completos de seguridad: docs/SECURITY.md, docs/architecture/PHASE_45_E2EE.md.