Arc OS — Архітектура
Огляд
Arc OS замінює 11 321 рядок кастомної Python/JS-інфраструктури нативними інструментами Claude Code. AI-агент І Є бекендом.
Системна архітектура (Phase 60)
graph TB
User[👤 User Browser :18888]
TG[📱 Telegram]
Local[💻 Local IDE]
subgraph "Edge"
Nginx[Nginx :18888<br/>basic-auth + deny-list]
FE[React CRM + Phaser<br/>frontend container]
end
subgraph "Master Bot Bun :19210 — 127.0.0.1 only"
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 Domain Modules — Phase 48"
D1[auth · projects · workers]
D2[skills · sage · chat]
D3[wiki · files · onboarding]
D4[billing · invites · analytics]
D5[+ 7 more]
end
end
subgraph "Federated Bots"
Master[Master Bot<br/>orchestrator]
Child[Child Bots<br/>per-project]
Claude[claude -p CLI]
end
subgraph "Intelligence Layer"
Eval[Binary Evals]
Ctx[Context Router top-5]
Learn[Learnings inject]
Karp[Karpathy nightly loop]
end
RAG[shared/rag.ts<br/>Cohere + sqlite-vec]
DB[(SQLite WAL<br/>50+ tables<br/>migrations 001-050)]
Vault[(AES-256-GCM Vault<br/>config/vault.json)]
Bridge[Local Bridge CLI<br/>WebSocket relay]
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.-> RAG
Child -.auto-sync.-> RAG
RAG --> DB
Router --> DB
Router --> Vault
Child --> Vault
Local --> Bridge
Bridge -.ws relay.-> ApiSrv
Karp -.nightly.-> DB
subgraph "Hetzner arc-cloud-prod 157.180.44.232 — Phase 60"
HNet[arc-cloud-net bridge]
C1[arc-user-xxxx<br/>claude CLI + child-bot<br/>2GB RAM / 1.5 CPU]
C2[arc-user-yyyy<br/>...]
end
Router -.SSH hetzner_ed25519.-> HNet
HNet --> C1 & C2
TG -.wake + /continue.-> C1
Ключові факти:
- 70+ REST-ендпоінтів у 19 доменних модулях у
shared/routes/ - Bind на 127.0.0.1 — Bun ніколи не виставляється назовні; nginx проксіює через loopback
- Multi-tenancy gate —
canAccessProject(registry, chatId, project)на кожному захищеному маршруті - Zero-Knowledge E2EE (Phase 45) — WebCrypto PBKDF2 + майстер-ключ AES-256-GCM у
sessionStorage - Флот із двох серверів (Phase 60) — API на Contabo (62.171.128.248), користувацькі контейнери на Hetzner (157.180.44.232), з'єднані через SSH
LEGACY (v1):
User → Telegram Bot (Python 111KB) → HybridEngine → command_queue.json
→ bridge_processor.sh → Claude → command_responses.json
→ FastAPI EventBus → WebSocket → Phaser UI
V2 (NATIVE-FIRST):
User → Official Telegram Channel → Claude Code Session
↓ ↓
reply/edit_message Agent Teams (TaskCreate/SendMessage)
↓
Write state → JSON files
↓
Arc OS Bridge MCP → HTTP/SSE → Phaser UI
Скорочення: 11 321 рядок → ~3 700 рядків (на 67% менше коду)
Компоненти
1. Сесія Claude Code (Мозок)
Сесія Claude Code замінює:
- FastAPI-бекенд (15 сервісів)
- HybridEngine (39KB)
- bridge_processor.sh (19.6KB)
- response_watcher.py (14KB)
- event_bus.py
- supply_chain.py (13KB)
Уся оркестрація відбувається нативно через Agent Teams.
2. Arc OS Bridge MCP Server (Адаптер стану)
TypeScript MCP-сервер (Bun), який передає стан Claude Code до фронтенду.
MCP-інструменти (сторона Claude Code):
| Інструмент | Напрям | Опис |
|---|---|---|
get_office_state |
read | Читання state/office-state.json |
update_agent_state |
write | Оновлення позиції агента, статусу, бульбашки |
get_tasks |
read | Читання файлів задач Agent Teams |
get_knowledge |
read | Читання індексу знань |
HTTP API (сторона фронтенду):
| Ендпоінт | Метод | Опис |
|---|---|---|
/api/state |
GET | Повний стан офісу |
/api/tasks |
GET | Список задач |
/api/knowledge |
GET | Індекс знань |
/api/events |
GET | SSE-потік |
3. Phaser Frontend (Візуальний шар)
Phaser 3.80 + Vite. Підключається до MCP-сервера через HTTP/SSE.
Ключова відмінність від v1: немає WebSocket — замінено на SSE від MCP-сервера. Немає UI для введення команд — Telegram є командним інтерфейсом.
4. Telegram-інтерфейс команд (Тактичний UI-шар — Phase 21.0)
Telegram — це основна панель керування всією Arc OS. Два рівні ботів:
Master Bot (@citadel_ceo_bot):
- Постійна reply-клавіатура:
Мої Проєкти/Новий Проєкт/Watchdog/Web UI - Inline-картки проєктів для кожного дочірнього бота: Restart, Delete, View MANIFEST, Active Skills
- URL-кнопки CRM: Project, Tasks, Files, Settings (заглушки-посилання на фронтенд)
- Роутер callback-запитів для всіх inline-дій
- Потік підтвердження видалення: inline-клавіатура → YES/CANCEL → редагування повідомлення
- Реєстрація
setMyCommandsпід час запуску
Дочірні боти (@cv2_pt_bot тощо):
- Кожна відповідь Claude отримує inline-кнопки на останньому фрагменті:
STOP(SIGKILL) /PAUSE(SIGSTOP) /RESUME(SIGCONT) — керування підпроцесомBTW— ставить у чергу додатковий контекст для наступного виклику ClaudeFix It— автоматично генерує fix-промпт з останньої відповіді бота
- Кнопка з міткою навичок, що показує завантажені компетенції проєкту
- Роутер callback-запитів для всіх дій із сигналами/контекстом
Інтеграція з CRM (у розробці):
CRM_BASE_URL = http://62.171.128.248:18888 (dev)
https://crm.citadel.v2 (future prod)
Усі розкладки клавіатур визначені у shared/ui_templates.ts — єдине джерело для змін UI.
Протокол callback-даних: action:target (макс. 64 байти)
- Master:
restart:pt,delete:pt,confirm_del:pt,cancel_del:pt,manifest:pt,skills:pt - Child:
stop,pause,resume,btw,fixit,skills_info
Потік даних
1. Користувач надсилає "/status" через Telegram
2. Сесія Claude Code отримує його через Telegram Channel
3. Rick читає state/office-state.json + TaskList()
4. Rick відповідає через Telegram (edit_message для live-оновлень)
5. Rick викликає update_agent_state() через MCP
6. MCP-сервер пише у state/office-state.json
7. File watcher помічає зміну → пушить SSE-подію
8. Фронтенд отримує SSE → оновлює спрайти агентів
Керування станом
Увесь стан живе у JSON-файлах у state/:
| Файл | Схема | Хто оновлює | Хто читає |
|---|---|---|---|
office-state.json |
Позиції агентів, статус, бульбашки | Claude (через MCP) | Фронтенд (через HTTP) |
knowledge.json |
Метадані індексованих файлів | Агент Squanchy | Фронтенд, Beth |
reports/*.json |
Результати аналізу | Beth, Summer | Фронтенд |
Задачі Agent Teams керуються Claude Code нативно у ~/.claude/tasks/citadel-v2/.
Агенти (6)
| Агент | Роль | Модель | Активація |
|---|---|---|---|
| Rick | CEO/Оркестратор | opus-4.6 | Завжди активний (лід команди) |
| Morty | SRE/Моніторинг | haiku-4.5 | Health-перевірки, cron |
| Summer | Пам'ять/Рев'ю | sonnet-4.5 | Code review, безпека |
| Jerry | Обслуговування | haiku-4.5 | Прибирання, документація |
| Squanchy | Архіваріус | haiku-4.5 | Індексація файлів |
| Beth | Аналітик | sonnet-4.5 | Дослідження, аналіз |
Ланцюг постачання
CEO → Rick (декомпозиція) → Agent Team (виконання)
→ Cross-Review (Summer валідує)
→ Rick (синтез)
→ CEO (фінальний результат)
Забезпечується через:
- Blueprints: конфіги департаментів, що визначають ролі агентів
- Навички: експертиза, що завантажується динамічно
- Протокол HANDOFF: структуроване передавання контексту між агентами
Технологічний стек
| Шар | v1 | v2 |
|---|---|---|
| Бекенд | FastAPI + Python 3.12 | Сесія Claude Code |
| База даних | SQLite (8 таблиць) | JSON-файли + Agent Teams |
| Обмін повідомленнями | WebSocket + EventBus | Agent Teams SendMessage |
| Стан | SQLite + JSON bridge | JSON-файли (state/) |
| Фронтенд | Phaser 3.86 + WebSocket | Phaser 3.80 + SSE |
| Telegram | Кастомний бот (111KB) | Офіційний Channel-плагін |
| Bridge | bash + jq (19.6KB) | Усунено |
| MCP | Немає | Arc OS Bridge (TypeScript) |
| Деплой | Docker Compose | Docker Compose |
Хуки життєвого циклу
Хуки Claude Code (~/.claude/settings.json) автоматично синхронізують стан агентів:
SubagentStop event → subagent-stop.sh → office-state.json (agent=idle)
↓
StateManager (fs.watch) → SSE → Phaser UI
Stop event → session-end.sh → latest_wrapup.txt + all agents=idle
Скрипти: scripts/citadel-hooks/subagent-stop.sh, scripts/citadel-hooks/session-end.sh
Ключові поля: subagentName (SubagentStop), stopReason (Stop), cwd (обидва).
Семантичний пошук — Self-hosted RAG (Phase 71, 2026-06-05)
Власний (self-hosted) retrieval поверх наявного SQLite SSOT. Замінює NotebookLM Bridge з Phase 36 (виведений з експлуатації, порт 19213 вільний, див. services/.archived-notebooklm-bridge-2026-06-05/ + docs/public/architecture/rag-architecture.md).
Chat / arc kb / Cloud PM
│
▼
shared/rag.ts search()
│
▼
shared/embeddings.ts ──► Cohere /v2/embed
embedQuery(text) (multilingual, 1024-dim float32)
│
▼
embeddings_vec (vec0 virtual) + embeddings (metadata)
KNN (k * 4 overfetch) → project + doc_type filter at JOIN → top-K passages
Fallback: executeLocalKnowledgeSearch (keyword scan over wiki + issues + roadmap)
when top-hit distance > 1.6 or zero results (covers brand-new projects).
- Write-хуки (Phase 71.5):
syncIssue/syncWiki/syncSkillспрацьовують у режимі fire-and-forget на відповідних шляхах запису. Помилки Cohere логуються і завершуються; запис у SQL/на диск ніколи не відкочується. - Простір імен per-project + sentinel-простір
_global_для навичок усього флоту. Виклики пошуку запитують обидва паралельно та зливають результати за відстанню. - Публічний ендпоінт:
GET /api/crm/projects/:name/rag/search?q=...&k=6&include_global=true&doc_types=wiki,issue,skill— живитьarc kb search+ чатовий інструментask_notebooklm(назва інструмента залишена стабільною для сумісності з downstream tool-use Anthropic). - Backfill:
scripts/phase-71-backfill-rag.ts(ідемпотентний,--forceперевизначає). Прод-запуск 2026-06-05: 814 документів / ~3 150 чанків / 0 помилок на Production-ключі. - Виміряний SLO (soak): p50 ≤ 250ms ✅ · p95 ≤ 500ms ✅ · p99 ≤ 1500ms ✅. Крос-мовний recall UK→EN — 100% на ground-truth парах.
Політика маршрутизації даних і задач
Трирівнева система. Кожен рівень має чітке призначення. Змішування рівнів = хаос.
┌─────────────────────────────────────────────────────────────────┐
│ TIER 1: Working Memory (Hot) │
│ office-state.json + state/tasks/ │
│ CLI: /citadel-task, /citadel-status │
│ │
│ Щоденні задачі агентів. Живуть під час сесії. Вмирають після. │
│ Завершена задача → /citadel-wrapup → Tier 3. │
├─────────────────────────────────────────────────────────────────┤
│ TIER 2: Strategic Backlog (Warm) │
│ GitHub Issues (Claude-CEO + citadel-v2 repos) │
│ │
│ Лише епіки: Phase 20, Phase 21, глобальні баги. │
│ Жодних щоденних задач. Жодних issue типу "виправити одрук". │
│ Одне Issue = одна багатотижнева ініціатива або критичний дефект.│
├─────────────────────────────────────────────────────────────────┤
│ TIER 3: Long-term Memory (Cold) │
│ docs/library-export/ + вікі проєкту + закриті issue │
│ → embedded via shared/rag.ts (Cohere + sqlite-vec, Phase 71) │
│ CLI: /citadel-wrapup, arc kb search "<query>" │
│ │
│ Енциклопедія. Результати сесій, архітектурні рішення, RAG. │
│ Read-only архів. Жодних активних задач. Без трекінгу статусів. │
└─────────────────────────────────────────────────────────────────┘
Правила маршрутизації
| Тип даних | Рівень | Приклад |
|---|---|---|
| «Полагодити deploy-скрипт» | 1 — Working Memory | /citadel-task "Fix deploy script" |
| «Phase 20: Multi-Tenant SaaS» | 2 — GitHub Issues | gh issue create --title "Phase 20: ..." |
| «Підсумок сесії: хуки реалізовано» | 3 — Library | /citadel-wrapup → вікі + автоембединг через хуки Phase 71 |
| «Архітектурне рішення: обрали SSE замість WS» | 3 — Library | Архівується у wrapup після сесії |
| «Баг: SSE обривається на VPS» | 2 — GitHub Issues | Лише якщо крос-сесійний / блокувальний |
| «Rick працює над хуками» | 1 — Working Memory | статус агента в office-state.json |
Життєвий цикл
CEO дає задачу → Tier 1 (агент працює над нею)
↓ завершено
/citadel-wrapup → Tier 3 (заархівовано)
↓ якщо стратегічна
gh issue create → Tier 2 (довгостроковий трекінг)
Антипатерни (НЕ РОБИТИ)
- НЕ створювати GitHub Issues для щоденних задач («виправити одрук», «оновити конфіг»)
- НЕ зберігати статус активних задач у файлах library-export/
- НЕ використовувати office-state.json для довгострокових рішень чи архітектурних нотаток
- НЕ дублювати: одна задача живе рівно на одному рівні в один момент часу
Інфраструктура (Phase 20.5)
Структуроване логування (shared/logger.ts)
Формат JSONL, подвійний вивід (файл + консоль), щоденне розбиття файлів за категоріями.
/var/log/citadel/
├── master/
│ ├── system-2026-04-02.log ← lifecycle, config, health
│ ├── dialog-2026-04-02.log ← (not used by master)
│ └── error-2026-04-02.log ← errors (also in system)
├── citadel-v2/
│ ├── system-2026-04-02.log
│ ├── dialog-2026-04-02.log ← user ↔ Claude messages
│ └── error-2026-04-02.log
└── <project-name>/ ← per onboarded project
Ротація логів: config/logrotate-citadel.conf → /etc/logrotate.d/citadel (щоденно, зберігання 7 днів).
Сховище секретів (shared/vault.ts)
Сховище токенів ботів, зашифроване AES-256-GCM.
Key source: SECRET_ENCRYPTION_KEY env → config/vault-key file → auto-generated
Storage: config/vault.json (atomic writes: tmp + mv)
Cache: In-memory after initVault() — no disk I/O per getSecret()
Fallback: getSecret("FOO") → vault cache → process.env.FOO
Naming: child:<project-name>:token
Власний токен майстра залишається в .env (vault завантажується всередині процесу майстра).
Self-Healing Watchdog (master-bot/watchdog.ts)
Фоновий монітор дочірніх ботів. Працює всередині процесу майстер-бота.
Every 30s: HTTP health check → /api/child/health (5s timeout)
Healthy → reset failures
Unhealthy → increment failures
3+ failures + backoff elapsed → auto-restart (kill tmux → start new with vault token)
Backoff: 30s → 1m → 5m → 15m → 60m (cap)
10 consecutive failures → permanently disable + notify CEO
Стан зберігається у config/watchdog-state.json (переживає перезапуск майстра).
Сповіщення CEO через Telegram: перший рестарт, невдалий рестарт, остаточне вимкнення.
Команда /watchdog: статус усіх дочірніх ботів у реальному часі.
Протокол видалення проєкту (Phase 20.4 + 21.0)
/remove_project <name> → потрійне підтвердження → повне очищення:
1. Kill tmux session: child-<name>
2. Mass Kill ghosts: ps aux | grep child-<name> → kill -9 all PIDs
3. Port check: ss -tlnp | grep :<port> → force-free if occupied
4. Remove from bot_registry.json + in-memory reload
5. Delete /opt/repos/<name>/ (safety: path must be under /opt/repos/, min 3 segments)
6. Delete /var/log/citadel/<name>/
Захищені імена: citadel-v2, citadel, claude-ceo, claude-CEO — видалення заблоковано.
Проблема процесів-привидів (вивчений урок): після kill tmux осиротілі процеси bun можуть тримати порти. Масовий kill + перевірка порту запобігають «фантомним ботам», які відповідають на health-перевірки, але ігнорують Telegram.
Керування навичками (Phase 21.0)
Дочірні боти завантажують навички з двох джерел під час запуску, з дедуплікацією через Set:
Source 1: MANIFEST.md (JSON)
→ manifest.skills[] (matched during onboarding)
→ manifest.library_skills[] (library .md files matched)
Source 2: skills/ directory
→ *.md files → filename without extension
Merge: Set<string>(manifest.skills + manifest.library_skills + skills/*.md)
Приклад (проєкт PT): 5 із маніфеста + 7 із skills/ = 12 унікальних навичок.
Навички відображаються як:
- Мітка inline-кнопки на відповідях дочірнього бота:
🏷️ odoo-expert, docker-ops, ... - Callback
skills_info: toast із повним списком - Команда
/skillsу майстра: виводить вміст директорії навичок
Безпека (Phase 42 — аудит Sentinel 2026-04-23, 4 проходи, 13 патчів)
Повний огляд: SECURITY.md. Звіт аудиту: security/audit-2026-04-23.md.
Секрети та зберігання:
- Жодних credentials у репозиторії; файли стану не містять секретів
- Токени ботів — у зашифрованому сховищі (
config/vault.json, AES-256-GCM).getSecret()із fallback наprocess.env - Ключ шифрування автогенерується у
config/vault-key(chmod 600).vault.json,vault-key,watchdog-state.json,data/citadel.db*— у gitignore
Автентифікація:
- JWT HMAC-SHA256, TTL 24 год, порівняння підпису через
crypto.timingSafeEqual - OAuth Google + GitHub із CSRF state (10 хв, одноразовий)
- Email/пароль з обов'язковою верифікацією перед логіном (TTL 24 год), скиданням пароля (TTL 30 хв), доставка через Resend
- Витягання токена —
extractChatId()читає Bearer-заголовок АБО query?token=(для браузерного EventSource), точно відповідаєcrmAuthMiddleware
Multi-tenancy (Phase 42):
- Gate
canAccessProject(registry, chatId, project)на кожному захищеному маршруті - CEO (
ceo_chat_id) і DBuser.role === 'admin'бачать усе; решта обмежена збігомowner_id(DB SSOT) - SSE-маршрути, WebSocket-термінал,
/api/cli/*,/api/mcp/*,/api/crm/projects/:name/*— усі захищені /ws/terminal/:name?mode=interactiveвимагає CEO або admin
Мережевий периметр:
- Bun біндиться лише на
127.0.0.1:19210— nginx проксіює через loopback /api/internal/*відхиляє будь-який запит із проксі-заголовками (X-Forwarded-For,X-Real-IP,Forwarded) як «канарку» неправильної конфігурації nginx- SSRF-allowlist на
handleScoutAnalyze— HTTPS + точний збіг hostname +redirect:"manual"(блокує обхід через ланцюг редиректів) - UFW блокує
:19210,:19200ззовні (:19213більше не використовується відтоді, як Phase 71.8 вивела з експлуатації NotebookLM bridge)
Безпека вводу / шляхів:
- Regex
isValidProjectName()на кожній точці входу (включно з internal-ендпоінтами) safePath()на всіх керованих користувачем шляхах файлів —handleSaveSkillзнайдено + виправлено у Phase 42.6- Deny-list Nginx:
/.*,/(state|scripts|config|data|knowledge-base|issues|skills|blueprints|mcp-server)/ - CORS-whitelist (
CRM_ALLOWED_ORIGINS), заголовки навіть на помилках - Атомарні записи для мутацій registry (
tmp.${pid}+mv) - Дешифрування vault-токена для запуску дочірнього бота: використовувати
bun -eіз node:crypto (НЕ Python)
Регресійне покриття: scripts/vps-sync.sh запускає 7+ post-deploy smoke-тестів після кожного деплою (loopback bind, path traversal, валідація chat/save, проксі-канарка, SSE ?token=, fail-closed валідація, блокування SSRF якщо задано CEO_TOKEN).
Модулі Master Bot (Phase 25 — закриття DEBT-1)
Майстер-бот організовано у сфокусовані модулі:
master-bot/
├── bot.ts ← Bootstrap: vault, registry, context, wire everything (106 lines)
├── context.ts ← MasterContext type + domain interfaces
├── api-server.ts ← Bun.serve() — HTTP, WebSocket, SSE, CRM routes
├── tg-api.ts ← Telegram Bot API wrapper (sendMessage, getUpdates, etc.)
├── child-state.ts ← Read child bot state, health, heartbeat, tmux, bridge
├── telegram-commands.ts ← All /command handlers, callback query handler, message router
├── telegram.ts ← Slim polling loop + re-exports for backward compat
├── watchdog.ts ← Self-healing child bot monitor
└── onboarding.ts ← Interactive project creation wizard
bot.ts імпортує лише з telegram.ts та api-server.ts. Усі інші модулі — внутрішні деталі реалізації.
Bridge CLI (Phase 25 — локальний шлюз)
bridge/
├── bin/citadel-bridge.ts ← CLI entry (commander.js): connect, pull, push, status, disconnect
├── src/
│ ├── auth.ts ← JWT validation against CRM
│ ├── config.ts ← ~/.citadel/bridge.json persistence
│ ├── inject.ts ← CLAUDE.md <!-- CITADEL:START/END --> markers
│ ├── sync.ts ← Pull skills-bundle + learnings, push local learnings
│ └── heartbeat.ts ← Session activity reporter
├── package.json
└── tsconfig.json
Ендпоінти CRM API (50+ загалом)
Основна CRM (Phase 22)
| Ендпоінт | Метод | Призначення |
|---|---|---|
/api/master/health |
GET | Health майстер-бота (публічний) |
/api/crm/projects |
GET | Список усіх проєктів + live health |
/api/crm/projects/:name |
GET | Деталі проєкту |
/api/crm/projects/:name/logs |
GET | Tail JSONL-логів |
/api/crm/projects/:name/files |
GET | Безпечний лістинг директорії |
/api/crm/projects/:name/files/upload |
POST | Завантаження файлів |
/api/crm/projects/:name/files/mkdir |
POST | Створення теки |
/api/crm/projects/:name/files/create |
POST | Створення файлу |
/api/crm/projects/:name/files/delete |
DELETE | Видалення файлу/теки |
/api/crm/projects/:name/files/clone |
POST | Клонування git-репозиторію |
/api/crm/projects/:name/files/read |
GET | Читання вмісту файлу |
/api/crm/projects/:name/wiki/tree |
GET | Список .md-файлів вікі |
/api/crm/projects/:name/wiki/file |
GET | Читання вмісту файлу вікі |
/api/crm/projects/:name/skills |
GET | Встановлені навички |
/api/crm/projects/:name/metrics |
GET | Часові ряди якості |
/api/crm/projects/:name/restart |
POST | Перезапуск дочірнього бота |
/api/crm/projects/:name/specs |
GET | Список специфікацій |
/api/crm/projects/:name/specs/:id/approve |
POST | Затвердження специфікації |
/api/crm/projects/:name/specs/:id/reject |
POST | Відхилення специфікації |
/api/crm/projects/:name/active-role |
GET/POST | Роль агента |
/api/crm/projects/:name/message |
POST | Поставити повідомлення воркеру в чергу |
/api/crm/projects/:name/workers |
GET/POST | CRUD реєстру воркерів |
/api/crm/projects/:name/workers/:id |
PUT/DELETE | Оновлення/видалення воркера |
/api/crm/projects/:name/workers/generate-prompt |
POST | AI-генерація системного промпту |
/api/crm/projects/:name/skills-bundle |
GET | Навички + evals для bridge |
/api/crm/projects/:name/learnings |
GET/POST | Синхронізація learnings |
/api/sse/logs/:name |
GET | SSE-потік логів (?category=) |
Дашборд і вікі (Phase 32)
| Ендпоінт | Метод | Призначення |
|---|---|---|
/api/crm/projects/:name/wiki/save |
PUT | Збереження/створення сторінки вікі |
/api/crm/projects/:name/skills/save |
PUT | Збереження файлу навички |
/api/crm/projects/:name/skills/delete |
DELETE | Видалення файлу навички |
Multi-Tenant (Phase 33)
| Ендпоінт | Метод | Призначення |
|---|---|---|
/api/crm/account/settings |
GET/PUT | API-ключі рівня акаунта |
/api/crm/projects/create |
POST | Полегшене створення проєкту |
/api/crm/onboarding/setup |
POST | Повний майстер онбордингу |
MCP та CLI (Phase 34)
| Ендпоінт | Метод | Призначення |
|---|---|---|
/api/mcp/issues/:project |
POST/GET | CRUD задач (issues) |
/api/mcp/issues/:project/:id |
PUT | Оновлення задачі |
/api/mcp/wiki/:project |
PUT | Синхронізація вікі через MCP |
/api/mcp/roadmap/:project |
GET/PUT | Читання/синхронізація roadmap |
/api/cli/init/:project/:mode |
GET | Хмарний контекст для CLI |
/api/mcp/skills/:project/:skill |
GET | Отримання навички для MCP |
/api/mcp/report/:project |
POST | Звіт місії |
/api/mcp/learnings/:project |
GET | Отримання learnings для MCP |
Live Terminal (Phase 35)
| Ендпоінт | Метод | Призначення |
|---|---|---|
/api/crm/projects/:name/terminal/log |
POST | Прийом термінального JSONL від ARC CLI |
Cloud PM та знання (Phase 36, оновлення Phase 71)
| Ендпоінт | Метод | Призначення |
|---|---|---|
/api/crm/projects/:name/chat |
POST | SSE-проксі чату до Anthropic API |
/api/crm/projects/:name/skills/generate |
POST | Neural Skill Generator. Phase 71.7: переведено з NotebookLM-як-генератора на Claude Sonnet із RAG-доповненим контекстом (top-5 результатів як приклади house-style). |
/api/crm/projects/:name/rag/search |
GET | Phase 71.7 (новий): семантичний пошук поверх embeddings + embeddings_vec (Cohere + sqlite-vec). ?q=...&k=6&include_global=true&doc_types=wiki,issue,skill. |
/api/crm/projects/:name/notebooks |
GET | Phase 71.8: legacy-заглушка — повертає { notebooks: [], retired: "phase-71.8" }. |
Auth та OAuth (Phase 37)
| Ендпоінт | Метод | Призначення |
|---|---|---|
/api/auth/register |
POST | Реєстрація через email/пароль |
/api/auth/login |
POST | Логін через email/пароль |
/api/auth/google |
GET | Редирект OAuth Google |
/api/auth/callback/google |
GET | Callback OAuth Google |
/api/auth/github |
GET | Редирект OAuth GitHub |
/api/auth/callback/github |
GET | Callback OAuth GitHub |
/api/auth/providers |
GET | Доступні OAuth-провайдери |
Закріплені нотатки (Phase 41.8)
| Ендпоінт | Метод | Призначення |
|---|---|---|
/api/crm/projects/:name/pins |
GET | Список закріплених нотаток (спочатку новіші) |
/api/crm/projects/:name/pins |
POST | Закріпити повідомлення воркера у Context Rail (body: worker_id, body, опційно title, author) |
/api/crm/projects/:name/pins/:id |
DELETE | Видалити закріплення |
Бекенд: міграція 009 (таблиця pinned_notes), pinnedNoteQueries у shared/db.ts. Фронтенд: ContextRail.jsx робить fetch при монтуванні, слухає CustomEvent crm-pin-created, оптимістичний DELETE.
Шар захисту даних (Phase 45)
Гібридне шифрування at-rest — клієнтська криптографічна основа + серверне шифрування сховища.
Клієнтська сторона (браузер)
frontend/src/crm/crypto/e2ee.ts— обгортка WebCrypto (214 рядків)- PBKDF2 (100k ітерацій, SHA-256) → майстер-ключ AES-256-GCM
- Життєвий цикл ключа:
initMasterKey(password)при логіні →sessionStorage→clearMasterKey()при логауті/401 - Відновлення:
generateRecoveryKey()→ формат 1Password (XXXX-XXXX-XXXX-XXXX-XXXX)
Серверна сторона (Bun + SQLite)
shared/vault.ts—encryptField()/decryptField()з vault-ключем AES-256-GCM (формат із префіксомv1:)- API-ключі: шифрування при збереженні, дешифрування при завантаженні (прозоро для фронтенду) —
routes/system.ts - Повідомлення чату: автошифрування INSERT, автодешифрування SELECT —
db.ts+ міграція 015 - Ключі відновлення: таблиця
recovery_keys(міграція 016), 4 API-ендпоінти
Заголовки безпеки
- CSP:
default-src 'self'; script-src 'self'на всіх CRM-відповідях X-Frame-Options: DENY,X-Content-Type-Options: nosniff,Referrer-Policy: strict-origin-when-cross-origin
Санітизація PII
shared/pii-sanitizer.ts— редагує emails, API-ключі (sk-ant-*,sk-*), JWT, номери карток- Застосовується до прийому термінальних JSONL-логів (
routes/chat.ts)
Ендпоінти ключів відновлення
| Ендпоінт | Метод | Призначення |
|---|---|---|
/api/crm/account/recovery |
POST | Створити ключ відновлення (зберігає зашифрований майстер-ключ) |
/api/crm/account/recovery |
GET | Список активних ключів відновлення |
/api/crm/account/recovery |
DELETE | Відкликати ключ(і) відновлення |
/api/crm/account/recovery/restore |
GET | Отримати зашифрований майстер-ключ для відновлення |
Повні деталі безпеки: docs/SECURITY.md, docs/architecture/PHASE_45_E2EE.md.
Standard Cloud — багатосерверний флот (Phase 60)
Повні деталі: docs/architecture/PHASE_60_STANDARD_CLOUD.md.
Сервери
| Сервер | IP | Роль |
|---|---|---|
| Contabo | 62.171.128.248 | API + Master Bot + DB + Nginx |
Hetzner arc-cloud-prod |
157.180.44.232 | Користувацькі Docker-контейнери |
SSH Bridge
Усі Docker-операції на Hetzner ініціюються з Contabo через SSH:
Contabo root → ssh -i /root/.ssh/hetzner_ed25519 [email protected] docker <cmd>
CONTAINER_SERVER_IP у vault керує маршрутизацією: 127.0.0.1 = локально, будь-яка інша IP = SSH.
Життєвий цикл контейнера
provision → ready → [idle 30min] → paused → [TG message] → ready
↑ wake
Lifecycle-cron: */5 * * * * на Contabo → scripts/cloud-lifecycle-cron.ts.
Хмарний waitlist
Користувачі приєднуються через POST /api/crm/cloud/waitlist. Адмін запрошує через POST /api/crm/cloud/waitlist/invite, що автоматично підвищує план до cloud. Таблиця: cloud_waitlist (міграція 029).