Arc OS — Roadmap
Native-first AI Office. Команди агентів Claude Code + CLI-First архітектура + канали. 70+ endpoints, SQLite SSOT, Sage Worker + бенчмарки + Marketplace Discovery + Knowledge Harvester. Останнє оновлення: 2026-06-11 (#429 P0 NFR-PERF-002 hardening DONE ✅ — concurrency gate для bcrypt обмежує хвостову латентність auth-шляху під навантаженням credential-stuffing; задеплоєно та перевірено на проді. Phase 82 SEO Foundation COMPLETE ✅ — meta/OG/JSON-LD, Docs SSG на 295 сторінок із hreflang, prerender лендингу, llms.txt + content-signals. Phase 81 Spotlight Tours + єдиний onboarding-чекліст COMPLETE ✅. Phase 78 COMPLETE ✅ — Notes Knowledge Collections: нотатки в стилі NotebookLM на проєкт із вибором джерел, inline-перейменуванням, аліасами S1/S2, захистом від галюцинацій, створенням задач через tool-use із чату. Phase 76 FULLY COMPLETE ✅. Phase 73 COMPLETE 9/9 ✅. Phase 71 RAG DONE ✅. Phase 62 Voice Input DONE ✅. Phase 70 Cloud Chat Routing DONE ✅. Phase 69 Cloud Repo Model DONE ✅.)
Таймлайн фаз
timeline
title Arc OS — From Native Birth to Public Beta
section Foundation (Feb 2026)
18 : Native Birth + Phaser
19 : Rich Integration
20 : Federated Bots
section Intelligence (Mar 2026)
21 : Binary Evals + Context Router + Learnings
22 : CRM Dashboard
24-26 : Dual Agent + Dynamic Workers
28-30 : Auto-ingest + Knowledge Harvester
section Marketplace (Apr 2026)
32-35 : Knowledge Dashboard + Live Terminal
36 : Cloud PM + NotebookLM Bridge
38 : ARC CLI compiled
40 : Sage + A/B + Marketplace Discovery
section Hardening (Apr 2026)
41 : UI Refresh + Context Rail
42 : Multi-tenancy + Loopback bind
44 : Analytics + Docs Coverage 95%
45 : Zero-Knowledge E2EE
section Architecture (Late Apr 2026)
47 : Timeline + Issues Redesign
48 : Decomposition 10779→373 LOC + Worker lazy lifecycle
49 : Doc-coverage pre-push hook
section Beta (May 2026)
50 : Trial Credits
51 : Stripe Billing Stage 1
52.1 : F&F Invite Codes + beta plan
53 : Sentinel hardening (2×P0 + 13×P1 + P2)
54 : Onboarding Engagement Layer
55 : Cosmic Editorial login + Magic Link
56 : AI Interop / Project Context Export
57 : Platform Settings UI
58 : Header / UserDropdown UX
59 : Localization Expansion (8 locales)
60 : Standard Cloud (Docker per user)
61 : Arc Help AI assistant
63 : UI/UX Consolidation + Token Usage
64 : Security & Compliance (GDPR + WCAG)
Де ми зараз: Phase 82 DONE ✅ (2026-06-11) — SEO Foundation (#458): meta/OG/Twitter/JSON-LD/canonical + sitemap.xml + robots.txt (#459); Docs SSG — 295 статичних HTML-сторінок, 8 локалей, hreflang (#460); prerender лендингу для ботів/no-JS + FAQPage JSON-LD (#461); GEO llms.txt + Content-Signal
search=yes, ai-input=yes, ai-train=no, вимкнено CF managed robots.txt (#462). Follow-ups: #464 OG-зображення, #465 чесна 404. Phase 81 DONE ✅ (2026-06-11) — Spotlight Tours (#431/#446: driver.js, 3 тури, i18n UA+RU, ланцюжок EN fallback) + єдиний onboarding-чекліст (#457: кроки plan/workers/issue/bot/cli, міні-тури "Show me where", передача тур→чекліст). Phase 79 DONE ✅ (Project Admin Worker). Phase 77 DONE ✅ (CEO Worker). Phase 78 DONE ✅ (Notes; 78.11 project-aware чат #447 + paste-to-source #448 закрито 2026-06-10/11). #429 DONE ✅ (2026-06-11) — P0 NFR-PERF-002: concurrency gatewithBcryptSlot(4 активних / 24 у черзі / overflow→503) уshared/auth.tsобмежує хвостову латентність auth-шляху під розподіленим credential stuffing (6-ядерний VPS, 20c p99 1709ms→752ms; виправлено хибну причину "bcrypt блокує event loop" — bcrypt працює в thread pool, без cross-endpoint stall). Задеплоєно main55a74e41, master перезапущено, перевірено наживо.Далі: (1) закрити хвіст QA/NFR hardening із циклу навантажувального тестування 2026-06-09 — повторно прогнати TC-PERF-LOAD-002 (NFR-PERF-003) + TC-PERF-LOAD-004 (NFR-PERF-004) із записаним cleanup probe, та розібрати відкриті traceability-баги (#246 P1 GDPR export 500; #242/#243/#254/#266 P2); потім (2) наступна фічева фаза Phase 75 — ⚠️ колізія нумерації в цьому документі: Project Collaboration (#150, P1) та Odoo CRM Integration (~Q1 2027) обидві позначені як "Phase 75". Потрібен renumber від CEO перед стартом будь-якої з них.
Phase 18: The Native Birth (COMPLETE)
18.0 — Repository Bootstrap (DONE)
- Створення репозиторію, CLAUDE.md, .clauderules
- Перенесення IP-активів (конфіги, blueprints, навички)
- Створення umbrella-задачі #35 у Claude-CEO
18.1 — Agent Teams Foundation
- Активація Agent Teams через TeamCreate
- Створення початкових задач для Morty, Squanchy, Beth
- Визначення Working Agreements для кожного агента
- Тестування міжагентського обміну повідомленнями
- Протокол оновлення стану (office-state.json)
18.2 — Telegram Native Channel
- Новий бот через @BotFather
- Офіційний плагін Telegram Channel
- Текстові команди: /status, /tasks, делегування
- Завантаження файлів → авто-класифікація → маршрутизація до агента
- Прогрес через edit_message, реакції
18.3 — Arc OS Bridge MCP Server
- MCP-сервер на Bun + TypeScript
- 4 MCP-інструменти: get_office_state, update_agent_state, get_tasks, get_knowledge
- HTTP API: /api/state, /api/tasks, /api/knowledge, /api/events
- SSE-стрім для real-time оновлень фронтенду
- File watcher на директорії state/
18.4 — Visual Restoration (Phaser Frontend)
- Свіже налаштування Phaser 3.80 + Vite 6
- OfficeScene, UIScene, сутності Agent
- StatePoller (SSE з MCP-сервера)
- HD-текст (системні шрифти, high DPI)
- Спрайти агентів (pixel art або кольоровий fallback)
- Без UI вводу команд (Telegram — інтерфейс)
18.5 — VPS Deployment & 24/7
- Docker Compose (3 сервіси: session, bridge, frontend)
- Nginx reverse proxy (:18888 → frontend, :19200 → API)
- Персистентність стану через Docker volumes
- Інтеграція heartbeat із Morty SRE
- SSL через Let's Encrypt (опційно)
Phase 19: Rich Integration (COMPLETE)
19.1 — Delta State Polling (DONE)
- Фронтенд опитує тільки змінений стан через параметр
?since= - StateManager відстежує
lastModifiedдля кожного файлу - SSE надсилає delta-події, а не повні дампи стану
19.2 — Context Bar & Canvas Theme (DONE)
- CTX-бар з активним агентом, задачею, інформацією про сесію
- Canvas-нативна тема Phaser (без HTML-оверлеїв)
- Виправлення асинхронної boot-послідовності
19.3 — Lifecycle Hooks (DONE)
- Хук
SubagentStop→ agent=idle в office-state.json - Хук
Stop→ session wrapup + всі агенти idle - Зареєстровано в
~/.claude/settings.json
19.4 — Library / NotebookLM Integration (DONE)
- CLI-команда
/citadel-wrapup→ експорт у docs/library-export/ - CLI-команда
/citadel-recall <query>→ локальний grep-пошук - README з інструкціями налаштування NotebookLM
- Файловий міст (в очікуванні API для повної інтеграції)
19.5 — CLI Operation Skills (DONE)
/citadel-status— дашборд агентів (working/idle, задачі, статистика бібліотеки)/citadel-task <text>— створення WISC-структурованої задачі з простого тексту/citadel-deploy— деплой на VPS (git push, SSH, Docker rebuild, health check)
Phase 20: Federated Bot Architecture (COMPLETE)
Архітектурний документ:
docs/architecture/PHASE_20_FEDERATION.mdРішення: Federation (Master + Children) замість Single Bot + Switcher.
20.1 — Master Bot Foundation (DONE)
- Telegram-бот на Bun + TypeScript (long-polling, НЕ сесія Claude)
config/bot_registry.json— реєстр дочірніх ботів- Команди:
/status,/emergency-stop,/list,/deploy,/health - Docker-контейнер у
docker/docker-compose.yml - Health endpoint:
/api/master/health
20.2 — Child Bot Protocol (DONE)
child-bot/bot.ts— проксі Telegram ↔ Claude CLI (claude -p)- Heartbeat-файл кожні 60с у
state/heartbeat_<name>.json - Smart Context Middleware:
reply_to_message→ ін'єкція GSD CONTEXT - Історія тредів: останні 50 повідомлень у
state/thread_history.json - Graceful shutdown (SIGINT/SIGTERM для emergency-stop)
- Health endpoint:
/api/child/healthна порту 19211 - Працює на ХОСТІ (потребує
claudeCLI), не в Docker - Загартовано: 5-хвилинний таймаут, retry при збої, ліміт max-turns (20), діагностика
20.3 — Onboarding Engine (DONE)
/new_project <name>— інтерактивне інтерв'ю (4 кроки: опис → лінки → токен → підтвердження)- Підбір навичок: авто-визначення з реєстру + бібліотеки
- Визначення blueprint: web, gamedev, debug, legal, service
- Авто-провіжинінг: mkdir, CLAUDE.md, MANIFEST.md, .env, git clone, реєстр, tmux
- Виділення портів із реєстру
- Підтримка завантаження
.mdфайлів з описом проєкту
20.4 — Skill Library & Project Removal (DONE)
/remove_project <name>— безпека з потрійним підтвердженням та захищеними іменами- Навички бібліотеки:
skills/library/*.mdавто-підбираються під час онбордингу - Копіюються в директорію
skills/нового проєкту під час провіжинінгу - Хук перезавантаження реєстру: оновлення в пам'яті після провіжинінгу/видалення
20.5 — Phantom-Ready Infrastructure (DONE)
shared/logger.ts— JSONL структурований логер із подвійним виводом (файл + консоль)- Щоденне розбиття файлів:
system-YYYY-MM-DD.log,dialog-YYYY-MM-DD.log,error-YYYY-MM-DD.log - Категорії: system (lifecycle), dialog (user↔Claude), error (→ і error, і system)
- Нуль зовнішніх залежностей — чисті Bun API
- Щоденне розбиття файлів:
shared/vault.ts— зашифроване сховище секретів AES-256-GCM- Ключ: env var → файл
config/vault-key→ авто-генерація - Кеш у пам'яті після init, fallback до
process.env - Атомарні записи (tmp + mv)
- Ключ: env var → файл
master-bot/watchdog.ts— фоновий монітор із самовідновленням- HTTP health check кожні 30с (таймаут 5с)
- Авто-рестарт упалих дочірніх ботів через tmux (токен із vault)
- Експоненційний backoff: 30с → 1хв → 5хв → 15хв → 60хв (стеля)
- Постійне вимкнення після 10 послідовних збоїв
- Сповіщення CEO: перший рестарт, збій, постійне вимкнення
- Стан зберігається у
config/watchdog-state.json
- Команда
/watchdog— статус здоров'я дочірніх ботів у реальному часі в Telegram - Онбординг зберігає токени у vault (не в
.env), створює/var/log/citadel/<name>/ config/logrotate-citadel.conf— щоденна ротація, зберігання 7 днів, компресіяscripts/setup-vps-logging.sh— налаштування лог-інфраструктури VPS- Усі
console.log/console.error→ структурований логер (child-bot + master-bot)
Phase 21: Arc OS Command Interface (COMPLETE)
Telegram стає повноцінним інтерактивним дашбордом з inline-клавіатурами, керуванням підпроцесами та CRM-лінками (заглушки).
21.0 — Tactical UI Layer (DONE)
shared/ui_templates.ts— центральний модуль побудови клавіатурmasterMainMenu()— постійна reply-клавіатура 2×2projectCard(name, crmBase)— inline-клавіатура на 4 ряди (Restart/Delete/Manifest/Skills/CRM)deleteConfirm(name)— inline YES/CANCELchildResponseButtons(skills?, crmBase?, projectName?)— STOP/PAUSE/RESUME/BTW/FixItparseCallback(data)— парсер"action:target"
- Оновлення master-бота:
- Маршрутизація тексту reply-клавіатури (Мої Проєкти → картки проєктів, Web UI → лінк на CRM)
handleCallbackQuery()— restart, флоу видалення, переглядач MANIFEST, список навичок- Хелпери
tgSendMarkup,tgEditMessage,tgAnswerCallback,tgSetMyCommands /startнадсилає довідку РАЗОМ із reply-клавіатурою- Кнопки CRM URL (конфігурований
CRM_BASE_URL, dev:http://62.171.128.248:18888)
- Оновлення child-бота:
- Стан на рівні модуля:
currentProc/isPaused/btwQueue handleStop()→ SIGKILL,handlePause()→ SIGSTOP,handleResume()→ SIGCONT- Режим BTW: збирає контекст → додає на початок наступного GSD-промпта
- FixIt: будує fix-промпт з останньої відповіді бота в історії треду
- Inline-кнопки тільки на останньому чанку відповіді
- Об'єднане завантаження навичок: manifest JSON + директорія skills/, з дедуплікацією
- Стан на рівні модуля:
- Експорт
restartChildз watchdog,executeRemovalз onboarding - Переглядач MANIFEST: перевірка
existsSync, HTML-escape, JSON pretty-print, виявлення EACCES scripts/start-child-pt.sh— запуск на основі vault (bun + node:crypto, не Python)
21.5 — Evolutionary Intelligence (DONE)
shared/evals.ts— Binary Eval Engine: 6 типів правил,.evals.jsonна кожну навичку, неблокуючі попередженняshared/context-router.ts— Context Router: скоринг тригерів/ключових слів, ін'єкція top-5 SKILLS_HINTshared/learnings.ts— Persistent Learnings: Fix It / thumbs-down →learnings.md→ кожен майбутній промптscripts/nightly-improve.ts— Karpathy Loop: нічний аналіз метрик → пропозиції покращень → затвердження CEO- Пілотні evals: code-review, git-manager, system-audit (разом 9 правил)
- Ключові слова додані до 11 навичок реєстру
docs/public/— 8 публічних файлів документації з навігаційним індексом
Phase 22: Bun CRM & Observability Hub (COMPLETE)
Архітектура:
docs/planning/phase-22-bun-crm.md| Бекенд:docs/architecture/crm-backend.mdТехнічний борг:docs/backlog/technical-debt.md(7 пунктів, 2 вирішено)
22.0 — CRM REST API (DONE)
shared/auth.ts— HMAC-SHA256 токен-автентифікація, CRM_SECRET у vault, TTL 24 год (DONE — #7)shared/crm-routes.ts— 5 CRM-хендлерів: projects, detail, logs, files, skills (DONE — #8)- Роутер Bun.serve: async fetch, auth middleware, CORS на всіх маршрутах /api/crm/* (DONE — #10)
infra/nginx/citadel-crm.conf— єдиний reverse proxy замість citadel-os (DONE — #14)- Telegram-команда
/admin_login— генерує лінк входу в CRM дашборд (DONE — #7; ВИДАЛЕНО у Phase 40.19b) scripts/vps-sync.sh— автоматизований деплой на VPS: git sync, заміна nginx, рестарт бота, health checks (DONE)- Задеплоєно на VPS і перевірено: всі 5 CRM endpoints живі, auth guard активний, path traversal заблоковано (DONE)
- Керування конфігурацією: PUT evals + skills на проєкт (DEFERRED — #9)
22.1 — Real-time Observability (DONE)
- SSE стрімінг логів:
/api/sse/logs/:name— live tail JSONL-логів у браузер (опитування 1с) - Endpoint метрик якості:
GET /api/crm/projects/:name/metrics?days=7— агрегація по днях із quality-events.log - Інтеграція CrmPoller у фронтенд: опитує
/api/crm/projects(15с), генерує події для сцен Phaser - Конфіг Nginx для SSE:
proxy_buffering off, таймаут 1 год для/api/sse/*
22.2 — Unified Command Center (DONE)
- Міст CRM→Phaser: CrmPoller → сутності ProjectPod у сцені Server Room
- LogPanel у стилі glassmorphism: SSE-консьюмер логів із фільтром категорій + авто-скрол
- Секція PROJECTS у сайдбарі з живими індикаторами здоров'я (зелений/жовтий/червоний)
- Клік на проєкт → відкривається LogPanel зі стрімінгом логів
frontend/src/config/constants.js— конфіг CRM_TOKEN, CRM_BASE_URL- Docker multi-stage збірка (node:22-alpine → nginx:alpine) із вшитим CRM-токеном
- Задеплоєно на VPS:
scripts/vps-sync.shіз Docker rebuild + health checks
22.3 — Metrics Charts, WebSocket Terminal & Power Controls (DONE)
frontend/src/ui/Sparkline.js— canvas stacked bar chart (120x24px, зелений=успіх, червоний=збої)frontend/src/ui/TerminalPanel.js— xterm.js WebSocket-термінал з ANSI-кольорами + FitAddon- WebSocket-термінал:
/ws/terminal/:name— опитування tmux capture-pane (200мс), read-only за замовчуванням, інтерактивний з?mode=interactive - Endpoint рестарту:
POST /api/crm/projects/:name/restart— cooldown 30с, викликаєrestartChild()через watchdog - Кнопка живлення ProjectPod: показ при наведенні, клік для рестарту з діалогом підтвердження
- Вкладки LogPanel: Logs | Terminal — перемикання з динамічним імпортом TerminalPanel
- Sparkline у LogPanel: рендерить timeseries метрик у заголовку панелі
- Зміцнення безпеки (DEBT-7): regex-валідація
isValidProjectName()у всіх 3 точках входу API (CRM router, SSE router, WS handler). Блокує path traversal через ім'я проєкту. - Цілісність даних (DEBT-2):
atomicWriteJson()— запис у.tmp.${pid}, потімmv. Застосовано до всіх 4 точок запису реєстру в onboarding.ts. - Аудит технічного боргу:
docs/backlog/technical-debt.mdіз 7 пунктами (DEBT-2 + DEBT-7 вирішено)
Phase 24: Dual-Agent Flow & CRM Enhancement (COMPLETE)
Архітектурний документ:
docs/architecture/dual-agent-flow.mdТема: Slate & Silver (темний glassmorphism)
24.5 — Dual-Agent Flow (DONE)
/c→ Consultant (sonnet, read-only),/d→ Developer (opus, повний доступ)- Без префікса → маршрутизація до активної ролі
- Специфікації авто-витягуються з патерну
### SPEC:у виводі консультанта - Воркфлоу
/approve <id>/ reject через CRM дашборд - 7 нових CRM endpoints: specs CRUD, active-role GET/POST, consultant SSE, message POST
- Фронтенд: 4 вкладки лог-панелі (Logs / Terminal / Consultant / Specs)
- Конфіг:
config/project_roles.json - Тема Slate & Silver на всіх UI-компонентах
Phase 25: Tech Debt Resolution + Local Gateway Foundation (COMPLETE)
Технічний борг:
docs/backlog/technical-debt.md(6/7 вирішено) Bridge: директоріяbridge/
25.0 — Tech Debt Sweep (DONE)
- DEBT-4: Опитування термінала 200мс→500мс (api-server.ts) — зменшення CPU на 60%
- DEBT-1: Розбиття моноліту
telegram.ts(881 рядок) на 4 модулі:tg-api.ts— обгортка Telegram API (~120 рядків)child-state.ts— читачі стану child-бота (~60 рядків)telegram-commands.ts— хендлери команд/колбеків + маршрутизатор повідомлень (~440 рядків)telegram.ts— тонкий polling loop + ре-експорти (~50 рядків)
- DEBT-5: Відкладено до Phase 26+ (UIScene.js, XL за обсягом, P3)
bot.tsбез змін — зворотна сумісність через ре-експорти
25.1 — Bridge CLI Foundation (DONE)
- Директорія
bridge/з CLIbin/citadel-bridge.ts(commander.js) - 5 команд:
connect,disconnect,pull,push,status src/auth.ts— валідація JWT-токена проти CRMsrc/config.ts— персистентність~/.citadel/bridge.jsonsrc/inject.ts— маркери<!-- CITADEL:START/END -->у CLAUDE.mdsrc/sync.ts— pull/push skills-bundle + learningssrc/heartbeat.ts— репортер активності сесіїpackage.json+tsconfig.json
25.2 — VPS API Extensions (DONE)
- 4 нові endpoints у
shared/crm-routes.ts:GET /api/crm/projects/:name/skills-bundle— JSON-бандл навичок + evalsGET /api/crm/projects/:name/learnings— розпарсений масив learningsPOST /api/crm/projects/:name/learnings— додавання нових learnings із bridgePOST /api/crm/projects/:name/heartbeat— збереження heartbeat від bridge
25.3 — Security Hardening (DONE)
- Токени ботів мігровано з
.envу зашифрований vault (getSecret()з env fallback)master-bot/bot.ts—getSecret("MASTER_BOT_TOKEN")післяinitVault()child-bot/bot.ts— доданоinitVault()+getSecret("CITADEL_BOT_TOKEN")scripts/nightly-improve.ts— доданоinitVault()+getSecret("MASTER_BOT_TOKEN")
- CORS закрито: wildcard
"*"→ whitelistCRM_ALLOWED_ORIGINS(налаштовується через env) - Загальний WebSocket endpoint
/wsтепер вимагає JWT-токен (query-параметр?token=)WebSocketManager.jsавто-вставляє токен зAuthManager
- Скрипт міграції:
scripts/migrate-tokens-to-vault.ts(одноразовий, читає.env→ зберігає у vault) .env.exampleоновлено з документацієюCRM_ALLOWED_ORIGINSтаSECRET_ENCRYPTION_KEY- Підтримка завантаження PDF для воркера Knowledge Archivist (фронтенд + бекенд)
Phase 23: The Local Gateway — Hybrid Workspace (SUPERSEDED фазами 25/38)
⚠️ SUPERSEDED — Основні результати поглинуто Phase 25 (Bridge CLI + API Foundation) та Phase 38 (скомпільований бінарник ARC CLI). Документацію Phase 23.2 розбито на 4 OS-специфічні гайди (2026-05-14). Решта підпунктів (23.2 локальні evals, 23.3 інтеграція з CRM) не в активному roadmap. Чернетка архітектури:
docs/planning/local-gateway.md(v3 — розділення Body/Brain) Кодова назва: "Activate Local Power"
Розробник підключає свій локальний IDE до Arc OS VPS. Код живе локально; інтелект доставляється через Bridge CLI + конфіг-директорію .citadel/.
23.1 — Bridge CLI + API Foundation (DONE → Phase 25)
- Перенесено у Phase 25.1 + 25.2 (завершено)
23.2 — Local Intelligence (PLANNED)
- Вендоринг
shared/evals.ts,shared/learnings.ts,shared/context-router.tsу bridge/src/ citadel-bridge eval— запуск evals локально, без мережіcitadel-bridge learn— додавання правила learning вручну- Інтервал авто-pull (налаштовується, за замовчуванням 60 хв)
- Розбиття документації (2026-05-14):
docs/public/guides/local-bridge.md(413 LOC, всі ОС укупі) декомпозовано на лендинг + 3 підсторінки за ОС (local-bridge-{macos,linux,windows}.md) + UK-дзеркало. Користувачі тепер потрапляють на платформо-специфічні інструкції прямо зі сторінки Bridge Setup або сайдбару Docs.
23.3 — CRM Integration (PLANNED)
- Поле
local_sync_statusу відповіді API проєкту - Індикатори активності розробника у геймифікованому офісі (IDE-бейдж, таймер сесії)
- Генерація + відкликання токенів у CRM дашборді
23.4 — Distribution & Polish (PLANNED)
- Bun compile в один бінарник
- Публікація npm-пакета (
@citadel/bridge) citadel-bridge doctor— команда діагностики
Phase 26: Dynamic Workers (COMPLETE)
Архітектура:
config/workers_registry.json+docs/architecture/dual-agent-flow.mdТема: заміна хардкоду бінарної пари Consultant/Developer на розширюваний реєстр воркерів.
26.0 — Stage 1: Worker Registry Foundation (DONE)
config/workers_registry.json— декларативні визначення воркерів (id, label, icon, type, model, tools, prompt_style, output_format, log_category, builtin)- Зареєстровано 3 воркери: Consultant (chat, sonnet), Developer (terminal, opus), UI/UX Designer (chat, sonnet)
child-bot/bot.ts— 175-рядковийif/else(consultant vs developer) замінено єдиним диспетчеромcallWorker()- Флоу
getWorkerConfig(workerId)→callWorker(workerId, text, options) - Відстеження тредів воркерів через Map
workerThreads(історія розмов на воркера) - Зворотна сумісність:
consultantThreadсинхронізується разом ізworkerThreads
- Флоу
shared/crm-routes.ts— 3 зміни:GET /api/crm/projects/:name/workers— повертає масив реєстру воркерівhandleSetActiveRole()— динамічна валідація проти ID воркерів реєструhandlePostMessage()— приймає та зберігає полеworker_idу JSONL
shared/logger.ts—log.worker(category, message, meta)для довільних категорій логів- Фронтенд
Workspace.jsx:useSSEStream(projectName, worker)— єдиний SSE-хук для типів chat і terminalWorkerPanel→ диспетчеризація уChatPanelViewабоTerminalPanelViewзаworker.type- Панель
[WORKERS]з пігулками воркерів (активний=accent, неактивний=сірий) - Весь SSE переведено з
/api/sse/consultant/на загальний/api/sse/logs/?category=
26.1 — Stage 2: Dynamic Grid Activation (DONE)
- Пігулки воркерів клікабельні —
toggleWorker(id)динамічно додає/прибирає панелі - Стабільність React:
key={worker.id}гарантує, що наявні панелі зберігають SSE-з'єднання при монтуванні/демонтуванні сусідів - Персистентність розкладки Workspace: ключ
localStoragecitadel-workspace-active-${project.name}- Читається при монтуванні та зміні проєкту, пишеться при кожному перемиканні
- Fallback:
['consultant', 'developer'], якщо збереженого стану немає
- Панель UI/UX Designer повністю функціональна: відмітити пігулку → з'являється 3-тя чат-панель, оновити сторінку → зберігається
Phase 27: Knowledge Base & Wiki (COMPLETE)
CRM дашборд отримує read-only переглядач wiki для виводу Knowledge Archivist.
27.0 — Wiki Viewer (DONE)
- 2 нові CRM API endpoints:
GET /api/crm/projects/:name/wiki/tree— рекурсивний список.mdфайлів зknowledge-base/wiki/GET /api/crm/projects/:name/wiki/file?path=— читання одного wiki-файлу із захистом від path traversal
- Фронтенд
pages/Wiki.jsx— двопанельна розкладка:- Сайдбар (240px): дерево файлів,
index.mdзакріплено першим, підсвічування активного файлу - Область контенту:
ReactMarkdown+remarkGfmзі стилями.chat-markdown - Внутрішні
.mdлінки навігують усередині переглядача, зовнішні відкриваються в новій вкладці - Empty state із підказкою використати Knowledge Archivist
- Сайдбар (240px): дерево файлів,
- Навігація: пункт
Wikiдодано до сайдбаруPROJECT_NAV(між Folders та Issues)
Phase 28: Auto-Ingest Watcher (COMPLETE)
Фоновий file watcher автоматично запускає Knowledge Archivist, коли нові файли з'являються в
raw/.
28.0 — Auto-Ingest Watcher (DONE)
- Новий модуль
child-bot/ingest-watcher.ts:fs.watch()наknowledge-base/raw/із debounce 3с на файл- Дедуплікація через персистентний
ingest_processed.jsonу директорії state - Вставляє повідомлення в CRM inbox (
worker_id: "archivist") — без рефакторингу callWorker - Graceful-очищення при зупинці бота
- Інтеграція в
bot.ts: читаєknowledge-base/config.json→ запускає watcher, якщоauto_ingest: true - Флоу:
raw/ новий файл → fs.watch → debounce → crm_inbox.jsonl → processCrmInbox() → /w:archivist → handleMessage() → callWorker("archivist") - Крайні випадки: бот зайнятий (inbox ставить у чергу), рестарт (стан зберігається), конкурентні файли (окремі таймери)
Phase 29: i18n — EN/UK Internationalization (COMPLETE)
Повна інтернаціоналізація CRM фронтенду з @lingui/react v5.
29.0 — i18n Infrastructure + Full Translation (DONE)
- Бібліотека: @lingui/react v5 + @lingui/core + @lingui/vite-plugin + babel macro
- Конфіг:
lingui.config.js— locales: [en, uk], format: po, compileNamespace: ts - Налаштування i18n:
src/crm/i18n/i18n.js— detectLocale (localStorage → navigator.language → 'en'), activateLocale, getDateLocale - LangSwitcher:
src/crm/i18n/LangSwitcher.jsx— перемикач EN/UA з emoji-прапорами у TopHeader - I18nProvider: обгортає
<App />уmain.jsx - 186 перекладених рядків у 25 компонентах:
- Shell: TopHeader, Sidebar, ProjectNav, ThemeToggle, UserDropdown, LoginOverlay
- Сторінки: Analytics, Docs, Wiki, ProjectSkills, Folders, Workspace, App
- FM: Toolbar, ContextMenu, CreateDialog, CloneDialog, LinkDialog, FilePreview, UploadDropZone, Breadcrumbs
- Патерни макросів:
<Trans>(JSX з @lingui/react/macro),t(рядки з @lingui/core/macro),msg(відкладені для масивів на рівні модуля) - Динамічна локаль: SpeechRecognition.lang, форматування дат через
getDateLocale() - Каталоги:
src/crm/locales/{en,uk}/messages.po(джерело), скомпільовані.ts(gitignored) - .dockerignore: запобігає перекриттю Docker npm ci застарілими node_modules
- Збірка:
lingui compile && vite buildу dev- та production-скриптах
Phase 30: Onboarding Wizard (COMPLETE)
30.0 — Self-Service Workspace Creation (DONE)
POST /api/crm/onboarding/setupприймає FormData (config JSON + файли)- Візард на 5 кроків: Welcome → Project → Team → API Keys → Integrations
- Пресети команд: 7 галузевих пресетів + 2 базові воркери (Manager, Keeper)
- Авто-провіжинінг: директорії, CLAUDE.md, MANIFEST, .env, workers_registry, wiki, child-bot, tmux
Phase 31: Web Authentication (COMPLETE)
31.0 — Session Auth + Multi-Tenancy (DONE)
/admin_login→ 6-значний код (TTL 5 хв) → JWT-токен → localStorage- Гард власності
canAccessProject()на всіх CRM-маршрутах - Фронтенд-компоненти LoginOverlay + AuthManager
31.5 — ARC CLI + Knowledge MCP (DONE)
- CLI-команди
arc login/logout/projects/start - 4 MCP-інструменти:
fetch_skill,report_mission,search_knowledge,get_learnings - 4 API endpoints:
/api/cli/init,/api/mcp/skills,/api/mcp/report,/api/mcp/learnings - Ін'єкція CLAUDE.md із cloud-контекстом + авто-конфіг .mcp.json
- Завантаження бінарника для 3 платформ
Phase 32: Knowledge Dashboard (COMPLETE)
32.0 — Reports, Skills, Wiki, NotebookLM (DONE)
- Reports.jsx: стрічка-таймлайн, групування за датою, кольорові теги джерел
- ProjectSkills.jsx: split-pane CRUD для файлів навичок
- Wiki.jsx: inline редагування/збереження/створення з рендерингом markdown
- NotebookLM.jsx: брендований лендинг + картки use-case
- Бекенд:
handleWikiSave,handleSaveSkill,handleDeleteSkill
32.1 — UI Hotfixes + Create Project Button (DONE)
- i18n для 11 нових рядків, прибрано дубльований пункт навігації "Docs"
- Кнопка "+ Create Project" у ProjectNav
Phase 33: Multi-Tenant Project Creation (COMPLETE)
33.0 — Account-Level Keys + Lightweight Modal (DONE)
handleOnboardingSetupвідрефакторено на 10 перевикористовуваних хелперів- Налаштування акаунта:
/opt/repos/.accounts/{chatId}/settings.json(0o600) - 3 нові endpoints:
GET/PUT /api/crm/account/settings,POST /api/crm/projects/create CreateProjectModal.jsx: модал на 3 поля (назва, ніша, пресет) для досвідчених користувачівAccountSettingsDialog.jsxчерез UserDropdown Profile- Директорії з user-неймспейсом:
/opt/repos/{chatId}_{projectName}/ - Авто-міграція з legacy
master-{chatId}/.env - Задача: #15
Phase 34: Autonomous Project Manager (COMPLETE)
34.1 — Local Issue Tracking (DONE)
- Сховище:
{cwd}/issues/issues.jsonна проєкт (авто-інкремент, P0-P3, мітки) - API:
POST/GET /api/mcp/issues/:project,PUT /api/mcp/issues/:project/:id - MCP-інструменти:
create_issue(title, body, priority, labels),list_issues(status?) - E2E перевірено на VPS
34.2 — Wiki Sync Tool (DONE)
- MCP-інструмент:
update_wiki(filename, content)— створення/оновлення wiki-сторінок markdown - Бекенд:
PUT /api/mcp/wiki/:project— санітизоване ім'я файлу, додавання у wiki-лог - knowledge-mcp.ts: всього 8 інструментів
34.3 — Roadmap Engine (DONE)
- MCP-інструмент:
sync_roadmap(phase, status, notes)— оновлення ROADMAP.md на місці - Бекенд:
GET /api/mcp/roadmap/:project— витяг фаз + наступна ціль - Бекенд:
PUT /api/mcp/roadmap/:project— заміна статусу за regex + додавання нотаток
34.7 — Init Injection (DONE)
handleCliInitвставляє список відкритих задач (top 10) у CLAUDE.md- Вставляється наступна ціль roadmap (перша фаза IN PROGRESS або PLANNED)
- Довідку MCP-інструментів оновлено всіма 8 інструментами
- Нуль додаткових API-викликів — перевикористовує loadIssues + читання ROADMAP.md з того ж CWD
Phase 35: Live Terminal Sync (COMPLETE)
35.1 — Backend Log Ingest (DONE)
POST /api/crm/projects/:name/terminal/log— приймає буферизовані JSONL-рядки від arc-cli- Дописує у
/var/log/citadel/{name}/terminal-DATE.log - Наявна SSE-інфраструктура (
handleSseLogsз?category=terminal) підхоплює автоматично
35.2 — arc-cli Stdout Interceptor (DONE)
Bun.spawn(["claude"], { stdout: "pipe", stderr: "pipe" })замінює успадкований stdiopipeAndBuffer()читає стрім, пише в локальний термінал ТА буферизує для APIstripAnsi()чистить escape-послідовності для чистого транспортуflushLogs()POST-ить буферизовані рядки кожні 2с на endpoint/terminal/log- Фінальний flush при виході процесу
35.3 — Frontend Live Terminal (DONE)
TerminalPanelViewтепер має перемикач вкладок Bot / Live- Вкладка Live підписується на SSE
?category=terminalчерезuseSSEStream - Зелена пульсуюча крапка, коли live-логи стрімляться
- Авто-перемикання на вкладку Live, коли стартує сесія arc-cli і логи бота порожні
- Плейсхолдер "Waiting for live terminal stream..." з підказкою про ARC CLI
Phase 36: Cloud Project Manager (COMPLETE)
36.1 — Backend SSE Chat Endpoint (DONE)
POST /api/crm/projects/:name/chat— SSE-стрімінговий проксі до Anthropic Messages API- Використовує Anthropic API-ключ користувача з Account Settings (Phase 33)
- Визначає інструмент
ask_notebooklm— запити до бази знань проєкту (wiki, задачі, roadmap, learnings, навички) - Серверний tool loop: до 3 нестрімінгових раундів для tool-викликів, потім стрімить фінальний текст
- Кастомні SSE-події:
text_delta,tool_status,message_complete,error
36.2 — Frontend Cloud PM Chat (DONE)
- Компонент
CloudPmPanelView— повний чат-інтерфейс із парсингом SSE-стріму - Bubble-повідомлення (користувач праворуч, асистент ліворуч) із рендерингом Markdown
- Індикатор статусу інструмента ("Querying: ...") під час серверного виконання інструментів
- Авто-скрол, Enter для надсилання, shift+Enter для нового рядка
- Доступний як вкладка воркера "Cloud PM" у Workspace
36.3 — NotebookLM Bridge (DONE)
- Python FastAPI сервіс у
services/notebooklm-bridge/(порт 19213, тільки localhost) - Асинхронний клієнт
notebooklm-pyдля семантичного пошуку Google executeAskNotebooklm→ асинхронний виклик мосту з таймаутом 15с, fallback до локального пошуку за ключовими словами- SyncWorker:
asyncio.Queue(200), затримка 2с, 3 ретраї з експоненційним backoff - Fire-and-forget синхронізація в
handleUpdateIssue(відкриття/закриття задачі) таhandleMcpWikiUpdate - Авто-ініціалізація ноутбука при створенні проєкту (
handleCreateProject+handleOnboardingSetup) - Авторизація: Google cookies у
/root/.notebooklm/profiles/default/storage_state.json - systemd:
citadel-notebooklm-bridge.service(авто-рестарт, тільки localhost) seed_knowledge.py <project> <cwd>для масового імпорту наявних знань
36.6 — Neural Skill Generator Wizard (DONE)
POST /api/crm/projects/:name/skills/generate— запит до NotebookLM bridge зі структурованим промптом, повертає Markdown-навичку- Payload:
{ notebookId, goal }— bridge/queryз таймаутом 30с, системний промпт Senior AI Architect - Відповідь містить згенерований Markdown + посилання на джерела з ноутбука
- Фронтенд: ProjectSkills.jsx отримує кнопку з іконкою мозку (видима, коли підключені ноутбуки)
- Модальний візард: дропдаун ноутбуків + textarea цілі витягу + спінер завантаження
- При успіху: модал закривається, згенерований Markdown потрапляє в редактор для перегляду + збереження
- Стани помилок: міст недоступний (503), невалідна ціль (<5 символів), помилка мосту (502)
36.7 — Neural Memory Sidebar (DONE)
GET /api/crm/projects/:name/notebooks— повертає підключені ноутбуки NotebookLM на проєкт- Читає
notebook_mapping.jsonдля мапінгу проєкт→ID ноутбука - Перевірка bridge
/health(таймаут 3с) для статусу синхронізації + кількості джерел - Фронтенд:
App.jsxотримує ноутбуки при зміні проєкту, прокидає черезCrmMainLayout→Sidebar - Секція "Neural Memory" у сайдбарі: закріплена внизу, зелена/червона крапка статусу, зовнішній лінк на NotebookLM
- Підзаголовок: "Synced · N sources" або "Offline", коли міст недоступний
- Авто-приховується, коли проєкт не має підключеного ноутбука
Phase 37: SSO & Social Auth (COMPLETE)
OAuth-інтеграція для входу через Google та GitHub.
37.0 — OAuth Google + GitHub (DONE)
- Google + GitHub OAuth у
shared/auth.ts(OAuthConfig, OAuthProfile, findOrCreateOAuthUser, state CSRF) - 5 нових маршрутів:
/api/auth/google,/api/auth/callback/google,/api/auth/github,/api/auth/callback/github,/api/auth/providers - Фронтенд: App.jsx витягує
?token=з URL після callback-редиректу, запитує/api/auth/providers - LoginOverlay перероблено: кнопки OAuth основні (зверху), форма email згорнута за "Continue with email"
- Авто-створення налаштувань акаунта для нових OAuth-користувачів
- Env vars:
GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET,GITHUB_CLIENT_ID,GITHUB_CLIENT_SECRET - Callback URLs:
https://arc-os.co/api/auth/callback/{google,github}
Phase 38: CLI-First Architecture (COMPLETE)
Заміна MCP-інструментів на CLI-підкоманди. Скорочення токенів на 85%.
38.0 — MCP → CLI Migration (DONE)
- 8 MCP-інструментів → 8 CLI-підкоманд (
arc skill/report/kb/learnings/issue/issues/wiki/roadmap) clients/lib/api.ts— 8 функцій-обгорток API- CLAUDE.md від
handleCliInitтепер посилається на### Cloud Commands (use via Bash tool)замість MCP-інструментів knowledge-mcp.tsdeprecated з банером (файл збережено для зворотної сумісності)- Ін'єкцію
.mcp.jsonприбрано —arc startтепер чистить застарілий записarc-knowledge build-arc.shзбирає тільки бінарникarc(без MCP)package.jsonv2.0.0, видалено@modelcontextprotocol/sdk
38.1 — SKILL.md Standard (DONE)
- Промпт Skill Wizard генерує формат SKILL.md з YAML frontmatter
handleSaveSkillподвійний шлях: SKILL.md frontmatter →.claude/skills/<name>/SKILL.md, інакше →skills/<name>.mdlistSkillNames+handleMcpGetSkillсканують обидві директорії
38.2 — Artifact Bridge (DONE)
- Python bridge: endpoint
POST /artifacts/downloadдля артефактів NotebookLM - Промпт Cloud PM оновлено CLI-рекомендаціями + стратегією lazy-завантаження навичок
- Вплив на токени: ~800 токенів MCP-схеми → ~120 токенів CLI-довідки = скорочення на 85%
38.8 — Admin Whitelist (DONE)
- Env var
SUPER_ADMIN_EMAILSдля призначення ролі admin - Видалено legacy UI з адмін-кодом
- Бейдж ролі admin у дропдауні користувача
Phase 39: Mobile Responsive Dashboard + Workspace Hub (COMPLETE)
Повна мобільна адаптація CRM Dashboard + життєвий цикл Workspace + Live Memory Cycle.
39.0 — Responsive Layout (DONE)
- Хук
useIsMobile()— на основіmatchMedia, breakpoint 768px CrmMainLayout.jsx— сайдбар як оверлей на мобільному,100dvh, окремі стани сайдбару mobile/desktopSidebar.jsx— режим оверлею (fixed + backdrop + slide-in анімація), винесено компонентSidebarContent- Кнопка Project Settings додана в сайдбар (видима при вибраному проєкті)
TopHeader.jsx— CSS-класи для responsive: центральна зона, Docs, LangSwitcher приховані на мобільномуProjectNav.jsx— компактні відступи, "Create Project" показує тільки "+" на мобільномуglobals.css—@keyframes sidebarSlideIn+@media (max-width: 767px)із 7 правиламиLoginOverlay.jsx—maxWidth: '92vw'для малих екранів
39.3 — Workspace Hub & Lifecycle Management (DONE)
- Сітка
ProjectCardна сторінці Analytics — візуальні картки проєктів зі статус-бейджами - Сторінка
ProjectSettings— ідентичність, візуал, підключення ноутбука, архівація - Заголовок Workspace у Sidebar — показує назву активного проєкту + шестерню налаштувань
- Конфіг на проєкт:
config/project-config.json— identity, visual, notebook_id, прапорець archived - Збагачений API
/api/crm/projects— повертає метадані конфігу проєкту (опис, іконка, колір) - Endpoints
handleGetProjectConfig/handleUpdateProjectConfig
39.4 — Live Memory Cycle (DONE)
handleMemoryRefresh— TypeScript-еквівалентseed_knowledge.py(MANIFEST, ROADMAP, wiki, задачі, learnings)handleMemoryFetchArtifact— проксі до NotebookLM bridge/artifacts/download- 2 нові API-маршрути:
POST /api/crm/projects/:name/memory/refresh,POST /api/crm/projects/:name/memory/fetch-artifact - ARC CLI: підкоманди
arc memory refresh+arc memory fetch-artifact [--type] - Інструмент Cloud PM:
memory_refresh— авто-спрацьовує, коли користувач каже "I updated docs" у PM-чаті CLOUD_PM_SYSTEM_PROMPTоновлено секцією Memory Refresh Detection- CLAUDE.md від
handleCliInitтепер посилається наarc memory refreshу Cloud Commands
Phase 40: Tabula Rasa — SQLite SSOT + Protocol System (COMPLETE)
Ядерне знесення legacy JSON → SQLite single source of truth. Трирівнева система протоколів. Централізований WorkspaceSelector. Персистентна історія чату.
40.0 — SQLite Migration (DONE)
shared/db.ts— синглтон bun:sqlite, WAL mode,userQueries/projectQueries/accountQueriesshared/migrations/001_initial_schema.ts— таблиці users/projects/account_settings (notebook_id у projects, без project_configs)scripts/migrate-to-db.ts— ядерне знесення legacy JSON →/opt/repos/_legacy_trash/{timestamp}/→ свіжа БДshared/totp.ts— RFC 6238 TOTP, нуль зовнішніх залежностейshared/auth.tsпереписано:loadUsers/saveUsersВИДАЛЕНО →userQueries.*, Admin Rebirth черезisSuperAdmin+ OAuthshared/crm-routes.ts:loadProjectConfig/saveProjectConfigчистий SQL, УСІ legacy dual-write прибраноbot_registry.jsonзалишається ТІЛЬКИ для інфраструктури (tmux/порти/health)- 4 нові маршрути:
/api/auth/2fa/{setup,verify,disable,login}
40.7 — Three-Level Protocol System (DONE)
shared/migrations/002_project_protocol.ts— колонкаproject_protocol- Експорт
SYSTEM_PROTOCOLуcli-routes.ts— універсальні правила агентів (SSOT, трекінг задач, синхронізація roadmap) generateProjectRules()уcrm-routes.ts— каркас PROJECT_RULES.md +docs/specs/+designs/- PM Laws у
CLOUD_PM_SYSTEM_PROMPT— 5 обов'язкових правил - Ін'єкція протоколу:
buildGsdPrompt(GSD-воркери) +callWorker(history-воркери) +handleCliInit(ARC CLI) - Поле
system_promptуworkers_registry.json— Developer Protocol + Designer Protocol - API:
GET/PUT /api/crm/projects/:name/protocol - Бюджет токенів: ~530–650 overhead
40.8 — Centralized WorkspaceSelector & Health Monitor (DONE)
- НОВЕ:
WorkspaceSelector.jsx— дропдаун у хедері замість таб-бару ProjectNav- Тригер:
[icon] DisplayName [▾]або "Project Hub", коли проєкт не вибрано - Крапки здоров'я:
deriveStatus()— зелена (ok), бурштинова (partial), червона (down); тип workspace завжди зелений - Поле пошуку з'являється при >5 проєктах
- Опція "Project Hub" для глобальної аналітики
- "+ Create Project" внизу
- Закриття по кліку зовні, анімація
dropdownFadeIn
- Тригер:
- TopHeader.jsx — центральну зону ("Connected" + дата) замінено на WorkspaceSelector; роздільник + дропдаун у лівій зоні
- CrmMainLayout.jsx — імпорт і рендер
ProjectNavприбрано; повернуто 40px вертикального простору - Sidebar.jsx — блок заголовка workspace (іконка + назва) замінено мінімальним uppercase-лейблом; прибрано невикористаний
accentColor - App.jsx —
handleSelectProjectзберігає уlocalStorage('crm-last-project'); fallback відновлення hash читає localStorage, коли hash відсутній
40.10 — Persistent Chat History / Immortal Chat (DONE)
shared/migrations/003_chat_messages.ts— таблицяchat_messages+ композитний індекс(project_name, worker_id, timestamp DESC)shared/db.ts— експортchatQueries: insert, getHistory (курсорна пагінація), getLatest (хронологічно), deleteByProject, count- Шлях запису A (повідомлення користувача):
handlePostMessageуcrm-routes.ts—chatQueries.insert()після додавання в inbox (нефатальний try/catch) - Шлях запису B (відповіді бота):
child-bot/bot.ts— fire-and-forgetfetch()доPOST /api/internal/chat/saveпісляcallWorker() - Внутрішній API:
POST /api/internal/chat/saveуapi-server.ts— тільки localhost, без auth, динамічний імпортchatQueries - Endpoint читання:
GET /api/crm/projects/:name/chat/history?worker=X&limit=50&before=TS— курсорна пагінація, стеля 100 - Фронтенд (
Workspace.jsx):- Хелпер
fetchChatHistory()з auth-заголовком - Стан
historyMessages/historyLoaded/loadingMore/hasMore useEffectна[project.name, worker.id]для початкового завантаження 50 повідомлень- Дедуплікація за префіксом контенту:
role:first100charsу вікні 5с (history vs SSE) - Кнопка "Load earlier messages" зі збереженням скролу (
requestAnimationFrame) - Розумний авто-скрол: тільки коли користувач біля низу (
scrollHeight - scrollTop - clientHeight < 100) - Skeleton завантаження до підвантаження історії; empty state тільки після завантаження
- Хелпер
- i18n: "Load earlier messages" / "Loading history..." у EN + UK
.poфайлах
Phase 40.11: Evolutionary Skill System + Sage Worker + Data-Driven Approvals (COMPLETE)
Навички в БД. Автономне покращення через Sage (Haiku). Сліпі A/B-бенчмарки перед затвердженням CEO.
40.11 — Evolutionary Skill System (DONE)
shared/migrations/004_skill_system.ts— 4 таблиці:skills_global,skills_project_forks,skill_evolution_logs,skill_update_requests+ 3 індексиshared/db.ts—skillQueries(~150 рядків): CRUD global, fork upsert із merged view через LEFT JOIN, логи еволюції, запити на оновлення,getActiveSkillsForRoutingз COALESCE-перекриттями форківscripts/migrate-skills-to-db.ts— ядерна міграція:_registry.json+*.md+ SKILL.md frontmatter +*.evals.json→ БД, переміщує у_legacy_skills/- 15 нових хендлерів у
crm-routes.ts: глобальний CRUD (list/get/create/update/deprecate), форки проєкту (list/create/update/delete), лог еволюції, запити на оновлення (list/approve/reject) - Маршрути:
/api/crm/skills[/:id[/evolution]],/api/crm/skill-updates[/:id/{approve,reject}],/api/crm/projects/:name/skill-forks[/:skillId] - Адаптовано наявні хендлери:
handleGetSkills,handleSaveSkill,handleDeleteSkill,handleGetSkillsBundle,handleMcpGetSkill— усі спершу пробують БД із fallback на файли routeContextFromDb()уcontext-router.ts(JSON-рядкові triggers/keywords)loadEvalsFromDb()уevals.ts- Фронтенд:
SkillEvolution.jsx(1113 рядків, дві панелі: explorer 280px + деталі з 4 вкладками: Content/Evals/Evolution/PRs, керування форками, inline diff, фільтри категорій) - i18n: 17 нових рядків EN+UK
40.11c — Sage Worker (Autonomous Skill Improvement) (DONE)
shared/sage.ts(~220 рядків):runSageAnalysis()+callSageModel()+buildSagePrompt()+buildReason(), модель Haiku, метрики якості + learnings → рядки БДskill_update_requests- 2 нові CRM-маршрути:
POST /api/crm/sage/analyze(завантажує API-ключ користувача з БД),GET /api/crm/sage/status(кількість pending + час останнього аналізу) scripts/nightly-improve.tsпереписано: прибрано файлові пропозиції (improvement-proposals.json), тепер викликаєrunSageAnalysisна кожного child → рядки БД, Telegram-звіт лінкує на вкладку PRs у CRM- Фронтенд: PRsTab у
SkillEvolution.jsx— кнопка "Analyze Skills" (фіолетова, станsageAnalyzing), викликає sage/analyze, показує toast - i18n: 6 нових рядків EN+UK
40.11d — Data-Driven Approvals (Benchmarks) (DONE)
shared/migrations/005_skill_benchmarks.ts— таблицяskill_benchmarks: FKrequest_id,test_scenario,old_output,new_output,score_old,score_new,judgment_reason+ індексshared/db.ts—benchmarkQueries: insert, listByRequestId, listBySkillId, deleteByRequestIdshared/sage.tsрозширено:runBenchmark()(генерує 3 тест-сценарії через Haiku, проводить сліпий A/B-тест старого vs нового контенту навички, LLM-суддя з рандомізацією проти position bias, детерміністичний скоринг eval_rules 60%/LLM 40%, зберігає уskill_benchmarks, оновлює метадані PR вердиктом). Авто-бенчмарк після кожного створення Sage PR- 3 нові промпти:
SCENARIO_SYSTEM,JUDGE_SYSTEM,parseJudgment() - 2 нові CRM-маршрути:
POST /api/crm/sage/benchmark(приймає requestId або skillId),GET /api/crm/skill-updates/:id/benchmarks(зі зведенням) - Фронтенд:
BenchmarkBadge(бейдж PASSED/FAILED/TIE на заголовку PR із метаданих),BenchmarkReport(розгортається, lazy-завантаження на PR), режим Battle Mode (Old vs New поруч із зіркою переможця, бал/10, обґрунтування судді), кнопка "Run Benchmark" на вкладці Content (небесно-блакитна), кнопка-якір на кожен PR - i18n: 11 нових рядків EN+UK
Phase 40.12: Marketplace Discovery (COMPLETE)
Пошук, аналіз та встановлення community-навичок із claudemarketplaces.com прямо у Skill Evolution Center.
Бекенд — shared/sage.ts
- Експортовано
callModel()(був приватним) - 2 нові промпти:
SCOUT_ANALYZE_SYSTEM(аналіз сумісності 0–10, JSON-вивід),SCOUT_CLEAN_SYSTEM(зачистка marketplace-сміття, збереження функціонального контенту)
Бекенд — shared/crm-routes.ts (3 нові хендлери + 3 маршрути)
POST /api/crm/sage/scout— пошук на claudemarketplaces.com, мультистратегічний HTML-парсер (JSON-LD → RSC payload → regex-картки), кеш у пам'яті (TTL 5 хв)POST /api/crm/sage/scout/analyze— завантаження сторінки окремої навички, витяг SKILL.md з RSC payload, LLM-аналіз сумісності через Haiku (compatibility_score, recommendation, overlapping_skills, suggested_name, suggested_category)POST /api/crm/sage/scout/install— очищення контенту черезSCOUT_CLEAN_SYSTEM, вставка глобально (insertGlobal) або upsert форку проєкту (upsertFork), перевірка admin для глобального встановлення, запис у лог еволюції (marketplace_install)
Фронтенд — SkillEvolution.jsx
- 5-та вкладка "Discovery" у таб-барі
- Підкомпонент
DiscoveryTab: рядок пошуку (input + клавіша Enter), сітка результатів (auto-fill, minmax(280px, 1fr)), картки навичок (назва, опис, репозиторій, встановлення, зірки), панель аналізу по кліку на картку - Панель аналізу: шкала сумісності (0–10, зелений/жовтий/червоний), бейдж рекомендації (INSTALL/SKIP/CUSTOMIZE), резюме, список навичок що перекриваються, лінк "View Source", кнопки дій: "Add to Global Library" (admin, зелена), "Add to Project" (фіолетова)
- Визначення admin через
GET /api/auth/me→role === 'admin' - Кнопка-шорткат "Browse Marketplace" в empty state (коли навичку не вибрано)
- Хелпер
formatNumber()(1.2M / 3.5k / 42)
i18n
- 17 нових рядків EN+UK (Discovery, Search, Compatibility, Installing, Browse Marketplace тощо)
Phase 40.12.1: Smart Rank — Compatibility Sorting & Quick Scan Cache (COMPLETE)
Пакетний скоринг сумісності для marketplace-навичок. Сортування за релевантністю, сумісністю чи популярністю.
Бекенд — shared/sage.ts + shared/crm-routes.ts
shared/migrations/007_marketplace_cache.ts— таблицяmarketplace_analysis_cache(skill_url UNIQUE, compatibility_score, recommendation, scan_type, analyzed_at) + індекс score DESCshared/db.ts—marketplaceCacheQueries: upsert, getByUrl, getByUrls, cleanup- Промпт
QUICK_SCAN_SYSTEMуsage.ts— пакетний скоринг сумісності через Haiku POST /api/crm/sage/scout/quick-scan— пакетне сканування до 40 навичок за один виклик (~2с), upsert у кеш, пропуск уже закешованих (<24 год)- Результати пошуку збагачуються закешованими оцінками на
POST /api/crm/sage/scout
Фронтенд — SkillEvolution.jsx (DiscoveryTab)
- Дропдаун сортування: Relevance (за замовчуванням) / Compatibility / Popularity
- Кнопка "Smart Rank" — запускає quick-scan, авто-перемикає на сортування за сумісністю
- Бейджі оцінок на картках:
N/10із кольором (зелений ≥7, жовтий ≥4, червоний <4)
i18n
- 6 нових рядків EN+UK
Phase 40.13: Autonomous Knowledge Harvester (COMPLETE)
Проактивне виявлення навичок. Gap Detector спрацьовує при нульових збігах context-router. Нічне пакетне сканування. UI пропозицій у вкладці Discovery.
Бекенд — shared/harvester.ts (новий модуль)
shared/migrations/008_harvester.ts— додає колонкиis_suggestion,source_queryуmarketplace_analysis_cache+ перемикачauto_harvestуaccount_settingsdetectGap(message, projectName)— витяг ключових слів (стоп-слова EN+UK, top 5 за частотою), пошук у marketplace, quick-scan свіжих збігів, позначення як пропозицій- Тротлінг на проєкт (мінімум 5 хв між запусками)
- Fire-and-forget у
child-bot/bot.ts, коли context-router не знаходить збігів - Тихо пропускає, коли БД не ініціалізована (workspace-режим)
Нічне пакетне сканування — scripts/nightly-improve.ts
- Вимагає увімкненого
auto_harvest+ налаштованого API-ключа - Витягує ключові слова з описів усіх проєктів
- Завантажує marketplace, фільтрує за збігом ключових слів, пакетно сканує до 40
- Звітує результати CEO через Telegram
API (2 нові endpoints)
GET /api/crm/harvester/suggestions?minScore=5&limit=20— запропоновані навички (is_suggestion=1, сортування за оцінкою)DELETE /api/crm/harvester/suggestions— відхилення пропозиції (ставить is_suggestion=0)
Фронтенд
AccountSettingsDialog.jsx— перемикач "Auto-Discover Skills" (opt-in, синхронізується зauto_harvest)DiscoveryTab— секція "Recommended for You": картки пропозицій із бейджами оцінок + кнопка відхилення (X), контейнер із синьою рамкою над рядком пошуку
i18n
- Нові рядки EN+UK (Recommended, Dismiss, Auto-Discover тощо)
Phase 40.14: CRM Roadmap & Issues UI (COMPLETE)
Фронтенд-сторінки для Roadmap та Issues — раніше були лише плейсхолдерами в сайдбарі. Самовідновлюваний backend-скаффолдинг.
Бекенд
cli-routes.ts:handleMcpGetRoadmapтепер повертає сирийcontent(повний markdown) разом із розпарсенимphases[]cli-routes.ts:loadIssues()— самовідновлення: пошкоджений/відсутнійissues.jsonавто-перестворюється з валідними дефолтамиcli-routes.ts:saveIssues()— атомарні записи через tmp-файл +renameSync(запобігає пошкодженню від конкурентних правок агентів)crm-routes.ts:generateProjectRules()скаффолдитьdocs/ROADMAP.md+issues/issues.jsonдля нових проєктів (самовідновлювана валідація наявних пошкоджених файлів)
Фронтенд — Roadmap.jsx (~220 рядків)
- Два режими перегляду: Phases (компактний список карток із кольоровими статус-бейджами) та Full View (сирий markdown через ReactMarkdown, той самий стиль
chat-markdown, що й у Wiki.jsx) - Статус-бейджі: DONE (зелений), IN PROGRESS (синій), PLANNED (сірий), BLOCKED (червоний)
- Банер Next Target (синій акцент) підсвічує поточну фазу
- Empty state із підказкою про
docs/ROADMAP.md - Кнопка оновлення, гард наявності проєкту
Фронтенд — Issues.jsx (~310 рядків)
- Список задач із фільтром-перемикачем Open/Closed/All
- Бейджі пріоритетів: P0 (червоний + анімація pulse glow), P1 (помаранчевий), P2 (синій), P3 (сірий)
- Моноширинна типографіка: ID (
#001з нулями), пріоритети, мітки, таймстемпи — естетика "Engineer's Console" - Анімація slide-down при розгортанні задачі (CSS
crm-issue-slide) - Розгорнуте тіло: ReactMarkdown + якір Phase 43 (
issue-skill-recommendations-{id}) + кнопка Close/Reopen - Модал створення задачі (картка 460px, поля title/body/priority/labels)
- CTA в empty state: описовий текст + помітна кнопка "Create Issue"
App.jsx
- Lazy-імпорти + роутинг для сторінок
roadmapтаissues
i18n
- 17 нових рядків EN+UK (Roadmap, Phases, Full View, Next Target, Issues, Create Issue, Priority, Labels тощо)
Phase 40.15: Lucide React Icons (COMPLETE)
Заміна всіх Unicode/emoji іконок на SVG-іконки Lucide React для консистентної, theme-aware, масштабованої іконографії.
Зміни
- Встановлено
lucide-react(tree-shakeable, MIT, 1500+ SVG-іконок) - Замінено ~100 emoji та Unicode-символів (
◣,☰,🧠,⚙,📋,▼,✓,⌛,➤тощо) у 22 файлах CRM - Компоненти (10): Sidebar, TopHeader, ThemeToggle, WorkspaceSelector, UserDropdown, ProjectNav, fm/Toolbar, fm/ContextMenu, BridgeSetup, OnboardingWizard
- Сторінки (12): Workspace (~43 іконки), Roadmap, SkillEvolution, EvalsTab, PRsTab, Reports, Wiki, NotebookLM, Folders, ProjectSkills, Docs, Issues
Збережено (свідомо)
- Крапки активності в Issues.jsx (
●◆★▸) — кольорові індикатори статусу - IconPicker.jsx — emoji-пікер для проєктів
- LoginOverlay.jsx — брендові SVG-логотипи Google/GitHub
- Emoji платформ у BridgeSetup/OnboardingWizard (
🐧🍎🍏) - Emoji пресетів команд в OnboardingWizard (
💻📢🎬🎨🏢🚀🛒) - Emoji-лейбли воркерів (consultant
💬, developer💻)
Конвенція розмірів іконок
- 16px — пункти сайдбару/навігації
- 18px — кнопки дій
- 14px — inline-іконки
Phase 40.16: Per-Worker Telegram Bot Token UI (COMPLETE)
Воркери можуть підключати/відключати індивідуальні токени Telegram-ботів із форми Worker Studio.
Зміни
- WorkerForm: додано стан
tgToken,tgConfigured,tgShowToken,tgSaving - useEffect: запитує
GET /workers/:id/telegram-tokenпри редагуванні воркера - handleTgSave/handleTgDisconnect: POST/DELETE до endpoints токенів на воркера
- JSX: секція Telegram Bot (індикатор налаштованості + Disconnect, або маскований input + Connect)
- i18n: UK-переклад нового рядка
Бекенд
- Усі 3 endpoints уже існували:
handleSetWorkerTelegramToken,handleGetWorkerTelegramToken,handleDeleteWorkerTelegramToken
Phase 40.17: Knowledge Graph + Open in Obsidian (COMPLETE)
Canvas-візуалізація графа знань (нуль залежностей) + інтеграція з протоколом Obsidian.
Задача #006: Open in Obsidian
- Кнопка в секції Neural Memory сайдбару
- Використовує протокол
obsidian://open?vault=knowledge-base&path=wiki - Іконка Vault + індикатор ExternalLink, тултіп для десктопа
Задача #007: Knowledge Graph
Бекенд:
- Endpoint
GET /api/crm/projects/:name/knowledge-graph - Сканує файли
knowledge-base/wiki/**/*.md - Витягує
[[wikilinks]]та markdown-лінки[text](file.md) - Повертає
{ nodes: [{id, label, type, size}], edges: [{source, target}] } - Додає неявні "missing" вузли для висячих лінків
Фронтенд:
KnowledgeGraph.jsx— Canvas force-directed граф (Fruchterman-Reingold)- Нуль зовнішніх залежностей (без vis.js чи react-force-graph)
- Pan/zoom (колесо миші + перетягування), пошук/фільтр вузлів
- Клік на вузол: панель деталей зі зв'язками, клік на зв'язок для навігації
- Мобільний: хендлери touch start/move/end
- Тулбар: zoom in/out, reset, лічильник вузлів/зв'язків
- 9.44 KB gzipped (~3.76 KB) — lazy-завантаження
Сайдбар:
- Пункт навігації "Graph" з іконкою
Networkу PROJECT_NAV
i18n
- 10 нових UK-рядків (Knowledge Graph, connections, nodes, links, Filter nodes тощо)
Phase 40.18: Deploy Safety — DB SSOT for Ownership (COMPLETE)
Постійний фікс зникнення проєктів після деплою (git pull перезаписує owner_id у bot_registry.json).
Проблема
bot_registry.json відстежується в git, але owner_id додається в рантаймі під час створення проєкту. Кожен git pull перезаписує файл, втрачаючи дані власності. handleGetProjects фільтрує за owner_id, тож усі проєкти стають невидимими.
Рішення — 3 рівні захисту
| Рівень | Що | Коли |
|---|---|---|
| DB SSOT | handleGetProjects + isProjectOwner спершу перевіряють projectQueries.findByName(), реєстр як fallback |
Кожен API-виклик |
| Deploy backup | vps-sync.sh бекапить реєстр перед git pull, відновлює поля owner_id після |
Кожен деплой |
| Startup enrichment | Master bot заповнює відсутні owner_id із БД при завантаженні |
Кожен рестарт |
Змінені файли
shared/crm-routes.ts—isProjectOwner()таhandleGetProjects()тепер використовують БД для власностіscripts/vps-sync.sh— backup/restore реєстру навколо git pullmaster-bot/bot.ts— цикл збагачення післяinitDb()- Фікс БД: перейменовано
arc-v2→citadel-v2у таблиці projects
Phase 40.19: Auth Completion — Full Login Form (DONE)
Завершення всіх методів автентифікації в LoginOverlay. Google OAuth, скидання пароля, верифікація email.
40.19a — Google OAuth Credentials (DONE) — задача #6
- Створено Google Cloud проєкт + OAuth consent screen
GOOGLE_CLIENT_ID+GOOGLE_CLIENT_SECRETналаштовано на VPS (vault)- End-to-end флоу перевірено на
https://arc-os.co
40.19b — Telegram OTP Login (REMOVED) — задача #7
- Фічу deprecated на користь email/пароль + OAuth.
- Увесь пов'язаний код видалено:
generateAuthCode/verifyAuthCode,/api/crm/auth/verify, команда бота/admin_login, UI в LoginOverlay, i18n-рядки.
40.19c — Password Reset Flow (DONE) — задача #8
POST /api/auth/forgot-password— генерація reset-токена (TTL 30 хв)POST /api/auth/reset-password— валідація токена + встановлення нового пароля- Інтеграція Resend: реальна доставка email через
shared/email.ts - Фронтенд: лінк "Forgot password?" → форма скидання в LoginOverlay
40.19d — Email Verification (DONE) — задача #9
- Сховище
verificationTokens(TTL 24 год) уshared/auth.ts POST /api/auth/verify-email— споживання верифікаційного токенаPOST /api/auth/resend-verification— повторна генерація для неверифікованих користувачів- Реєстрація тепер надсилає верифікаційний email + повертає
{requires_verification, email}(без JWT) loginUserблокує неверифікованих користувачів — повертає{requires_verification, email}з 403- OAuth-користувачі авто-верифіковані (Google/GitHub уже підтверджують email); прив'язка OAuth до наявного email-користувача підвищує
email_verified=true - Фронтенд: блокуючий екран
verification_required(займає весь оверлей) із кнопкою "Resend verification email" - URL
?verify_token=<token>авто-споживається при завантаженні сторінки → екран успіху → "Continue to sign in"
40.19e — Email Delivery Infrastructure (DONE)
shared/email.ts— абстракція над Resend + console fallback- Env
EMAIL_PROVIDER(resend | console, за замовчуванням: console) RESEND_API_KEYзберігається у vault (AES-256-GCM)EMAIL_FROM(за замовчуваннямArc OS <[email protected]>),APP_URLналаштовується- HTML + текстові шаблони для скидання пароля + верифікації email
Phase 41: UI Refresh — Vercel Redesign Adaptation (COMPLETE)
Поетапна міграція концепцій Vercel-згенерованого Next.js редизайну (
arc_web_design_vercel/) у наявний стек React+Lingui+Vite. Кожен етап — самостійний shipable-інкремент.
41.1 — Design Tokens (задача #10) — DONE
- Колірний простір OKLCH у
frontend/src/crm/styles/globals.css - Primary глибокий teal, Accent теплий бурштин, фон теплий ivory
- Токени chart-1..5, шрифти Inter + JetBrains Mono, утиліта
.bg-grid - Світлу + темну теми перекалібровано обидві
41.2 — Worker Selector Pills (задача #11) — DONE
- Горизонтальні пігулки з іконками-аватарами tone-ring (5 chart-тонів через хеш id)
- Активна = темна foreground-пігулка, неактивна = з рамкою та hover-ефектом
41.3 — Chat Message Bubbles + Action Bar (задача #12) — DONE
- Бульбашки користувача інвертовано в темний foreground (патерн Vercel)
- Бульбашки воркерів: tone-ring аватар + рамка + shadow-card + радіус 16
- Action bar на повідомлення збережено (Save to note, Copy, 👍, 👎)
41.4 — Chat Composer Refresh (задача #13) — DONE
- Радіус 24→16, focus ring через box-shadow halo
- Чіп лічильника інструментів (показує кількість активних), чіп швидкої вставки /btw
- Action dock під композером без змін (уже відповідав патерну Vercel)
41.5 — Sidebar Badge Counters + Recent Activity (задача #14) — DONE
- Бейдж кількості задач на пункті навігації (моноширинний шрифт, accent-відтінок коли активний)
- Секція Live Activity: top 3 події з агрегованих логів задач, опитування 30с
- Анімація pulse-dot у Neural Memory у стані synced
41.6 — TopBar Search with ⌘K (задача #15) — DONE
- SearchButton з platform-aware kbd ⌘/Ctrl K
- Глобальний слухач Cmd/Ctrl+K фокусує кнопку
- Підключення command palette відкладено як follow-up
41.7 — Context Rail (задача #16) — DONE
- Нова права панель 320px у CrmMainLayout
- Секції: Current Goal (roadmap), метрики 2×2, список Active Skills, Pinned із треду, футер git+sync
- Видима тільки при viewport ≥ 1280px ТА activePage = workspace
41.8 — Pinned Notes Feature (задача #17) — DONE
- Міграція 009: таблиця
pinned_notes, pinnedNoteQueries у shared/db.ts - Endpoints
GET/POST/DELETE /api/crm/projects/:name/pins[/:id] - Кнопка "Save to note" у чаті → POST /pins, генерує подію
crm-pin-created - ContextRail рендерить піни з кнопкою видалення + відносним часом
Phase 42: Security Hardening — Sentinel Audit 2026-04-23 (COMPLETE)
Довідка:
docs/security/audit-2026-04-23.md(3 критичні + 2 серйозні + дрібні знахідки). Розблоковує multi-user продакшн. Вердикт після патчів: GREEN.
42.1 — Multi-tenancy: SSE owner_id guard (SEC-1, задача #6) — DONE
routeSseRequestрозширено параметромchatId+ перевіркоюcanAccessProject- Захищає
/api/sse/logs/:name+/api/sse/consultant/:name
42.2 — Multi-tenancy: WS terminal guard + admin-only interactive (SEC-2, задача #7) — DONE
- Гейт
canAccessProjectна/ws/terminal/:name ?mode=interactiveвимагає CEO chat_id АБО DB user.role === "admin"- Закриває ескалацію до root-shell через WebSocket
42.3 — Multi-tenancy: CLI/MCP block guard (SEC-3, задача #8) — DONE
- Вхідний гейт
canAccessProjectна блоці/api/cli/*+/api/mcp/* - Skip-список для
/api/cli/device/*,/api/cli/download/*,/api/cli/chat-save - Закриває вектор prompt-injection через PUT
/api/mcp/wiki/:project+ 11 інших
42.4 — Bun.serve bind to 127.0.0.1 (SEC-4, задача #9) — DONE
hostname: "127.0.0.1"на Bun.serve- Перевірено через
ss -tlnp:127.0.0.1:19210(було*:19210) - Хостовий nginx проксіює через loopback — публічний шлях не зачеплено
42.5 — chat/save project_name validation (SEC-5, задача #10) — DONE
- Перевірка
isValidProjectNameна/api/internal/chat/save
42.6 — Minor hardening (SEC-6, задача #11) — DONE
timingSafeEqualуverifyToken(усуває timing side-channel)- Розширено deny-список Nginx:
state|scripts|config|data|knowledge-base|issues|skills|blueprints|mcp-server - Аудит
safePathзавершено: знайдено + виправлено path-traversal уhandleSaveSkill(body.name потрапляв несанітизованим у.claude/skills/<name>→ додано строгий regex + обгортку safePath) - Маркер TODO debt-7 видалено
42.7 — Sentinel re-audit remediation — DONE
- SEC-FN1 (P2): fail-closed вхідний гейт C3 — невалідне ім'я проєкту тепер відхиляється на вході в блок, а не тихо пропускається
- SEC-FN2 (P3): видалено мертве посилання
/api/cli/chat-saveзі skipGuard - SEC-V1 (P2):
/api/internal/bridge-event/:projectтепер валідує project_name (belt+suspenders поверх loopback bind + UFW) - SEC-V2 (P2): аудит env-витоку
handleCliInit— ЧИСТО, без змін коду - SEC-V3 (P3): регресійні тести path-traversal + loopback-bind + chat-save
додано до post-deploy smoke-тестів у
scripts/vps-sync.sh
42.8 — Hotfix SEC-REG1 (extractChatId browser EventSource) — DONE
- Регресія від Phase 42.1 (SEC-1):
extractChatIdчитав лише заголовокAuthorization, але браузернийEventSourceнадсилає токен через query?token=(відповідає логіціcrmAuthMiddleware) - Результат:
canAccessProjectотримувавchatId=null→ усі автентифіковані браузерні SSE-запити повертали 403 — зламаний live-стрімінг логів - Фікс: 2-кроковий витяг токена (header → query fallback) у
shared/crm-routes.ts:extractChatId - Додано smoke-тест
SEC-REG1 SSE ?token=доvps-sync.sh(за умови envCEO_TOKEN— опційно) - Перевірено на проді:
curl 'http://localhost:19210/api/sse/logs/arc-v2?token=<valid>'→HTTP/1.1 200 OK+: connected✅
42.9 — SSRF hotfix + relay hardening (SEC-NEW1..3) — DONE
- SEC-NEW1 (P0 Critical):
handleScoutAnalyzeзавантажував контрольовані користувачем URL без жодного allowlist → будь-який автентифікований користувач міг змусити VPS звертатися доhttp://127.0.0.1:19210/api/internal/*та інших loopback-сервісів, обходячи весь периметровий захист Phase 42.- Фікс: парсинг URL, вимога
https:, allowlist хостів (claudemarketplaces.com+ www) - Виявлено 3-м повторним аудитом Sentinel 2026-04-23
- Фікс: парсинг URL, вимога
- SEC-NEW2 (P1): аудит
ALLOWED_RELAY_TOOLSвиявивexecute_command+write_file— високий вплив у разі експозиції. Уже потрійно захищено (loopback bind, UFW, SSRF allowlist). Додано belt+suspenders: відхиляти запити/api/internal/*із заголовкамиX-Forwarded-For,X-Real-IPабоForwarded(ловить мисконфіг nginx, який міг би випадково відкрити внутрішні endpoints). - SEC-NEW3 (P2): регресійні тести SSRF + proxy-заголовків у
vps-sync.sh
Live-перевірка на проді:
| Атака | Очікувано | Фактично |
|---|---|---|
http://127.0.0.1:19210/... |
відхилити | 400 "Only https URLs allowed" ✅ |
http://claudemarketplaces.com/ |
відхилити схему | 400 ✅ |
/api/internal/bridges із X-Forwarded-For |
відхилити | 403 ✅ |
https://claudemarketplaces.com/ |
дозволити | 200 ✅ |
https://claudemarketplaces.com.evil.com/ |
відхилити | 403 "Domain not allowed" ✅ |
Вердикт 3-го повторного аудиту Sentinel: 🟢 GREEN. Усі 12 патчів перевірено на проді.
42.10 — Redirect-based SSRF close-out (SEC-NEW4, P3) — DONE
- 4-й повторний аудит Sentinel (2026-04-23) позначив теоретичний ланцюжок
open-redirect → SSRF: Bun
fetch()за замовчуванням слідує за 3xx, тож скомпрометований чи багованийclaudemarketplaces.comміг би повернути302→http://127.0.0.1:...й обійти allowlist (валідатор перевіряєbody.url, а не фінальний URL) - Фікс:
redirect: "manual"+ явне відхилення 3xx (502 "Redirects not allowed") - Закриває весь клас обходів SSRF через редиректи + DNS rebinding
42.11 — Sentinel 4th pass: Non-blocker hardening — DONE
- SEC-NEW5 (P2): переставлено spread тіла bridge-event —
type: "bridge_event"тепер іде ПІСЛЯ...body, тож контрольований атакувальником payload не може перекрити його й підробити внутрішні типи повідомлень (напр."tool_request"), які локальний bridge інакше виконав би як relay-tool виклик. - SEC-NEW6 (P2): in-memory rate limiter на
/api/auth/forgot-passwordта/api/auth/resend-verification. На IP+email 3/хв burst, на email 5/10 хв глобально. Тротльовані запити все одно повертають enumeration-safe тіло успіху (без витоку стану лімітера). - SEC-NEW7 (P3): padding часу відповіді на обох email-endpoints
(
authTimingPad— 220мс + 0–120мс джитеру) для non-happy path, звужує existence-timing side channel з ~200мс до шуму.
42.12 — Worker identity + model wiring — DONE
arc startбільше не хардкодить прапорець--model— Claude Code використовує локально налаштовану модель (напр. opus 4.7), а не застаріле значення з реєстру.- Воркери, запущені локально, успадковують конфіг моделі Claude Code користувача; вибір моделі VPS child-bot не зачеплено.
Phase 42 FINAL SIGN-OFF
| Метрика | Значення |
|---|---|
| Знайдено проблем безпеки за 5 проходів аудиту | 16 |
| Виправлено | 16 |
| Security-борг (блокер) | 0 |
| Вердикт | 🟢 GREEN — Multi-user ready |
Phase 43: UI/UX Audit Implementation (COMPLETE)
Довідка:
docs/design/ui-ux-audit-2026-04-23.md(Vanguard deep dive, прохід #2) Створено 21 задачу (#13–#33), усі закрито. Оцінка повторного аудиту: A- (95/100).
43.1 — Accessibility (WCAG 2.1 Level A) — DONE
- Focus visible (#13): глобальні стилі
*:focus-visible, прибраноoutline: 'none'із 15 компонентів - Контраст темного режиму (#14): text-tertiary піднято oklch 0.55→0.62, рамка 0.28→0.32
- Контраст метрик ContextRail (#19): лейбли підвищено до text-secondary, дефолтні значення до text (9.1:1)
- prefers-reduced-motion (#20): глобальний media query вимикає всі анімації
43.2 — Navigation & Layout Cleanup — DONE
- Чистка TopHeader (#15): прибрано мертві вкладки (Issues, Reports, Files, NotebookLMs), прибрано кнопку-заглушку Search. 14 елементів → 6.
- Візуальна ієрархія Sidebar (#24): система рівнів primary/secondary/tertiary з диференційованими вагами, розмірами, кольорами
- Empty state Pinned Notes (#26): покращений текст-підказка, що пояснює флоу hover іконки pin
43.3 — Design System & Architecture — DONE
- Ієрархія z-index (#16): 8-рівнева шкала CSS-змінних (
--z-dropdownдо--z-critical), усі 26+ компонентів переведено з хардкоду - Хардкод кольорів (#17): 24 hex-кольори у Workspace → CSS-змінні (сім'я токенів
--term-*для термінальної панелі) - Завантаження шрифтів (#23): прибрано фантомний Fira Code зі стека шрифтів
- Typing dots (#32): швидкість анімації 1.4с → 0.9с
- Відступи списків на мобільному (#31):
padding-left: 1emнижче 768px
43.4 — UX Improvements — DONE
- Авто-розширення композера (#18): мін 88px (3 рядки), макс 240px,
resize: vertical - Хук useEscapeKey (#22): спільний хук, застосовано до DevResultModal, WorkerForm, CreateProjectModal
- Система Toast (#21):
toast.error/success/infoзамінює всі викликиalert()(40+ входжень у 6 файлах), компонент ToastContainer,esbuild.drop: ['console']прибирає console.log у проді - Гілка ContextRail (#33): прибрано хардкод 'main', показує назву проєкту
- Backoff у Sidebar (#28): експоненційний backoff (30с → макс 5 хв) при помилках API, скидається при успіху
43.5 — Documented / Deferred — DONE
- Мобільна нижня навігація (#25): відкладено, потребує окремої ітерації дизайну
- Планшетні breakpoints (#27): відкладено, потрібні дані аналітики (поріг >8%)
- Шкала розмірів іконок (#29): задокументовано 5-рівневу конвенцію (12/14/16/20/24px)
- Сітка відступів 8px (#30): конвенцію задокументовано для нових компонентів
43.6 — Re-audit Polish (Phase 43.1) — DONE
Повторний аудит дизайнера: A- (95/100). Знайдено й виправлено 2 дрібні прогалини:
- Чистка hex у вкладці Terminal: 2 залишкові хардкод-hex (
#e0e0e0,#555,#f59e0b,#22c55e) →--term-text,--term-text-dimmer,--term-log-warn,--term-log-ok - Розширення useEscapeKey: хук додано в AccountSettingsDialog, BridgeSetup, CreateIssueModal, модал генератора ProjectSkills (LoginOverlay пропущено — повноекранний auth, без закриття)
Phase 44: Analytics Page Redesign (COMPLETE)
Довідка:
docs/design/analytics-page-redesign-2026-04-24.mdПеретворення статичної сторінки метрик на actionable intelligence dashboard.
44.1 — DB Migration & Backend (задачі #47-#48) — DONE
- Таблиця
project_phases(міграція 010) для трекінгу roadmap - Таблиця
activity_log(міграція 011) для структурованого логування подій analyticsQueriesу db.ts: recentActivity, hotProjects, topWorkers, issueStats, getActivePhases, upcomingDeadlines, upsertPhaselogActivity()— fire-and-forget авто-логер із 8 хуками: створення/закриття/перевідкриття задачі, збереження wiki, збереження навички, створення проєкту, рестарт workspace, upsert фази, деплой- 3 analytics endpoints:
/api/crm/analytics/activity,/sidebar,/phases(GET+POST) - Подія деплою авто-логується через
vps-sync.sh(прямий insert у SQLite)
44.2 — Frontend Components (задачі #49-#50) — DONE
- ActivityTimeline — стрічка недавньої активності з іконками, відносними таймстемпами, метаданими воркера/проєкту
- ActivePhasesList — картки-зведення roadmap із progress bars, зворотним відліком дедлайну, статус-бейджами
- Адаптивний режим ContextRail —
AnalyticsContextRail(Quick Links, Hot Projects, Top Workers, Upcoming Deadlines) vsProjectContextRail(наявний) - Responsive 2-колонкова сітка (auto-fit min 340px)
44.3 — Polish & i18n (задача #51) — DONE
- 20 нових i18n-рядків перекладено (EN/UK, всього 458)
- Skeleton-стани завантаження для всіх асинхронних секцій
- Збірку перевірено, без помилок
44.4 — Token Economy Benchmark + Optimization — DONE
Дата: 2026-04-27
Звіти: docs/benchmarks/token-economy-2026-04-27.md, optimization-results-2026-04-27.md
Інфраструктура: benchmarks/token-economy/ (перевикористовуваний A/B test suite)
Phase A — Базовий бенчмарк:
- A/B-тест: Pure Claude + Skills vs ARC Mode (+ CLAUDE.md)
- Модель: Claude Sonnet 4.5, 2 ходи (cache write + cache read)
- Результат: overhead CLAUDE.md +24.1% (6,702 токени, +$0.028 за 2 ходи)
Phase B — Оптимізація (Option C - Hybrid):
- Endpoints → навичка:
crm-api-reference.md(68+ маршрутів, Context Router авто-вставляє) - Структура файлів → стиснута: 6-рядкова семантична мапа (було дерево на 20 рядків)
- Задачі → зведення по фазах: Top-5 P0/P1 + підсумки (було 11+ повним списком)
Фінальні результати:
- CLAUDE.md скорочено: 6,702 → 5,430 токенів (−19%)
- Overhead впав: 24.1% → 3.7% (покращення на −82%!)
- Вартість: $0.146 → $0.140 (ARC тепер майже на рівні Pure Claude)
- ROI: $600 економії на 100k сесій за весь час
Стратегічна перемога:
- Цінність збережено: 100% (архітектура, протоколи безпеки, директиви ролей)
- Продуктивність: деградація <5% (мінімум додаткових tool-викликів)
- ARC коштує майже як базовий Claude, але дає доменну експертизу
Активи:
benchmarks/token-economy/token-benchmark.ts— скрипт A/B-тестуskills/crm-api-reference.md— каталог endpoints на 11KB (глобальна навичка)docs/benchmarks/— 3 аналітичні звіти- Wiki:
benchmarks.md,optimization-results.md
Phase 44.6: Workspace Redesign — Evolution (COMPLETE)
Довідка:
docs/design/prototype/WEB_REDESIGN_ANALYSIS.mdДизайн-система warm clay + status dots + ActionBar + slash-підказки. На основі професійного дизайн-хендофу (Variant A - Workspace Evolution).
44.6.1 — Centralized Design System (задача #6) — DONE
P0 CRITICAL — Single source of truth для дизайн-токенів
- Створено
frontend/src/crm/styles/design-system.css(OKLCH кольори, відступи, типографіка) - Акцент warm clay (#c25b3f) замість teal (#44627A)
- Тепла off-white драбина поверхонь (#f7f5f1 → #ffffff)
- 6 кольорів під воркерів (consultant, developer, designer, archivist, sentinel, po)
- Повна шкала відступів (база 4px), драбина тіней, криві анімацій
- Стани статус-індикатора (idle/active/thinking/error)
Файли: design-system.css (300+ рядків, повністю задокументовано) Імпорт в index.html, заміна хардкод-кольорів у всіх компонентах
44.6.2 — Worker Status Dots with Glow (задача #7) — DONE
P0 CRITICAL — Візуальна ясність статусу
- Додати компонент status-dot (коло 6px) із 4 станами
- Thinking: бурштиновий + пульсуюче світіння (анімація pulse-glow)
- Active: зелений, Idle: сірий, Error: червоний
- Оновити пігулки воркерів у Workspace.jsx (рядки ~2871-2906)
Заблоковано: #6
44.6.3 — ActionBar Component (задача #8) — DONE
P0 CRITICAL — Керування оркестрацією кількох воркерів
- Кнопки Resume/Pause/Stop для всіх активних воркерів
- Safety gate "Confirm last action"
- Живе зведення статусів: "X workers thinking · Y idle"
- Таймер сесії (опційно)
- Розкладка: висота 48px, позиція футера, flexbox
Файли: Workspace.jsx (футер), components/ActionBar.jsx Бекенд: можуть знадобитися API endpoints pause/resume
Заблоковано: #6
44.6.4 — Slash Command Hints (задача #9) — DONE
P1 HIGH — UX автодоповнення
- Чіпи-пігулки для /spec, /issue, /recall, /handoff, /review
- Показ при фокусі композера або введенні "/"
- Дизайн: моноширинний шрифт 10px, фон bg3
Файли: Workspace.jsx (композер ~1668-1700) Заблоковано: #6
44.6.5 — A/B Test: Warm Clay vs Teal (задача #10) — PENDING
P1 HIGH — Валідація користувачами
- Feature flag:
warm_clay_accent_test - Розподіл 50/50, трекінг тривалості сесії + завершення задач
- Хук useAccentColor() з localStorage
- Тривалість: 1 тиждень, 100+ сесій на варіант
Файли: config/features.json, hooks/useAccentColor.js
Вплив: Сучасна тепла дизайн-система, покращений multi-worker UX, професійний polish. Оцінка: 2-3 тижні загалом (5-7 днів активної роботи)
Phase 45: Zero-Knowledge E2EE Architecture (DONE ✅)
"Ми не можемо прочитати ваші дані, навіть якби хотіли" — шифрування at-rest для приватності користувачів. Гібридний підхід: клієнтський крипто-фундамент + серверне at-rest шифрування.
45.1 — E2EE Foundation (задача #16) — DONE ✅ (2026-04-28)
P0 CRITICAL — Клієнтський фундамент шифрування
- Обгортка WebCrypto API (
frontend/src/crm/crypto/e2ee.ts, 214 рядків) - Виведення ключа PBKDF2 (100k ітерацій, SHA-256) → AES-256-GCM
- Життєвий цикл master key: виведення при логіні →
sessionStorage→ очищення при logout/401 - Генерація recovery key + зашифрований бекап master key
45.2 — API Key Encryption (задача #17) — DONE ✅ (2026-04-28)
P0 CRITICAL — Серверне vault-шифрування для API-ключів
vault.ts:encryptField()/decryptField()/isFieldEncrypted()із AES-256-GCM vault-ключемroutes/system.ts: шифрування при збереженні, дешифрування при завантаженні (прозоро для фронтенду)- Оновлено всіх споживачів:
sage.ts,chat.ts,onboarding.ts,worker-spawn.ts - Зворотна сумісність: незашифровані значення проходять без змін
45.3 — Chat Message Encryption (задача #18) — DONE ✅ (2026-04-28)
P0 CRITICAL — At-rest шифрування повідомлень чату в SQLite
- Міграція 015: колонка
encryptedуchat_messages db.ts: авто-шифрування при INSERT, авто-дешифрування при SELECT (прозоро)- Серверне шифрування (child-bot потребує plaintext для обробки Claude CLI)
45.4 — Recovery Keys & Backup (задача #19) — DONE ✅ (2026-04-28)
P1 HIGH — Відновлення та комплаєнс
- Міграція 016: таблиця
recovery_keysіз зашифрованими бекапами master key recoveryKeyQueriesу db.ts: create, list, revoke, restore- 4 API endpoints:
POST/GET/DELETE /api/crm/account/recovery,GET /recovery/restore - UI-компонент
RecoveryKeySection.jsxінтегровано в Account Settings - Формат ключа у стилі 1Password:
XXXX-XXXX-XXXX-XXXX-XXXX
45.5 — Security Hardening (задача #20) — DONE ✅ (2026-04-28)
P1 HIGH — Defense-in-depth
- CSP-заголовки на всіх відповідях CRM API:
default-src 'self',script-src 'self',X-Frame-Options: DENY - Заголовки безпеки:
X-Content-Type-Options: nosniff,Referrer-Policy: strict-origin-when-cross-origin shared/pii-sanitizer.ts: редагує emails, API-ключі, JWT, номери карт у логах- Санітизацію PII застосовано до прийому термінальних JSONL-логів
45.6 — Advanced Features — PLANNED
P2 MEDIUM — Nice-to-have
- Синхронізація ключів між пристроями: зашифрований key vault, парування через QR-код
- Forward secrecy: ratcheting у стилі Signal для чату
- Політика зберігання даних: авто-видалення старих повідомлень (30/90 днів)
- UI права на видалення (#55): комплаєнс GDPR стаття 17
Вплив: Zero-knowledge архітектура. Сервер зберігає лише зашифровані blob-и, не може дешифрувати дані користувача.
Phase 44.5: Documentation Coverage Expansion (COMPLETE)
Покриття документації: 65% → ~95%. Вісім нових публічних документів, оновлений індекс, розширені thinking-підказки Workspace. Дата аудиту: 2026-04-27.
44.5.1 — Documentation Audit & Gap Analysis (DONE)
- Повний аудит
docs/public/проти фактичних фіч кодової бази - Виявлено 14 категорій прогалин: CLI, Telegram, Bridge, Workers, API, Troubleshooting
- Пріоритизовано P0/P1/P2 з оцінками трудомісткості
44.5.2 — New Public Documentation (DONE)
Вісім нових документів у docs/public/:
guides/arc-cli-reference.md(425 рядків) — усі 16 CLI-команд, прапорці, env vars, приклади воркфлоуguides/telegram-bots.md(160 рядків) — архітектура Master/Child ботів, команди, inline-клавіатури, маршрутизація воркерівguides/notebooklm-bridge.md(162 рядки) — семантичний пошук, тригери авто-синхронізації, кеш, 3-рівнева модель пам'ятіarchitecture/workers-and-intelligence.md(214 рядків) — 6 вбудованих воркерів, Binary Evals (6 типів), скоринг Context Router, Learnings, Karpathy Loopapi/api-reference.md(272 рядки) — 68+ endpoints у 13 категоріях, коди помилок, модель безпекиarchitecture/database-schema.md— 14 таблиць, 12 міграцій, foreign keys, ER-діаграма, прагми SQLiteguides/development-setup.md— локальна розробка: вимоги Bun/Node, порти, env vars, Docker, структура проєктуguides/troubleshooting.md— діагностика за симптомами: auth, воркери, bridge, фронтенд, БД. Таблиця швидкої довідки
44.5.3 — Index & Navigation Update (DONE)
docs/public/index.md— 8 нових записів у Quick Navigation, By Section, By Mechanism, Document Status- Додано нову секцію "API" в By Section
- 7 нових записів у довідковій таблиці механізмів (Telegram, NotebookLM, Workers, API, Database, Troubleshooting)
44.5.4 — Workspace Thinking Tips (DONE)
- Додано 11 інтеграційних підказок (NotebookLM Bridge, Telegram-боти, Master/Child, OAuth, термінал, Context Rail)
- Додано 12 бренд-підказок "ARC OS — Why We're Great" (федерація, самонавчання, CLI-first, zero-trust тощо)
- Додано опційне поле
docіз клікабельним лінком "Docs →" на сторінку документації
Phase 46: Parallel Worker Execution (COMPLETE)
Кожен воркер = окремий процес. Більше жодного глобального м'ютекса
isProcessing, який блокує всі воркери. Consultant, Developer, Sentinel тощо працюють конкурентно у власних tmux-сесіях.
46.1 — Registry Schema Evolution (задача #57) — DONE
P0 CRITICAL — execution_mode: "parallel" + масив workers[] у bot_registry.json
- Додати поле
execution_mode:"parallel"|"single"(за замовчуванням) - Додати масив
workers:{ id, tmux_session, health_port }на воркера - Виділення портів: 19220–19229 для arc-v2, діапазони по 10 портів на проєкт
- Legacy-проєкти без поля продовжують працювати в однопроцесному режимі
46.2 — Worker Spawn Utility (задача #58) — DONE
P0 CRITICAL — shared/worker-spawn.ts
- Витяг логіки
startWorkerBot()ізcrm-routes.ts:3471у перевикористовувану утиліту spawnWorkerProcess(): запуск одного воркера зFORCED_WORKER_ID+ унікальним health-портомspawnAllWorkers(): запуск усіх воркерів проєкту в parallel-режимі- Воркери з vault-токеном → Telegram-режим; без →
WORKSPACE_MODE=1
46.3 — Worker-Specific Inbox Routing (задача #59) — DONE
P0 CRITICAL — Завжди маршрутизувати до crm_inbox_{worker_id}.jsonl
handlePostMessageзавжди пише у воркер-специфічний inbox для parallel-проєктів- Усунути залежність рішення про маршрутизацію від існування vault-токена
- Deprecated спільний
crm_inbox.jsonlдля parallel-проєктів
46.4 — Watchdog Multi-Worker (задача #60) — DONE
P1 HIGH — Health checks на кожен процес воркера
- Розширити інтерфейс
ChildBotполямиworker_id,project_name getChildren()розгортає parallel-проєкти у N записів- Незалежний health check + авто-рестарт на воркера (а не на проєкт)
46.5 — Restart API Per-Worker (задача #61) — DONE
P1 HIGH — Гранулярний контроль рестарту
POST /restart→ рестарт усіх воркерівPOST /restart?worker_id=developer→ рестарт конкретного воркера- Використовує утиліти
worker-spawn.ts
46.6 — Telegram Routing + /status (задача #62) — DONE
P1 HIGH — Токен головного бота → consultant; агрегований статус
- Головний
child:arc-v2:tokenпризначено процесу воркера consultant /statusу consultant агрегує health із портів сусідніх воркерів
46.7 — Activate for arc-v2 (задача #63) — DONE
P0 CRITICAL — Увімкнути перемикач
- Додати
execution_mode: "parallel"+ масив workers для arc-v2 у bot_registry.json - Зупинити стару tmux-сесію
citadel-child - Перевірити, що всі воркери стартують незалежно й обробляють повідомлення паралельно
Вплив: Справжнє конкурентне виконання воркерів. Більше жодних черг — надсилайте повідомлення Developer та Consultant одночасно.
Phase 47: Timeline Observability — DAW for AI Teams (COMPLETE ✓)
Довідка:
docs/design/prototype/WEB_REDESIGN_ANALYSIS.md(Variant B) Метафора Logic Pro — воркери як доріжки, події як кліпи на спільному таймлайні. Інновація: Унікальна IP, жоден інший інструмент оркестрації AI не має такого виду.
47.1 — Message Timestamps (задача #10) — COMPLETE ✓
P1 HIGH — Фундамент бекенду
Зроблено:
- Міграція 013: додано
timestamp_ms INTEGERу таблицю chat_messages - Backfill наявних рядків з ISO-таймстемпа (конвертація julianday)
- Оновлено всі точки вставки повідомлень:
shared/crm-routes.tshandlePostMessagemaster-bot/api-server.ts/api/internal/chat/saveshared/cli-routes.tsCLI chat endpointshared/db.tsсигнатура chatQueries.insert
- Створено індекс:
idx_chat_msg_timeline (project_name, timestamp_ms DESC) - Перевірено на VPS: 266 повідомлень успішно backfill-нуто
Файли: shared/migrations/013_timeline_timestamps.ts, shared/db.ts, shared/crm-routes.ts, master-bot/api-server.ts, shared/cli-routes.ts Завершено: 2026-04-27 Розблоковує: #11
47.2 — Timeline Events Table (задача #11) — COMPLETE ✓
P1 HIGH — Шар зберігання подій
Зроблено:
- Міграція 014: CREATE TABLE timeline_events
- Схема: id, project_name, worker_id, event_type (message/tool/status), timestamp (Unix ms), duration, label, content, metadata
- Індекси: idx_timeline_project_ts, idx_timeline_worker
- Backfill 266 подій із chat_messages
- shared/db.ts: timelineQueries
- insert() — створення нової події таймлайна
- getRange() — вибірка подій у часовому вікні
- getWorkerRange() — таймлайн конкретного воркера
- getLatest() — останні N подій
- shared/crm-routes.ts: handlePostMessage створює подію таймлайна на повідомлення користувача
- Перевірено на VPS: 266 подій, коректні таймстемпи
Файли: shared/migrations/014_timeline_events.ts, shared/db.ts, shared/crm-routes.ts Завершено: 2026-04-27 Розблоковує: #12
47.3 — Timeline Frontend Components (задача #12) — COMPLETE ✓
P1 HIGH — UI у стилі DAW
Зроблено:
- 7 нових компонентів (разом 1009 рядків):
- TimelinePage.jsx — головний контейнер зі станом Mute/Solo/подій (209 рядків)
- LaneHead.jsx — заголовки воркерів із контролами M/S (140 рядків)
- Lane.jsx — горизонтальні доріжки подій із сітковим фоном (52 рядки)
- Event.jsx — позиціоновані чіпи подій (user=темний, assistant=clay) (68 рядків)
- TimeRuler.jsx — вісь часу з playhead (106 рядків)
- ChatPanel.jsx — правий сайдбар (440px) з історією повідомлень (154 рядки)
- Transport.jsx — Play/Pause/Stop + scrubber прогресу (109 рядків)
- API endpoint: GET /api/crm/timeline/:name/events
- Інтеграція: маршрут App.jsx + навігація Sidebar (primary-рівень, іконка Clock, бейдж BETA)
- i18n: рядок Timeline (EN/UK)
Фічі:
- Mute/Solo воркерів (метафора аудіо-мікшера)
- Клік на подію → підсвічування в чаті
- Playhead на позиції останньої події
- Сітковий фон із 12 поділок
- Позиціонування подій: ((timestamp - start) / duration) * 100%
- Підтримка бейджів для пунктів навігації
Файли: frontend/src/crm/pages/TimelinePage.jsx, components/timeline/*, shared/crm-routes.ts Завершено: 2026-04-27 Розблоковує: #13
47.4 — Feature Flag & Route (задача #13) — COMPLETE ✓
P1 HIGH — Opt-in бета
Зроблено:
- Маршрут
/timelineдодано в App.jsx (lazy-завантаження) - Пункт навігації Sidebar із бейджем BETA (primary-рівень, іконка Clock із lucide-react)
- Підтримка рендерингу бейджів: бурштиновий фон + uppercase-текст
- i18n: Timeline → "Таймлайн" (UK-локаль)
- Публічна бета — без feature flag (доступно всім користувачам)
Рішення: Поки що пропустити складність feature flag. Timeline достатньо стабільний для публічної бети з індикатором BETA.
Файли: frontend/src/crm/App.jsx, components/Sidebar.jsx, locales/uk/messages.po Завершено: 2026-04-27 Розблоковує: #15
47.5 — Documentation (задача #15) — COMPLETE ✓
P1 HIGH — Оновити всю документацію
Зроблено:
- ROADMAP.md — Phase 47 позначено завершеною
- CLAUDE.md — Timeline додано в архітектуру
- Пам'ять хабу — засвоєні уроки Файли: docs/ROADMAP.md, CLAUDE.md Завершено: 2026-04-28 Розблоковує: #16 (Phase 47.6)
47.6 — Color Themes & Pastel Palette — COMPLETE ✓
P2 MEDIUM — Кольорові теми на вибір користувача
Зроблено:
- Компонент ThemeSelector (168 рядків)
- 4 пастельні палітри: warm-clay (за замовчуванням), ocean-teal, lavender, sage
- Сіткова розкладка з кружечками-прев'ю кольорів
- Персистентність теми через localStorage
- Українські лейбли та описи
- Оновлення дизайн-системи:
- Пастельні кольори воркерів (6 ролей): consultant (#6ba89d), developer (#7ba3cf), designer (#b899d4), archivist (#9d89c7), sentinel (#d47a70), po (#d4a574)
- Пастельний акцентний колір: #d4876e (теплий теракотовий)
- CSS-селектори [data-color-theme] для всіх 4 тем
- Тепла off-white драбина поверхонь: #f7f5f1 → #ffffff
- Інтеграція:
- ThemeSelector у діалозі Account Settings
- Авто-завантаження збереженої теми при старті застосунку (App.jsx useEffect)
- Перемикання теми застосовується миттєво через document.documentElement.setAttribute
Кольорові палітри:
- warm-clay (за замовчуванням): акцент #d4876e, теплий теракотовий
- ocean-teal: акцент #5eb3a6, прохолодний м'ятний
- lavender: акцент #b799d4, м'який фіолетовий
- sage: акцент #82b894, природний зелений
Файли: frontend/src/crm/components/ThemeSelector.jsx, AccountSettingsDialog.jsx, App.jsx, styles/design-system.css Завершено: 2026-04-28 Розблоковує: #17 (Phase 47.7)
47.7 — Custom Theme Builder + Gemini UX — COMPLETE ✓
P2 MEDIUM — Користувацькі кольорові теми + сучасні чат-бульбашки
Зроблено:
- MVP Custom Theme Builder (ThemeSelector.jsx, +211 рядків):
- Кнопка "+ Custom" із нативним color picker (type="color")
- Поле hex-вводу з валідацією (
/^#[0-9A-Fa-f]{0,6}$/) - Хелпери авто-генерації:
darkenColor(hex, percent)— на 15% темніше для hover, на 30% для activehexToRgba(hex, alpha)— варіанти прозорості (12% bg, 35% ring)
- Прев'ю в реальному часі з кольоровим кружечком
- Персистентність у localStorage (
custom-theme-color) - Динамічна ін'єкція CSS-змінних через
root.style.setProperty()
- Повідомлення користувача в стилі Gemini:
- Фон:
oklch(0.93 0.015 260)— світлий блідо-синій - Текст:
var(--ink)— темний для читабельності - Замінює старий патерн темної бульбашки (Phase 41.3)
- Відповідає сучасному AI chat UX (ChatGPT, Gemini, Claude.ai)
- Фон:
Технічне:
- Кастомна тема застосовується через
[data-color-theme="custom"]+ inline-стилі - Fallback на пресет при невалідному кольорі
- Працює з усіма 4 пресет-темами
- Без бекенду — чистий фронтенд
Файли: frontend/src/crm/components/ThemeSelector.jsx, styles/globals.css Завершено: 2026-04-28
47.8 — Issues Redesign (Variant B Hybrid) — COMPLETE ✓
P1 HIGH — Керування задачами за фазами
Зроблено:
- IssuesRedesign.jsx (1100+ рядків) — повне переписування UI:
- Групування за фазами: автоматичний витяг із заголовка (
Phase XX:) або міток (phase-XX) - Згортувані секції: компонент PhaseGroup із розгортанням/згортанням
- Трекінг прогресу: X/Y закрито + відсоткова шкала (кольорова: <30% червона, 30-70% бурштинова, >70% зелена)
- Табличні рядки: IssueTable з колонками #ID, Title, Priority, Status, Updated
- Пульс-анімація P0: збережено з оригінального Issues.jsx (ефект червоного світіння)
- Slide-in панель деталей: права панель 440px із:
- Повними деталями задачі (заголовок, пріоритет, статус, мітки)
- Рендерингом markdown-опису (ReactMarkdown + remarkGfm)
- Таймлайном активності з кольоровими рамками (created=фіолетова, status_change=зелена, field_change=синя)
- Кнопкою Close/Reopen з optimistic-оновленнями UI
- Закриттям по Escape (хук useEscapeKey)
- Групування за фазами: автоматичний витяг із заголовка (
- Мобільна адаптивність (breakpoint 767px):
- DetailPanel → повноекранний модал (100vw)
- Рядок пошуку → вертикальний стек
- Заголовки фаз → менші шрифти, щільніші відступи
- Таблиця → приховано колонку "Updated", зменшено відступи
- Весь текст і відступи масштабуються вниз
- Інтеграція:
- Оновлення маршруту App.jsx (
issues→ IssuesRedesign) - Lazy-завантаження через React.lazy()
- Використовує наявний endpoint
/api/mcp/issues/:project - Клієнтське групування за фазами (без змін бекенду)
- Оновлення маршруту App.jsx (
Дерево компонентів:
IssuesRedesign
├── Header (search, status filters, issue count)
├── PhaseGroup[] (collapsible)
│ ├── PhaseHeader (name, progress bar, X/Y count, expand icon)
│ └── IssueTable (table rows sorted by ID desc)
│ └── IssueRow (clickable, P0 pulse)
└── DetailPanel (slide-in, backdrop blur, escape to close)
├── Header (ID, priority badge, status icon, labels)
├── Description (ReactMarkdown)
├── Activity timeline (colored borders, icons, timestamps)
└── Footer (Close/Reopen button, created/updated times)
Фічі:
- Група Orphans для задач без міток фази
- Хелпер timeAgo() (напр., "3h", "2d", "1w")
- Mobile-first адаптивний дизайн
- Узгоджено з дизайн-системою ARC OS (пастельні кольори, теплі поверхні)
- Optimistic-перемикання статусу + toast-сповіщення
Файли: frontend/src/crm/pages/IssuesRedesign.jsx, frontend/src/crm/App.jsx Завершено: 2026-04-28
47.9 — Favicon Redesign + Branding Cleanup — COMPLETE ✓
P2 MEDIUM — Polish брендової ідентичності
Зроблено:
- SVG-favicon (warm-clay дуги, <500 Б) + варіант для темного режиму
- PNG-fallback кількох розмірів (16/32/48/192/512) + мульти-роздільний .ico
- site.webmanifest із maskable-іконкою + theme-color #c25b3f
- Заміна "Arc OS" → "ARC OS" в UI для користувачів: · TopHeader: текстовий лейбл → ArcLogo classic h=28 · LoginOverlay: emoji 🏰 → ArcLogo classic h=56 · OnboardingWizard: emoji 👋 → ArcLogo + "Welcome to ARC OS"
- Ключі localStorage збережено (зламали б auth/E2EE)
Файли: frontend/public/favicon.svg, AppFooter.jsx, TopHeader.jsx, LoginOverlay.jsx, OnboardingWizard.jsx Завершено: 2026-04-28
47.10 — Resizable Worker Panels — COMPLETE ✓
P2 MEDIUM — UX polish
Зроблено:
- Drag-роздільник між панелями воркерів (1px → 4px при hover/перетягуванні)
- Подвійний клік по хендлу скидає до рівних ширин
- Мінімальна ширина панелі 12% (без повного колапсу)
- Персистентність у localStorage на розкладку (
panel-flex-{project}-{ids}) - Вимкнено на мобільному (одна панель)
Файли: frontend/src/crm/pages/Workspace.jsx Завершено: 2026-04-28
47.11 — Token Error Banner + CLI Promo — COMPLETE ✓
P1 HIGH — Промоція моделі підписки
Зроблено:
utils/apiErrors.js: 8 regex-патернів, що виявляють помилки Anthropic/OpenAI (no-key, credits-exhausted, rate-limit, auth-error, загальна помилка API)TokenErrorBanner(у ChatThread): показується над чатом із заголовком + CTA-кнопками (Open Account Settings, Copyarc <project> <worker>, лінк на Docs)CliSubscriptionTip: ненав'язливе промо внизу праворуч, cooldown 7 днів, заохочує підписку Claude Pro замість оплати за токени- 25 нових UK-перекладів
- Закривається окремо для кожного коду помилки
Файли: utils/apiErrors.js, components/TokenErrorBanner.jsx, components/CliSubscriptionTip.jsx, ChatThread.jsx Завершено: 2026-04-28
47.12 — Slim Gemini-Style Footer — COMPLETE ✓
P3 LOW — Trust + polish навігації
Зроблено:
- Компонент
AppFooter(28 px заввишки, один рядок) - Дисклеймер: "ARC OS використовує AI — перевіряйте важливі рішення."
- Inline-лінки: Documentation · Community · Support · Status · GitHub
- Підказка-іконка зовнішнього лінку, зміна кольору при hover
- Прихований на мобільному (економить вертикальний простір)
- Підключено до наявного хендлера onOpenDocs з App.jsx
Файли: components/AppFooter.jsx, layouts/CrmMainLayout.jsx Завершено: 2026-04-28
47.13 — Easter Eggs (1 of N) — COMPLETE ✓
P3 LOW — Delight-фічі
Зроблено:
EasterEggLogoобгортає ArcLogo у TopHeader- Утримання hover 1.5с (або клік) запускає одну з 6 випадкових анімацій: volcano shake · spin 360° · sparkle burst · rainbow hue-cycle · bounce · glitch
- Cooldown 5с між спрацюваннями; поважає
prefers-reduced-motion docs/easter-eggs.mdкаталогізує 12 запланованих майбутніх eggs (код Konami, /dance, /matrix, founder mode за 7 кліків, /coffee, idle doodle, бейдж midnight owl, six-worker symphony, drag-to-fire pill, triple-click TTS, секретна сторінка /about, thinking favicon pulse)
Файли: components/brand/EasterEggLogo.jsx, TopHeader.jsx, docs/easter-eggs.md Завершено: 2026-04-28
47.14 — Easter Eggs (5 more) — COMPLETE ✓
P3 LOW — Delight-фічі (продовження)
Зроблено:
utils/eggs.js— центральний markEggFound() + lookup EGGS, персистентність Set у localStorageEasterEggManager, змонтований в App.jsx — глобальні слухачі клавіатури + slash-команд + achievement toast- EE-02 Konami code → 10с ретро-тема (hue-rotate, scanlines, monospace)
- EE-04
/matrixу будь-якому полі → 5с canvas цифрового дощу катакани - EE-05 7 кліків по лого за 3с → фінал rainbow+sparkles + ачівка Founder Mode
- EE-09 Six-worker symphony → 600мс трясіння екрана при 6 відкритих панелях
- EE-11 Потрійний клік по повідомленню → speechSynthesis TTS читає повідомлення вголос
- Achievement toast (зверху по центру, 4.5с) показується лише при першому відкритті
- Усі анімації поважають
prefers-reduced-motion: reduce
Файли: utils/eggs.js, components/EasterEggManager.jsx, components/brand/EasterEggLogo.jsx, pages/Workspace.jsx, pages/workspace/ChatThread.jsx, App.jsx Завершено: 2026-04-28
47.15 — Per-mode Theme Presets + Custom Colors — COMPLETE ✓
P1 HIGH — Кастомізований користувачем інтерфейс
Зроблено:
ThemeAwareLogo— авто-перемикання між classic (світлим) та темним варіантами через MutationObserver наdata-theme. Використовується в TopHeader (через EasterEggLogo), LoginOverlay, OnboardingWizard- 7 dark-mode пресетів у design-system.css (neutral-gray, warm-clay, ocean-teal,
lavender, sage, crimson-night, midnight-blue) — селектори скоуплені до
[data-theme="dark"][data-color-theme=...] - ThemeSelector v2:
· Авто-визначення поточного режиму через MutationObserver
· Показує світлі або темні пресети відповідно
· Персистентність на режим (
color-theme-light,color-theme-dark) · Бейдж режиму (іконка Sun/Moon) у заголовку - Кастомний color builder (4 контроли): Accent, Background, Surface, Text
· Персистентність на режим (
custom-colors-light,custom-colors-dark) · Live-прев'ю через inline CSS-змінні · Кнопка скидання до дефолтів · Редагування будь-якого кольору активує пресет Custom - App.jsx застосовує правильний пресет при монтуванні + перезастосовує, коли ThemeToggle перемикає
data-theme(чистить inline-перекриття з попереднього режиму) - 15 нових UK-перекладів
Файли: components/brand/ThemeAwareLogo.jsx, components/ThemeSelector.jsx, styles/design-system.css, App.jsx, components/LoginOverlay.jsx, components/OnboardingWizard.jsx, components/brand/EasterEggLogo.jsx Завершено: 2026-04-28 Задеплоєно: 2026-04-28
47.16 — Issue Detail Wizard with Inline Editing — COMPLETE ✓
P1 HIGH — Редагування задач без виходу зі списку
Зроблено:
- Сильніший backdrop blur (10px) + 65% чорний оверлей — справжнє відчуття візарда
- Ширша панель (520px, було 440px) для комфортного редагування
- Inline-редагування заголовка (textarea, Enter — зберегти, Esc — скасувати)
- Inline-редагування опису (markdown textarea + перемикач Edit/Preview)
- Дропдаун пріоритету в заголовку (P0-P3, миттєва зміна)
- Поле Phase — input → автоматично оновлює мітку
phase-XX - Поле Owner — дропдаун із 6 ролей воркерів → оновлює мітку
owner:xxx - Вільний редактор міток із контролами чіп + / ×
- Кнопка Save з'являється тільки коли чернетка відрізняється від задачі (dirty flag)
- Бекенд: PUT /api/mcp/issues/:p/:id тепер приймає масив
labels(санітизація, макс 20 елементів, макс 50 символів кожен, запис у лог активності)
Файли: pages/IssuesRedesign.jsx, shared/cli-routes.ts Завершено: 2026-04-28 Закриває Phase 47
Use Cases (Timeline):
- Дебаг взаємодій кількох воркерів (видно прогалини координації)
- Моніторинг 4-6+ воркерів у довготривалих флотах
- Ретроспективний аналіз (скрол назад, клік на подію → повний контекст)
- Solo-режим для фокусу (mute нерелевантних воркерів)
Вплив: Унікальна observability-фіча. Тільки desktop (1440px+), експериментальна бета. Оцінка: 3-4 тижні (15-20 днів активної роботи)
Phase 48: Architecture Decomposition — Logical Service Boundaries (P0 COMPLETE)
Від моноліту до логічної архітектури. Три монолітні файли (10,779 рядків) розбиті на 30 доменних модулів (373 рядки в dispatcher'ах). Задеплоєно: 2026-04-28. Zero behavioral changes — чистий рефакторинг з backwards-compat re-exports.
Before / After
graph LR
subgraph "Before (10,779 LOC)"
M1[crm-routes.ts<br/>6,181 LOC<br/>~120 handlers]
M2[api-server.ts<br/>1,464 LOC]
M3[Workspace.jsx<br/>~3,134 LOC]
end
subgraph "After (373 LOC dispatchers + modules)"
R[router.ts<br/>512 LOC dispatch]
AS[api-server.ts<br/>196 LOC]
WP[Workspace.jsx<br/>168 LOC orchestrator]
subgraph "shared/routes 17 modules"
S1[projects · files · workers · skills · chat]
S2[wiki · sage · onboarding · pins · docs]
S3[learnings · specs · restart · system · analytics]
end
subgraph "master-bot/routes 4 modules"
B1[auth · internal · cli · websocket]
end
subgraph "pages/workspace 9 modules"
W1[ChatThread · Composer · TerminalPanel · CloudPmPanel]
W2[WorkerSelector · WorkerStudio · ThinkingTips]
W3[QuickActionBar · useSSEStream]
end
end
M1 -.refactor.-> R
R --> S1 & S2 & S3
M2 -.refactor.-> AS
AS --> B1
M3 -.refactor.-> WP
WP --> W1 & W2 & W3
Чистий результат: кожен модуль ≤900 LOC, single responsibility. Hot-reload швидший, code-review менший, поверхня конфліктів вужча.
48.1 — Decompose crm-routes.ts (задача #16) — DONE ✅
6181 → 9 рядків (re-export shim). 17 доменних модулів у shared/routes/:
shared/routes/
├── _utils.ts (343) — types, safePath, isValidProjectName, extractChatId, canAccessProject, cachedReadJson
├── router.ts (512) — routeCrmRequest() dispatch table, re-exports
├── projects.ts (723) — handleGetProjects, handleGetProjectDetails, handleGetLogs, handleGetMetrics, handleGetChatHistory
├── files.ts (381) — 8 file handlers (CRUD + upload + git clone)
├── workers.ts (636) — worker CRUD, active role, message posting, TG token management
├── skills.ts (665) — 18 skill handlers (global CRUD, evolution, forks, generate)
├── chat.ts (862) — SSE streams, Cloud PM chat, terminal log ingest, routeSseRequest
├── wiki.ts (258) — wiki tree, knowledge graph, file read/save/download
├── sage.ts (757) — marketplace scout, Sage analysis, benchmarks
├── onboarding.ts (601) — project creation, onboarding setup, directory/config generation
├── system.ts (182) — system handlers
├── pins.ts (80) — pin CRUD
├── learnings.ts (111) — learnings get/post, bridge heartbeat
├── docs.ts (131) — docs tree/file
├── specs.ts (113) — spec approve/reject
├── restart.ts (78) — worker restart
└── analytics.ts (10) — analytics stub
48.2 — Decompose api-server.ts (задача #17) — DONE ✅
1464 → 196 рядків. 4 route-модулі у master-bot/routes/:
master-bot/
├── api-server.ts (196) — Bun.serve() thin dispatcher + in-memory state
└── routes/
├── auth.ts (562) — /api/auth/* (register, login, OAuth, 2FA, device code, rate limiters)
├── internal.ts (282) — /api/internal/* (chat/save, bridge-event, relay) + binary downloads
├── cli.ts (293) — /api/cli/* + /api/mcp/* (ARC CLI integration)
└── websocket.ts (303) — WebSocket upgrade + handlers (terminal, event-stream, local-bridge)
48.3 — Decompose child-bot/bot.ts (задача #19) — DONE ✅
1952 → 1047 рядків. 4 модулі:
child-bot/
├── bot.ts (1047) — config, init, message handler, main loop
├── claude-runner.ts (763) — subprocess management, retry logic, worker dispatch
├── telegram.ts (149) — Telegram API (send, typing, callbacks)
├── workers.ts (139) — worker registry, thread management, hot reload
└── inbox.ts (124) — CRM inbox processing, attachment handling
48.4 — Frontend Workspace Decomposition (задача #18) — DONE ✅
3134 → 168 рядків. 9 компонентів у frontend/src/crm/pages/workspace/:
frontend/src/crm/pages/
├── Workspace.jsx (168) — layout shell + state orchestration
└── workspace/
├── ChatThread.jsx (899) — sendMessage, CopyButton, ChatPanelView, fetchChatHistory
├── Composer.jsx (447) — ModelSelector, ToolsMenu, MicButton, useFileAttach, AttachmentChips
├── WorkerStudio.jsx (557) — WorkerForm, WorkerStudioModal, WORKER_TOOL_OPTIONS
├── TerminalPanel.jsx (384) — TerminalPanelView (xterm.js, tool icons, rich logs)
├── CloudPmPanel.jsx (244) — CloudPmPanelView (Cloud PM chat panel)
├── WorkerSelector.jsx (197) — WorkerSelectorBar, WORKER_TONES, workerTone, loadActiveWorkers
├── ThinkingTips.jsx (147) — spinner + rotating tips with doc links
├── useSSEStream.js (150) — SSE connection + message parsing hook
└── QuickActionBar.jsx (77) — footer action bar (/btw, Pause, Stop, Approve)
48.5 — Event-Driven Inbox via fs.watch — DONE ✅ (2026-04-28)
P1 HIGH — Замінити 500ms file polling на instant delivery без додаткових залежностей.
Рішення: після порівняння Redis/RabbitMQ/Kafka обрано native fs.watch() (Linux inotify через Bun). Усі три брокери — overkill для single-VPS, 10KB/msg, 1-to-1 per-worker FIFO use case. Файлова durability вже забезпечує необхідні гарантії; єдина проблема була latency 500ms polling.
Реалізація (child-bot/inbox.ts + child-bot/bot.ts):
startInboxWatcher()—fs.watch(stateDir)з фільтром поcrm_inbox*.jsonltriggerInbox()— coalescing mutex запобігає race на множинних event'ах від одного запису- Safety-net poll кожні 30s — захист від пропущених inotify events (рідкі на Linux)
- Workspace mode: видалено
while { processCrmInbox(); sleep(500) }loop - Telegram mode: видалено per-iteration poll inbox після
tgGetUpdates
Результат: latency 500ms→~5ms (100x), zero new dependencies, повна сумісність з існуючим JSONL форматом.
48.6 — Worker Lazy Lifecycle (idle-kill + wake-up) — DONE ✅ (2026-04-28)
P1 HIGH — Capacity scaling без додавання hardware або Docker split.
Замість оригінального плану (Docker Compose split) проведено capacity analysis: VPS bottleneck = RAM від idle worker bot.ts процесів (~85MB кожен × 6 workers per project = ~510MB idle per user). Container split не вирішує цю проблему — це той самий код.
Рішення: worker self-idle-shutdown після 10 хв тиші + wake-up on demand при першому повідомленні через CRM.
Компоненти:
child-bot/bot.ts— idle timer у workspace mode loop'і; track activity черезmarkActive()callback з inbox; exit + write markeridle_${project}_${worker}.flagколи idle ≥ 10 minchild-bot/inbox.ts—onActivity?: () => voidcallback викликається коли inbox'у є messagesmaster-bot/watchdog.ts—isIdleExited(child)skip перевіряє marker file; якщо існує — НЕ restart, не вважає unhealthyshared/worker-spawn.ts—rmSync(markerFile)перед respawn, щоб watchdog знов моніторивshared/routes/workers.ts—handlePostMessageзамістьNO_BOT_RUNNING503 виконуєspawnWorkerProcess+ чекає до 5s на heartbeat
Результат:
- ~425MB RAM звільнено per user (5 idle workers × 85MB).
- Capacity 2 → 6-10 concurrent users на тому самому VPS.
- Cold-start latency ~2-4s на перше повідомлення після idle (Bun startup + DB load + tmux session).
- Backwards compat: WORKER_IDLE_TIMEOUT_MS env var для tuning, default 10хв.
48.6.1 — Single-mode wake-up parity (закриває #20) — DONE ✅ (2026-04-30)
Wake-up logic при іділ-kill існував лише для parallel-mode проєктів. Single-mode (більшість user-створених через CRM) повертав NO_BOT_RUNNING 503 на ~30s до того, як watchdog рестартує.
Фікс:
shared/worker-spawn.ts— доданоspawnChildBot()(workspace + Telegram режими, BYOK + trial keys)shared/routes/workers.ts—handlePostMessagesingle-mode тепер викликаєspawnChildBotсинхронно (5s wait), віддає 503 тільки якщо spawn проваливсяmaster-bot/watchdog.ts—restartChildlegacy path делегує до того ж helper (DRY, спільна логіка resolve key + clear idle marker)
48.7 (перейменовано) — Service Entry Points & Docker Compose (задача #21) — BACKLOG
P2 MEDIUM — Незалежні процеси для кожного сервісу. Відкладено: реальний bottleneck вирішено в 48.6 без архітектурного перекройка.
48.7 — Auth Gateway & Shared Types (задача #22) — BACKLOG
P2 MEDIUM — Централізована авторизація + типи
Результат: 12,731 → 1,420 рядків у dispatcher'ах. 34 доменних модулі, всі ≤900 рядків. Задеплоєно 2026-04-28. Виконання (затверджено PO): P0 (#16, #17, #18) + P1 (#19) — DONE. P2 (#20-#22) — backlog.
Phase 49: Doc Enforcement & GitHub Integration (COMPLETE)
Виключити людський фактор з documentation discipline. CEO втомився нагадувати воркерам оновлювати docs після кожного push'а — переходимо на system-level enforcement.
49.1 — Pre-push doc coverage hook — DONE ✅ (2026-04-28)
P1 HIGH — Negative safety net.
scripts/check-docs-coverage.ts— Bun-script, читає stdin pre-push protocol (<local-ref> <local-sha> <remote-ref> <remote-sha>), порівнюєorigin/main..HEAD, mapping rules.githooks/pre-push— викликає check-docs-coverage в hook modescripts/setup-hooks.sh—git config core.hooksPath .githooks(one-time per clone)- Mapping rules:
shared/migrations/*→docs/public/architecture/database-schema.mdshared/routes/*→docs/public/api/api-reference.md- "Phase NN" у commit msg →
docs/ROADMAP.md+docs/status/current-state.json - ≥3 backend files & ≥50 LOC →
learnings.md
- Bypass:
git push --no-verify(для emergency / non-code commits — видно у git log)
49.2 — arc wrapup CLI helper — DONE ✅ (2026-04-28)
P1 HIGH — Positive workflow assist (доповнення до negative gate 49.1).
clients/lib/wrapup.ts— модуль ізrunChecklist()+runGenerate()arc wrapup— read-only чекліст (делегує доscripts/check-docs-coverage.ts)arc wrapup --generate— додає skeleton-записи з маркерами TODO:learnings.md— таймстемп + авто-визначений scope (api/backend/frontend/infra/process) + subject першого комітуdocs/ROADMAP.md— заголовок Phase NN + зведення комітівdocs/status/current-state.json— підняття версії + новий запис latest_changes на початку
- Маркери TODO навмисно валять review, доки не заповнені
--fix(авто-коміт) відкладено — preview-then-edit безпечніше; користувач переглядає черезgit diff
49.2.1 — arc wrapup --from-summary для research-driven роботи — DONE ✅ (2026-04-28)
P1 HIGH — Закриває blind spot: research/decisions/findings без code commits.
runFromSummary()уclients/lib/wrapup.ts— приймає prose summary- Auto-classification: type (decision/lesson/finding/spike) + scope (infra/perf/security/frontend/api/process) через regex hints
- Додає запис із таймстемпом до
learnings.md - Use case: research-сесія без коду (порівняння брокерів, capacity analysis, trade-off review) → один CLI-виклик зберігає insight
- Трекати використання 1-2 тижні (
git log --grep="capture"); якщо ≥5/тиждень — реалізувати Phase 49.2.2 (auto-extract зarc report)
49.3 — GitHub Light integration — DONE ✅ (2026-04-28)
P1 MEDIUM — Webhooks → Telegram-сповіщення (UI-сайдбар відкладено до 49.3.1).
Компоненти:
- Міграція 017:
github_links(id, project_name, owner, repo, webhook_secret, created_at, created_by)+ індекси shared/db.ts—githubLinkQueries(create, listByProject, findBySecret, delete)shared/routes/github.ts— 4 хендлери:POST /api/crm/projects/:name/github— створення лінку, повертає webhook URL + секрет + інструкції налаштуванняGET /api/crm/projects/:name/github— список підключених репозиторіївDELETE /api/crm/projects/:name/github/:id— відключенняPOST /api/webhooks/github— публічний приймач, валідація HMAC-SHA256, rate limit 100 req/хв
shared/github-notifier.ts— Telegram-форматер (іконки за типом події, скоуп проєкту до чату власника)infra/nginx/citadel-crm.conf— location/api/webhooks/github(без auth_basic, таймаут 5с, тіло 64KB)master-bot/api-server.ts— webhook endpoint вставлено перед WS upgradeclients/arc-cli.ts— підкомандиarc github link/links/unlink
Підтримувані події: push, pull_request, workflow_run, issues (покриття 95%).
Безпека: timing-safe перевірка HMAC-SHA256, 32-байтові hex-секрети, тиха відмова при невалідному підписі, rate limit 100/хв, payload макс 50KB.
Воркфлоу налаштування:
arc github link <project> <owner/repo>→ CLI друкує webhook URL + секрет + покрокову інструкцію- CEO вставляє URL/секрет у GitHub Settings → Webhooks
- GitHub надсилає події → master сповіщає власника проєкту через Telegram
49.3.1 — GitHub UI sidebar feed — DONE ✅ (2026-04-28)
P1 MEDIUM — Візуалізація подій GitHub поряд із чатом.
- Міграція 018:
github_events(id, link_id, project_name, event_type, action, summary, url, actor, created_at)+ FK CASCADE githubEventQueriesуshared/db.tshandleGithubWebhookтепер зберігає подію в БД перед Telegram notifyGET /api/crm/projects/:name/github/events?limit=N(max 200)frontend/src/crm/components/github/GithubFeed.jsx— опитування 30с, авто-приховується якщо немає підключених репозиторіїв, іконка на подію, відносний час, клік → GitHub URL- Інтегровано у ContextRail після Pinned notes
- Заміна lucide-react: GitBranch замість Github (іконка відсутня)
49.3.2 — Public guides for Phase 49 features — DONE ✅ (2026-04-28)
P2 LOW — Self-serve документація для воркерів та зовнішніх читачів.
- Нове:
docs/public/guides/github-integration.md(повний walkthrough налаштування, модель безпеки, troubleshooting, API-довідка) - Оновлено:
arc-cli-reference.md(секції команд wrapup + github),troubleshooting.md(hook block / webhook 401 / rate limit),development-setup.md(крок налаштуванняbash scripts/setup-hooks.sh),index.md(лінки + лічильники) - Фікс бага сайдбару:
docs/public/index.mdпарситься/api/crm/docs/treeлише через патерни### Section+- **[Name](path)**. Гайди Phase 49 були додані лише в таблицю "By Mechanism" — формат таблиці парсер ігнорує. Перереєстровано під секцією### Guides, тож вони з'являються в сайдбарі arc-os.co/#docs.
49.4 — GitHub Medium (BACKLOG, P2)
- Опитування API, вкладка GitHub у Workspace, multi-repo вид
49.5 — GitHub Heavy (BACKLOG, P2)
- Двостороння синхронізація задач, auto-PR review воркери
Phase 50: Registration Conversion Lift (COMPLETE)
Конверсія 4% → ціль 9.5% (+138%). Аудит:
docs/design/REGISTRATION_UX_AUDIT.md. 3 P0-блокери відвантажено атомарно за PO Plan A.
50.1 — Auth gate removal + trial credits scaffolding (Stage 1) — DONE ✅ (2026-04-28)
P0 CRITICAL — Задачі #17 + #18, бекенд. Frontend-банер + трекінг токенів — Stage 2.
Зміни auth (задача #17):
loginUser— повертає{ token, needs_verification: true }замість 403 для неверифікованих користувачівregisterUser— повертає userId; маршрут одразу видає JWT (token+needs_verification: true), тож користувач потрапляє в дашборд- Верифікація email все ще обов'язкова для чутливих дій (видача trial, у майбутньому: інвайти, білінг)
- IP-тротлінг на
/api/auth/register: макс 3 реєстрації з IP за 24 год (HTTP 429)
Скаффолдинг trial credits (задача #18):
- Міграція 019:
users.trial_granted_at(одноразовий прапорець) +projects.trial_mode+projects.trial_tokens_remaining(за замовчуванням 100,000) trialQueries:grantToUser,hasReceivedTrial,activateForProject,consumeTokens,hasBudget,getStatus- Endpoint
verify-emailвидає trial при успіху (повертаєtrial_granted: bool) - OAuth (Google + GitHub) callbacks видають trial одразу новим користувачам (email верифіковано провайдером)
handleOnboardingSetupактивує trial, коли API-ключ пропущено + користувачу видано trialworker-spawn.ts— колиproject.trial_mode=1, експортуєANTHROPIC_API_KEYіз vaultPLATFORM_ANTHROPIC_KEY+ ставитьARC_TRIAL_MODE=1/ARC_TRIAL_PROJECT=.... Відмовляє у spawn, якщо бюджет вичерпано чи платформений ключ відсутній.
В очікуванні (Stage 2):
- Трекінг токенів із виводу Claude CLI → декремент
trialQueries.consumeTokens(...) - Endpoint
GET /api/crm/account/trial-statusдля UI - Frontend-банер: "Verify email to unlock 100K free tokens" + progress bar використання trial
Блокер для Stage 2: PLATFORM_ANTHROPIC_KEY має бути у vault. Спершу відвантажити Stage 1, щоб зняття auth gate потрапило в продакшн; trial credits лишаються скаффолдингом, доки vault-ключ не додано.
50.1 — Stage 2 (token tracking + UI banner) — DONE ✅ (2026-04-28)
P0 CRITICAL — Trial credits повністю наживо.
PLATFORM_ANTHROPIC_KEYдодано у vault (окремий Anthropic billing-акаунт, ізольований від dev-ключа)- Трекінг токенів у
child-bot/claude-runner.ts: колиARC_TRIAL_MODE=1, перемикає CLI з--output-format textнаjson, парсить блокusage(input + output + cache_creation), fire-and-forget POST до master/api/internal/trial/consumeіз проєктом + токенами - Endpoint
/api/internal/trial/consume(тільки loopback) декрементує черезtrialQueries.consumeTokens GET /api/crm/account/trial-status— повертаєemail,email_verified,trial_granted,has_trial_active, залишок на проєктTrialBanner.jsxзмонтовано під TopHeader уCrmMainLayout:- Стан 1 — email НЕ верифіковано: бурштиновий банер "Verify email to unlock 100K tokens" + кнопка Resend
- Стан 2 — trial активний: акцентний банер із progress bar (47K / 100K)
- Стан 3 — вичерпано: червоний банер CTA "Add your API key"
- Опитує
/api/crm/account/trial-statusкожні 60с, dismiss у sessionStorage
Результат: повний trial-онбординг наживо. Новий email/password користувач: signup → дашборд ✓ → верифікація email → видано trial → створення проєкту (пропуск API-ключа) → trial_mode=1 → воркери стартують із PLATFORM_ANTHROPIC_KEY → токени декрементуються на кожен виклик Claude → банер показує використання в реальному часі.
OAuth-користувачі повністю пропускають крок верифікації (верифіковано провайдером) і отримують trial при реєстрації.
50.2 — Wizard 5→3 steps (задача #19) — DONE ✅ (2026-04-28)
P0 CRITICAL — Зменшує кумулятивний відтік 69% під час онбордингу.
Старий флоу (5 кроків, 5-8 хвилин):
- Welcome (ім'я + роль)
- Project (назва, ніша, тон, файли, URL)
- Пресет команди
- API Keys (БЛОКЕР — обов'язково)
- Integrations
Новий флоу (3 кроки, ~50 секунд):
- Quick Start — лише ім'я + projectName (злиті 1+2, ~30с)
- API Keys — опційно з trial fallback (пропуск = 100K trial credits, ~10с)
- Integrations — Local Bridge / Telegram (без змін, ~10с)
Відкладені поля → дашборд:
- role/niche/toneOfVoice → порожні дефолти (користувач може заповнити віджет у дашборді пізніше)
- files/urls → порожні (відкладено до підказки "Upload knowledge base" у Wiki)
- teamPreset → авто-дефолт
'software-dev'(користувач редагує воркерів у Worker Studio)
Файл: frontend/src/crm/components/OnboardingWizard.jsx — новий компонент StepQuickStart, StepApiKeys оновлено: дозволяє порожній ключ із підказкою trial-режиму, прибрано StepWelcome/StepProject/StepTeam з render path (функції поки збережені, tree-shake або видалення пізніше).
Результат: час до першого проєкту 5-8 хв → ~50с. Разом із #17 (без email gate) та #18 (trial credits): конверсія 4% → прогнозовано 9.5%.
50.2.1 — Quick Start ReferenceError fix (закриває #25) — DONE ✅ (2026-04-30)
handleCreateProject (shared/routes/onboarding.ts:631) посилався на out-of-scope ownerChatId у фінальному виклику logActivity — змінна в цьому scope називається chatId. Catch-блок перетворював ReferenceError на 500 з error: "ownerChatId is not defined", що проявлялося червоним банером під сіткою Team Preset і блокувало все створення проєктів через Quick Start. Фікс на один символ: ownerChatId → chatId. Побічний ефект: аудит-рядок project_created нарешті записує актора (Phase 50.4 обіцяла це для всіх викликів logActivity, але пропустила цей).
50.3 — Roadmap Redesign (Variant A) — DONE ✅ (2026-04-28)
P1 HIGH — Замінює плаский список фаз таблицею в стилі Linear.
Довідка: ARC OS Mob App-handoff/arc-os-mob-app/project/redesign-arc-os-roadmap.html (Variant A).
Зроблено:
- Новий компонент
RoadmapRedesign.jsx, змонтовано через маршрутApp.jsx - Заголовок: кількість проєктів + поле пошуку
- Банер "Now" — пульсуюча бурштинова крапка, перелічує всі фази
IN PROGRESSв один рядок, показує сумарну кількість відкритих задач + CTA "Open" зі стрибком до першого активного рядка - Чіпи фільтра статусів: All · Active · Complete · Done early · Planned (з лічильниками)
- Таблиця в стилі Linear: chevron · бейдж
P{id}· пігулка статусу · заголовок + теги · progress bar · коли - Рядок активної фази: тепло-бурштиновий відтінок + 2px ліва акцентна смуга (відповідає ДНК IssuesRedesign)
- Розгортувані рядки: клік → markdown-тіло (скрол із обмеженням 320px) + список підфаз
- Список підфаз показує іконку статусу +
P{id}+ заголовок + пігулку статусу на елемент - Парсер тіла витягує:
Owner:,Tags:,Completed: YYYY-MM-DD,Progress: NN%, посилання на задачі#NN(кількість) — fallback на агрегований прогрес підфаз, якщо відсутні - Додано 15 UK-перекладів (Now, Search phases..., Sub-phases, Active тощо)
- Старий
Roadmap.jsxзбережено на диску для fallback-відкату
Файли: frontend/src/crm/pages/RoadmapRedesign.jsx, App.jsx, locales/uk/messages.po
Відкрито: Варіанти B (дошка Now/Next/Later) та C (Gantt + деталі) відкладено — відвантажувати лише якщо PO-сигнал вимагатиме stakeholder/planning view. Variant A покриває ~80% щоденних потреб воркфлоу PO + dev.
Followup (того ж дня): рядки підфаз у розгорнутому батьку тепер теж клікабельні — chevron перемикає inline-тіло + drill-down метаданих на підфазу (відкрита лише одна за раз на батька). Виправляє скаргу користувача, що під-рядки виглядали клікабельними, але нічого не робили.
Phase 50.4 — Audit Trail + OAuth Last-Login (DONE ✅)
GitHub-задачі #16 (P0) + #17 (P1) — виявлені Ludus під час research-аудиту гейміфікації.
gh #16 — поле actor у logActivity() порожнє у всіх callsites:
- 9 callsites у
cli-routes.ts(×3),wiki.ts,skills.ts,restart.ts(×3),onboarding.ts,router.ts— усі передавалиactor=undefined - Колонка
activity_log.actorзавжди булаNULL→ audit trail не мав інформації хто-що-зробив - Фікс: прокинути
extractChatId(req)(абоownerChatIdв onboarding) у 4-й аргумент - Чому P0: майбутня XP/гейміфікація потребує атрибуції актора; розбір security-інцидентів без цього зламаний
gh #17 — OAuth-флоу не оновлює users.last_login:
findOrCreateOAuthUserоновлювавname/avatar_url/role, але пропускавlast_login- Логін email/password уже оновлював коректно (
auth.ts:508) - Зачіпало ~50% користувачів (усі, хто через Google/GitHub OAuth)
- Фікс: додати
last_login: new Date().toISOString()в усі 3 OAuth code paths (повернення за provider_id, повернення за email, нова реєстрація)
Обидва баги — швидкі фікси (~30 хв разом), але розблоковують майбутню роботу з телеметрією.
Phase 51: Stripe Billing — Stage 1 (DB + middleware + status) — DONE ✅ (2026-04-29)
Задача #20 (P0). Атомарний фундамент: схема БД, middleware лімітів плану, endpoint статусу. Stripe SDK = Stage 2.
Модель ціноутворення (OR-семантика лімітів):
| План | Ціна | Проєкти | Воркери |
|---|---|---|---|
| Free | $0 | 1 | 5 |
| Min | $4.99/міс | 5 OR 25 разом | OR-семантика |
| Max | $11.99/міс | 20 OR 150 разом | OR-семантика |
Trial credits — уже наживо (Phase 50.1), одноразово на email, ніколи не поповнюються апгрейдом. Платформена плата покриває лише інфраструктуру; користувачі приносять власний Anthropic-ключ (або Local Bridge безкоштовно).
Компоненти Stage 1:
- Міграція 020: таблиця
subscriptions+stripe_events(лог ідемпотентності) subscriptionQueries: getOrCreate (лінивий free-рядок), upsertFromStripe, findByStripeCustomer, hasFeature- Константа
PLAN_LIMITS— single source of truth для мапінгу план→ліміти→фічі shared/routes/billing.ts:- Middleware
checkPlanLimit(userId, action)— OR-семантика, повертає{allowed, reason, current, limit, plan} GET /api/crm/billing/status— поточний план, використання, ліміти, таблиця цін, фічіPOST /api/crm/billing/checkout-session— заглушка 501 (Stage 2)POST /api/crm/billing/portal-session— заглушка 501 (Stage 2)
- Middleware
- Enforcement підключено до:
handleOnboardingSetup(створення проєкту) → 402 зі структурованою помилкоюhandleCreateWorker(створення воркера) → 402 зі структурованою помилкою
- Реальний підрахунок воркерів (читає
config/workers_registry.jsonкожного проєкту, fallback 5)
Поза Stage 1 (пізніше):
- Stage 2: Stripe SDK (Checkout, webhooks, Customer Portal). Потребує Stripe API-ключів у vault + Products у Stripe Dashboard.
- Stage 3: Frontend Billing UI (Settings → вкладка Billing, SoftLimitModal, картки планів).
- Stage 4: Polish (TOS, діалог GDPR-згоди, end-to-end QA у Stripe test mode).
Acceptance для Stage 1 (перевірено): наявні користувачі отримують авто-створений Free-рядок при першому виклику billing/status; створення нового проєкту користувачем із 1+ проєктами повертає HTTP 402 з {error: "plan_limit_reached", reason, current, limit, plan, message}; те саме для створення воркера; endpoint статусу повертає коректний знімок використання.
Phase 52: Friends & Family Beta Launch (DONE ✅)
Публічний запуск відкладено, доки F&F-валідація не пройде критерії успіху. 10-20 користувачів × 1 місяць = реальний сигнал перед активацією Stripe. За мета-рев'ю PO/Sentinel: інвайт-коди (не whitelist), гібридний туторіал (sample + тур на 5 кроків, не повний у стилі Notion), підтримка 24/7, lifetime-знижка 50% як стимул.
Критерії успіху (мають бути досягнуті перед публічним запуском)
- ≥70% конверсія signup → first_message_sent
- ≥40% returned_after_24h (ретеншн Day 1; галузевий бенчмарк 30-40%)
- ≥25% returned_after_7d (липкість Day 7)
- 0 P0-багів за останні 3 дні бети
- Середній час онбордингу <10 хв (signup → перше повідомлення)
- ≥80% F&F-користувачів оцінюють досвід 4-5/5
Протокол тріажу фідбеку
- 🔴 P0 (фікс того ж дня): блокери, втрата даних, безпека
- 🟡 P1 (фікс перед публічним запуском): UX-тертя, згадане ≥50% F&F
- 🟢 P2 (backlog): nice-to-have, крайні випадки, <20% згадок
Рекрутинг + каденція + стимул
- Рекрутинг: 10-20 особистих Telegram/email звернень (мережа CEO + засновники/інженери з LinkedIn). НЕ розсилка у Twitter/Discord.
- Каденція: Щотижневий дайджест (п'ятниця) у Telegram-каналі — що відвантажено, топ виправленого фідбеку, ETA наступного. Real-time DM для P0-багів. Авто-changelog у футері дашборду.
- Стимул: Lifetime-знижка 50% + бейдж "Founding Member" у профілі + прямий доступ до Slack/Discord після запуску + ім'я на публічній Founders Wall.
Підфази
52.1.1 — Documentation Overhaul (P0/P1) — DONE ✅ (2026-05-04)
- PO-аудит виявив: CLAUDE.md відставав на 4 фази (хедер показував 48.6 як останню, реальний стан 52.1), PRODUCT.md — на 10 фаз (Current Status на 42.10). 0 із 66 .md файлів містили mermaid/PlantUML діаграми. user-guide.md востаннє оновлювався 2026-04-15 (Phase 40.18), бракувало фіч Phase 41-52. shared/routes/docs.ts хардкодив DOCS_DIR=docs/public, приховуючи deep-dives architecture/ + security/ від кінцевих користувачів.
- Синхронізовано CLAUDE.md + PRODUCT.md до Phase 52.1 (endpoints 68→70+, модулі 17→19, Open Issues #20-26).
- Додано 5 mermaid-блоків: architecture graph TB, ER erDiagram, phase timeline gantt, Phase 48 before/after graph LR, onboarding sequenceDiagram.
- Symlink docs/architecture/* + docs/security/* під docs/public/, щоб відкрити просунуту документацію без дублювання (safePath поважає symlinks через path.resolve, без realpath).
- Переписано user-guide.md, додано §21 Timeline, §22 Trial+Billing, §23 Beta Access (інвайт-коди).
- Задачі #21-26 створені через arc CLI, потім закриті в коміті 9e78d15.
52.1 UK debt closure (#32, #33, #34) — DONE ✅ (2026-05-17)
- Розблоковує Phase 59 (мультилокальне розширення). Закрито 3 задачі:
- #33 (Phase 52.1.6 переклад symlink-документів): AI-переклад 5 відсутніх UK arch-документів (crm-backend 320L, dual-agent-flow 329L, evolving-intelligence 370L, phase-20-federation 290L, phase-45-e2ee 985L = 2294 рядки) через 5 паралельних Claude-субагентів із зафіксованим глосарієм (Orchestration System → Система оркестрації, worker → воркер не відмінюється, skill → скіл, імена воркерів-персонажів + крипто-примітиви + CLI-команди ніколи не перекладаються, неформальний тон на "ти"). Паритет UK-архітектури: 9 EN = 9 UK.
- #32 (Phase 52.1.5 людська вичитка 17 UK-документів): quality-pass носія української на 19 UK-документах (index/features/api-ref/3 product/13 guides/4 arch). Вердикт B+/A-, нуль файлів потребують повного перекладу заново. 6 inline-фіксів: 1× залишок "Операційна система" у product/overview.md, 5× формальне Ви → неформальне ти в index.md + telegram-bots.md. Довгостроковий quality loop = feedback widget Phase 59.4 (#122) після відвантаження.
- #34 (Phase 52.1.7 запис відео-walkthrough): уточнення скоупу — 10 production-grade текстових сценаріїв у docs/public/media/scripts/ уже слугують авторитетним walkthrough-результатом (вбудовані в user guide, ~21 хв загального хронометражу, voiceover + таймінг + візуал усе написано). Запис відео потребує ~14-18 год роботи лише CEO, не на критичному шляху. Не відкладено за правилом never-defer — перепогоджено оригінальний скоуп Phase 52.1.7; сценарії І Є результатом.
52.1.5 — Video walkthrough scripts (P2) — DONE ✅ (2026-05-06)
- 10 production-ready розкадровок у
docs/public/media/scripts/для відео ключових user-journey. Кожен сценарій прив'язано до цільового гайду через лінкEmbeds in:; після запису вставити Loom URL у відповідний блок🎬 Video placeholder. - Файли (всього 11, 625 LOC): README (головний TOC + порядок запису + план batch-сесій), 01-onboarding (3:00), 02-bridge-setup (1:30, у парі з наявним SHOTLIST), 03-workspace-tour (3:00), 04-worker-studio (2:00), 05-cloud-pm-notebooklm (1:30), 06-issues-wiki (2:00), 07-skills-sage (2:00), 08-telegram (1:30), 09-trial-billing (1:30), 10-arc-cli (1:30).
- Структура кожного сценарію: pre-flight чекліст + таблиця розкадровки (час | дія на екрані | EN voiceover | UK voiceover | вшитий підпис) + production-нотатки (zoom курсора, музика, B-roll, редагування чутливого) + критерії успіху.
- Загальний хронометраж ~21 хв, трудомісткість запису 14-18 годин включно з монтажем. Порядок запису оптимізовано для мінімізації перемикань стану застосунку (5 web-only відео за один ранковий сеанс на свіжому проєкті, 5 mixed-surface по обіді).
- Задача на фактичний запис відео = Phase 52.1.7 (або коли CEO/дизайнер запланують день запису).
52.1.4 — Bulk UK translation pass (P1) — DONE ✅ (2026-05-05)
- Phase 52.1.3 додала фреймворк lang-fallback, але перекладено було лише
index.md(~150 LOC). Решта 17 user-facing гайдів усе ще віддавалися EN із банером. scripts/translate-docs.ts(Bun, 130 LOC) — масовий переклад черезclaude -psubprocess:- Рекурсивно обходить
docs/public/*.md, пропускаючи symlinks (deep-architecture документи),uk/,media/та вже перекладенийindex.md. - Системний промпт: 8 строгих правил — зберігати markdown-синтаксис + код-блоки + mermaid + URL + продуктові ідентифікатори (Master Bot, Sage Worker, ARC CLI тощо), перекладати лише прозу, природна українська, ти-форма для другої особи.
- На файл: stdin до
claude -p --output-format text --max-turns 1, stdout пишеться уdocs/public/uk/<rel>. - Ідемпотентно: пропуск якщо UK існує,
--forceдля повторного перекладу, аргумент<relpath>для режиму одного файлу.
- Рекурсивно обходить
- 17/17 файлів перекладено, 0 збоїв. Загалом ~17 хв wall time. Найбільший файл user-guide.md (25 KB → 27 KB UK за 3:23).
- Покриття: api/api-reference, product/{overview,pain-points,competitive-analysis}, guides/{user-guide,local-bridge,arc-cli-reference,telegram-bots,troubleshooting,development-setup,creating-skills,multi-project-skills,notebooklm-bridge,github-integration}, architecture/{database-schema,intelligence-layer,workers-and-intelligence,system-report-21.5}.
- Якість: базова 90-95% за вибірковими перевірками (Master Bot/ідентифікатори збережені, mermaid-блоки незаймані, ASCII-арт збережено, ER-діаграма ціла, природна українська проза). Прохід людської вичитки відкладено до Phase 52.1.5 (задачу створено).
- Symlink-овані deep-architecture документи (Phase 20/45 E2EE/dual-agent-flow тощо) НЕ авто-перекладені — вони вказують на docs/architecture/* поза public/. Буде зроблено вручну як Phase 52.1.6 за потреби.
52.1.3 — Docs UX Polish (P1) — DONE ✅ (2026-05-05)
- Фідбек PO: 3 UX-прогалини в arc-os.co/#docs.
- Скрол до якоря — лінки на кшталт
[§22 Trial+Billing](user-guide.md#22-trial-credits--billing)нічого не робили по кліку; перехід кидав на початок файлу. - Пошук — фільтр сайдбару знаходив записи, але клік не вів до збігу в контенті, без підсвічування в тексті.
- i18n — документація була лише EN, попри повний @lingui i18n у застосунку (438 рядків EN/UK).
- Скрол до якоря — лінки на кшталт
- Фікси:
frontend/src/crm/pages/Docs.jsxпереписано (244 → 360 LOC):- Кастомні heading-компоненти вставляють GitHub-style slug
idна h1-h6. useEffectнаactiveAnchor+loadingContent→scrollIntoViewпісля рендеру.- Пошук використовує пост-рендерний TreeWalker для обгортання збігів у
<mark class="docs-search-mark">, скролить до першого збігу, показує лічильник "N match(es) on this page". - Esc чистить пошук, внутрішні лінки
[anchor](#id)скролять плавно без перезавантаження. - Читає локаль із
useLingui(), надсилає?lang=до API, показує банер коли віддано EN fallback.
- Кастомні heading-компоненти вставляють GitHub-style slug
shared/routes/docs.ts— хелперresolveLangPath(), обидваhandleDocsTree+handleDocsFileприймають?lang=. Відповідь міститьserved_lang,is_fallback,requested_lang.shared/routes/router.ts— передає query доhandleDocsTree.docs/public/uk/index.md— повний український переклад індексу документації (~150 LOC). Інші UK-гайди поки що через fallback; фреймворк готовий.docs/public/api/api-reference.md— задокументовано query?lang=.
- Задача на повний UK-переклад (Phase 52.1.4) — решта 18 гайдів.
52.1.2 — overview.md How-It-Works clarity (P2) — DONE ✅ (2026-05-04)
- Питання PO: діаграма How-It-Works показувала
CRM Dashboard / Telegramяк рівнозначні точки входу, натякаючи що Telegram обов'язковий. - Реальність: web CRM — основний (~95% використання), Telegram — мобільний компаньйон (
/status, чат child-бота, боти на воркера), ARC CLI — для локальної розробки (arc <project> devчерез Local Bridge). - Фікс: замінено ASCII-арт на mermaid graph TB. Жирне ребро для основного CRM-шляху; пунктирні ребра для опційних Telegram + CLI. Додано таблицю "Why three channels?". Уточнено one-liner.
- Оновлено цифри: 62→70+ endpoints, 40.18→52.1 фази, +рядок E2EE. Get Started: блок self-hosted замінено на invite-gated SaaS флоу згідно з memory feedback (Citadel OS не пропонується для self-hosting клієнтами).
- Коміт: 08c23be.
52.1 — Invite Codes + Feedback Channel (P0, 1 день) — DONE ✅ (2026-04-29)
- Міграція 021: таблиця
invites(code PK, created_by, used_by, parent_invite_code, status, note) inviteQueries: generateBatch, findByCode, consume, listByOwner, revoke, countActive, countUsed- Формат коду:
arc-XXXX-XXXX(8 hex-символів через дефіс, crypto.randomBytes) - Гейт реєстрації:
/api/auth/registerвимагає полеinvite_code, інакше 403 invite_required - Адмін-endpoints:
POST/GET/DELETE /api/crm/admin/invites(перевірка ролі admin) - ARC CLI:
arc invites generate --count N,arc invites list,arc invites revoke <code> - Фронтенд: форма реєстрації отримує моноширинне поле інвайт-коду з лінком на @arcos_beta_feedback
- TODO (ручні операції): створити Telegram-канал @arcos_beta_feedback, згенерувати перші 5 кодів, надіслати друзям
52.1.1 — beta plan tier для F&F-тестерів (закриває #20) — DONE ✅ (2026-04-30)
- F&F-тестери мають користуватися системою без упирання в ліміти Free-тарифу (1 проєкт / 5 воркерів), але не повинні ставати role=admin (який несе крос-тенантні модераторські повноваження).
- Новий план
betaуPLAN_LIMITS:projects: Infinity,workers: Infinity, усі feature-прапорці Max-рівня. checkPlanLimit()робить short-circuit колиsubscription.plan === 'beta', на додачу доuser.role === 'admin'.- Призначення — ручний SQL upsert у
subscriptions(CLI-підкоманди поки немає — додати коли когорта зросте). - Перше призначення реальному F&F-користувачу (email не в git; зафіксовано внутрішньо).
52.2 — Sample Project + Onboarding Tour (P0, 0.5 дня)
- Після першої реєстрації авто-створення demo-проєкту "Welcome to Arc OS" із 3 sample-воркерами + 2 прикладами повідомлень чату
- Тур React-joyride: 5 кроків (Welcome → Sidebar → Workspace → Send message → Wiki/Issues), кнопка Skip, одноразово на користувача (прапорець у localStorage)
- Вбудоване Loom-відео (2-3 хв walkthrough від CEO) при першому візиті дашборду
52.3 — Funnel Analytics (P0, 1 день)
- 5 подій трекаються в
activity_log:signup_completed,email_verified,first_project_created,first_message_sent,returned_after_24h - Адмін-сторінка "F&F Funnel" — відсотки конверсії крок-до-кроку, список застряглих користувачів (signup-no-verify, verify-no-project)
- Активація події
returned_after_24hчерез щоденний cron, що перевіряє дельти last_login 52.4 — Error UX + Status Page (P1, 1 день) - Аудит типових станів помилок: порожній список воркерів, master не відповідає, trial вичерпано, мережа лежить
- Frontend toast-компонент для graceful fallbacks (заміна generic "Error" alerts)
- Проста статична сторінка
status.arc-os.co(HTML + JSON-опитування /api/master/health) — окремий домен або шлях - Telegram-канал
@arcos_statusдля оновлень про інциденти
52.5 — Doc Cleanup (P2, 0.5 дня)
- Виправити колізію назв Phase 48.7 у ROADMAP (Docker split ТА Auth Gateway мають однаковий номер)
- Чистка застарілих записів реєстру (watchdog-шум
solar/arc-marketing/gapap/pmr-18) - Бенчмарк cold-start latency для follow-up Phase 48.6 (реальний таймінг wake-up)
52.6 — Uptime Monitoring (P1, 0.5 дня)
- UptimeRobot free tier — пінг
/api/master/healthкожні 5 хв - Telegram alert на failure → DM CEO негайно
- Alert на recovery теж — щоб знати що відновилося
52.7 — Buffer Day (P0, 0.5 дня)
- Зарезервовано для неминучих проблем, знайдених під час налаштування тестування
- Перша хвиля інвайтів (5 друзів) — спостерігати → фіксити → запрошувати наступних 5
Разом: 5 днів до F&F-ready.
- DEBT-5: декомпозиція UIScene.js (частково зроблено в ac36a5f — lazy-loading + dedup utils; Phaser-офіс — низький пріоритет)
- Редактор спрайтів агентів + drag-and-drop меблів
- Редактор розкладки офісу + theme packs
- Stripe billing + usage metering
Phase 53: Post-F&F Notifications (DONE ✅)
Mobile UX gap: коли CEO працює через CRM/CLI/bridge, per-worker TG-боти мовчать, бо
child-bot/telegram.tsжорстко блокує всіtgSendу workspace mode (інакше відповіді з CRM протікали б у TG-чат). Phase 53 додає паралельний events-only канал, що обходить gate — пінги, ніколи не дублює розмову.
53.11.1 — Bot Creation Wizard (закриває #48) — DONE ✅ (2026-05-10)
- Дані F&F-бети: медіана 3-7 воркерів на проєкт = 3-7 ручних створень у @BotFather × ~4-5 хв кожне = 20-25 хв болю онбордингу. Тіло задачі позиціонувало це як конверсійний блокер для нових інвайтів.
- Бекенд: новий
POST /api/crm/projects/:name/workers/:id/suggest-bot-usernameповертає 5 кандидатів (<project>_<worker>_bot+ 4 нумеровані fallback'и). Slugifier замінює дефіси на підкреслення (TG забороняє дефіси в username — gotcha проти project/worker ID). Обрізає >32 символів, спершу зменшуючи worker-частину; доповнює <5 символів підкресленнями. Відфільтровує username'и, уже прив'язані у vault цього CRM. НовийPOST /api/crm/metrics/wizardпише рядкиactivity_log(event_type=wizard_metric); приземлився під/api/crm/, а не оригінальним/api/internal/*із задачі (фронтенд не дістає loopback). НовийGET /api/crm/analytics/wizard-metrics?hours=168агрегує воронку черезjson_extract. - Фронтенд:
BotCreationWizard.jsx(~505 LOC) — 3-кроковий модал із progress bar, copy-to-clipboard хелперами, кнопкою deep-link на BotFather (https://t.me/BotFather), real-time regex-валідацією токена (\d+:[A-Za-z0-9_-]{20,}). Мобільна ширина =min(440px, calc(100vw - 24px)). Підключено уWorkerStudio.jsxяк основний CTA "Set up with wizard"; наявне поле ручної вставки згорнуто у<details>для power-користувачів (additive, без міграції). - Телеметрія: 6 подій (started / username_selected / botfather_opened / token_pasted / completed / abandoned) із payload
duration_ms+attempts. ВіджетWizardMetricsCardна сторінці Analytics показує starts / completions / abandons / success rate / avg duration / avg attempts (останні 7 днів, прихований докиstarts > 0). - 21 новий unit-тест у
tests/bot-username-suggest.test.ts(крайні випадки slugify, обрізання до 32 символів, унікальність, доповнення до мінімуму 5 символів). Разом 83 кейси / 205 expects, усі зелені. Frontend-бандл 409 → 414 KB (+5 KB). - Архітектурні інваріанти дотримано за
docs/architecture/onboarding-wizard.md(§ "honored"): gate WORKSPACE_MODE незайманий (тільки CRM-сторона), унікальність ботів Phase 53.4 досі забезпечується уhandleSetWorkerTelegramToken, vault SSOT збережено (без нових ключів, лише читання:bot_usernameдля фільтрації колізій), контрактparseCallbackнезайманий. - 53.11.2 (Topics Mode, #49) лишається BLOCKED на design doc + Sentinel sign-off — окремий шип.
53.11 — Multi-Worker TG UX Overhaul (задачі #48, #49) — IN PROGRESS (2026-05-10)
- Дані F&F-бети: медіана 3-7 воркерів на проєкт = 3-7 ручних створень бота через @BotFather + 3-7 окремих TG чатів. Mobile fragmentation = real onboarding/daily-use friction. Розбито на дві задачі, шипимо послідовно.
- 53.11.1 (#48) — Bot Creation Wizard — DONE ✅ (2026-05-10) — див. запис вище.
- 53.11.2 (#49) — Telegram Topics Mode, P1, ~12-15 днів після затвердження дизайну. BLOCKED на design doc (
docs/architecture/PHASE_53_11_TOPICS_MODE.md) + Sentinel threat-model sign-off. Модель бота на проєкт (зсув vault-неймспейсуworker:*:*→project:*+ таблицяtopic_worker_map), єдиний tmuxproject-bot-<name>long-poll, parseCallback-роутер черезmessage_thread_id. Навмисно ламає аудит-інваріанти #3 (CEO_CHAT_ID gate → from.id), #4 (унікальність ботів), #5 (vault SSOT), #6 (fs persistence). Вимога resilience: per-worker try/catch + circuit breaker (краш одного воркера ≠ краш усіх). Opt-in feature flag, beta-gated rollout (1-2 power-користувачі → ≥80% prefer → розширення), 7-денний grace period для відкату. - Discovery-розмова: рев'ю PO + Developer підтвердило оцінку Sprint 2 5-7д → 12-15д (зсув process-моделі, не розширення). Міграція тільки opt-in (примусова зламала б робочі F&F-прив'язки).
53.21 — Sentinel P2 batch 2 (trial-tenant + feedback gate + Docker pin) — DONE ✅ (2026-05-12, закриває #107 #108 #109)
- #107 P2-10 —
/api/internal/trial/consumecross-tenant drain: endpoint приймав{project, tokens}без перевірки власності. Підроблений envARC_TRIAL_PROJECT(або баг на стороні master) міг спричинити декремент trial-бюджету чужого проєкту. Фікс: вимагатиowner_idу тілі + звіряти зprojects.owner_idіз БД; відмова 403 при розбіжності з warn-логом[trial/consume] owner mismatchдля аудиту.shared/worker-spawn.tsтепер експортуєARC_TRIAL_OWNER='${project.owner_id}'поруч ізARC_TRIAL_PROJECT(обидві гілки: legacyrestartChild+ parallel worker).child-bot/claude-runner.ts:200прокидає обидва значення в consume POST. - #108 P2-11 — дрейф атрибуції
handleSubmitFeedback: викликач міг надіслати фідбек на будь-яку назву проєкту — спотворював per-project метрики фідбеку + порушував патерн tenant isolation (низька серйозність, бо фідбек іде лише адміну, але варто виправити). Додано перевіркуcanAccessProject(registry, chatId, body.project); відмова 403 якщо користувач не має доступу до проєкту. Порожній/глобальний фідбек все одно проходить (немає проєкту = немає tenant scope). - #109 P2-12 — Docker-образи з плаваючими тегами:
oven/bun:1,node:22-alpine,nginxinc/nginx-unprivileged:alpineусі були плаваючими. Upstream може підмінити вміст (скомпрометований реєстр, зловмисний maintainer, ransomware-on-tag). Запінено до поточних digest'ів@sha256:, розрезолвлених через Docker Hub manifest API.scripts/refresh-docker-digests.shавтоматизує щорічне оновлення: запитує заголовокdocker-content-digestдля multi-arch індексу кожного нашого образу; оператор копіює нові хеші у дваDockerfile, запускаєdocker compose build --no-cacheдля перевірки. Каденція оновлення: щорічно або при розкритому CVE для будь-якої запіненої бази. - 100/242 expects досі зелені;
tsc --noEmit0 помилок. - Статус: 6 із 10 P2 закрито (P2-3/6/9 із Phase 53.20 + P2-10/11/12 тут). Лишилися: P2-1 (vault KDF без солі), P2-2 (device-коди в Map), P2-4 (Master CryptoKey extractable), P2-5 (PII sanitizer обгорнути всі записи логів). Усі середньої трудомісткості — окремий спринт.
53.20 — Sentinel P2 fast-wins batch — DONE ✅ (2026-05-12, закриває #104 #105 #106)
- 3 P2 зі статичного аудиту (
audit-2026-05-10.md) закриті одним батчем. Кожен малий + ізольований; пакетування зменшує deploy churn. - #104 P2-3 — TOTP timing oracle (
shared/totp.ts:78):verifyTotpвикористовував рядкове===для порівняння введеного користувачем коду з обчисленим HOTP. JS обриває на першому відмінному байті — спостережуваний timing leak. Замінено наtimingSafeEqualнаBufferах однакової довжини + early-return guard наcode.length !== 6. Простір 6-значних кодів малий (1M), але TOTP-коди мають grace period±window(3 валідні кандидати на виклик), і витік префіксу за таймінгом суттєво звужує цей простір. - #105 P2-6 — покриття патернів PII sanitizer (
shared/pii-sanitizer.ts): оригінальний набір regex ловив лише Anthropic-стильsk-ant-*/ загальнийsk-<alnum>{20+}. Додано патерни для: OpenAIsk-proj-*_*, Stripesk_live_*/sk_test_*/rk_*, webhook-секретиwhsec_*, GitHubghp_/gho_/ghu_/ghs_/ghr_+github_pat_*, Slackxoxb-*/xoxp-*/xoxe.*, AWSAKIA*+ евристикаaws_secret_access_key, GoogleGOCSPX-*, Telegram bot<digits>:<token>, загальнийBearer <jwt-ish>. Також виправлено історичний баг email-патерну[A-Z|a-z](був char class із літеральним|, працював для ASCII, але неправильної форми; тепер[A-Za-z]). Спіймано footgun*/-в-JSDoc під час власної правки (урок 6 ізremediation-report-2026-05-10.md— той самий що Phase 53.13 #44). - #106 P2-9 — rate-limit на
/api/cli/device/new: endpoint видає device-код → 10-хв верифікація → 30-денний CLI-токен. Без тротлінгу = атакувальник спамить/newдля генерації фішингових кодів (жертва вводитьuser_codeатакувальника на сторінці верифікації → атакувальник отримує 30-денний прив'язаний токен). Додано per-IPcheckEmailRate("device-new:ip:<ip>", 3/min)із 429 при переповненні. ЕкспортованоcheckEmailRate+clientIpзmaster-bot/routes/auth.tsдля кросс-маршрутного перевикористання (попри legacy-назву,checkEmailRate— загальний token-bucket примітив). - 100/242 expects досі зелені;
tsc --noEmit0 помилок.
53.19 — mTLS CF Authenticated Origin Pulls — ACTIVATED IN PROD ✅ (2026-06-01, #96 закрито)
Stage 2 deploy 2026-06-01: CF dashboard Global toggle ON → CF_MTLS_ENABLE=1 bash scripts/vps-sync.sh успішно → nginx ssl_verify_client on активний. Перевірка: CA=OK, directives=1, https://arc-os.co/api/master/health HTTP/2 200, прямий TLS handshake по IP показує Request CERT (13) — запити без сертифіката вмирають до HTTP. Defense-in-depth Layer 3 поверх geo lockdown тепер наживо. CA закінчується 2029-11-01 → задача-нагадування про ротацію #318.
Підготовка в репо (оригінальне приземлення Phase 53.19, 2026-05-11):
- Закриває останній вектор обходу після Phase 53.17 / PT-CF1 (lockdown
geo $cf_origin): навіть між cron-оновленнями CF IP-діапазонів, не-CF з'єднання, що підробляєHost: arc-os.co, тепер вмиратиме на TLS handshake (до досягнення nginx HTTP), бо не може пред'явити клієнтський сертифікат, підписаний Cloudflare CA. - Defense-in-depth, не основний захист. Geo lockdown лишається основним. mTLS ловить рідкісне вікно між публікацією CF-діапазонів та підхопленням нашим cron.
- Артефакти приземлено 2026-05-11, активовано 2026-06-01:
infra/nginx/cloudflare-origin-pull-ca.pem— CF Origin Pull CA (2154 байти,CN=origin-pull.cloudflare.net, дійсний до 2029-11-01)infra/nginx/snippets/cloudflare-mtls-enabled.conf— фактичні директивиssl_client_certificate+ssl_verify_client oninfra/nginx/snippets/cloudflare-mtls-disabled.conf— no-op плейсхолдер (mTLS вимкнено)infra/nginx/citadel-crm.confarc-os.co :443 —include /etc/nginx/snippets/cloudflare-mtls.conf;scripts/vps-sync.shStep 2 — завжди копіює CA-сертифікат; за замовчуванням копіює disabled сніпет.CF_MTLS_ENABLE=1 bash scripts/vps-sync.shкопіює enabled сніпет.scripts/vps-sync.shStep 6 — нова assertionSEC-CF3перевіряє присутність CA + відповідність стану сніпета прапорцю.infra/vps/cloudflare-origin-pulls-setup.md— переписано з 3-етапним runbook (перемикач у CF dashboard → деплойCF_MTLS_ENABLE=1→ перевірка), rollback, нагадування про ротацію CA.
- Замінив попередній
infra/nginx/cloudflare-origin-pull.conf(тільки документація, замінено парою сніпетів). - Флоу активації (коли користувач готовий):
- CF Dashboard: зона arc-os.co → SSL/TLS → Origin Server → Authenticated Origin Pulls → ON
curl -sI https://arc-os.co/має все ще повертати 200/401 (~60с на пропагацію CF)CF_MTLS_ENABLE=1 bash scripts/vps-sync.shSEC-CF3 mTLS state: CA=OK directives=1 (expected: ENABLED / directives=1)- Прямий по IP
https://62.171.128.248/має падати на TLS handshake (було 403 через geo; тепер SSL-помилка)
- Безпека: двоетапна активація запобігає сценарію повного outage, коли origin вимагає mTLS, а CF його не надсилає (
ERR_SSL_PROTOCOL_ERRORбез ясної помилки в браузері). Дефолтний деплой завжди безпечний — disabled-сніпет тримає nginx валідним + mTLS вимкненим до явного прапорця.
53.18.2 — Secret rotation runbook + script для #103 — DONE ✅ (2026-05-11)
- Sentinel #103 (5 секретів витекли через
bash -xпід час prod-дебагу) потребує ротації у 5 дашбордах провайдерів: Anthropic, BotFather (×2: master + arc-v2 child), GitHub OAuth, Google OAuth. Ротація = ручні кліки в дашбордах + атомарна заміна.env+ цикл рестарту. Без runbook легко зламати прод, відкликавши старе до встановлення нового. infra/vps/secret-rotation-runbook.md— покроково на провайдера з правильним порядком (зібрати нове СПЕРШУ, замінити, перевірити, відкликати старе ОСТАННІМ) + повний шлях відкату.scripts/rotate-secrets.sh— інтерактивний скрипт, що:- Бекапить поточний
.envу.env.bak-pre-rotate-<ts> - Запитує кожне нове значення (прихований ввід, без scrollback)
- Атомарна заміна
.envчерезtmp + mv tmux kill-server+ respawn через wrapper-basedstart-*.sh- Health check + скан на витік секретів (5 токенів мають мати 0 входжень у
ps) - Друкує шлях відкату + фінальний TODO
- Бекапить поточний
- Шлях відкату:
cp .env.bak-pre-rotate-<ts> .env && tmux kill-server && bash scripts/start-master-bot.sh(з PT тощо). - Токен PT-бота не в списку ротації — токен
ptживе уconfig/vault.json(AES-256-GCM), ніколи не був експонований. - Після того як користувач пройде ротацію + перевірку:
arc issue update 103 --status closed.
53.18.1 — Wrapper-script fix для витоку секретів — DONE ✅ (2026-05-11)
- Phase 53.18 (коміт
ca7c584) замінилаbash -c "export X='val'; bun ..."наtmux -e VAR=val ... bun .... Live-перевірка після деплою показала, що обидві форми мають ідентичну експозицію: будь-який CLI-аргумент потрапляє в/proc/PID/cmdlineнезалежно від того, чи цеexport-вираз усерединіbash -c, чи прапорець-eдляtmux. Оригінальна рекомендація Sentinel базувалася на неправильному прочитанні документації tmux (прапорець-eпередає env у нову сесію, але саме значення все одно є звичайним CLI-аргументом). - Справжній фікс: три wrapper-скрипти (
run-master.sh,run-child-arc-v2.sh,run-child-pt.sh), які source-ять.envусередині через bash builtinsource— у argv іде шлях до файлу, значення лишаються в пам'яті shell.start-*.shскоротилися до 3-рядкового kill+respawn wrapper'а. - Master-скрипт:
tmux new-session -d -s citadel-master /opt/repos/citadel-v2/scripts/run-master.sh- результуючий cmdline tmux: чистий (тільки шлях до файлу)
- результуючий cmdline bash:
/bin/bash /opt/.../run-master.sh— без секретів - результуючий cmdline bun:
bun run bot.ts(черезexec) — без секретів
- PT-скрипт: vault-дешифрування відбувається всередині wrapper'а через
bun -e "<inline decrypt>"; розшифрований PT_TOKEN тече через shell-змінну, ніколи через argv. - Витік до Phase 53.18:
/proc/cmdlineSERVER-демона tmux був заморожений з 2026-04-24 із найпершою командою запуску, що містилаexport MASTER_BOT_TOKEN='...' GITHUB_CLIENT_SECRET='...'. Знадобивсяtmux kill-server+ свіжий respawn для очищення. - Очікує перевірки: деплой +
ps -eo cmd | grep -c <secret-pattern>має повертати 0 для всіх 5 відстежуваних токенів.
53.18 — tmux -e flag refactor: закрити витік секретів через /proc/cmdline (закриває #102) — SUPERSEDED через 53.18.1 (2026-05-11)
- Pentest Sentinel 2026-05-11 виявив, що
tmux new-session ... "export MASTER_BOT_TOKEN='X'; bun run bot.ts"зберігає УСІ експортовані значення в/proc/PID/cmdline— видимо будь-якому non-root процесу черезps aux. Зачіпає 5 call-sites:start-master-bot.sh(найгірший — містить реальні prod-секретиMASTER_BOT_TOKEN,GITHUB_CLIENT_SECRET,GOOGLE_CLIENT_SECRET),start-child-bot.sh,start-child-pt.sh,master-bot/bot.ts:restartWorkspaceBot,shared/routes/onboarding.ts:startWorkspaceBot. - Фікс: кожен call site переписано на
tmux new-session ... -e VAR=val ... bun run bot.ts(server-side env-pass прапорець tmux) замістьbash -c "export X='val'; ...". Прапорець-eкладе значення в server-side таблицю середовища tmux — ніколи в командний рядок, ніколи в/proc/cmdline. - Workspace-mode call sites (
restartWorkspaceBot/startWorkspaceBot) ТАКОЖ позбулися ланцюжкаset -a && source .env && set +a— авто-завантаження.envBun'ом із cwd + батьківських директорій обробляєANTHROPIC_API_KEYтощо автоматично, коли Bun стартує вchild-bot/(Phase 53.16 уже писала per-project перекриття уchild-bot/.env). - Після деплою:
ps aux | grep bunмає показувати лишеbun run bot.tsбез видимих експортованих токенів. Команда перевірки в post-deploy assertions (SEC-CB2 буде додано). - Компаньйон до Sentinel P1-1 #68 (display_name RCE через інтерполяцію bash -c): той самий клас причини —
bash -cз інтерполяцією небезпечний двома способами водночас (injection ТА disclosure).tmux -eзакриває обидва.
53.16.1 — Завершення міграції Sprint 2 P1-14 + виявлено tmux secret-leak P0 — DONE ✅ / IN PROGRESS (2026-05-11)
- Phase 53.16 / #80 P1-14 прибрала хардкод fallback
CEO_CHAT_ID = 474903718із 6 файлів + додалаthrow if env unsetуchild-bot/bot.ts:99. Неповна міграція:.env,start-child-bot.sh,.env.exampleне були оновлені, тож перший рестарт master 2026-05-11 поклав усі child-боти при старті. Sentinel екстрено відновив прод (поставивCEO_CHAT_ID=474903718у/opt/repos/citadel-v2/.env, пропатчив репо), і боти повернулися на loopback (PT-CB1 перевірено: SEC-CB1 = 0). - Патчі репо приземлені:
scripts/start-child-bot.sh:42—export CEO_CHAT_ID='${CEO_CHAT_ID:-}'.env.example— плейсхолдерCEO_CHAT_ID=YOUR_TELEGRAM_CHAT_ID(урок P1-14 — навіть chat-id це зв'язка з персональним ідентифікатором, не хардкодити)..gitignore— виняток!.env.example, щоб шаблон відстежувався.
- НОВИЙ P0 #102 виявлено під час того ж prod-дебагу:
ps auxпоказавtmux new-session -d ... "export MASTER_BOT_TOKEN='...'; export GITHUB_CLIENT_SECRET='...'; bun run bot.ts"зберігає УСІ секрети в/proc/PID/cmdline— видимо будь-якому non-root процесу. Зачіпає всіstart-*.sh+restartWorkspaceBot+startWorkspaceBot. Фікс у черзі на Phase 53.18: прапорецьtmux new-session -e VAR=val. - CRITICAL #103 — 5 секретів витекли в транскрипт сесії Sentinel через
bash -xпід час дебагу:ANTHROPIC_API_KEY,MASTER_BOT_TOKEN,CITADEL_BOT_TOKEN,GITHUB_CLIENT_SECRET,GOOGLE_CLIENT_SECRET. Потрібна негайна ротація (кроки на провайдера в тілі задачі). Порушення директиви Sentinel залоговано для розбору. - Урок: будь-яка зміна коду, що вимагає env, МУСИТЬ супроводжуватися плейсхолдером у
.env.example+ export-проводкою вstart-*.sh. Додати doc-coverage hook для цього в майбутньому.
53.17.5 — mTLS Authenticated Origin Pulls (Stage 0 prep, чекає дії користувача в CF dashboard) — IN PROGRESS (2026-05-11, #96)
- Defense-in-depth поверх lockdown Phase 53.17
geo $cf_origin— закриває вікно TLS handshake (атакувальники, що дізналися IP + підробляють Host-заголовок, сьогодні все ще досягають TLS; з mTLS приймається лише клієнтський сертифікат, підписаний CA Cloudflare). - Stage 0 (DONE 2026-05-11): CF Origin Pull CA завантажено у
/etc/ssl/cloudflare/origin-pull-ca.pem(issuerCN=origin-pull.cloudflare.net, дійсний до2029-11-01). Репо SSOT:infra/nginx/cloudflare-origin-pull.conf(docs-only сніпет, ще не включений зcitadel-crm.conf) +infra/vps/cloudflare-origin-pulls-setup.md(повний 3-етапний runbook із rollback). - Stage 1 (ДІЯ КОРИСТУВАЧА): Увімкнути
Authenticated Origin Pullsу дашборді Cloudflare (зона arc-os.co → SSL/TLS → Origin Server). Перевірити, що CF-трафік усе ще проходить через ~60с. - Stage 2 (після перевірки Stage 1): Додати
ssl_client_certificate /etc/ssl/cloudflare/origin-pull-ca.pem; ssl_verify_client on;у server-блок arc-os.co:443вinfra/nginx/citadel-crm.conf. Деплой через vps-sync. - Rollback:
sed -i 's/ssl_verify_client on/ssl_verify_client optional/'+ nginx reload + CF toggle OFF. - Чому два етапи: якщо користувач вимкне CF toggle при
ssl_verify_client on— повний outage (без ясної помилки в браузері). Перехід optional → on виконується тільки після перевірки CF-сторони.
53.17.2 + 53.17.4 — Репо SSOT для sshd_config + fail2ban + UFW docs + server_tokens off — DONE ✅ (2026-05-11, закриває #93 #95)
- Прямий follow-up до Phase 53.17 — Sentinel автономно загартував SSH/fail2ban на проді 2026-05-10 (PT-IM1/IM2), але конфіги жили лише в
/etc/ssh/sshd_config+/etc/fail2ban/jail.local. Ця підфаза піднімає їх у репо SSOT, щоб будь-який rebuild / новий VPS міг відтворити hardening без повторного пентесту. infra/vps/sshd_config— top-levelPermitRootLogin prohibit-password+PasswordAuthentication no, документує ризик регенерації50-cloud-init.conf.infra/vps/fail2ban-jail.local— sshd jail (maxretry=3 findtime=10m bantime=24h backend=systemd mode=aggressive).infra/vps/ufw-rules.md— поточний стан (імперативний) + команди для rebuild + drift-verify diff. Документує, чому 80/443 лишається Anywhere (co-tenantopenclaw.msolution.funшлях прямого IP; CF-захист скоуплений до nginx vhost).infra/nginx/server-tokens-off.conf(P3 косметика #95) —server_tokens off;на рівніhttpчерезconf.d/, щобServer: nginx/1.24.0зник із кожної відповіді.scripts/vps-sync.shStep 2: копіює все вищезгадане +systemctl reload fail2ban+ diff-перевіркаsshd_config(warn-only — перезавантаження sshd інтерактивне).- Після деплою: повний SSOT
infra/vps/1:1 із продом.
53.17 — Sentinel pentest follow-up: CF lockdown + child-bot loopback + repo SSOT (закриває #91) — DONE ✅ (2026-05-11)
- Pentest Sentinel 2026-05-10 (
docs/security/pentest-2026-05-10.md) виявив 3 критичні infra-знахідки поза статичним аудитом: живу SSH brute-force кампанію (8+ невдалих root-логінів за 10 хв), обхід Cloudflare через прямий IP62.171.128.248, та config drift репо ≠ прод. Sentinel автономно закрив усі infra-фікси на проді 2026-05-10; Phase 53.17 приземлює репо-сторону. - PT-IM1 (fail2ban):
apt install fail2ban+/etc/fail2ban/jail.local(sshd:maxretry=3 findtime=10m bantime=24h). Наживо: 2 IP забанено за першу годину, 0 failed-passwords протягом 24 год після hardening. - PT-IM2 (SSH harden): видалено
/etc/ssh/sshd_config.d/50-cloud-init.conf(cloud-init перекриттяPasswordAuthentication yes);/etc/ssh/sshd_configвстановлює top-levelPermitRootLogin prohibit-password+PasswordAuthentication no.sshd -Tефективний; reload (не restart — наявні сесії незаймані). Самоперевірка: логін свіжим ED25519-ключем успішний до застосування. - PT-IM3 (file perms):
chmod 600наvault.json,citadel.db,db-wal,db-shm. Defense-in-depth — vault зашифрований, але world-readable at-rest усе одно відкриває offline-поверхню атаки, якщо скомпрометовано non-root контейнер. - PT-CF1 + PT-CF2 (мітигація обходу Cloudflare): UFW-allowlist зламав би co-tenant
openclaw.msolution.fun(прямий IP, не CF). Натомість використано lockdown на рівні nginx-vhost: новий/etc/nginx/conf.d/cloudflare-geo.confізgeo $realip_remote_addr { ... }(22 CF IPv4/IPv6 діапазони →$cf_origin);if ($cf_origin = 0) { return 403; }в обох server-блокахarc-os.co. Критична пастка real_ip: Phase 53.15.1 увімкнулаset_real_ip_from + real_ip_header CF-Connecting-IP, що переписує$remote_addrна фактичного клієнта — тожgeo $remote_addrНІКОЛИ б не збігся з CF-діапазонами. Фікс:$realip_remote_addr(ОРИГІНАЛЬНИЙ IP з'єднання до підстановки real_ip). Початковий деплой використавallow/denyі зламав arc-os.co на 403 → відкочено → підхідgeoприземлився чисто. Оновлення:/usr/local/sbin/update-cloudflare-allowlist.sh(атомарний запис у.new+ валідаціяnginx -t+mv+ reload) на cronMon 03:30 UTC. Репо SSOT:infra/nginx/cloudflare-geo.conf,infra/vps/{update-cloudflare-allowlist.sh,cloudflare-allowlist.cron}. Live-перевірка: прямийhttps://62.171.128.248/→ 403 (обхід закрито), arc-os.co через CF → 200,msolution.fun/openclaw.msolution.fun/:18888незаймані. - PT-CB1 (loopback bind для child-bot, архітектурний фікс Phase 42.4):
child-bot/bot.ts:928+mcp-server/server.ts:111додають явнийhostname: "127.0.0.1"доBun.serve(). Раніше слухали0.0.0.0:19220-19222— UFW тримав зовні, але один мисконфіг від публічної експозиції. Master опитує їх через localhost; зовнішньої потреби немає. Код пропатчено + задеплоєно; запущені процеси підхоплять зміну на наступному циклі рестарту (задача #92). - PT-SYNC (репо ↔ прод nginx 1:1): Pull-back diff показав, що репо ВЖЕ мав HSTS / rate-limit / X-Frame DENY на рядках
108/76-77,210,399/111,273відповідно — P0-4/P0-5/P1-9 у статичному аудиті були false positives (початковий grep Sentinel мав обмежений скоуп). Чисто нове в репо: тільки файли CF lockdown.scripts/vps-sync.shStep 2 тепер копіюєcloudflare-geo.conf→/etc/nginx/conf.d/,update-cloudflare-allowlist.sh→/usr/local/sbin/,cloudflare-allowlist.cron→/etc/cron.d/. Репо↔прод 16928 байтів ідентичні (diffexit 0). - PT-ASSERT (3 нові post-deploy assertions у
vps-sync.sh):SEC-CF1(прямий IPhttps://62.171.128.248/→ 403),SEC-CF2(CF через-H "Host: arc-os.co"→ 200/401),SEC-CB1(ss -tlnp | grep ':1922'не показує*:біндингів).bash -nсинтаксис OK. - Корекції статичного аудиту: P0-4 / P0-5 / P1-9 підтверджені як false positives. Прикладні знахідки, які pentest Sentinel позначив "needs dev review" (P0-1, P0-2, P0-3, P1-1..P1-6, P1-13) — усі вже закриті в Sprint 1 (#62-67) + Sprint 2 (#68-80), Sentinel рев'ював знімок до Phase 53.15+53.16.
- 100 unit-тестів досі зелені;
tsc --noEmit0 помилок. Породжено під-задачі #92-96 для хвоста (рестарт child-bot, репо SSOT для sshd/ufw/fail2ban, аудит/opt/repos/pt,server_tokens off, mTLS Origin Pulls).
53.16 — Sentinel Sprint 2: 13 × P1 — DONE ✅ (2026-05-10, закриває #68-80)
- Усі 13 решти P1-знахідок аудиту Sentinel 2026-05-10 закриті одним батчем (P1-9 уже відвантажено в Sprint 1 / Phase 53.15).
- #69 P1-2 + #70 P1-3 (
shared/routes/files.ts) —handleMkdir/handleCreateFileтепер відхиляютьbody.nameщо містить..,.,/,\; обидва повторно проганяютьsafePath()на з'єднаному результаті як defense-in-depth.handleSaveFileотримав перевіркуisProtectedPath(), якуhandleUploadFilesзавжди мав —.env/CLAUDE.md/.git/*більше не перезаписуються черезPUT files/save. - #68 P1-1 (
master-bot/bot.ts+shared/routes/onboarding.ts) —notebook_id/display_name(контрольовані користувачем черезPUT /api/crm/projects/:name/config) інтерполювалися в рядкиbash -c export X='...';'у payload виривався й виконувався як root при кожному spawn workspace-бота. Тепер пишуться уchild-bot/.envіз санітизацією shell-метасимволів (вирізаються[\r\n"\$\], стеля 256 символів); читання обробляє авто-завантаження Bun. Shell-масивextraEnvs` зник — inline-інтерполяції не лишилося. - #71 P1-4 (
shared/db.ts:analyticsQueries+shared/routes/router.ts) —recentActivity/hotProjects/topWorkersтепер вимагаютьownerIdтаJOIN projects ON ... WHERE owner_id = ?. Без цього будь-який залогінений користувач бачив перші 80 символів кожного assistant-повідомлення + назви проєктів + ID воркерів усіх тенантів. - #72 P1-5 (
master-bot/routes/websocket.ts) —WsBridgeData.chatIdзаповнюється з JWT при upgrade/ws/local-bridge; init-хендлер виконуєcanAccessProject(registry, wsChatId, projectName)і відхиляє з 1008 Forbidden при розбіжності. Закриває bridge-relay шлях, який дозволяв користувачу A інжектити в історію чату користувача B. - #74 P1-7 (
master-bot/routes/auth.ts:clientIp) — XFF-парсер тепер читає ОСТАННІЙ сегмент (доданий nginx, довірений) замість ПЕРШОГО (контрольованого клієнтом). У комбінації з #77 P1-11 нижче. - #77 P1-11 (
infra/nginx/citadel-crm.conf, 17 callsites) — коженproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for(append) перемкнено на$remote_addr(overwrite). З CFreal_ip_headerіз Phase 53.15.1$remote_addrтепер відображає фактичного клієнта → XFF-ланцюг стає single trusted hop end-to-end. - #73 P1-6 (
shared/routes/_utils.ts:extractChatId) — функція тепер викликаєverifyToken()перед довірою claim'уsub. Був footgun: будь-який майбутнійskipAuthмаршрут успадкував би chatId-spoofing. Defense-in-depth — поточні маршрути вже гейтяться черезcrmAuthMiddlewareспершу. - #75 P1-8 (
master-bot/routes/auth.ts+frontend/src/crm/App.jsx) — OAuth callback redirect використовує фрагмент#token=замість?token=. Токен ніколи не потрапляє в історію браузера, access-логи nginx чи заголовокRefererпри подальшій навігації. Фронтенд читає зwindow.location.hash(з backward-compat fallback на?token=на один deploy-цикл). - #78 P1-12 (
docker/Dockerfile.frontend+docker/docker-compose.yml+docker/nginx.conf) — базовий образ перемкнено зnginx:alpine(root master) наnginxinc/nginx-unprivileged:alpine(біндить 8080 як користувачnginx). Порт контейнера 80 → 8080; хостовий порт 18889 без змін. МасовийCOPY config/замінено явним allowlist (agents.json,office-layout.json,branding.json), щоб rebuild на dev-машині не міг злити gitignoredvault.json/vault-keyу Docker Hub. - #80 P1-14 (6 файлів) —
CEO_CHAT_IDприбрано з хардкод-fallback'ів уchild-bot/bot.ts,shared/tg-notify.ts,scripts/nightly-improve.ts,scripts/get-token.ts,scripts/start-child-pt.sh.master-bot/bot.tsчитає env спершу з fallback на реєстр + попередженням. Майбутня ротація CEO більше не потребує пошуку по коду. - #76 P1-10 (
master-bot/api-server.ts+docker/nginx.conf) — викинуто'unsafe-inline'із CSP API JSON (style-src 'self'). Шар роздачі frontend HTML тепер ставить строгий CSP (default-src 'self'; script-src 'self'; ... frame-ancestors 'none') — повністю був відсутній уdocker/nginx.conf. Це і є фактична XSS-поверхня (E2EE master key уsessionStorage). - #79 P1-13 (
frontend/src/crm/crypto/e2ee.ts) — виведення обгортки recovery-key тепер використовує 16-байтову випадкову сіль на ключ (NIST SP 800-132). Форматv2:<base64-salt>:<encrypted-payload>вбудовано в ту саму колонку БД — без зміни схеми. Legacy-ключі (без префіксаv2:) відкочуються до старої солі"citadel-recovery-v1"для зворотної сумісності. Два користувачі з однаковим recovery-ключем більше не ділять wrapping-ключі; rainbow tables неможливі. - 100 unit-тестів досі зелені;
tsc --noEmit0 помилок.
53.15.1 — Довіра до Cloudflare CF-Connecting-IP для rate-limit — DONE ✅ (2026-05-10)
- Phase 53.15 задеплоїла
limit_req_zone $binary_remote_addr zone=auth:5r/m, але пост-деплойна перевірка показала: 15 швидких хітів/api/auth/loginусі повернули 401, жодного 429 — rate-limit тихо неефективний. - Причина:
arc-os.coза Cloudflare. Безset_real_ip_from+real_ip_headernginx бачить CF edge IP як$remote_addr; CF ротує edges на кожен запит, тож усі хіти виглядають як різні клієнти для limit-зони. - Фікс: додано опубліковані IPv4/IPv6 діапазони Cloudflare як
set_real_ip_from+real_ip_header CF-Connecting-IP+real_ip_recursive on.$remote_addrтепер відображає фактичного клієнта;limit_req_zoneпрацює як задумав Sentinel. Прямі хіти на origin (повз Cloudflare) зберігають$remote_addrяк connecting peer — досі rate-limited. - CF IP-діапазони з https://www.cloudflare.com/ips/ перевірені 2026-05-10. Поставлено календарне нагадування щорічної перевірки.
53.15 — Sentinel Sprint 1: 5×P0 + редагування PII — DONE ✅ (2026-05-10, закриває #62-67)
- Аудит безпеки Sentinel 2026-05-10 (
docs/security/audit-2026-05-10.md) позначив 5 P0 / 13 P1 / 12 P2 дефектів. Sprint 1 закрив усі 5 P0 плюс quick-win редагування клієнтських PII одним батчем. - #62 (P0-1)
shared/auth.ts:418,427— прибрано fallback|| "citadel-admin-2026"(fail-closed throw якщо envADMIN_PASSWORDне задано, потрібно ≥12 символів) + викинуто plaintext-пароль із рядкаconsole.log. Новий seed-лог: лише[Auth] Admin user seeded: [email protected] (chat_id=…). Наявні prod-адміни вже засіяні → throw-шлях спрацьовує лише на свіжих установках. - #63 (P0-2)
shared/routes/skills.ts— додано гейтrequireAdmin(req)на кожен мутатор глобальних навичок:handleCreateGlobalSkill,handleUpdateGlobalSkill,handleDeleteGlobalSkill,handleApproveSkillUpdate,handleRejectSkillUpdate. Без цього будь-який beta-користувач міг опублікувати навичку, яку Context Router авто-вставляє в промпт кожного child-бота всіх тенантів — fleet-wide RCE-via-prompt-injection.requireAdminвинесено уshared/routes/_utils.tsдля перевикористання майбутніми модулями без копіювання. Сигнатури роутера оновлено для передачіreqу delete/approve хендлери. - #64 (P0-3)
master-bot/routes/auth.ts:589-605+shared/auth.ts:loginUser—/api/auth/loginкрок 1 тепер видає одноразовий 5-хвилиннийtfa_challenge_token(зберігається вephemeral_tokensіз новим типомtfa_challenge), прив'язаний до userId після успішної перевірки пароля./api/auth/2fa/loginкрок 2 приймає{challenge_token, code}(було{userId, code}); споживає токен черезconsumeTfaChallenge(); відмова 401 при відсутньому/простроченому. Супутній rate-limit на userId черезcheckEmailRate("2fa:user:<id>", 5, 15*60_000)із 429 — defense-in-depth навіть якщо challenge витече. Закриває TOTP brute-force лазівку (1M кодів — питання годин без прив'язки до пароля). - #65 (P0-4)
infra/nginx/citadel-crm.conf— розділено server-блок: новий:80 → return 301 https://$host$request_uri, щоб downgrade-атаки першого візиту (SSLstrip) не могли читати JWT/паролі. ДоданоStrict-Transport-Security: max-age=31536000; includeSubDomains; preloadу блок:443. Запіненоssl_protocols TLSv1.2 TLSv1.3+ssl_prefer_server_ciphers. Бонус P1-9:X-Frame-Options: SAMEORIGIN→DENY(узгоджується з claim документації Phase 45) в обох server-блоках. - #66 (P0-5)
infra/nginx/citadel-crm.conf— додано дві top-levellimit_req_zone:auth=5r/m(на$binary_remote_addr) таwebhook=30r/m. Застосованоlimit_req zone=auth burst=10 nodelay; limit_req_status 429;до/api/auth/в обох публічному + IP-direct server-блоках;zone=webhook burst=20 nodelayдо/api/webhooks/github. Закриває вектори bcrypt brute-force + signup flood + webhook event-flood. - #67 (редагування PII) Замінено
[email protected](email клієнта) уdocs/ROADMAP.md:2369+docs/status/current-state.jsonнейтральним формулюванням. Замінено персональний[email protected]у 6 design-prototype файлах на[email protected]. Аудит-документ (docs/security/audit-2026-05-10.md) навмисно зберігає посилання як джерело цитування. - 100 unit-тестів досі зелені;
tsc --noEmit0 помилок. Sprint 2 (батч P1) трекається окремо.
53.14 — Міграція issues.json у SQLite (project_issues) — DONE ✅ (2026-05-10, закриває #53)
- Прямий follow-up до Phase 53.12 / 53.12.1:
preserve-auto-append.shбув safety net навколо симптому (text-merge issues.json між деплоями); 53.14 усуває причину, переносячи зберігання задач уdata/citadel.db. JSON-файл тепер похідний експорт, не авторитетний. - Нова міграція
023_project_issues— композитний PK(project_name, id), тож кожен проєкт зберігає власну 1-based послідовність id.labels+activityзберігаються як JSON TEXT. Єдиний індекс на(project_name, status)для найчастішого фільтра. - Нові
issueQueriesуshared/db.ts—list/get/nextId/insert/upsert/replaceAll/bulkImport/countByProject.replaceAllпрацює вdb.transaction(...)для атомарності.bulkImportвикористовуєINSERT OR IGNORE, тож імпортер ідемпотентний. loadIssues(child)таsaveIssues(child, store)уshared/cli-routes.tsтепер тонкі обгортки —loadIssuesповертає{ next_id, issues }синтезований зissueQueries.list+issueQueries.nextId;saveIssuesвикликаєreplaceAll(DB SSOT) потімmirrorIssuesJson(пише JSON-файл для legacy-читачів — NotebookLM seeder,_utils.getLastTask, frontend ContextRail). Збій mirror некритичний, бо БД має авторитетний стан.- Зміна сигнатур:
loadIssues(cwd)→loadIssues(child),saveIssues(cwd, store)→saveIssues(child, store). Оновлено всі 4 хендлери (handleCreateIssue/handleListIssues/handleUpdateIssue/handleAddIssueLog) плюсhandleCliInit. issues/issues.jsonдодано в.gitignore+git rm --cached. Повністю усуває merge-поверхню. Список PROTECTED уpreserve-auto-append.shскорочено з 3 файлів до 2 (лишаються тількиlearnings.md+wiki/log.md).- Новий
scripts/import-issues-to-db.ts— одноразовий seeder. Обходить childrenbot_registry.json+ master cwd, читає коженissues/issues.json, викликаєbulkImport. Ідемпотентний при повторних запусках.vps-sync.shStep 1 викликає його післяgit pull+ preserve merge, тож БД засіяна до рестарту master. scripts/test-preserve-auto-append.sh— формалізований harness у репо (був тільки в/tmp/), покриває решту 2 захищених файлів. 9 assertions / 3 сценарії.- 17 нових unit-тестів у
tests/issues-db.test.ts(CRUD round-trip, ізоляція кількох проєктів, фільтр статусу, upsert, атомарність replaceAll, ідемпотентність bulkImport, countByProject). Разом тестів проєкту: 100 / 242 expects, усі зелені. - Стратегія деплою: імпортер пише в БД до рестарту master, тож новий код знаходить рядки при першому init. Старий код більше не може зіпсувати стан через
git stash apply, бо JSON-файл у gitignore — нічого стешити.
53.13 — Кореневий tsconfig.json + tsc --noEmit у pre-push та CI (закриває #44) — DONE ✅ (2026-05-10)
- Phase 53.7 (задача #43) додала CI workflow із коментарем "Cheap stand-in for tsc until issue #43 follow-up adds a root tsconfig" — ця фаза і є тим follow-up.
bun build --no-bundleлише транспілює, пропускаючи справжні TS-помилки (discriminated unions не звужені, відсутні обов'язкові поля, readonly vs mutable масиви). - Новий кореневий
package.json(devDepstypescript@5+@types/bun) +tsconfig.json(базлайнstrict:false,skipLibCheck:true, включаєmaster-bot/child-bot/shared/clients/scripts/tests/).bun installчерез корінь резолвить обидва.bun.lockвідстежується. - Базлайн
bun run typecheckвиявив 32 помилки у 8 файлах. Виправлено:- 3× дубльований інтерфейс
ChildBot(master-bot/context.ts, shared/routes/_utils.ts, shared/cli-routes.ts) зведено до єдиного SSOT уshared/routes/_utils.ts. master-bot/context.ts ре-експортує. master-bot/watchdog.ts розширює полями parallel-worker. - shared/routes/_utils.ts ChildBot розширено:
bot_username,heartbeat_file,health_endpoint,statusзроблено опційними (runtime-дані не завжди їх мають; напр. owner_id-збагачені workspace-записи з БД ставлять лише name/type/cwd/tmux_session/health_port). - Звуження discriminated-union
if (!r.ok)зламане підstrict:false. Замінено наif (r.ok === false)(10× уtests/roadmap-sync.test.ts, 1× уshared/cli-routes.ts).requireAdmin()уshared/routes/system.tsвідрефакторено повертатиResponse | { userId }, щобinstanceof Responseзвужував чисто. scripts/migrate-skills-to-db.ts:11мав*/усередині JSDoc, що передчасно закривав блок коментаря (.claude/skills/*/SKILL.md→ перейменовано в<id>/).shared/routes/workers.tsDEFAULT_WORKERS позбувсяas const(readonly tuples vs mutable string[]), полеkeywordsдодано у fallback role pattern,tools/focus_dirsзвужено через Array.isArray guard.scripts/bridge.tsтип дефолтного параметра color-хелперів розширено з літерала"[36m"доstring.shared/tg-notify.tsприватнийInlineButtonзведено до імпорту зshared/ui_templates(розбіжність callback_data optional vs required).master-bot/api-server.tsObject.fromEntries(resp.headers)→[...resp.headers as unknown as Iterable<[string,string]>](тип Bun Headers без деклараціїentries()).master-bot/bot.tsмісця push registry-children тепер включають полеtype(обов'язкове за shared ChildBot).
- 3× дубльований інтерфейс
.githooks/pre-pushдодає крокbun run typecheck(лише якщо присутнійnode_modules/typescript/— пропускається для fresh-clone розробників безbun install). Backend-job.github/workflows/ci.yml:bun install+ крокbun run typecheck+ зберігаєbun build --no-bundleяк надлишковий smoke test.- 83 unit-тести досі зелені. Фінальний
bun run typecheck→ 0 помилок.
53.12.1 — preserve-auto-append.sh: авто-перенумерація при колізії id (закриває #54) — DONE ✅ (2026-05-10)
- Деплой Phase 53.12 live-протестував скрипт і виявив його власну прогалину: детекція колізій id видавала WARN ("VPS wins; origin issue dropped"), але тіло jq-merge фактично НЕ викидало колізійний origin-запис. Результат: задеплоєний
issues.jsonмав два записи зid=1(VPS-ний "Phase 53.x" + старий git-івський "Mobile chat overflow"). Знадобився ручний jq splice для ремонту. - Фікс: класифікацію
merge_issues_jsonjq переписано на три кошики — origin-only (id немає в local), origin-same-id-same-created (union activity з local), origin-same-id-divergent-created (справжня колізія). Колізійний кошик перенумеровується послідовно відmax(local_next_id, origin_next_id, max-existing-id+1)— тож VPS зберігає оригінальний id, А запис origin виживає на свіжому id. Повідомлення WARN оновлено: показує мапінг перенумерації (original_id → renumbered_to) замість хибного claim'у "dropped". Поле_warnвбудовано у jq-вивід, вирізається перед фінальним записом. - Розширено test harness: сценарій 3 (одна колізія) тепер assert'ить що обидва записи виживають + немає дублікатів id + перенумерований id за межами max; новий сценарій 3b (3× колізії на щільному просторі id 1-3) assert'ить що VPS зберігає 1-3, а origin перенумеровується в 4-6 із
next_id=7. Разом: 27 assertions / 7 сценаріїв (було 18 / 6). - Чому це важливо: попередня політика "VPS wins; origin dropped" тихо втрачала дані на реальних колізіях. Нова політика "VPS зберігає id; origin перенумеровується" не втрачає нічого — обидві легітимні задачі виживають.
53.12 — Deploy hygiene: структурний merge для auto-append SSOT файлів (закриває #51) — DONE ✅ (2026-05-10)
- 3+ історичні записи
pre-deploy-stash-*спостерігалися, боvps-sync.shробив голийgit pullбез захисту файлів, які master-сервер мутує в рантаймі:issues/issues.json,learnings.md,knowledge-base/wiki/log.md. CEO обходив це вручну; 2026-05-10git stash applyтихо зіпсував issues.json (регресія 50 → 30 задач — JSON 3-way text-merge викинув 20 записів). - Новий
scripts/preserve-auto-append.shвиконує структурний merge, якийgitне вміє. Дві фази: snapshot (cp захищених файлів уmktemp -d), та merge (per-file структурна реконсиляція). Три стратегії merge:issues.json—jqmerge заid. Origin-only задачі беруться як є. Same-id задачі: тіло VPS перемагає, масивиactivityоб'єднуються з дедупом за(ts + text). Same-id із розбіжнимcreated_at(справжня колізія: обидві сторони створили нову задачу з тим самим авто-інкрементним id) видає WARN у stderr — VPS усе одно перемагає, оператор переглядає.next_idпереобчислюєтьсяmax(local, origin, max-id+1).learnings.md— порядковийgrep -F -x -v -f origin localзнаходить локально-унікальні повні рядки, додає в origin.wiki/log.md— розбиття за заголовками^##на секції, додаються секції, чий заголовок відсутній в origin.
- Переписано Step 1
vps-sync.sh: snapshot →git checkout --скидає зміни working tree (дані вже в snapshot, запобігає абортуgit pullна "local changes would be overwritten") → чистийgit pull→ merge зі snapshot. - Test harness
/tmp/test-preserve.sh: 18 assertions у 6 сценаріях — origin-додає-задачу + VPS-додає-activity, колізія тіла, колізія id (розбіжний created_at), додавання рядків learnings, додавання секцій wiki, відсутній origin (перший деплой). - Рішення: VPS перемагає при конфлікті тіла (свіжі runtime-дані б'ють закомічений знімок); без commit-back із VPS (drift лишається one-shot на деплой, простіше за двосторонню синхронізацію).
- Discovery-примітка: всупереч ранішій пам'яті,
issues.jsonІ Є SSOT для задач —data/citadel.dbзберігає лише аудит-трейлactivity_log, НЕ самі задачі. Міграція в БД трекається окремо як cloud-задача #1 (Phase 53.x, P2).
53.10 — Інформативні TG notify hooks (закриває #47) — DONE ✅ (2026-05-10)
- Дотепер Stop hook постив статичний heartbeat
✅ Claude Code (local) finished turn at HH:MM:SS— корисний як пінг "ще живий", але марний для тріажу що агент фактично сказав. Permission-промпти не пінгували взагалі, тож сесія, що чекає схваленняBash, у TG була невідрізнима від сесії, що чисто завершилася. - Новий
.claude/notify-lib.sh(~140 LOC): спільні хелпери — перевірка свіжості JWT, ланцюг резолюції auth (ARC_TOKENenv →CRM_TOKENenv →~/.arc/config.json), PII sanitizer (редагуєsk-…API-ключі,eyJ…JWT,Bearer …, 40+ hex-рядки), обрізання по межі слова, curl-обгорткаnotify_post()з jq JSON-safe побудовою тіла, таnotify_last_assistant_text(), який реверсно обходить транскрипт-JSONL і конкатенуєtext-блоки найсвіжішогоassistant-запису. .claude/notify-stop.shпереписано як тонкий wrapper: читає stdin payload Stop-хука ({session_id, transcript_path, cwd, stop_hook_active}), бере останній assistant-хід, санітизує + обрізає до 600 символів, надсилає✅ HH:MM:SS · finished turn\n\n<snippet>. Відкочується до legacy heartbeat-рядка, якщо jq відсутній чи в транскрипті ще немає assistant-тексту.- Новий
.claude/notify-notification.shпідключено до Notification-хука: виводить полеmessageхука напряму (напр. "Claude needs your permission to use Bash command: …"), тож TG отримує⏸ HH:MM:SS · awaiting input\n\n<message>. CEO може реагувати на permission-промпти з мобільного, не відкриваючи ноутбук. .claude/settings.jsonдодає запис хукаNotificationпоруч із наявнимStop.- Smoke-тест обох хуків проти прод
arc-os.co/api/crm/projects/arc-v2/workers/developer/notify: msg_id 191 (finished, len=114) + msg_id 192 (notification, len=98), обидва 200 OK.
53.7 — CI/CD foundation (закриває #43, #44, #45, #46) — DONE ✅ (2026-05-07)
- Проєкт мав нуль CI-інфраструктури та нуль unit-тестів на старті цієї роботи. Помилки типів і регресії Python-лінту могли потрапляти в main непоміченими, доки хтось вручну не запустить
bun build. - #43 — перший
.github/workflows/ci.yml. Три паралельні job'и на push/PR: backend (bun build --no-bundleна entry-точках master-bot/child-bot/arc-cli), frontend (npm ci+lingui compile+vite build), python (ruff check services/notebooklm-bridge/). ~30с wall, зелений з першого push. - #44 —
.githooks/pre-pushрозширено для локального дзеркалення CI-гейтів (build-check + ruff + unit-тести + наявне doc-coverage). Розробники ловлять регресії за 5с замість чекання GitHub-рану. Bypass через--no-verifyдля аварійних випадків. - #45 — Tier 1 unit-тести через
bun:test: vault encrypt/decrypt round-trip, one-time-use семантика ephemeral_tokens, auth JWT mint+verify+OAuth-state CSRF. 28 кейсів / 82 expects. - #46 — Tier 2-3: subscription-запити +
checkPlanLimitOR-семантика з обходом admin/beta, state machine device-code флоу + regression guard 30d TTL. Ще 24 кейси. - Загальна кількість тестів проєкту: 52 кейси / 139 expects / 113мс wall — детерміністичні, ізольовані temp-шляхи на suite.
- Tier 4 (onboarding/інвайти/IP-тротлінг) відкладено — потребує більше integration-setup.
53.7.1 — Глобальний Stop hook для non-citadel CWD — DONE ✅ (2026-05-07)
arc <project> devзапускає Claude зі успадкованим CWD користувача, тож коли CEO запускавarc pt odoo-devіз non-citadel директорії, проєктно-локальний.claude/settings.json(що несе Stop hooknotify-stop.sh) не завантажувався — пінги pt/odoo-dev ніколи не спрацьовували.- Фікс: додано
notify-stop.shяк другий запис у глобальний масивStopу~/.claude/settings.json, що вказує на скрипт у репо проєкту (single source of truth). Тепер кожна сесія Claude Code — незалежно від CWD — запускає хук, і хук читаєARC_PROJECT/ARC_WORKER_IDз env (ставить arc CLI), щоб маршрутизувати пінг до правильного бота. - Це user-level конфіг, живе поза репо; задокументовано тут, щоб конвенція була виявлюваною.
53.6 — Фікс дрейфу коду проєктів (закриває #42) — DONE ✅ (2026-05-07)
- Спливло 3× за одну сесію: кожна backend-зміна в /opt/repos/citadel-v2 була невидимою для наявних проєктів (pt, gapap, msol, ks-crm, …), доки хтось вручну не зробить rsync. Старий Step 3 vps-sync.sh ітерував лише children
bot_registry.json(більшість проєктів випали з реєстру через чистку #28) і використовував нерекурсивнийcp shared/*.ts, тож нові піддиректорії (shared/routes/з ранішої декомпозиції) тихо пропускалися. - Новий
scripts/sync-projects.shобходить/opt/repos/*/ізchild-bot/і рекурсивно rsync-ає*.ts. Per-project стан (.env,mcp-server/state/,knowledge-base/,CLAUDE.md) незайманий; без--delete. Можна запускати ad-hoc із--dry-runта опційним фільтром за назвою. - Step 3
vps-sync.shделегує до нього — єдине джерело sync-логіки. - Symlink-based single-source-of-truth (оригінальна рекомендація в #42) відкладено на follow-up. Rsync обрано першим як безпечніший шлях відкату.
53.4 — Фікси надійності TG-ботів воркерів (закриває #41) — DONE ✅ (2026-05-07)
- Діагностовано три накладені баги з реальної прив'язки користувача (pt/odoo-dev): (a)
shared/routes/відсутній у проєктах до Phase 48 → краш child-бота на імпорті (workaround: rsync із citadel-v2 у pt; довгостроковий фікс провіжинінгу трекається окремо); (b) розбіжність vault-неймспейсів — master писавworker:<>:<>:bot_tokenу vault citadel-v2, а child-bot читав із проєктно-локального vault →BOT_TOKENпорожній → тихо лишався у WORKSPACE_MODE; (c) конфлікт однакових токенів — користувач вставив project-level токен бота, два long-poll клієнти змагалися б за одного Telegram-бота. - Фікс (b) — passthrough vault-шляху:
startWorkerBotекспортуєMASTER_VAULT_PATHу запущений tmux.child-bot/bot.tsчитає його перед fallback на проєктно-локальний vault. - Фікс (c) — перевірка унікальності:
handleSetWorkerTelegramTokenтепер (1) валідує токен через TelegramgetMe, (2) ітерує записиworker:*:*:bot_username, (3) повертає 409, якщо резолвлений username уже прив'язаний деінде, з дружньою підказкою "create a new bot via @BotFather". - Бонусний UI-win: username бота тепер зберігається у vault як
worker:<>:<>:bot_usernameі показується у Worker Studio біля зеленої крапки — "Bound to @cv2_pt_bot" замість просто "Token configured".
53.5 — Бейдж BETA + in-app feedback widget — DONE ✅ (2026-05-07)
- F&F закрита бета потребує (1) видимого сигналу "це бета", щоб тестери калібрували очікування, і (2) one-click шляху баг-репорту для швидкої реакції.
- TopHeader: pill-бейдж
BETA · 1.0.0.1поруч з ArcLogo (warm-clay акцентне кільце + крапка, клік → відкриває Docs).color-mix(in oklch, ...)для graceful підтримки тем. - Новий
FeedbackWidget(frontend/src/crm/components/FeedbackWidget.jsx, ~280 LOC): плаваюча кнопка message-circle внизу праворуч (зсув 64px над футером), відкриває центрований модал. Форма: пігулки типу (🐞 bug / 💡 feature / 📝 other), заголовок (≤200), опис (≤5000). Esc закриває, success toast 2.2с autoclose. Авто-додаєproject+browser(UA + viewport + локаль) для тріажу. - Новий
shared/routes/feedback.ts— хендлериhandleSubmitFeedback+handleListFeedback(тільки admin). POST зберігає рядокactivity_logevent_type=feedback_reportі пінгує CEO через колбекnotifyCeo(best-effort, неблокуючий). 401 unauth, 400 validation, 403 admin-only на list. - Проводка:
RouteCrmOptionsотримав опційний колбекnotifyCeo;MasterContext.services.notifyCeoзаповнюється після готовностіtgApi(master-bot/bot.ts:262). api-server.ts прокидає колбек уrouteCrmRequest. - Бандл: crm chunk 400 → 409 KB (+10 KB FeedbackWidget). Build ✓ за 8с.
- Створено задачу #39: налаштування email
[email protected](DNS/MX-робота, не код) — Cloudflare Email Routing free tier рекомендовано для F&F-фази.
53.3b — Zero-touch через наявну інфраструктуру arc CLI — DONE ✅ (2026-05-07)
- Розслідування знайшло дві частини інфраструктури, що вже існують: (1)
arc <project> devекспортуєARC_TOKEN/ARC_PROJECT/ARC_WORKER_ID/ARC_SERVER_URLу запущений Claude-підпроцес (clients/arc-cli.ts:332), (2) device-code флоуarc loginпише~/.arc/config.jsonз{server_url, token, connected_at}(clients/lib/config.ts). Означає, що F&F-флоу потребує нуль нової проводки. notify-stop.shпереписано з коректним пріоритетом:ARC_TOKENenv (zero-touch при запуску черезarc <project> dev) →CRM_TOKENenv (перекриття для power-користувачів) →~/.arc/config.json(післяarc login). Той самий ланцюг для полів project/worker/api.- TTL CLI/device-code токена піднято з 24 год до 30 днів (
approveDeviceCodeуshared/auth.ts), щоб хук перестав щодня вмирати на бездоглядних сесіяхarc <project> dev. generateCeoTokenприймає опційний аргументttlSec; web-логіни зберігають 24 год, device-code шлях передає 30 днів.- Перевірено:
env -u ARC_TOKEN -u CRM_TOKEN bash notify-stop.sh→ хук резолвить токен лише з~/.arc/config.json→ пінг #159 повернув{"ok":true}. Ручний seed не потрібен. - Інтеграція
install.shНЕ потрібна: bridge install (file monitor) та arc CLI (session driver) — незалежні інструменти; флоу arc CLI покриває F&F user journey.
53.3a — Hook читає ~/.arc/credentials.json (без танців із shell-rc) — DONE ✅ (2026-05-07)
- Налаштування 53.2 вимагало від користувача ssh+bun-mint токена, export у shell rc, рестарт Claude Code. CEO позначив це як жорсткий блокер для F&F-клієнтів ("Має бути мінімум ручної роботи").
.claude/notify-stop.shтепер резолвить auth у порядку: (1) CRM_TOKEN env, (2)~/.arc/credentials.json. Той самий fallback для полів project / worker / api.- jq-aware із grep fallback для портабельності. Файл 0600, директорія 0700.
- Діагностичний side-effect: наявні Stop-події весь час спрацьовували коректно (3 записи в /tmp/arc-notify-stop.log між 11:33-11:43) — вузьким місцем був відсутній токен, не конфіг хука. Ручний seed credentials.json → пінг #158 повернув
{"ok":true,"message_id":158}на наступному ході. - 53.3b (окрема задача): bridge install.sh пише credentials.json автоматично + device-code флоу
arc auth login+ 30d TTL для CLI-токенів.
53.2.1 — Повне оновлення README — DONE ✅ (2026-05-07)
- README.md застряг приблизно на Phase 42 (без version header, двічі "65+ endpoints", Key Features закінчувалися на Security Hardening, блок Self-Hosted суперечив memory feedback "Citadel OS is not offered for client self-hosting", ARC CLI URL досі 62.171.128.248, а не публічний домен).
- Оновлення (88 → 109 LOC, коміт f91c0fe): хедер тепер показує Phase 53.1 + last-updated + статус invite-only бети; діаграму архітектури оновлено до 70+ endpoints + 19 модулів + callouts multi-tenancy/SSRF; Quick Start використовує invite-флоу з публічним URL arc-os.co; Self-Hosted прибрано; блок Maintainers відокремлено; таблицю Components оновлено рядком lazy-lifecycle; Key Features розширено 11 → 17 пунктів від найновіших; моделі Agents підняті (Opus 4.6 → 4.7 Rick, Sonnet 4.5 → 4.6 Summer/Beth); секція Docs починається з live-лінка
arc-os.co/#docs+ директорія video scripts.
53.2 — Локальний Claude Code Stop hook → /notify endpoint — DONE ✅ (2026-05-07)
- Новий endpoint
POST /api/crm/projects/:name/workers/:id/notify(shared/routes/workers.ts:handleWorkerNotify) обгортаєnotifyWorker()для зовнішніх викликачів. .claude/notify-stop.shcurl-ить цей endpoint на кожну Stop-подію, використовуючи$CRM_TOKENіз shell rc користувача. Env-перекриттяARC_PROJECT/ARC_WORKER, дефолтarc-v2/developer..claude/settings.jsonреєструє хук глобально для проєкту (закомічено). Per-user секрет лишається у shell, не в git.- Закриває прогалину з 53.1: локальні термінальні сесії тепер теж пінгують прив'язаний TG-бот, не лише VPS workspace-флоу.
53.1 — Per-worker TG event notifications — DONE ✅ (2026-05-07)
- Новий
shared/tg-notify.ts: шукає у vaultworker:<project>:<id>:bot_token, надсилає TelegramsendMessageнапряму. Тихий no-op, коли токен відсутній абоCRM_DISABLE_TG_NOTIFY=1. - Workspace-бот (
ws-<project>) емітує 4 типи подій з наявних тригер-точок уchild-bot/bot.ts:worker_finished— лише для запусків >15с (уникнути спаму на швидких чат-відповідях)spec_pending— з inline-кнопками[Approve][Reject]subprocess_failed— claude-runner вичерпав ретраї, включає хвіст stderrquality_low— спрацював eval-набір правил, називає невдалі rule_ids
- Бот
worker-<project>-<id>обробляє колбекиnotify-approve:<specId>/notify-reject:<specId>через наявний switchparseCallback— викликаєupdateSpecStatusі підтверджує в чаті. - Спрацьовує лише коли
WORKSPACE_MODE=1(у TG-прив'язаному флоу користувач уже бачить живу розмову, подія лише дублювала б відповідь).
Phase 54: Onboarding Engagement Layer (DONE ✅)
Phase 50 вирішила "signup → дашборд" (3-кроковий візард, trial credits, без email gate). Phase 53.11 вирішила налаштування ботів на воркера (#48). Phase 54 закриває решту прогалини: "дашборд → перша успішна AI-команда". Ставка на CLI — кожен крок чекліста завершується перевіркою через
arc <command>.
User journey після Phase 50: користувач потрапляє в порожній Workspace, пресет-воркери існують, але немає ясного шляху до першої цінності. Phase 54 додає постійний згортуваний 5-етапний чекліст (1 Workers → 2 Install CLI → 3 First skill → 4 Telegram bot → 5 First issue) з auto-verify polling, кнопкою replay та CLI-командою arc tour для hardcore-користувачів.
54.1 — Schema + telemetry foundation (задача #56, P0) — DONE ✅
- Міграція 025
onboarding_progress— нова окрема таблиця (chat_id PK, JSON state per 5 steps, derived completed_count, started_at/completed_at/dismissed_at, sourceweb|cli). Не торкаєтьсяusers— onboarding state живе незалежно. onboardingQueries(shared/db.ts):getProgress / recordEvent / dismiss / replay. Ідемпотентні: повторний(chat_id, step, status)повертаєchanged=false, без duplicate writes в activity_log.dismiss/replaynon-destructive — state виживає цикл.- 4 endpoints:
GET /api/crm/onboarding/progress,POST /event,POST /dismiss,POST /replay(shared/routes/onboarding.ts). Whitelist 5 steps × 2 statuses; 400 на junk. - SSOT для funnel-метрик = події в
activity_log(event_type LIKE 'onboarding_%'); таблиця — derived cache. Емітуються:onboarding_step_completed,onboarding_step_skipped,onboarding_completed(зduration_ms),onboarding_dismissed,onboarding_replayed. - 13 backend-тестів (
tests/onboarding-db.test.ts) — initial-state, idempotency, skipped→completed transition, dismiss/replay non-destructive, валідація вводу. - Блокує 54.2-54.6.
54.2 — Checklist UI + кнопка replay (задача #57, P0) — DONE ✅
- Новий
frontend/src/crm/components/OnboardingChecklist.jsx— згортувана картка з progress bar, 5 рядків кроків (workers / cli / skill / bot / issue), Mark done / Skip на крок, Undo skip, dismiss X, aria-progressbar. frontend/src/crm/hooks/useOnboarding.js— single source of truth, піднято вApp.jsx, передається вниз у Workspace (панель) та TopHeader (help-меню).- Меню '?' у TopHeader (іконка
HelpCircle) з пунктом "Replay onboarding" — викликає/api/crm/onboarding/replay; вимкнено коли чекліст уже видимий. - Логіка видимості: панель показується коли не dismissed ТА не завершено 5/5; replay-пункт активний лише коли
isDismissed || isComplete. - 25 нових EN-рядків + переклад UK.
- MVP-скоуп: конфеті, авто-ретригер після 7 днів dismissed та CLI auto-verify відкладені (територія Phase 54.3+54.5).
54.3 — CLI-first етап із командою arc tour (задача #58, P0) — DONE ✅
- Бекенд: подія
cli_invocationпишетьсяshared/auth.ts:pollDeviceCodeпри успішному device-code логіні (actor=userId, metadata{event:"login_completed", source:"cli"}). Новий endpointGET /api/crm/onboarding/cli-statusскануєactivity_log(вікно 30 днів) і повертає{installed, last_cli_at}. - CLI: нова інтерактивна підкоманда
arc tourпроводить 5 етапів із термінала — readline-промпти, ANSI-кольоровий прогрес, ідемпотентні повторні запуски (розпізнає вже завершені кроки зgetOnboardingProgress). Події постяться зsource:"cli", тож funnel-атрибуція (#61) може розділяти web vs CLI. - Фронтенд: детектор ОС (
detectOS.js— UA-Client-Hints → navigator.platform → UA regex fallback) живить 3-вкладкову панель встановлення на CLI-кроці (macOS / Linux / Windows), одна curl/iwr команда на ОС із Copy в один клік. Поки CLI-крок pending, чекліст опитує/cli-statusкожні 10с; приinstalled=trueкрок авто-перемикається в completed (ідемпотентний guard запобігає подвійному спрацюванню). - MVP cut: без inline-симулятора термінала, без troubleshooting-акордеону Gatekeeper/SmartScreen/PATH — документи Phase 23.2
local-bridge-{macos,linux,windows}.mdце покривають. - 3 нові EN-рядки + переклад UK. tsc 0, vite build + 238/238 тестів зелені.
54.4 — Skill generator wizard (задача #59, P1) — DONE ✅
- Винесено Neural Skill Generator (Phase 36.6) із
ProjectSkills.jsxу перевикористовуванийfrontend/src/crm/components/SkillGeneratorWizard.jsx(~225 LOC). Пропси:project,notebooks,onClose,onSuccess(markdown, skillName). ESC-to-close вбудовано. Empty state при 0 ноутбуків ("knowledge base initializing…"). ProjectSkills.jsxсхуд на ~125 LOC — inline-модал замінено на<SkillGeneratorWizard />, стан генератора зведено до одного прапорцяshowGenModal.- Stage 3
OnboardingChecklistотримує кнопку "Generate first skill" (SkillStepExtras), що відкриває візард. Вимкнено без активного проєкту. При успіху →recordEvent('skill','completed')(ідемпотентно на сервері per #56). App.jsx → Workspace → OnboardingChecklistтепер прокидає пропсиproject+notebooks, щоб візард мав потрібні дані.- Паритет телеметрії з
BotCreationWizard: подіїwizard_metricна/api/crm/metrics/wizardзworker_id="skill-generator", action ∈{started, generated, abandoned}. Спрацювання 'abandoned' на unmount відбувається лише коли ні generated, ні свіжий abandon ще не записані. - 5 нових EN-рядків + переклад UK. tsc 0, 238/238 тестів, vite build зелений.
54.5 — Empty states + віджет завершеності профілю (задача #60, P1) — DONE ✅
- Новий перевикористовуваний
frontend/src/crm/components/EmptyState.jsx— іконка, заголовок, опис, primary + secondary дії, опційна CLI-команда з copy-to-clipboard. Пропcompactдля inline-використань. - Підключено 3 поверхні:
ProjectSkills.jsxстан 0 навичок — primary "Generate from memory" (відкриваєSkillGeneratorWizard, вимкнено при 0 ноутбуків), secondary "New blank skill", CLI-підказкаarc skill list.IssuesRedesign.jsxстан 0 задач (без пошукового запиту) — CLI-підказкаarc issue create --title "My first task" --priority P1.ChatThread.jsxстан 0 повідомлень — замінює простий текст "Send a message" компактним EmptyState, CLI-підказкаarc <project> dev.
- Новий
frontend/src/crm/components/ProfileCompletionWidget.jsx, змонтований уSidebarContentпід навігацією проєкту. Читає/projects/:name/config+/projects/:name/files?path=knowledge-base/raw, виводить 3-пунктову перевірку готовності (опис заданий / notebook_id підключений / KB-файл завантажений). Ховається коли все готово АБО session-dismissed. Кнопка "Complete in Settings" →onSelectPage('project-settings'). MVP-скоуп: без inline-редакторів — це рефакторинг ProjectSettings. - 15 нових EN-рядків + переклад UK. tsc 0, 238/238 тестів, vite build зелений.
- MVP cut: niche + tone of voice не виведені (зберігаються в MANIFEST.md + CLAUDE.md, сьогодні немає read/write API); авто-ретригер після 7 днів dismiss відкладено.
54.6 — Funnel analytics (задача #61, P2) — DONE ✅
- Нова агрегація
analyticsQueries.onboardingFunnelStats(hours)над подіямиactivity_log(SSOT —onboarding_progressлише derived cache за дизайном Phase 54.1). Повертає: per-step лічильники completed + skipped, started_users (унікальні актори з будь-якою onboarding-подією), completed_users + completion_rate (% досягнення 5/5), тривалість p50/p90 (мс, ізonboarding_completed.metadata.duration_ms), TTFC p50 + розмір вибірки (час від першого кроку до першої подіїcli_invocationна актора через julianday-математику). - Новий endpoint
GET /api/crm/analytics/onboarding-funnel?hours=N(за auth-гейтом, парсить hours, clamp усередині запиту). OnboardingFunnelSectionдодано доAnalytics.jsx— KPI-стрічка з 4 плиток (Started · Reached 5/5 + % · Median time to 5/5 · Median TTFC), вертикальна діаграма з 5 стовпців (розділення completed/skipped через CSS-градієнт), мітки drop-off червоним під кожним стовпцем (відносно попереднього етапу), перемикач вікна 24h/7d/30d. Секція повністю ховається до першого started_user, тож порожні розгортання виглядають чисто.- 6 backend-тестів (
tests/onboarding-funnel.test.ts) покривають zero state, per-step лічильники, математику completion_rate, вибір перцентилів p50/p90, обчислення TTFC через julianday (з толерансом ±1с для float-точності), hours-clamp. - 16 нових EN-рядків + переклад UK. tsc 0, 244/244 тестів, vite build зелений.
- A/B-інфраструктура DEFERRED (заплановано далі окремою задачею): таблиця
experiment_assignments+ hash-based розподіл варіантів + funnel-атрибуція. Memo SSOT-нотатка: вибірка F&F-бети замала для статистичної значущості — абсолютний drop-off на етап зараз правильна метрика. - Цілі для трекінгу після шипу: 40% досягають 5/5 за 7 днів; медіана TTFC <10 хв.
Архітектурні інваріанти (збережено):
- ✅ Gate WORKSPACE_MODE незайманий
- ✅ Vault SSOT (візарди read-only)
- ✅ Персистентність activity_log (без in-memory стану — виживає рестарт master, пор. #27)
- ✅ Візард Phase 50.2 незайманий (Phase 54 — шар після візарда)
- ✅ Інваріант Phase 53.13: tsc --noEmit чистий
- ✅ Інваріант Phase 53.14: SSOT задач у БД
Оцінка трудомісткості: ~8.5 днів разом. MVP (54.1-54.3) = 5 днів.
Послідовність: 54.1 → 54.2 → 54.3 (критичний шлях); 54.4, 54.5 паралельно після 54.1; 54.6 останнє (потребує повних funnel-даних).
Phase 54 follow-up — Welcome feature tour (задача #114) — DONE ✅
- 5-слайдова карусель після реєстрації (
WelcomeFeatureTour.jsx): Welcome / Multi-worker / CLI-first / Knowledge+Skills / Telegram+Issues. - Авто-відкривається один раз після завершення візарда Phase 50.2 (за умовою
token && projects.length > 0 && !localStorage.feature-tour-seen). Повторно відкривається звідусіль через window-подіюcrm-open-feature-tour. - Новий
docs/public/features.md(+UK) — каталог "Main Features" / "Основні фічі" з лінком watch-the-tour, підключеним до dispatch події повторного відкриття (Docs.jsx спеціально обробляє якір#feature-tour-trigger). - 19 нових EN-рядків + переклад UK. tsc 0, vite build зелений.
Phase 54 follow-up — Issue discipline enforcement (задача #115) — DONE ✅
- Закриває прогалину аудиту gapap (2026-05-16): воркери знають "кожна задача = issue", але ніщо в рантаймі цього не забезпечувало. Кожна активна робоча поверхня тепер прив'язується до одного issue ID з авто-логованими lifecycle-подіями.
- Бекенд:
ActivityEntry['type']розширено тегамиsession_start/session_end/switched_in/switched_away/auto_summary/reopened+ whitelist-валідація. НовийPOST+GET /api/crm/projects/:name/active-issue(пише вactivity_logevent_typesession_active_issue). - CLI: інтерактивний пікер
pickActiveIssue(сортування P0→P3 + recent-first, fuzzy-фільтр при >10, шорткат для empty-state, підтвердження reopen-on-pick-closed,[q]skip із подвійним підтвердженням). Env varARC_ISSUE_IDдля обходу в CI.ARC_ACTIVE_ISSUE_IDінжектиться у запущений Claude + блок active-issue додається до CLAUDE.md, щоб воркери могли само-логуватися посеред сесії. Нова підкомандаarc issue switch <id>.arc continueавто-підбирає попередній активний ID;--reselect-issueпримушує повторний вибір. - Session-end hook: розширює
scripts/citadel-hooks/session-end.sh— читаєactive_issue_idіз session state JSON, POST-ить auto-summary лог-запис (тривалість хв, коміти з started_at, кількість dirty-файлів) ізtype=session_end. - Web Workspace: модал
ActiveIssuePicker.jsxдзеркалить форму CLI; авто-відкривається при першому візиті на проєкт на вкладку. ХукuseActiveIssueгідратується зsessionStorage, потім GET. Клікабельна пігулка активної задачі у worker bar показує + перемикає контекст. Персистить через новий endpoint. - Telegram: набір
/issueуchild-bot/bot.ts(/issue,/issue list,/issue switch <id>,/issue create <title>,/issue close <id>). Активна задача користувача читається зactivity_log. - Нічний аудит: cron
scripts/audit-issue-discipline.tsпозначає проєкти з ≥5 activity-подіями але 0 оновлень задач за 24 год; TG-пінгує власника через токен master-бота. - 8 backend-тестів на
clients/picker-logic.ts(чисті функції sort + filter + partition). 18 нових EN-рядків + переклад UK. tsc 0, 252/252 тестів, vite build зелений. - Супутні задачі #116 (pre-commit hook, що вимагає
#<id>у commit message) та #117 (ретроспективна реконструкція gapap) відкриті окремим скоупом.
Phase 54 follow-up — commit-msg hook, що вимагає #<id> (задача #116) — DONE ✅
- Новий
.githooks/commit-msgперевіряє, що кожне commit message містить#<n>(абоcloses/fixes/refs/resolves #<n>/(#<n>)). Трейлери Co-Authored-By + Signed-off-by вирізаються, щоб PR-номери в трейлерах не задовольняли правило. - Allowlist: maintenance-префікси Conventional-commits (
chore/docs/style/test/build/ci/refactor/perf, з опційним scope та breaking-маркером!:), Merge / Revert / fixup! / squash! / amend!,[ci skip]/[skip ci]. - Підказка active-issue: якщо env
ARC_ACTIVE_ISSUE_ID(або~/.arc/sessions/*.json) має id, повідомлення про збій показує його напряму для paste-and-go. - Компаньйон до #115 — щойно сесія прив'язана до задачі, кожен коміт із цієї сесії має трасуватися до неї.
- Розширено список відповідальності
scripts/setup-hooks.sh. AssertionSEC-CM1уscripts/vps-sync.shперевіряє hook +core.hooksPath=.githooksна проді після деплою. - 19 backend-тестів (
tests/commit-msg-hook.test.ts) покривають allow / reject / крайні випадки. tsc 0, 271/271 тестів, vite build зелений.
Phase 54 follow-up — PostToolUse auto-log hook (задача #125) — DONE ✅
- Новий
scripts/citadel-hooks/post-tool-use-log.shспрацьовує на PostToolUse Claude Code дляEdit/Write/MultiEdit/Bash. Читає JSON payload зі stdin, поститьauto_summaryзапис у активну задачу (ARC_ACTIVE_ISSUE_ID). Гейти виходу: немає активного id / немає токена / інструмент не в whitelist → тихий пропуск. Тротлінг: sha-ключ на(session, tool, summary), вікно 30с — згортає ланцюги ідентичних операцій. Edit/Write/MultiEditлогуютьfile_path;Bashформатуєcommandзі згорнутими пробілами + обрізанням до 80 символів.--connect-timeout 1 --max-time 2на curl, щоб недоступний сервер ніколи не блокував сесію..claude/settings.jsonреєструє хук із matcherEdit|Write|MultiEdit|Bash.- 16 тестів (
tests/post-tool-hook.test.ts) — bail-outs (5), форми summary для всіх 4 інструментів вкл. довгі+багаторядкові (6), ізоляція тротлінгу (3), стійкість до HTTP 500 / недоступності (2). 16/16 проходять.
Phase 54 follow-up — ROADMAP gate на closes-#N (задача #127) — DONE ✅
- Розширює
scripts/check-docs-coverage.tsновим правилом: тригер наcloses #N/fixes #N/resolves #Nу commit messages, вимагає правкиdocs/ROADMAP.md. Allowlists: коміти Phase NN (покриті наявним Phase-правилом, без подвійного тригера), коміти де кожне message — maintenance-префікс (chore/docs/style/test/build/ci/refactor/perf). - Закриває практичну прогалину #49.1 — досі лише явні
Phase NNкоміти примушували запис у ROADMAP. Закриття під-задач (closes #57тощо) тихо проскакували — саме так довгі спринти накопичували незадокументовані закриття. - Експортує
check,RULES,hasPhaseRef,hasCloseRef,allMaintenancePrefixes, щоб тести могли ганяти rule engine без git. - Assertion SEC-DC1 у
scripts/vps-sync.shпроганяє synthetic-context probe черезcheck()на VPS-клоні після деплою для підтвердження, що правило досі реєструється. - 14 тестів (
tests/check-docs-coverage.test.ts) — предикати (3 кейси), правило closes-#N (6), наявні правила досі працюють (3), комбіновані сценарії (2). 14/14 проходять.
Phase 54 follow-up — Scope-drift watcher (задача #126) — DONE ✅
- Новий
.githooks/pre-commitчитаєARC_ACTIVE_ISSUE_ID(env або~/.arc/sessions/*.json), отримує заголовок + тіло активної задачі через наявний list-endpointGET /api/mcp/issues/:project, проганяє чистий аналізатор уclients/scope-drift.tsпротиgit diff --cached --name-only. - Чиста логіка (
extractPathHints+fileMatchesScope+computeDrift) експортується зclients/scope-drift.ts, тож bash-хук — лише оркестрація. Витяг підказок: path-like у бектіках + сирі path-like токени (whitelist 15 розширень файлів) із тіла, дедуп + lowercase. Substring-збіг зі staged-файлами (без урахування регістру). - Warn-not-fail за замовчуванням: shouldWarn =
hints.length > 0 AND ≥3 staged AND >50% drifting. Навмисно консервативно — задачі, описані прозою, не дають false-positive, однофайлові фікси не спрацьовують. - Інтерактивний промпт через
/dev/tty: Enter — продовжити,s— надрукувати запропонований шаблон під-задачіarc issue create(потім commit переривається, щоб користувач міг пере-stage),cancel— перервати.git commit --no-verifyзавжди працює. - 21 backend-тест (
tests/scope-drift.test.ts) — порожнє тіло / тільки бектіки / тільки сирі / дедуп / регістр / мульти-розширення; fileMatchesScope substring + регістр + директорія + fallback без підказок; computeDrift drift ratio + minStaged + поріг + порожній список + title-as-body інтеграція. 21/21 проходять.
Phase 54 follow-up — Ретроспективна реконструкція задач (задача #117) — DONE ✅
- Нова CLI-підкоманда
arc retro <project>реконструює задачі ретроактивно з історії сесій + git log. Dry-run за замовчуванням;--applyфактично створює задачі. - Сканує
~/.arc/sessions/<project>-*.jsonна непов'язані сесії (сесії після #115 повністю пропускають пікер, якщоactive_issue_idзаданий). Читає перший user-промпт ізtranscript_pathJSONL для виведення заголовка;git log --since=started_at --until=ended_atзбирає коміти для тіла + per-commitauto_summaryactivity-записи. - Дедуп через Jaccard-on-words
titleSimilarity(поріг 0.55), схрещений з вікном перетину ±48 год — запобігає створенню вже заведених задач. - Activity-записи датуються заднім числом оригінальними таймстемпами через нове опційне поле
tsуPOST /api/mcp/issues/:project/:id/log(clamp майбутніх значень до now).--since YYYY-MM-DDдля пропуску древніх сесій;--worker <id>для фільтра. - Старші сесії (>30 днів за замовчуванням) з комітами авто-закриваються при створенні; недавні лишаються відкритими, щоб користувач міг підхопити й завершити їх.
- Новий чистий planner-модуль
clients/retro-planner.tsвідокремлює побудову плану від side-effects; 11 тестів уtests/retro-planner.test.tsпокривають фільтрацію (linked / warm-up / since cutoff), побудову кандидатів (виведення заголовка, тіло з комітів, activity-записи, авто-закриття) та дедуп (позитивний + негативний). tsc 0, 282/282 тестів.
Phase 55: Login Page Redesign — Cosmic Editorial (PLANNED)
Замінити поточний статичний
LoginOverlay.jsx(593 LOC) +LoginBackdrop.jsx(98 LOC) хендофом Claude Design "Variant A — Cosmic Editorial": анімована планета (terminator-as-ARC), зоряне поле + супутники, glassmorphismCosmicCardз повним state machine, editorial-сторона з headline + слайдером можливостей + tickertape agent-chatter. Підтягує екран логіна до бренд-планки Phase 47/47.8 (Timeline/IssuesRedesign).
Source bundle: arc-os-login-page/project/parts/*.jsx (Sign-in.html + 5 jsx parts, ~2.1k LOC дизайн-коду).
Документ аналізу: designs/login-redesign-analysis-2026-05-10.md.
Оригінальний промпт: designs/login-redesign-prompt-2026-05-10.md.
55.1 — Зачистка дизайнерських тогглів перед merge (задача #82, P0) — DONE ✅ (2026-05-13)
- Видалено з
arc-os-login-page/project/:tweaks-panel.jsx,design-canvas.jsx,index.html(explore canvas),parts/app.jsx,parts/mobiles.jsx,parts/variant-b.jsx,parts/variant-c.jsx,parts/variant-d.jsx. parts/variant-a.jsx:VA_HEADLINES[]→ єдинийVA_HEADLINE;VA_PALETTES{}(clay/aurora/sage/earth) → єдинаVA_PALETTE(clay);PlanetA/VariantAспрощено — гілкиpaletteKey/isEarth+ тоггли density/cardSide/planetPos прибрано; production-значення хардкоднуто (headlineos, paletteclay, motionlush, densityregular, планета внизу ліворуч, картка праворуч, швидкість слайдера 5000 мс, tickertape on).parts/signin-app.jsx:TWEAK_DEFAULTS+useTweaks+TweaksPanel(і всіTweakSection/Select/Radio/Toggle/Slider/Color) прибрано;HEADLINE_OPTIONS+PALETTE_OPTIONS+PALETTE_KEYS+paletteIndex+ скейлерFitToViewportвирізано. 252 LOC → 99 LOC.parts/cosmic-card.jsx:accent || window.VA_PALETTES?.clay→accent || window.VA_PALETTE.Sign-in.html: викинуто тег<script src="tweaks-panel.jsx">.- Diff: −2891 LOC / +78 LOC у 12 файлах. Усі 5 решти JSX-файлів парсяться чисто через
@babel/parser. Без осиротілих посилань на прибрані символи. - Розблоковує 55.2–55.6.
55.2 — Анімований космічний фон (задача #83, P1) — DONE ✅ (2026-05-13)
frontend/src/crm/components/login/LoginBackdrop.jsxзамінює legacy 98-LOC статичний градієнт. ~290 LOC.- 9-шарова композиція Planet (глибока димка + Fresnel rim + dayside halo + базовий диск + хмари + обертання поверхні + полярні шапки + тінь термінатора + sunset Rayleigh + specular + SVG noise + terminator-as-ARC clay-дуги).
- 10-шаровий parallax Starfield + туманні wisps + падаюча зірка + Satellites на 4 орбітах із glow-фільтром.
- Mouse parallax (±10 px),
prefers-reduced-motionзгортає анімації.
55.3 — Форма CosmicCard (задача #84, P1) — DONE ✅ (2026-05-13)
frontend/src/crm/components/login/CosmicCard.jsx~580 LOC, glass-картка + state machineidle / loading / error / magic / success.- Збережено: режими email+password, OAuth (Google+GitHub), invite-експандер Phase 52.1,
initMasterKeyPhase 45.1, gate верифікації email, флоу скидання пароля. - Додано: перемикач show/hide пароля, індикатор caps-lock, кнопка magic-link, анімація успіху з відліком 1.5 с.
55.4 — Editorial-сторона (задача #85, P1) — DONE ✅ (2026-05-13)
EditorialPanel.jsx+CapabilitySlider.jsx+Tickertape.jsx.- 5-слайдовий авто-ротатор із Trans-локалізованими заголовками, 8-рядковий tickertape із mask fade, FooterRow
session_key · e2ee · aes-256. - Headline через
clamp()(48–84 px), безtransform-scale.
55.5 — Magic-link флоу (задача #86, P2) — DONE ✅ (2026-05-13)
- Бекенд:
shared/auth.tsgenerateMagicToken/consumeMagicToken(TTL 10 хв черезephemeral_tokensтипmagic_link, одноразовий, видає JWT + перемикаєemail_verifiedпри споживанні). master-bot/routes/auth.ts:POST /api/auth/magic-link/request(анти-енумерація: той самий rate-limit + timing pad що й forgot-password) +POST /api/auth/magic-link/verify.shared/email.tssendMagicLinkдзеркалитьsendPasswordReset.- Фронтенд: UI стану
magic+ 60-с відлік resend + авто-споживання?magic_token=при монтуванні. - Розширено union
EphemeralTokenType.
55.6 — 2FA / TOTP — BLOCKED на дизайні Sentinel (задача #87, P2) — STILL BLOCKED
- Досі потрібен дизайн схеми + endpoint від Sentinel. State machine логіна має місце для стану
2fa, щойно дизайн приземлиться.
55.7 — Мобільні + responsive breakpoints (задача #88, P2) — DONE ✅ (2026-05-13)
- Хук
useViewportMode+ CSS Grid template уLoginOverlay.jsx. ≥1024 px: колонки 60/40. <1024 px: одна колонка, editorial прихований, картка по центру. - Без
transform-scale;clamp()-відступи всюди.
55.8 — Аудит A11y + i18n + reduced-motion (задача #89, P1) — DONE ✅ (2026-05-13)
aria-invalidна полях форми,role=alert+aria-live=assertiveна error Banner,role=status+aria-live=politeна info / success банерах,aria-labelна icon-only кнопках, focus ring через 3 px акцентну тінь.prefers-reduced-motion: reduceзгортає кожну анімацію в no-op або 0.001 с.- 44 нові lingui-рядки витягнуто + переклад UK.
55.9 — Анімація успіху + відлік редиректу (задача #90, P2) — DONE ✅ (2026-05-13)
- Анімований пульс галочки + "Welcome back" + progress bar 1.5 с перед спрацюванням
onLogin. - Keyframes поважають
prefers-reduced-motion.
55.10 — QA-фікси проти канонічного дизайну (задача #110, P1) — DONE ✅ (2026-05-13)
QA-прохід Sentinel виявив 5 розбіжностей deploy-vs-design у CosmicCard.jsx + EditorialPanel.jsx:
- Копію хедера повернуто до дизайн-рядків:
Sign in to continue+Your AI command center. - Прибрано hide-then-reveal "Continue with email"; email + password рендеряться inline після роздільника OR.
- Викинуто tab-пігулку "Sign in / Create account"; одна основна кнопка "Sign in →" за дизайном.
- Beta-invite експандер завжди доступний (був за умовою
mode=register); присутність визначає авто-детекцію endpoint'аregistervsloginпри submit. Плейсхолдер відповідає дизайну:arc-XXXX-XXXX (beta invite). FooterRowпортовано зarc-os-login-page/shared.jsx:303-327— новийlogin/FooterRow.jsx. Замінює стрічку session_key внизу editorial-колонки наDocs · Terms · Privacy · ● Status · EN / UK. Перемикач EN/UK підключено доactivateLocaleзi18n/i18n.js.- Плейсхолдер email
Email→[email protected]. - Стан почищено: викинуто
mode,setMode,emailFormOpen,setEmailFormOpen. 9 нових EN-рядків + UK-переклади.
Архітектурні інваріанти (збережено):
- ✅ E2EE-флоу незайманий (
crypto/e2ee.tsinitMasterKey виконується до редиректу) - ✅ Наявні OAuth (Google/GitHub) + email/password + reset/verification флоу цілі
- ✅ Regex інвайт-коду Phase 52.1 (
arc-XXXX-XXXX) збережено - ✅ Єдина бренд-палітра (clay) — альтернативні палітри не шипляться
- ✅ Інваріант Phase 53.13: tsc --noEmit чистий
Оцінка трудомісткості: ~6д MVP (55.1-55.4 + 55.7-55.9; піднято з 5д після re-export фону 2026-05-13), +1д на magic-link (55.5), +2-3д на 2FA після розблокування (55.6). Разом з усіма підфазами: ~8-9д.
Послідовність: 55.1 (P0 gate) → паралельно: 55.2, 55.3, 55.4 → 55.7, 55.8 → 55.9 (audit gate); 55.5 паралельно будь-коли; 55.6 відкладено.
Задачі: #82 (P0), #83-#85 (P1), #86 (P2), #87 (P2 blocked), #88 (P2), #89 (P1), #90 (P2).
Phase 56: AI Interop Layer — Project Context Export (PLANNED)
Power-user фіча на тезі "OS for AI Teams": дати власникам проєктів передавати повний санітизований знімок проєкту будь-якому зовнішньому AI (Gemini, ChatGPT, Perplexity, Claude.ai) без copy-paste театру. Валідований pain point — вручну будувалося двічі для product-owner сесій до рішення продуктизувати.
Інверсія Phase 54. Де 54 онбордить користувача в Arc OS, 56 допомагає користувачу винести контекст Arc OS в інший AI-інструмент. Обидві розширюють поверхню user empowerment навколо власних даних проєкту.
Скоуп: вхід у TopHeader + Project Settings → вкладка Export → 3-кроковий модал (секції → обов'язковий secret scan → preview & download). Вихід — один .md файл з назвою <project>-context-<date>.md.
Приватність — це ставка, а не післядумка. Дірявий експорт = юридична + довірча катастрофа. Багаторівневий сканер (regex + ентропія + контекстні евристики), авто-редагування критичних знахідок, примус користувача переглянути кожну high/medium знахідку, обов'язковий чекбокс підтвердження перед завантаженням.
56.1 — Модуль secret scanner (задача #97, P0) — DONE ✅ (2026-05-13)
shared/pii-sanitizer.tsвідрефакторено: PATTERNS → експортованийPATTERN_REGISTRY(типізованийPatternRule[]зkind+severity), backward-compatsanitizePII/sanitizeObjectзбережено.- Відвантажено
shared/secret-scanner.ts— 3-рівневий сканер: Tier 1 regex черезPATTERN_REGISTRY, Tier 2 ентропія Шеннона (≥4.5 біт/символ на послідовностях ≥20 символів), Tier 3 контекстні евристики наkey=/token:/secret=/password=. - Whitelist приглушує UUID, git SHA, SHA-256, повторювані символи, короткий hex, низькоентропійний base58.
- Рівні серйозності: critical (авто-редагування за замовчуванням) / high / medium / low — керує review-флоу модала.
ScanResult { findings, sanitized, stats }; хелперgroupBySeverity().tests/secret-scanner.test.ts— 51 тест зелений: усі 3 рівні, мапінг серйозності, авто-редагування, точність line/column, перевірено перф-бюджет 1 MB / <500 мс.docs/architecture/secret-scanner.md— інваріанти + API + нотатки майбутніх рівнів.- Увесь репо: 151/151 тестів,
tsc --noEmit0 помилок.
56.2 — Export endpoint + рендерер секцій (задача #98, P0) — DONE ✅ (2026-05-13)
- Відвантажено
shared/routes/context-export.ts—GET /api/crm/projects/:name/context-export?include=...&scanOnly=...&activityHours=...&commitLimit=...&issueStatus=.... - 7 рендерерів секцій: identity (CLAUDE.md) / workers (registry +
config/workers_registry.json) / architecture (шаблонна константа — без живого читання БД) / issues (issueQueries) / activity (analyticsQueries.recentActivity, owner-scoped) / commits (git logчерезBun.spawnSync) / learnings (learnings.md, останні 30 KB). - Пайплайн: assemble →
scanForSecrets({ autoRedactSeverity: ["critical"] })→ повертає{ project, exportedAt, filename, scanOnly, sections, markdown, findings, stats }. - Multi-tenancy:
extractChatId+isCeo+isProjectOwner. Роль admin НЕ обходить owner gate (owner-only за дизайном). - Підключено у switch
shared/routes/router.ts(case "/context-export"). - 28 тестів зелені: auth-матриця (401/400/403/200), форма відповіді, режим scanOnly, фільтрація секцій, пайплайн авто-редагування (знахідки AKIA + sk-ant із line/column), 8 fallback'ів рендерерів, перф-бюджет <2 с.
- Увесь репо: 179/179 тестів,
tsc --noEmit0 помилок.
56.3 — Модал Project Context Export (задача #99, P0) — DONE ✅ (2026-05-13)
- Відвантажено
frontend/src/crm/components/ProjectContextExportModal.jsx— 3 кроки, що дзеркалять візуальний патернBotCreationWizard(progress bar, навігація у футері, мобільний розмір картки). - Крок 1: 7 чекбоксів секцій + Advanced-колапс (
issueStatus,activityHours,commitLimit). - Крок 2: авто-виклик
/context-export?scanOnly=trueпри вході, групує знахідки за серйозністю, ack gate над кожною high/medium знахідкою перед Next. - Крок 3: панель markdown-прев'ю + підказка
Filename:+ обов'язковий чекбокс "I reviewed this file" + кнопки Download (blob URL) та Copy (navigator.clipboard). - Owner-only gate забезпечується бекендом (Phase 56.2) — модал чисто обробляє 403 через перекладену помилку.
- Вхідний CTA змонтовано у
frontend/src/crm/pages/ProjectSettings.jsx(секція "AI Interop" над Danger Zone). - Чисті хелпери винесені у
frontend/src/crm/components/contextExportHelpers.jsдля покриття bun:test (немає React DOM тест-інфри в репо). - 23 unit-тести для хелперів: збірка section-параметрів, групування за серйозністю, ack gate (3 ack-сценарії), форматування назви файлу, лейбли серйозності, обрізання match.
- EN/UK i18n: 25 нових рядків витягнуто + UK повністю перекладено (
npx lingui extract && compile). npm run buildзелений: chunk ProjectSettings 30.59 KB.- Увесь репо: 202/202 тестів,
tsc --noEmit0 помилок.
MVP COMPLETE — 56.1 + 56.2 + 56.3 відвантажують повний owner-driven export-флоу end-to-end (secret-scanner → endpoint → модал).
56.4 — Settings + audit log (задача #100, P1) — DONE ✅ (2026-05-13)
- Міграція 024: таблиці
export_audit_log+export_preferences. exportQueries:insertAudit/listAudit/getPreferences/upsertPreferences/countExportsByOwnerSince/aggregateExportStats.context-export.tsчитаєprefs.auto_redact_critical(за замовчуванням ON) і пише audit-рядок на кожен не-scanOnlyекспорт.- Нові маршрути:
GET /api/crm/projects/:name/exports(список audit, owner-only),GET+PATCH /api/crm/projects/:name/settings/export(prefs round-trip). - 23 unit-тести покривають CRUD + запис/пропуск audit + перекриття auto-redact + auth-матрицю endpoint.
- UI вкладки Settings відкладено — наявна секція "AI Interop" у ProjectSettings адекватна для MVP; багатша вкладка — кандидат 56.4.1.
56.5 — Telemetry + alerts (задача #101, P2) — DONE ✅ (2026-05-13)
- Audit log — це telemetry sink — паралельний пайплайн не потрібен.
context-export.tsзапускаєlogActivity("export_alert", ...), коли власник має ≥3 експорти за 24 год ТА prefnotify_on_exportopt-in (за замовчуванням OFF). Виводиться через наявний TG notify пайплайн Phase 53.10.- Новий endpoint
GET /api/crm/analytics/exports→aggregateExportStats(hours), що повертає{ total, byProject[{project_name, n, last}], severitySums }. - Константа порога в
context-export.ts(ALERT_THRESHOLD_PER_24H = 3). - Frontend analytics-картка відкладена до майбутнього polish-проходу — endpoint є gating-частиною.
56.4 — Settings tab + audit log (задача #100, P1) — PLANNED
- Нова вкладка "Export" у Project Settings: quick-export CTA (перевикористовує модал 56.3) + таблиця audit log (останні 50 експортів: таймстемп, користувач, секції, кількість знахідок, розмір) + per-project преференції (always-include-emails, auto-redact-critical, notify-on-export).
- Нові endpoints:
GET /api/crm/projects/:name/exports,PATCH /api/crm/projects/:name/settings/export. - 10+ тестів. М'яко залежить від #101 (audit log багатший із telemetry-даними).
56.5 — Telemetry + алерти витоку секретів (задача #101, P2) — PLANNED
activity_logevent_typeproject_context_exportіз PII-чистими метаданими{sections_included, findings_count, output_bytes, user_id, project_name}.GET /api/crm/analytics/context-exports— 30-денні агрегати на власний проєкт.- Нова Analytics-картка з bar chart + попередженням "High secret-found rate", якщо critical >5 за 7 днів.
- Алерт: in-app toast + опційний TG-пінг (перевикористовує notify-інфру Phase 53.10), якщо ≥3 експорти за 24 год АБО залоговано critical-знахідку.
- Залежить від #98, м'яко від #100, Phase 53.10.
Архітектурні інваріанти (збережено):
- ✅ PII sanitizer Phase 45 розширено, не продубльовано
- ✅ Multi-tenancy gate Phase 42 забезпечено (
canAccessProject+ новийisProjectOwner) - ✅ Інваріант Phase 53.13: tsc --noEmit чистий
- ✅ Патерн персистентності activity_log (SSOT Phase 53.14)
- ✅ Vault SSOT — сканер читає контент, ніколи vault напряму
- ✅ Notify-інфра Phase 53.10 перевикористана для алертів (без паралельного notification-стеку)
Оцінка трудомісткості: ~3.5 дня. MVP (56.1-56.3) = 2.5 дня. Settings tab + telemetry додають 1 день. Послідовність: 56.1 (фундамент, блокує все) → 56.2 → 56.3 (точка відвантаження MVP) → 56.4 + 56.5 паралельно після MVP.
Задачі: #97 (P0), #98 (P0), #99 (P0), #100 (P1), #101 (P2).
Phase 57: Platform Settings UI (follow-up Sentinel #103, DONE ✅)
Закриває вектор витоку за #103: ротація платформених секретів (ключі Anthropic / OAuth / TG / Resend) більше не потребує воркфлоу ssh + редагування
.env+ вставка в чат. Super-admin клікає "Rotate" у CRM UI → нове значення атомарно лягає у vault.json → прив'язані боти рестартують → пишеться audit-рядок.
Мотивація. Sentinel #103 (2026-05-13) — випадковий bash -x на start-child-bot.sh надрукував повний .env в історію розмови. Наступна спроба ротації повторно злила 3 із 5 свіжих токенів через chat-paste. Корінна причина — воркфлоу, а не людська помилка: кожен канал, який людина використовує для ротації (shell, редактор, AI-чат), є логуючою поверхнею. Єдиний безпечний канал — UI password input — значення ніколи не ехається, ніколи не персиститься у scrollback, ніколи не копіюється через історію буфера обміну.
Архітектура. Бекенд = тонка оболонка над наявним AES-256-GCM API shared/vault.ts + нова append-only таблиця platform_audit_log + гейт requireAdmin з Phase 53.15. Фронтенд = сітка карток на керований ключ, rotate-модал із password-input, шухляда audit log. Hot-reload через detached Bun.spawn(["nohup", "bash", "-c", "tmux kill-session ... && bash start-*.sh"]), щоб рестарт master не вбивав власну відповідь.
57.1 — Backend MVP (Stage 1, DONE ✅ 2026-05-15, коміт 6171d32)
shared/migrations/026_platform_audit_log.ts— append-only таблиця (id PK AUTOINCREMENT, ts UTC, user_chat_id, user_email, action, key_name, ip, result, user_agent) + 3 індекси (idx_ts / idx_user / idx_key).shared/db.ts—platformAuditQueries.insert/recent/lastRotated(доступ read-only — без UPDATE/DELETE хендлерів; інваріант append-only).shared/routes/platform.ts— 5 хендлерів: list / rotate / test / restart / audit. Allowlist на 9 ключів (ANTHROPIC_API_KEY,PLATFORM_ANTHROPIC_KEY,GITHUB_CLIENT_ID/SECRET,GOOGLE_CLIENT_ID/SECRET,MASTER_BOT_TOKEN,CITADEL_BOT_TOKEN,RESEND_API_KEY). Жорстке виключенняNEVER_EXPOSE:CRM_SECRET(підпис JWT) +SECRET_ENCRYPTION_KEY(мета-ключ vault) — відмова навіть з admin-токеном.- Редагування:
prefix(12)…suffix(4)+ довжина, повне значення ніколи не перетинає HTTP-межу. - SaaS-проби (лише ключі
testable: true): Anthropic/v1/modelsізx-api-key, TelegramgetMe, Resend/api-keys. OAuth client secrets standalone → 501 "not testable". Таймаут 8 с черезAbortController. - Аудит: успіх + кожен збій (
fail:not_in_allowlist,fail:value_too_short,fail:vault_write,fail:networkтощо) пише рядок з IP + UA + email. shared/routes/router.ts— 5 диспетчерів для/api/crm/platform/{settings, settings/:name, settings/:name/test, settings/:name/restart, audit}.- Збірка:
bun build master-bot/bot.ts→ 77 модулів, 0.56 MB, чисто.
57.2 — Frontend (Stage 2, DONE ✅ 2026-05-15)
frontend/src/crm/pages/PlatformSettings.jsx(НОВИЙ, ~620 LOC) — responsive сітка карток (9 карток із редагованим прев'ю + lastRotated + 3 кнопки Rotate/Test/Restart), rotate-модал із<input type="password">+ повторне підтвердження + перемикач видимості Eye/EyeOff, шухляда audit log (slide-in справа з фільтром на ключ).frontend/src/crm/App.jsx— підключено маршрут сторінкиplatform-settings+ lazy-імпорт.frontend/src/crm/components/TopHeader.jsx— додано Shield-іконкуPlatformу GLOBAL_NAV з прапорцемadminOnly: true, фільтрується заuserRole === "admin"з/api/auth/me. Не-адміни ніколи не бачать пункту.- Defence-in-depth: серверний
requireAdmin— справжній гейт; не-адмін, що відкриває URL напряму, отримує 403 + повідомлення "Access denied". - Збірка:
vite buildчиста.dist/assets/PlatformSettings-*.js16.10 kB / 4.20 kB gzip.
57.3 — Hot-reload інтеграція (Stage 3, DONE ✅ 2026-05-15, коміт 444a101) — shared/auth.ts loadOAuthConfig() читає getSecret() на кожен виклик; restartTargets очищено для GitHub/Google/Resend (RESEND уже hot-reload через shared/email.ts:47). Після ротації наступний запит читає нове значення з vault — без рестарту master, без обірваних з'єднань. Ключі ANTHROPIC + Telegram лишаються restart-required (споживаються при spawn child-бота / ініціалізації TG long-poll через env).
57.3.1 — UI polish (DONE ✅ 2026-05-15, коміт 56191b0) — фідбек "картки однією купою, без контексту": сітку відрефакторено на 4 категоризовані секції (Anthropic / OAuth Providers / Telegram Bots / Transactional Email) із заголовком + іконкою + підказкою + лічильником елементів. Кожна картка отримує згортувану панель довідки (перемикач через іконку Info) зі структурованим контекстом: USED IN (файли/флоу, що читають ключ), GET NEW VALUE FROM (deeplink на SaaS-дашборд), EFFECT AFTER ROTATE (миттєво vs restart-required + крайні випадки), RISK IF LEAKED (масштаб ураження компрометації). Бекендовий MANAGED_KEYS отримує 5 нових полів (category / usedIn / getFromUrl / effectAfterRotate / riskIfLeaked); list-відповідь їх прокидає. Новий компонент HelpRow для рядків із лейблами всередині панелі.
57.3.2 — UK i18n каталог (DONE ✅ 2026-05-15, коміт 6747331) — lingui extract виявив 66 відсутніх UK-рядків після відвантаження Phase 57 (текст Platform Settings не перекладався при додаванні). Батч-переклад 65 за один прохід (1 внутрішній плейсхолдер пропущено): 35 із Platform Settings + 11 із FeedbackWidget + 6 BotCreationWizard + 4 DocsSearch + 6 relative-time/onboarding/banner + 3 лейбли таксономії. Скомпільовані каталоги + vite build чисто. Follow-up фікс (коміт 6970849): початковий коміт пропустив скомпільовані .ts каталоги — застейджено лише .po. Згідно з нотаткою CLAUDE.md (коментар у .gitignore): "Docker build skips lingui compile due to issue #23 — .ts must be committed alongside .po". Файли .ts перекомічено для розблокування проду.
57.3.3 — Повна локалізація бекенду (DONE ✅ 2026-05-16, Option B) — фідбек: лейбли карток / описи / вміст довідкових панелей (Used in, Get new value from, Effect after rotate, Risk if leaked) були TypeScript-літералами бекенду в MANAGED_KEYS, lingui-макроси не можуть витягувати динамічні рядки. Workaround: додано реєстр _PLATFORM_BACKEND_I18N усередині PlatformSettings.jsx — явні виклики msg\…`для кожного бекенд-рядка, тож Babel-екстрактор lingui підбирає їх уmessages.po. Render використовує _(item.label)черезuseLingui()._для резолюції в рантаймі. Підказки CATEGORIES теж конвертовано вmsg`…`. Витягнуто 70 нових msgid; 69 перекладено на UK за один прохід (1 внутрішній плейсхолдер). Бекенд shared/routes/platform.ts` без змін — тримає EN як SSOT, фронтенд обробляє переклад. Дисципліна дрейфу: будь-яке нове поле MANAGED_KEYS має дзеркалити рядки в реєстрі.
57.3.4 — Фікс мапи MessageDescriptor (DONE ✅ 2026-05-16, коміт 5e9e929) — UK-переклади не застосовувалися в рантаймі попри наявність у каталозі: lingui compile генерує короткі hash-msgid (напр. 8lt1P5 → "Anthropic — Platform Inference") для зменшення бандла, тож lookup _(plainBackendString) промахується (каталог ключований hash'ем, не вихідним текстом). Фікс: побудувати PLATFORM_I18N = new Map(descriptors.map(d => [d.message, d])), щоб render міг _(MAP.get(item.label)) — дескриптор несе свій hash-id як .id, lingui знаходить запис каталогу. Новий хелпер tx(_, source) робить map lookup + fallback на вихідний рядок при промаху. Оновлено всі 8 render call sites.
57.4 — Використати для живої ротації (Stage 4) — повторити ротацію #103 через новий UI. Audit log записує дії. Старі токени відкликано в SaaS-дашбордах.
Задачі: #103 (P0 — ротація секретів, OPEN до завершення Stage 4), #102 (P0 — tmux-витік закрито).
Phase 58: Header / UserDropdown UX (DONE ✅ 2026-05-16)
UX-рефакторинг за патерном Claude.ai: пігулка користувача внизу ліворуч замість кластера Docs/Help/Lang/Theme/Avatar угорі праворуч. Чистить TopHeader і дає меню користувача єдиний виявлюваний дім.
58.1 — Пігулка користувача внизу ліворуч (DONE) — UserDropdown.jsx переписано як fixed-пігулку внизу ліворуч viewport (ширина 240px, над 28px AppFooter). Поповер відкривається вгору. Нове 3-рівневе меню: account (Profile/Bridge/Billing/Subscriptions) → роздільник → app (Docs/Replay onboarding/Language/Theme) → роздільник → Logout. Lang і Theme — inline-перемикачі з лейблом поточного значення.
58.2 — Чистка TopHeader (DONE) — викинуто кнопку Docs, меню Help, LangSwitcher, ThemeToggle, UserDropdown із правої зони. Права зона тепер порожня; ліва зона (гамбургер + лого + BETA + перемикач проєктів + глобальна навігація) володіє всім header-баром. Прибрано невикористані імпорти + стан helpOpen + replay-хендлер + onboarding-проп.
58.3 — Нижній відступ Sidebar (DONE) — Sidebar.jsx додає paddingBottom: 60px на overlay та inline aside, щоб скрол навігації проєкту не заїжджав під fixed-пігулку. Overflow inline aside змінено hidden → hidden auto для збереження вертикального скролу.
CrmMainLayout.jsx тепер рендерить <UserDropdown onOpenDocs onboarding /> як fixed-сусіда і перестає передавати onboarding у TopHeader. 4 файли, +342/-330 LOC, vite build зелений.
58.1.1 — Onboarding modal wizard + per-step підказки (DONE ✅ 2026-05-16) — фідбек користувача: inline OnboardingChecklist на Workspace з'їдав забагато місця, а абстрактні лейбли кроків на кшталт "Confirm your workers" не давали жодної підказки що клікати. Фікс із двох частин:
- Новий
OnboardingModal.jsxіз backdrop blur + закриттям по ESC. РендеритьOnboardingChecklistу новомуmode='modal'(без зовнішнього card chrome, кнопка X веде до onClose замість постійного dismiss). - Новий
OnboardingProgressPill(той самий файл, named export) — маленька плаваюча кнопка внизу праворуч над FeedbackWidget із круговим SVG progress ring + лейблом "Setup N/5". Видима лише покиonboarding.visible. Клік → відкриває модал. - Кожен запис
STEP_METAотримав нове полеhintіз конкретними навігаційними breadcrumbs (workers: "Open Workspace → click any worker pill → WorkerStudio panel opens on right → review → close → Mark done"; cli/skill/bot/issue аналогічно явно). Підказка рендериться в м'якому акцентному блоці з іконкою Lightbulb, поки крок pending. UserDropdown.jsx"Replay onboarding" відкриває модал напряму; лінивий бекендовий resetreplay()лише коли фактично dismissed/complete.Workspace.jsxприбрано inline-монтуванняOnboardingChecklist+ імпорт.CrmMainLayout.jsxволодіє станомonboardingModalOpenі рендерить модал + пігулку глобально.
Файли: 5 (1 НОВИЙ, 4 змінені). Build vite ✓ 8.63с.
Phase 59: Localization Expansion — 6 нових локалей (DONE ✅ — 59.1-59.4 завершені)
Arc OS сьогодні шипиться в EN + UK (438 рядків, lingui v5). Phase 59 додає 6 локалей паралельно: DE (німецька), ES (іспанська), PL (польська), RU (російська), pt-BR (португальська Бразилія), FR (французька). Стратегія — AI-only переклад із in-app beta-feedback loop — без платних людських перекладачів наперед. RU явно включена за рішенням CEO 2026-05-16 (перекриття рекомендації PO пропустити; обґрунтування: російськомовна dev-діаспора велика, бренд лишається глобальним інструментом, не політично-вирівняним, future-proofing).
Gating-передумова (НЕ всередині скоупу Phase 59): спершу має закритися UK-борг — задачі #32 (людська вичитка 17 AI-перекладених UK-документів), #33 (переклад 6 deep-architecture symlink-документів), #34 (10 відео-walkthrough). Реплікація неперевіреного пайплайна на 6 локалей = 6× борг неперевіреного контенту.
Мови назавжди поза скоупом (не відкладені — інша інженерна категорія):
- JA / zh-CN — CJK-рендеринг, font subsetting, line-height — окремий клас проблем
- AR — RTL-розкладка потребує обробки напрямку на рівні компонентів, окрема фаза якщо взагалі
- HI / KO / TR / IT / NL — низький LTV відносно зусиль
59.1 — Lingui-інфра + глосарій + конвенції тону (задача #119, P0) — DONE ✅ (2026-05-17)
- 6 нових файлів
messages.po, засіяних з EN master, оновлено lingui.config.js, vite build перевірено для 8 локалей. - Конвенції тону ЗАФІКСОВАНО на локаль: DE "du", ES "tú", PL дієслівні форми 2-ї особи (уникнення Pan/Pani), RU "ты", pt-BR "você", FR "tu".
- Глосарій на локаль
config/i18n-glossary/<lang>.json: бренд-терміни, CLI-команди (ніколи не перекладаються), імена воркерів (Rick/Morty/Beth тощо ніколи не перекладаються), правила збереження tech-жаргону. - Скелет AI-пайплайна перекладу (
scripts/i18n-translate.ts) споживає глосарій + тон + вихідний рядок → Claude-промпт → кандидат перекладу. - Фундамент — блокує весь 59.
59.2 — AI-пайплайн перекладу + UI-рядки × 6 (задача #120, P0) — DONE ✅ (2026-05-17)
- Батч-переклад: ~438 рядків × 6 локалей = ~2628 перекладів через Claude API.
- Правила збереження плейсхолдерів: ICU
{name}, плюрали Lingui, React<0>tags</0>, markdown-лінки — все збережено. - Авто-перевірки якості: цілісність плейсхолдерів, відповідність глосарію, sanity довжини (0.5×-2.5× джерела).
- Lingui compile + vite build зелені для всіх 8 локалей. Скріншотний smoke test Login + Workspace + Settings × 6.
- Залежить від #119.
59.3 — Переклад публічної документації × 6 (задача #121, P0) — DONE ✅ (2026-05-18, 216/216 файлів)
- Дзеркалення структури
docs/public/uk/для 6 нових локалей: ~40 markdown-файлів × 6 = 240+ документів. - Markdown-aware пайплайн: пропуск код-блоків, inline-коду, URL, image alt; переклад frontmatter title/description, але не slug/tags; збереження heading-якорів для крос-документних лінків.
- Стратегія fallback: неперекладені документи показують EN із банером на локаль.
- Найбільша підфаза за обсягом контенту. Виконано через 13 паралельних Claude-субагентів (інфраструктура Anthropic, без витрат CEO-токенів).
- Залежить від #119, паралельно з #120.
- Follow-up (2026-05-21): Синхронізовано locale docs з Phase 63 змінами — додано міграції 027-032 до
database-schema.mdтаGET /account/usage+ Phase 63 changelog доapi-reference.mdдля всіх 7 локалей (DE/ES/FR/PL/RU/pt-BR/UK). UK окремо отримав міграції 023-026 (раніше відсутні). Зміни в коміті376dec4. - Поточні переклади (2026-05-21): Cloud/Billing/AdminDashboard UI перекладено на всі 7 локалей; ThinkingTips та WorkspaceEmptyState strings локалізовано; Arc Help + token usage strings скомпільовано для 7 локалей.
59.4 — Translation feedback widget + per-locale review dashboard (задача #122, P1) — DONE ✅ (2026-05-21)
FeedbackWidget: 4-й типtranslation_issue(Globe, фіолетовий) — поля locale/msgid/suggestion/severity; submit →/api/crm/feedback/translationTranslationsDashboard: admin-only сторінка, locale filter tabs, status filter (open/accepted/rejected/all), per-item Accept/Reject з optional note- Accept action патчить
.poфайл на диску; glossary_suggestion flag коли 3+ accepted для одного msgid - Stats tab: per-locale health cards (open/accepted/rejected/critical counts)
UserDropdown: "Translations" пункт меню (Languages icon) в Admin section- Міграція 030: таблиця
translation_feedback(locale/msgid/suggestion/severity/status/resolved) - 5 нових API endpoints:
POST /feedback/translation,GET /admin/translations,GET /admin/translations/stats,POST /admin/translations/:id/accept|reject - 98 нових перекладів для widget + onboarding strings × 7 локалей
- Залежить від #120, м'яко від Phase 53.5.
59.5 — UI visual regression × 6 локалей (задача #123, P1) — PLANNED
- Chrome DevTools / Playwright скріншот-diff проти EN baseline на 9 ключових сторінках × 3 viewport × 6 локалей = 162+ скріншотів.
- Ловить довгі німецькі складені слова, вужчі кириличні гліфи, багатослівні дієслова ES/FR/pt-BR, польські діакритики, російські 3-формні плюрали.
- Мобільна адаптивність ≥360px тестується на локаль.
- Новий
scripts/i18n-visual-regression.tsвидає HTML diff-звіт; CI падає при >2% pixel diff на критичних елементах (CTA, навігація, модали). - Залежить від #120, м'яко від #121.
59.6 — Аналітика мов + browser auto-detect + polish перемикача (задача #124, P2) — PARTIALLY DONE (2026-05-18)
- ✅
UserDropdown: inline<select>замість cycle-button для перемикання мови (2026-05-18) - ✅ Повні назви мов у всіх locale selects (login footer, UserDropdown, LangSwitcher)
- ✅
navigator.languageauto-detect відключено для не-UK локалей (запобігає нав'язуванню) - ✅ One-time localStorage migration — очищає auto-detected non-EN/UK locale
- 🔲 Колонка БД
users.preferred_locale+ cross-device sync — PLANNED - 🔲
GET /api/crm/analytics/locale-usage(admin) — PLANNED - Залежить від #120, м'яко від #122.
Архітектурні інваріанти (збережено):
- ✅ Інваріант Phase 53.13: tsc --noEmit чистий по всій локалізаційній роботі
- ✅ Doc-coverage hook Phase 49.1: кожна підфаза оновлює відповідну документацію
- ✅ Multi-tenancy гейти цілі (зміни локалі user-scoped, не project-scoped)
- ✅ Feedback widget Phase 53.5 перевикористано (без паралельного notification-стеку)
- ✅ Lingui v5 SSOT —
.poджерело,.tsскомпільований вихід - ✅ Vault SSOT — жодних API-ключів через пайплайни перекладу (санітизація джерела перед AI-викликом)
Оцінка трудомісткості: ~8.5-9.5 днів. MVP (59.1-59.3) = 6-7 днів, P1+P2 polish додає ~2.5 дня.
Послідовність: 59.1 (фундамент) → 59.2 + 59.3 паралельно (UI-рядки + документація) → 59.4 + 59.5 + 59.6 паралельно.
Задачі: #119 (P0), #120 (P0), #121 (P0), #122 (P1), #123 (P1), #124 (P2).
Технологічний стек
| Шар | Технологія |
|---|---|
| Brain | Сесії Claude Code (Agent Teams) |
| CRM API | Bun HTTP-сервер на Master Bot (:19210) — 62+ REST endpoints + SSE + WebSocket + Cloud PM chat + Sage Worker + Marketplace Scout + Knowledge Graph, JWT + OAuth auth |
| Proxy | Nginx (:18888) — статичний фронтенд, reverse proxy API/SSE/WS |
| ARC CLI | Скомпільований Bun-бінарник — 8 cloud-підкоманд (skill, report, kb, learnings, issue, issues, wiki, roadmap) + memory refresh/fetch-artifact |
| Frontend | React CRM (responsive, mobile-first) + Phaser 3.80 (геймифікований офіс) + термінал xterm.js + @lingui/react i18n (EN/UK) |
| Commands | Федеровані Telegram-боти (Master + Children) |
| Auth | JWT (HMAC-SHA256) + OAuth (Google, GitHub) + реєстрація email/пароль |
| State | SQLite SSOT (shared/db.ts, WAL mode) + JSON лише для інфраструктури (bot_registry, heartbeat) |
| Intelligence | Binary Evals + Context Router + Learnings + Karpathy Loop + Sage Worker (Haiku) + A/B Benchmarks + Marketplace Scout |
| Secrets | AES-256-GCM vault (shared/vault.ts) |
| Logging | JSONL structured (shared/logger.ts) → /var/log/citadel/ |
| Resilience | Самовідновлюваний watchdog (master-bot/watchdog.ts) |
| NotebookLM Bridge | Python FastAPI (:19213) — семантичний пошук через notebooklm-py + авто-синхронізація |
| Memory | 3 рівні: Hot (JSON) / Warm (GitHub) / Cold (семантичний пошук NotebookLM) |
| Deploy | Docker Compose, Nginx, Contabo VPS |
Legacy-міграція
| Компонент | Рядків у v1 | Заміна у v2 |
|---|---|---|
| FastAPI backend | ~3,000 | Сесія Claude Code |
| telegram_bridge.py | ~2,800 | Офіційний плагін Channel |
| hybrid_engine.py | ~1,000 | Нативне виконання Claude |
| bridge_processor.sh | ~500 | Усунено |
| database.py | ~700 | JSON state-файли |
| WebSocketManager.js | ~200 | StatePoller.js (SSE) |
| Разом | ~11,321 | ~3,700 |
Скорочення кодової бази на 67%.
Security Hardening — окремі задачі (2026-05)
#130 — Auth IP Logging (DONE ✅ 2026-05-19, коміт 79cb1cb)
Append-only таблиця auth_events (міграція 027) фіксує IP + auth-події для всіх кінцевих флоу автентифікації: signup, login, OAuth (Google/GitHub), magic-link, device_code_approve. Окремо від platform_audit_log (адмінські vault-мутації).
- Події:
signup/login/oauth_login/magic_link/device_code_approve - Результати:
success/failed/rate_limited/invalid_invite/already_registered/2fa_required/invalid_token - Резолюція IP: CF-Connecting-IP → X-Real-IP → останній сегмент XFF (через наявний
clientIp()) - Індекси: ts/user_id/ip/event+result для запитів threat-detection
- Запити:
authEventQueries.insert/recentуshared/db.ts
#132 — TG notify-stop.sh неправильний контент (DONE ✅ 2026-05-19, коміт 2eb362c)
Виправлено race condition у Stop hook: tac | head -n 1 повертав перший рядок виводу попереднього багаторядкового ходу, якщо JSONL ще не скинувся. Фікс: jq -rRs + last (читає всі рядки, бере хронологічно найновіший assistant-запис) + sleep 0.5 перед читанням.
Phase 60: Standard Cloud — Docker container per user (DONE ✅, 2026-05-20, задача #129)
Security hardening SEC-60 (#152, 2026-05-21): C1 StrictHostKeyChecking=yes + hetzner_known_hosts, C2 per-container network arc-net-{id}, H3 static GitHub fingerprint у Dockerfile. DONE ✅
Security hardening SEC-60 Phase 2 (#154, 2026-05-22): H1 WS idleTimeout=120s, H5 git clone timeout 60s, C3 ARC_TOKEN через docker exec (не в docker inspect). DONE ✅
Security hardening SEC-60 Phase 3 (#155, 2026-05-22): H2 docker logs --since 1h (запобігання memory pressure). DONE ✅
Security hardening SEC-60 Phase 4 (#156, 2026-05-22): C4 виділений користувач arcapi на Hetzner (лише група docker, без root/sudo) + docker-only SSH wrapper (не-docker команди заборонені) + окремий ключ hetzner_arcapi. DONE ✅
Bug fix #157 (2026-05-22): ізоляція навичок між проєктами — колонка owner_project у skills_global, backfill навичок plasthetica-*, listForProject фільтрує за власником. Виправлено крос-проєктний витік навичок. DONE ✅
Core job-to-be-done: "Закрив ноут — воркер живе." Розробник може продовжити роботу з Telegram або будь-якого пристрою без перезапуску сесії.
Проблема
Claude Code зараз прив'язаний до локальної машини. Закрив ноут — воркер помер. Втрачається контекст, сесія, прогрес.
Рішення
Кожен користувач отримує ізольований Docker container на центральному сервері Arc OS:
- Claude Code CLI — користувач приносить власну підписку Claude Pro/Max
- git + SSH ключ → GitHub проєктів користувача
- Arc OS child-bot (always-on, не залежить від ноутбука)
/workspace/volume — persistent storage проєктів
Use case (головний)
23:00 — попрацював локально, воркер закоммітив feature
Закрив ноут
08:00 — Telegram: "продовжуємо?"
Воркер: "Вчора закоммітили auth middleware, залишились тести. Починаю."
Воркер продовжує на VPS поки ти п'єш каву
Що будуємо
| Задача | Завдання | Статус |
|---|---|---|
| #134 | Hetzner arc-cloud-prod (CPX32, Helsinki, 157.180.44.232) + Cloud Waitlist | DONE |
| #135 | Dockerfile.worker (ubuntu:22.04 + Bun + Claude CLI + arc binary) | DONE |
| #136 | Provisioning API + міграція 028 managed_containers | DONE |
| #137 | Claude Code auth UI (web terminal) | DONE |
| #138 | GitHub SSH key setup UI | DONE |
| #139 | WebSocket proxy CRM → container | DONE |
| #140 | /continue в Telegram (SSH-aware) | DONE |
| #141 | Container lifecycle — idle suspend + wake on message + crontab | DONE |
| #142 | Stripe Billing Stage 2 — BillingPage UI + Checkout + Portal (pending EU entity) | DONE |
Відвантажено 2026-05-20:
- Флот із двох серверів: API на Contabo, контейнери користувачів на Hetzner
arc-cloud-prod(157.180.44.232) - Усі docker-команди маршрутизуються через SSH (
hetzner_ed25519) —cloud.ts,bot.ts,lifecycle-cron.ts,billing.ts CONTAINER_SERVER_IPу vault — єдина точка конфігурації для перемикання local/remote- Lifecycle cron активний:
*/5 * * * *на Contabo, призупиняє контейнери idle >30 хв - Cloud Waitlist: таблиця
cloud_waitlist(міграція 029), endpoints join/status/invite/admin-list BillingPage.jsx: картки планів, usage, Stripe Checkout/Portal (503 доки не налаштовано EU entity)
#135 / #136 відвантажено (2026-05-19):
docker/Dockerfile.worker— ubuntu:22.04, non-rootarcuser, volumes: /workspace + ~/.claude + ~/.ssh, security-прапорці при rundocker/worker-entrypoint.sh— SSH known_hosts, arc config, health-сервер :3000- Міграція 028 таблиця
managed_containers+managedContainerQueriesвshared/db.ts shared/routes/cloud.ts— POST /provision (billing gate + IDOR +docker runз--cap-drop=ALL --security-opt=no-new-privileges --cpus=1.5 --memory=2g), GET /status, POST /deprovision- Тип Plan розширено: tier
"cloud"+ записPLAN_LIMITS.cloud
Ціноутворення
- Arc OS Standard Cloud: ~$10-15/міс (інфраструктура + софт)
- Клієнт окремо платить Anthropic: ~$20/міс (Claude Pro — приносить власну)
- Витрати Arc OS: ~$3-5/користувач/міс (shared server capacity)
Не входить → Phase 61 (Enterprise)
- Dedicated VPS, власний IP, compliance isolation, guaranteed compute
Phase 61.1: Arc Help — вкладка AI-асистента у FeedbackWidget (DONE ✅ 2026-05-21, задачі #146/#147/#151/#153)
- Arc Help AI чат як перша вкладка у FeedbackWidget (AI | Bug | Feature | Other | Translation)
- Бекенд: POST
/api/crm/help/chat— RAG (NotebookLM Bridge + local docs fallback) + Claude Haiku, rate limit 30/день - Anti-hallucination hardening (#151): GROUNDING RULE system prompt, NEVER CLAIM блок, temperature=0, wiki RAG +
arc-help-boundaries.md - Персистентність історії чату (#153): міграція 033
arc_help_messages, GET/DELETE/api/crm/help/history, фронтенд завантажує при відкритті
Phase 61: Enterprise Cloud — dedicated VPS per client (PLANNED, задача #133)
Гейтінг: не починати поки Phase 60 не має 10+ платних користувачів. Реалізувати після того як Stripe billing протестований з реальними підписками.
Коли потрібен
- Compliance вимоги (дані не можуть бути на shared infra)
- Гарантований compute (no noisy neighbor)
- Корпоративні мережі з IP whitelist вимогами
Рішення
Окремий Hetzner VPS per enterprise клієнт, провіжнінг через Hetzner Cloud API:
- Повна ізоляція: процеси, файлова система, мережа, IP
- cloud-init bootstrap Arc OS на чистому Ubuntu
- SSH management channel: central server → client VPS
- Все те саме що Standard Cloud але фізично ізольовано
Ціноутворення (орієнтовно)
- Arc OS Enterprise: ~$29-49/міс (включає Hetzner CX21 ~€3.79)
- Клієнт окремо платить Anthropic за Claude підписку
Stack
- Hetzner Cloud API (
shared/hetzner.ts) - Таблиця
managed_vpsу БД (міграція 028) - SSH management layer
- Billing: Stripe flat enterprise plan
Phase 63: UI/UX Consolidation + Token Usage Tracking (DONE ✅, 2026-05-21, задача #148)
Контекст
UI/UX аудит виявив кілька критичних проблем: UserDropdown внизу-ліво не помітний на малих екранах, OnboardingProgressPill конфліктував з іншими іконками хедера, воркер-кольори використовували Tailwind chart-токени замість семантичних ролей. Паралельно реалізовано токен-трекінг для видимості витрат клієнтів.
Доставлено
Phase 63.1 — Header UX (задача #148)
UserDropdown: переміщено з фіксованої позиції внизу-ліво → компактний avatar у правій зоні хедера- Dropdown тепер відкривається вниз-направо; admin badge переміщено всередину dropdown identity секції
OnboardingProgressPill: redesigned як inline header dropdown з circular progress іконкою; розкривні рядки кроків з Mark done/Skip (без модалу)- Sidebar: прибрано
paddingBottom: 60pxрезерв для старого pill
Phase 63.2 — Worker semantic colors
WorkerSelector.jsx: об'єктROLE_TONES→ CSS-змінні--worker-{consultant|developer|designer|archivist|sentinel|po}workerTone(id)витягує base role з id, fallback на hash-based колір зFALLBACK_COLORS
Phase 63.3 — Token Usage Tracking
- Міграція 031:
token_usage_log(project_name, owner_id, worker_id, input/output/cache/total_tokens, created_at) claude-runner.ts: завжди використовує--output-format json;logUsagecallback dep для fire-and-forget до/api/internal/usage/log/api/internal/usage/log: новий internal endpoint записує рядки в БД/api/crm/account/usage: CRM endpoint повертає history + totals для auth'd user- UserDropdown:
UsageCardміні-картка (total tokens + "Details →") при відкритті; warning dot на avatar коли trial < 20% - BillingPage: секція "Token Usage" з totals bar + таблиця останніх 50 записів
Phase 63.4 — BillingPage Redesign
- Enterprise план: indigo колір, штрихований фон, бейдж "In development", CTA "Contact us"
PLAN_DETAILSmap: опис + розширений список фіч для кожного плануdetailstoggle на кожній картці — inline expansion повного списку- Хелпер
featureIcon(): keyword-based mapping → lucide icons (Folder, Users, BarChart3, Cloud, Server, Shield, Bot, MessageSquare…) - 4 плани (2026-05-21): Free / Starter ($4.99) / Starter Cloud ($14.99) / Enterprise — верхній рядок 3 колонки (Free/Starter/Starter Cloud), Enterprise повна ширина знизу; план Pro ($11.99) видалено; Cloud перейменовано в Starter Cloud з
highlight: true
Файли
shared/migrations/031_token_usage_log.ts(новий)shared/db.ts(+міграція 031)shared/routes/router.ts(+/api/crm/account/usage)master-bot/routes/internal.ts(+/api/internal/usage/log)child-bot/claude-runner.ts(json output завжди, logUsage dep)child-bot/bot.ts(logUsage callback)frontend/src/crm/components/UserDropdown.jsx(позиція в хедері, UsageCard, trial badge)frontend/src/crm/components/OnboardingModal.jsx(inline dropdown, розгортувані кроки)frontend/src/crm/components/TopHeader.jsx(права зона: OnboardingProgressPill + UserDropdown)frontend/src/crm/layouts/CrmMainLayout.jsx(прибрано standalone UserDropdown/OnboardingPill)frontend/src/crm/components/Sidebar.jsx(прибрано резерв нижнього відступу)frontend/src/crm/pages/workspace/WorkerSelector.jsx(семантичні кольори ролей)frontend/src/crm/pages/BillingPage.jsx(повний редизайн з Enterprise + details + іконками)
Phase 63.5: UI Polish — Tooltips, Icon Fix, Drag Resize (DONE ✅, 2026-05-21)
Доставлено
HoverTip — новий shared компонент
frontend/src/crm/components/HoverTip.jsx(новий): tooltip з 500ms затримкою при наведенніReact.cloneElementприкріплює handlers безпосередньо до child-елемента — уникаєgetBoundingClientRect()= 0 наdisplay:contentswrappercreatePortal→document.body— tooltip ніколи не обрізаєтьсяoverflow: hiddensidebar- Підтримка
placement="right"(default) іplacement="bottom"
Sidebar — tooltips на всіх пунктах меню
- Кожен
PROJECT_NAVitem отримав полеhintз коротким описом - Всі кнопки nav обгорнуто в
<HoverTip label hint>— з'являється після 500ms hover
WorkerSelector — tooltips на воркер-таблетках
- Кожна воркер-таблетка обгорнута в
<HoverTip placement="bottom">зw.descriptionабо fallback "Active — click to deactivate" / "Click to activate"
WorkspaceSelector — виправлено іконку
- Замінено broken
▣Unicode-символ →<Layers size={15}>з lucide-react triggerIcon = activeProject?.icon || null; якщо null — рендерується<Layers>
FeedbackWidget (Arc Help) — drag-resize замість expand
- Видалено кнопку expand/minimize (
Maximize2/Minimize2) - Замінено на
GripHorizontalіконку у верхньому лівому куті панелі onResizeMouseDown:windowevent listeners, dx = startX − currentX (ліво = ширше), dy = startY − currentY (вгору = вище), обмеження min 300×280 / max (window − 40)- Стан
panelSize { width, height }керує розміром;transitionвидалено для плавного ресайзу
Файли
frontend/src/crm/components/HoverTip.jsx(новий)frontend/src/crm/components/Sidebar.jsx(+hints, +HoverTip wrappers)frontend/src/crm/pages/workspace/WorkerSelector.jsx(+HoverTip wrappers)frontend/src/crm/components/WorkspaceSelector.jsx(Layers icon fallback)frontend/src/crm/components/FeedbackWidget.jsx(drag-resize, GripHorizontal)
Phase 64 — Security & Compliance Sprint (DONE ✅, 2026-05-23)
Мета: Закрити security/legal беклог Sentinel (#161–#175).
Sprint 1 (відвантажено)
- #172 nginx Permissions-Policy header (camera/mic/geo/payment/usb=())
- #173 /.well-known/security.txt — RFC 9116 responsible disclosure
- #164 Сторінка PrivacyPolicy.jsx у CRM
- #174 password_version — інвалідація JWT-токенів при зміні пароля (міграція 035)
- #170 CI: npm audit --audit-level=high
Sprint 2 (відвантажено)
- #162 DELETE /api/auth/account — каскадне видалення GDPR Art. 17 (15+ таблиць)
- #167 Заголовки List-Unsubscribe у всіх транзакційних email
- #161 Банер Cookie Consent (на основі localStorage)
- #168 Cron ретенції даних (щодня: chat 180д / auth_events 90д / activity 365д / tokens 730д)
Sprint 3 (відвантажено)
- #171 HIBP k-anonymity перевірка скомпрометованих паролів (shared/hibp.ts)
- #175 eslint-plugin-jsx-a11y у CI (WCAG 2.1 AA, базлайн --max-warnings=200)
- Виправлено 7 файлів: anchor-as-button, mouse events без focus, tabIndex на role=button
Бонус
- #163 GET /api/auth/export — переносимість даних GDPR Art. 20 (JSON download, rate-limited 3/24h)
- #151 Arc Help hardening: anti-injection regex, short-circuit на порожньому RAG-контексті, покращений wiki-пошук
Відкладено (потребує реєстрації компанії)
- #165 Impressum (вимога DE/AT/CH) — blocked на e-Residency
- #166 Шаблон DPA — blocked на e-Residency
Підтримується Rick (Orchestrator). Оновлюється після завершення кожної фази.
Phase 55.x: Login Cosmic Backdrop — Color Picker (DONE ✅, 2026-05-26, задача #200)
feat(login): cosmic background palette picker
- Додано 4 кольорові пресети до
LoginBackdrop.jsx: Orange (default), Teal, Purple, Blue - Віджет
PalettePicker(нижній лівий кут, з'являється при hover) — 4 кольорові крапки - Усі шари фону (Planet, Starfield, Satellites) приймають проп
palette— повністю реактивно - Градієнт фону тонується за палітрою; вибір зберігається у
localStorage('cosmic-palette')
Phase 65: Plata by mono — Recurring Billing (DONE ✅, 2026-05-26, задача #202)
Замінено Stripe (так і не активований) на Plata by mono — інтернет-еквайринг monobank. Перший реальний платіжний флоу для Arc OS.
shared/routes/billing.ts: Plata API (https://api.monobank.ua/api/merchant), токенізовані recurring-підписки, dual-token routing (test/prod)- Vault-ключі:
PLATA_MERCHANT_TOKEN,PLATA_TEST_TOKEN,PLATA_TEST_MODE - Endpoints:
/billing/checkout-session,/billing/webhook(X-Token verified, ідемпотентно черезplata_events),/billing/cancel runBillingCycle(): щоденний cron у master-bot, списує всі підпискиnext_billing_date <= todayчерез збережений card token- Міграція 038: колонки
plata_card_token,plata_wallet_id,plata_masked_pan,next_billing_date,billing_failures - PlatformSettings: вкладка Payments із перемикачем test/prod + редизайн на 5 вкладок (Anthropic / OAuth / TG / Email / Payments)
- 3 послідовні невдалі списання → автоматичний downgrade до free
Ціни (UAH):
- Starter: ₴199/місяць
- Starter Cloud: ₴599/місяць
Phase 66: Tech Debt Cleanup Sprint (DONE ✅, 2026-05-26)
Архітектурна чистка після Phase 65, керована аудитом Nexus Product Owner (docs/roadmap-analysis-2026-05-26.md).
- #205: Видалено мертвий код Stripe — міграція 040 (DROP
stripe_customer_id, таблицяstripe_events) + міграція 041 (rebuild subscriptions для викидання UNIQUE-обмеженогоstripe_subscription_id). ПерейменованоupsertFromStripe→upsertPlan. Прибрано маршрут/billing/portal-session+ Stripe-заглушки. Lingui авто-почистив 73 застарілі рядки × 8 локалей. - #206: Викинуто mirror
issues.json— БД єдиний writer для project_issues. 4 читачі мігровано наissueQueries.list(projectName)(admin-dashboard, chat.ts RAG, cli-routes memory refresh, getLastTask). - #208: Розв'язано колізію назв Phase 63 — collaboration design перейменовано Phase 63 → Phase 67.
- #209: Видалено legacy-директорію
bridge/(замінена бінарником ARC CLI у Phase 38). - #210: Консолідовано потрійне зберігання навичок — БД є SSOT-writer,
.claude/skills/<n>/SKILL.md— write-through артефакт для авто-виявлення Claude Code CLI. Прибрано legacy reader/writer шляхиskills/<n>.md. - #215: Автоматизація бекапу SQLite —
scripts/backup-db.sh(.backupAPI + integrity_check + gzip + ротація), щоденний cron 03:17 UTC + pre-deploy snapshot у vps-sync.sh, runbook уdocs/ops/db-backup-restore.md. Закриває recovery-прогалину, відкриту #206. - #214 частина 1: WorkerSelector UI для Phase 66 — 7 нових кольорових токенів
--worker-*, ROLE_TONES full-id таблиця покриває всі 13 воркерів (виправлено multi-segment мапінгui-designer/product-owner), i18n-хелперworkerDescription()з 13 EN + UK описами. Породжені під-задачі: #227 visual QA, #228 preset library, #226 data seed. - Documentation sync (2026-05-27): post-batch вирівнювання документації з Phase 66 changes. workers-and-intelligence.md розширена з 6 до 12 worker presets + нова секція SYSTEM_PROTOCOL зі списком 15 baseline rules. creating-skills.md веде з "check existing 40+ first" + секції seeding/owner_project. Новий user guide
worker-presets-wizard.mdпокриває 3-step wizard flow + кастомізацію. PROJECT_MANIFEST.md (bridge context) отримує секцію Workers & Skills, що відображає wizard endpoint + auto-injection chain. - #237 + #238 + #239: Батч Tier 3 generic skills —
mcp-builder(архітектура серверів Model Context Protocol, примітиви tool/resource/prompt, інтеграція Claude Desktop),svg-graphics(патерни векторних постерів/графіків/діаграм, шаблон OG 1200×630, мінімізація svgo),standup-aggregator(патерн компіляції daily/weekly recap з dedupe + авто-категоризація Conventional Commits). Реєстр навичок тепер 40 записів. #240 (CLI-команда arc plan) відкладено на P3 — фіча, не навичка. - #233 + #234 + #235 + #236: Батч Tier 2 generic skills —
seo-foundations(технічне SEO + Core Web Vitals + JSON-LD),postgres-patterns(дизайн схем + індекси + EXPLAIN + транзакції + JSONB),react-best-practices(Server/Client Components + Suspense + правила хуків + дерево рішень state),slide-deck-html(single-file HTML шаблон pitch deck, 15-слайдова інвесторська структура). Усі зачищені від project-internals, generic-приклади в стилі Linear/Acme. - #230 + #231 + #232: Tier 1 generic skills додано згідно з планувальним документом skills-research —
commit-discipline(Conventional Commits + розбиття на кілька комітів),frontend-design-principles(типографіка/контраст/відступи/motion + AI-generic антипатерни),tdd-flow(Red-Green-Refactor + test-first шаблон промпта + цілі покриття). Плюсscripts/seed-skill-category.tsgeneric seeder (перевикористовуваний для майбутніх батчів Tier 2/3). Усі 3 навички глобальні, контент зачищено від project-internals. - #229: SYSTEM_PROTOCOL quality baseline — розширено з 5 правил Mandatory Workflow до 15 (додано 10 Quality-правил, що покривають пріоритети, session report, DoD-docs, trade-offs, лаконічний формат, цитування джерел, no silent failures, чесний прогрес, convention over invention, learnings feedback). Вирізано 797 символів дублікатів із 6 worker presets (po, developer, analyst, sentinel, ui-designer, qa-engineer). Авто-інжектиться через child-bot/claude-runner.ts при наступному spawn — міграція не потрібна.
- #228: WorkerCreationWizard — 3-кроковий guided flow (Identity → Capabilities → Instructions) замінює монолітну форму як дефолтний
+ Addфлоу. Preset library живиться новим endpoint'омGET /api/crm/workers/presets; вибір пресета пре-заповнює кожне downstream-поле. Smart warnings на Step 2 ловлять мисконфігурації read-only-роль + write-інструмент. Live preview на Step 3 показує, що воркер отримає при першому повідомленні. Лінк "Show advanced form →" обходить візард для power-користувачів. 22 нові i18n-рядки (19 перекладено UK). - #226: Startup skill seeder —
scripts/seed-startup-skills.ts(ідемпотентний, drift-aware). Засіяно 10 startup-навичок (market-analysis / financial-modeling / gtm-strategy / pitch-deck / customer-development / fundraising / founder-brand / service-design / metrics-dashboard / legal-startup) уskills_globalзcategory='startup'. Розблоковує фільтр SkillEvolution, авто-ін'єкцію Context Router, Active Skills у ContextRail для воркерів Phase 66.
Вплив: -776 LOC нетто, 333/333 тестів проходять, поверхні дрейфу схеми не лишилося, point-in-time recovery доступне з добовою гранулярністю.
Phase 67: Security & Bug Fix Sprint (DONE ✅, 2026-05-28)
P1 security та compliance багфікси:
- #246 (DONE ✅): Фікс
GET /api/auth/export→ 500 (зламаний GDPR Art.20). Корінна причина:data-export.tsзапитував неіснуючу колонкуformatуexport_audit_log(міграція 024 її ніколи не додавала). Фікс: використати правильні колонки (sections,bytes) + обгорнути DB-блок у try/catch для майбутньої безпеки схеми. - #221 (VERIFIED ✅): Rate limit на
/api/auth/login— уже реалізовано в auth.ts:208-216 (подвійний bucket: 10/IP/15хв + 5/email/15хв). Задачу можна закрити. - #242 (VERIFIED ✅): Відмова proxy-заголовків на
/api/internal/*— уже реалізовано в api-server.ts:68-72 (повертає 403 на X-Forwarded-For / X-Real-IP / Forwarded). Задачу можна закрити. - #192 (DONE ✅): DB fallback для context_assets у child-bot — loadContextAssets читав лише file paths; тепер спершу запитує skillQueries.listForProject(projectName). projectName передається через ClaudeRunnerDeps.
- #243 (DONE ✅): /.well-known/security.txt повертав 403 — блок nginx
~ /\.спрацьовував раніше за frontend proxy. Додано exact-match location блок= /.well-known/security.txt(комплаєнс RFC 9116). - #243 (DONE ✅): Виправлено nginx
location ~ /\., що блокував/.well-known/security.txt. Замінено на negative lookahead~ ^/\.(?!well-known/)в обох server-блоках. Корінна причина: неправильна ціль деплою (/citadel-crm.confvs symlink/citadel-crm). - #192 (DONE ✅):
loadContextAssets(child-bot) тепер спершу запитуєskillQueries.listForProject(projectName)перед fallback на file path.projectNameдодано доClaudeRunnerDeps, передається зBOT_NAME. - #289 (DONE ✅): GithubFeed 403 flood — проп
projectбув повним об'єктом,${project}в URL →[object Object]. Виправлено: витягprojectNameзproject.technical_name || project.name. - #288 (DONE ✅): Обрізання логіна в Mobile WebView — вкладений
position:fixedусерединіoverflow:hiddenламає Android in-app браузери. Виправлено:position:absolute+minHeight:'100%'на внутрішньому<main>. - #266 (DONE ✅):
context_assetsдля qa-engineer — додано["tdd-flow","testing-strategy-pyramid","arc-os-architecture"]уconfig/workers_registry.json. - #199 (DONE ✅): TG notify при вступі у waitlist —
notifyCeoPlain()спрацьовує післяcloudWaitlistQueries.join()уshared/routes/cloud.ts. - #193 (DONE ✅): Команда
arc update— детекція платформи, завантаження бінарника, атомарнийrenameSync."update"додано вKNOWN_COMMANDS. ФайлARC_VERSIONу корені репо. - #188 (DONE ✅): Ін'єкція PROJECT_MANIFEST.md у CLI bridge context —
handleCliInitчитає і вставляє під "## Project Context" (стеля 8000 символів). Виправлено refs міграцій + шлях design-system. - #184 (DONE ✅):
git pull --rebase --autostashвиконується перед кожним spawn arc-сесії. - #204 (DONE ✅): Старт/кінець CLI-сесії логується і в
activity_log, і вtimeline_events. Додано endpointPOST /api/cli/session-end/:project/:mode. - #196 (DONE ✅): Issues UI — фільтр пріоритету + фільтр статусу (у дропдауні Filters, відкритий за замовчуванням) + Group By (none/phase/priority) + колонка Created (з DB-поля
created_at) + сортовані заголовки (клік для сортування за #/title/priority/status/created/updated, toggle asc/desc). - #255 (DONE ✅):
arc issues --status all— тег статусу тепер показується на всіх рядках (раніше лише для non-open). ПрапорецьshowStatusуclients/lib/api.ts. - #189/#195 (DONE ✅): банер старту arc-сесії показує 3 рядки навичок:
Context(авто-завантажені з workercontext_assets),Matched(підібрані за заголовком задачі),Skills(решта доступних). 8 unit-тестів уtests/context-assets.test.ts.
#87: 2FA / TOTP Full Implementation (DONE ✅, 2026-05-29)
Розблоковано з Phase 55 (було BLOCKED на дизайні Sentinel — реалізував Developer).
- міграція 042: колонка
totp_backup_codes TEXTу users - shared/totp.ts:
generateBackupCodes,hashBackupCode,consumeBackupCode(SHA-256, timing-safe) - auth.ts (5 endpoints):
GET /2fa/status, setup повертає backup-коди при verify,POST /2fa/loginприймає fallbackbackup_code,POST /2fa/backup-codes/regenerate - TwoFactorSettings.jsx: 3-кроковий setup-модал (QR через бібліотеку
qrcode→ верифікація 6-значним кодом → сітка backup-кодів із copy/download + підтвердження збереження), модал disable, модал regenerate. Підключено до вкладки Security у AccountSettingsDialog. - CosmicCard: стан
totpUseBackup, текстове поле backup-коду, лінк-перемикач "Lost your phone? Use a backup code" - Перевірено наживо на arc-os.co ✅
Companion: сторінка Channels (DONE ✅, 2026-06-01, #299)
- Нова per-project сторінка Channels показує кожну комунікаційну поверхню в одному виді.
- Картка Telegram: жива конфігурація (GET/POST/DELETE
/api/crm/projects/:name/telegram-token) із regex-валідованим полем токена, show/hide eye, станами connect/disconnect. - Картки Discord + Slack: coming-soon плейсхолдери з CTA Vote, що відкриває FeedbackWidget, пре-заповнений контекстом каналу (розширено подію
arc-help-openдля прийому{detail.prefill}). - Sidebar PROJECT_NAV: запис
channelsміж Workers і Timeline (іконкаMessageCircle). - UA-переклади всіх нових рядків; інші локалі fallback на EN.
Companion: візуали pitch-deck (DONE ✅, 2026-06-01, #312 + #313)
- Діаграма архітектури слайда 3: ручний SVG (
docs/pitch/assets/slide-03-architecture.svg) — hub-and-spoke з 6 worker presets (dev/designer/QA/PM/CEO/sentinel), кільцем persistent-memory, 3 канальними поверхнями (CLI · TG · Web). - Конкурентна матриця слайда 8: SVG (
docs/pitch/assets/slide-08-competition.svg) — 2×2 (single↔multi × IDE↔workflow). Arc OS у NE "відкритому квадранті"; Accio Work чесною приміткою (China-enterprise фокус). - Обґрунтування дизайну + інструкції вбудовування:
designs/pitch-slides-2026-06-01.md. SVG замість Figma — single source of truth, векторно-чисто, відстежується в репо.
Phase 69: Cloud Repo Model — GitHub bot org для авто-керованих репозиторіїв (DONE ✅ 2026-06-04, #341/#344/#347 deferred)
Закриває прогалину "де живе мій код у Cloud?". Кожен Arc-проєкт отримує приватний GitHub-репозиторій під
arc-os-platform(bot org), невидимо керований через GitHub App. Local Bridge авто-комітить при збереженні; користувач виконуєarc pushдля публікації. Cloud-контейнер клонує всі репозиторії проєктів користувача при провіжинінгу, пушить snapshot при паузі. Зовнішні репозиторії досі додаються за URL або через GitHub OAuth.
Parent: #337. Під-задачі: #338 (67.1 bot org bootstrap), #339 (69.2 авто-створення репо), #340 (69.3 container bootstrap + lifecycle), #341 (69.4 Bridge sync + arc CLI), #342 (69.5 панель Repos у CRM + OAuth), #343 (69.6 backfill), #344 (69.7 docs).
Повна специфікація: docs/architecture/PHASE_69_CLOUD_REPO_MODEL.md.
Рішення зафіксовані (CEO call 2026-06-03)
- 1b — GitHub bot org, не self-hosted Gitea. Проєкція витрат: економія ~5kEUR за 24 міс. Міграційна страховка: runbook
scripts/phase-69-export-to-gitea.ts+ погодинний S3 manifest mirror cron (уже відвантажено у #338). - 2a — репозиторій проєкту створюється при створенні Arc-проєкту (не при Cloud-провіжинінгу)
- 3c — авто-коміти при збереженні файлу, ручний
arc pushдля публікації - 4c — зовнішні репозиторії через UI-форму АБО GitHub OAuth дропдаун
Статус підфаз
- 69.1 (#338) DONE ✅ (2026-06-04) — обгортка
shared/github-bot.ts+ GitHub App + вкладка Platform Settings + погодинний manifest mirror + заглушка ban-day експорту. - 69.2 (#339) DONE ✅ (2026-06-04) — міграція 047 (
projects.github_repo_url/name/synced_at),shared/auto-repos.ts(ensureSystemRepo/ensureProjectRepo/archiveProjectRepo), fire-and-forget хук уhandleCreateProject. - 69.3 (#340) DONE ✅ (2026-06-04) —
shared/cloud-bootstrap.ts: git auth через installation-token (~/.git-credentials,credential.helper=store), клонування кожного system+project репозиторію у/workspace/<slug>, хуки вhandleProvision/pauseContainer/wakeContainer. Pivot від per-repo deploy keys (заблоковано org policy + колізією ключів). - 69.5 (#342) DONE ✅ (2026-06-04) —
handleListReposповертає{ sections: { system, project[], external[] } }; переписанаReposPanelз 3 секціями, індикаторами статусу, GitHub-лінком, бейджами. OAuth picker відкладено до #347. - 69.6 (#343) DONE ✅ (2026-06-04) —
scripts/phase-69-backfill-repos.tsз--dry-run/--user/паузою rate-limit. Прод-запуск: 19 репозиторіїв на 7 користувачів за ~2 хв. БД: 20/20 підключено. - 69.4 (#341) NEXT — синхронізація Local Bridge + команди
arc push/pull/cloud sync. - 69.7 (#344) — Docs у 8 локалях.
- 69.5a (#347) — GitHub OAuth picker для зовнішніх репозиторіїв.
Phase 70: Chat ↔ Cloud Container Routing (DONE ✅ 2026-06-04)
Воркери працюють усередині Hetzner-контейнера користувача, не на master. Кожне чат-повідомлення для cloud-plan користувачів маршрутизується через
docker exec --workdir /workspace/<slug>із bash login wrapper, щоб envANTHROPIC_API_KEYзавантажувався коректно. Хуки pause/wake із Phase 69.3 відправляють роботу назад у bot-org репозиторії; неперервність сесії через паузу використовує volume mount.claude/projects. Пігулка в CRM-хедері показує статусCloudабоCloud · asleep.
Parent: #350. Під-задачі: #351 (рішення про маршрутизацію у worker-spawn), #357 (docs Phase 70 у 8 локалях).
Що відвантажено
shared/cloud-route.ts—getWorkerTarget(userId, project)per-chat рішення маршрутизації: local vs container на основі tier-плану користувача- Обгортка
docker exec— login shellbash -lc, щоб~/.bashrcзавантажувавANTHROPIC_API_KEYз env контейнера - Workdir locking —
/workspace/<slug>обмежує воркера репозиторієм проєкту (клонованим при провіжинінгу за Phase 69.3) - Неперервність сесії — хуки pause/wake зберігають директорію
.claude/projectsна volume; resume підхоплює точний стан - Пігулка в хедері — CRM показує живий стан контейнера (
Cloudактивний /Cloud · asleepпризупинений) - Фікс маршрутизації — розв'язано
#348 P0(втрачений auth-стан Claude: токен у keyring, але контейнер його не має) - Авто-snapshot при паузі — робота пушиться в bot-org репозиторій через інфраструктуру Phase 69
Статус підфаз
- 70.1 (#351) DONE ✅ — шар маршрутизації
cloud-route.ts+ інтеграція з worker-spawn - 70.7 (#357) DONE ✅ —
docs/public/cloud-chat-routing.mdEN + переклади на 7 локалей - 70 parent (#350) DONE ✅ (2026-06-04)
- Рішення: Phase 68 Project Collaboration fork epic перенумеровано → Phase 75 (відкладено за комітом
515f382)
Побічні ефекти
- #348 закрито — втрачений Claude auth у контейнері (корінна причина — відсутня маршрутизація + завантаження env)
- Бачення Phase 75 Odoo CRM-інтеграції використовує cloud routing Phase 70 як фундамент (воркери можуть працювати на стороні клієнта)
Phase 62: Voice Input Mode (DONE ✅)
CEO підтвердив 2026-06-05: L1 (Web Speech API native, Chrome/Edge) + L2 (self-hosted whisper.cpp на Contabo), послідовно. Без OpenAI-залежності — whisper.cpp працює на нашому VPS; байти аудіо ніколи не покидають Contabo. Hetzner worker-контейнери лишаються чистими (аудіо-шлях = Browser → Contabo → текст → Phase 70 маршрутизує за планом користувача). Специфікація:
designs/phase-62-voice-input-2026-05-21.md.
Parent: #149 (закрито). Усі 5 під-задач відвантажено: #370 (62.1), #371 (62.2), #372 (62.3), #373 (62.4), #374 (62.5). #149.3 + #149.7 deferred за scope-рішенням CEO.
Що відвантажено (L1 COMPLETE)
- 62.1 (#370) DONE ✅ — рефакторинг MicButton:
continuous=true+interimResults=true;getSpeechLocale()BCP-47 мапа для всіх 8 локалей (en-US, uk-UA, de-DE, es-ES, fr-FR, pl-PL, ru-RU, pt-BR); новий колбекonInterim(батьки, що передають лишеonTranscript, зберігають поведінку до #149.1); авто-рестарт на Chrome'івський silence-inducedonend, поки користувач ще хоче слухати;.abort()при unmount гасить OS mic LED; диференційовані error toasts (mic-blocked → підказка налаштувань, generic, тиша на no-speech/aborted). ChatThread вплітаєvoiceInterimу textarea як живе прев'ю, тримаючиinputяк source of truth — перше натискання клавіші або фінальний результат комітить; handleSend чистить interim. Користувачі Firefox/Safari отримують ясний toast "needs Chrome or Edge" із вказівкою на 62.4. - 62.2 (#371) DONE ✅ — MicButton тепер емітує
onStateChange('idle'|'listening')і відкриваєtoggle()черезforwardRef+useImperativeHandle. НовийWaveformIndicator(5-смугова pure-CSS анімація, keyframesvoiceWaveformBarуglobals.css, БЕЗ WebAudio) рендериться inline біля мікрофона під час live. Рамка контейнера Composer товщає до 2px accent з 4px 18%-mix ring shadow під час прослуховування — listening перекриває focus highlight. - 62.3 (#372) DONE ✅ — глобальний
Ctrl+Shift+V(Cmd+Shift+V на Mac) keydown-слухач у ChatThread; викликаєmicRef.current.toggle(). Пропускає, коли фокус на password/email/number полях. Проп title MicButton показує шорткат для discoverability. - 62.x nginx Permissions-Policy fix (після деплою L1) — перший live-тест виявив, що Phase 64
#172встановилаPermissions-Policy: microphone=()на всю сторінку, перекриваючи browser-level дозвіл мікрофона і ламаючи voice input навіть після "allow" користувача. Змінено наmicrophone=(self)в обох server-блокахinfra/nginx/citadel-crm.conf; camera/geo/payment повністю заборонені. Задеплоєно + перезавантажено, перевірено черезcurl https://arc-os.co/.
Що відвантажено (L2 backend)
- 62.4 (#373) DONE ✅ —
arc-whisper.serviceна Contabo (127.0.0.1:19214), що запускаєwhisper.cppwhisper-serverіз preloaded моделлюggml-base; зібрано через cmake-DCMAKE_BUILD_TYPE=Releaseдля нативного AVX2. Бенчмарки на JFK 11с семплі (AMD EPYC віртуалізований, 6 vCPU):tiny=15с,base=12с,small=80с — модельsmallнепридатна на цьому CPU (значно повільніше за realtime);base— sweet spot. Warm latency (модель preloaded між запитами): 3.4с для 11с аудіо = ~3.1× realtime, ~1.5с для типової 5с голосової команди. Міграція 051 додаєvoice_usage_log(user_id, date, seconds_used). Новий маршрутPOST /api/crm/voice/transcribe(shared/routes/voice.ts): multipart audio + locale, семафор обмежуєMAX_CONCURRENT=2, добова стеля 60 хв/користувача, таймаут 30с, чесний 4xx/5xx мапінг. Підключено вrouter.tsперед project-scoped блоком. Байти аудіо ніколи не покидають Contabo; Hetzner-контейнери чисті; результуючий текст маршрутизується за Phase 70 у local-vs-container за планом користувача.
Що відвантажено (L2 frontend — закриває Phase 62)
- 62.5 (#374) DONE ✅ — state machine
MicButtonрозширеноidle → listening → recording → processing. Click router обираєSpeechRecognitionколи доступний (Path A з 62.1), інакшеMediaRecorder+ POST до/api/crm/voice/transcribeз Bearer-токеном ізlocalStorage('crm-token'). Звільняє OS-мікрофон негайно при зупинці. Пульсуюча анімація + waveform-індикатор + підсвічування рамки композера тепер вмикаються для ОБОХ станів listening (нативний) та recording (fallback), тож користувачі Firefox/Safari отримують той самий UX що Chrome. Варіанти тултіпа: listening / recording / transcribing / idle — усі підказуютьCtrl+Shift+V. Cleanup при unmount вбиває recognition + MediaRecorder + аудіо-стрім.
Phase 71: Self-Hosted RAG — Cohere + sqlite-vec (DONE ✅)
Заміна
services/notebooklm-bridge/(Python FastAPI + Playwright auth + Google NotebookLM із 90% збоїв синхронізації + стелею 326 джерел Plus-тарифу) на provider-agnostic embeddings на sqlite-vec. Воркери запитують семантичний контекст проєкту через Cohere embed-multilingual-v3.0 (1024-dim float32), збережений у vec0 virtual table всередині наявного SQLite SSOT. Працює з будь-яким LLM (узгоджується з #293 multi-model стратегією).
Parent: #321 (спочатку відкладено за project_rag_decision_2026-06-02.md, REVERSED — un-deferred і відвантажено). Під-задачі: #358 (vault-запис + проба Platform Settings), #359 (встановлення sqlite-vec + міграція 049).
Чому un-deferred
- Стеля NotebookLM Plus tier (326 джерел) досягнута на проді, evict джерел → 90% збоїв синхронізації
- Auth-патч Option A не виправив би корінну проблему стелі
- Cohere/sqlite-vec узгоджується з #293 multi-model (provider-agnostic RAG)
- Dev мав bandwidth + визнав, що корінна причина потребує структурного фіксу
Що відвантажено
- 71.1 (#358) DONE ✅ — vault-запис
COHERE_API_KEY+ вкладка Platform Settings + кнопка live-проби для перевірки з'єднання - 71.2 (#359) DONE ✅ — встановлення розширення sqlite-vec + міграція 049:
- Таблиця
embeddings—(project, doc_type, doc_id, chunk_ix, text)з підтримкою аудиту + JOIN embeddings_vec— vec0 virtual table зFLOAT[1024](розмірність Cohere)- Обґрунтування розділення: vec0 не вміє ефективно тримати метадані; воркфлоу LIST/DELETE потребують plain SQL
- Розміри: 1024-dim float32 = 4096 байт/рядок; 100K рядків = ~400MB на диску; ок на масштабі 50 користувачів, переглянути при 1M+
- Sanity check: міграція переривається з ясною помилкою, якщо розширення sqlite-vec не завантажене
- Таблиця
- 71.3 (#360) DONE ✅ — обгортка Cohere-клієнта
shared/embeddings.ts:embedBatch(texts, inputType)для індексації — авто-чанкінг до ≤96 input'ів на викликembedQuery(text)для runtime-запитів — використовує input_typesearch_query(збіг підпросторів)- 3× експоненційний retry (250/500/1000мс) на тимчасових помилках; fail-fast на 401/403 auth
- Повертає
Float32Array[1024], що відповідає розмірностіembeddings_vec - Live smoke проти prod vault: 3 документи (EN+EN+UK) ~237мс + запит ~144мс, мультимовність підтверджена
- 71.4 (#361) DONE ✅ — фасад семантичного пошуку
shared/rag.ts:upsert(project, doc_type, doc_id, text)— paragraph-aware чанкер (ціль ~1800 символів, мін 200) + атомарна tx, щобembeddings+embeddings_vecлишалися синхроннимиsearch(project, query, {k, doc_types})— ембедить запит, KNN надembeddings_vecз overfetchk * 4, потім фільтр project + опційного doc_type на JOINremoveDoc/removeProject/stats— каскадне видалення + діагностика- Ідемпотентність PASS: повторний upsert ідентичного тексту дає ту саму кількість рядків
- Крос-мовний smoke: UK-запит
"Як побудована архітектура Arc OS?"ставить EN wiki-сторінку #1 (d=0.85), Б'Є відповідну EN-EN відстань — вирівнювання мультимовних підпросторів підтверджено
- 71.5 (#362) DONE ✅ — fire-and-forget re-embed хуки на write-шляхах:
shared/rag-hooks.ts—syncIssue/syncWiki/syncSkill(+ дзеркалаremove*+GLOBAL_SKILL_PROJECT='_global_') — помилки Cohere друкуються + вмирають, ніколи не відкочують записи на диск/SQL- Підключено в:
wiki.tshandleWikiSave;cli-routes.tshandleCreateIssue+handleUpdateIssue(навмисно НЕhandleAddIssueLog— activity log не змінює індексований title/body);skills.ts5 хендлерів (project save/delete + global create/update/delete, update переембедить лише якщо контент справді змінився); цикл GDPR Art. 17 вerasure.tsкаскадуєremoveRagProject, щоб embeddings не переживали видалення акаунта - Live VPS smoke: issue/wiki індексовані під неймспейсом проєкту + глобальна навичка під неймспейсом
_global_, пошук коректно знаходить (d=0.86-1.00 на обох поверхнях), усі 3 шляхиremove*лишають 0 рядків
- 71.6 (#363) DONE ✅ — одноразовий seed
scripts/phase-71-backfill-rag.ts:- Прапорці:
--dry-run/--force/--skip-global/--project NAME/--doc-types wiki,issue,skill/--limit N/--throttle MS - SSOT-пікер проєктів через
projects.technical_name; cwd черезconfig/bot_registry.json, fallback/opt/repos/<name> - Ідемпотентність через перевірку присутності
embeddings(project, doc_type, doc_id);--forceперекриває - Прод-запуск завершено: 814 документів / ~3,150 чанків на 20 проєктів +
_global_. Trial Key спалено на першому проході (стеля 1000/місяць) → CEO апгрейднув до Production tier → другий прохід (ідемпотентний пропуск 636 + дозавершення 178) чисто за 57с, 0 помилок
- Прапорці:
- Tech Debt burn-down (2026-06-05, C-track після Phase 71) — 7 задач закрито одним свіпом. Лише #368 вимагала справжніх змін коду (enforcement строгого формату
learnings.md+ 9 essay-form записів Phase 71 мігровано в однорядковий формат + 3 застарілі записи NotebookLM-port-19213 викинуто + стелюformatForPromptпіднято 2000→3500, файл худне на 2KB при зростанні парсабельних рядків 85→93). Решта 6 (#329 SPA preload-error recover, #273 layout shift хлібних крихт, #337 Phase 69, #350 Phase 70, #160 NLM session monitor, #321 батьківська Phase 71) — застарілі трекерні рядки для вже відвантажених комітів. Записано урок: "перед відкриттям Tech Debt задач у роботу — grep git log на fix(#NNN) — економить години." - Чистка документації після шипу (2026-06-05) — вичищено залишкові згадки NotebookLM із CLAUDE.md / PROJECT_MANIFEST.md (bridge-context для ін'єкції воркерам),
docs/ARCHITECTURE.md,docs/PRODUCT.md,docs/architecture/{crm-backend,evolving-intelligence}.md,docs/public/api/api-reference.md, чотирьох EN-гайдів + повного UK-дзеркала гайдів, та банерів Phase 71 у DE/ES/FR/PL/RU/pt-BRindex.md(за патерном часткової локалізації #121). Попутно закрито #160 (застарілий NLM session monitor — startNlmMonitor видалено у 71.8) та #321 (трекінг батьківської фази). - 71.10 (#367) DONE ✅ — soak-валідація (Option A, прийнято CEO 2026-06-05):
- 5 ітерацій × 100+100 запитів проти живого prod-корпусу arc-v2 (555 чанків / 408 документів)
- Медіана між запусками: EN p50 ~195мс / p95 ~342мс / p99 ~650мс; UK p50 ~198мс / p95 ~367мс / p99 ~855мс
- Крос-мовний recall 100% (5/5 grounded UK→EN пар)
- Успіх синхронізації 0/178 помилок уже доведено в #363 на Production Cohere key
- Оригінальна чернеткова ціль
<300ms p95виявилася виставленою з одиничного smoke-виклику (#361, ~144мс), що не враховував природну хвостову дисперсію Cohere на окремих викликах/v2/embed. Архітектура верифіковно правильна — p50 стабільно ~195мс, наша власна частина KNN + project filter — менше 10мс; хвіст належить Cohere upstream. - Переглянутий SLO baseline (повні дані:
docs/architecture/PHASE_71_SOAK_2026-06-05.md):p50 ≤ 250ms ✅ · p95 ≤ 500ms ✅ · p99 ≤ 1500ms ✅ - Кандидати на follow-up (P3, поза скоупом #367): LRU-кеш query-embed, region pinning Cohere, щоквартальний re-soak
- 71.9 (#366) DONE ✅ — документація (EN + заглушки 7 локалей):
- Новий канонічний:
docs/public/architecture/rag-architecture.md— 11 секцій: проблема → мапа компонентів → модулі → вибір Cohere → зберігання sqlite-vec → re-embed хуки → read-path фасади → прапорці backfill → межі безпеки → таблиця міграцій → операційні нотатки - Замінено:
docs/public/guides/notebooklm-bridge.mdпереписано як документ "decommissioned, ось новий шлях" із таблицею before/after + кроками оператора + рецептом self-host міграції; 7 локальних дзеркал (UK повна локалізація, DE/ES/FR/PL/RU/pt-BR локалізований банер + EN-тіло за патерном проєкту з #121) - Пом'якшення маркетингової копії (закриває залишок #322):
docs/public/index.md(3 згадки NotebookLM → RAG),product/overview.md(2 згадки),features.md(3 згадки включно зі стовпом "Persistent project memory" у заголовку)
- Новий канонічний:
- 71.8 (#365) DONE ✅ — демонтаж
services/notebooklm-bridge/:systemctl stop && disable && rm /etc/systemd/system/citadel-notebooklm-bridge.serviceна проді; порт 19213 вільний/opt/citadel/services/notebooklm-bridge → .archived-notebooklm-bridge-2026-06-05; локальний шлях у репо віддзеркалено- Міграція 050 видаляє
projects.notebook_id(перевірено застосування на проді) - Видалено
shared/routes/notebooklm.ts(адмінські endpoints status/refresh-session/resync) + проводку в роутері - Замінено на місці:
help.tsragNotebookLM→ragSemantic(Cohere + навички_global_);cli-routes.tssyncSource→rag.upsert(memory-refresh стає user-triggered кнопкою "переіндексувати все");handleMemoryFetchArtifactповертає 410 (audio overview NotebookLM не має RAG-еквівалента) - Вирізано: поле схеми
notebook_idуprojects.ts+ handleGetNotebooks зведено до порожньої заглушки для legacy-клієнтів; два виклики/notebooks/initвonboarding.ts+ ін'єкція env NOTEBOOK_ID; константаNLM_URLвerasure.ts;startNlmMonitor+ викликач уmaster-bot/bot.ts; опція--syncнаarc wrapupуclients/arc-cli.ts - Закрито: #324 (band-aid проти eviction більше не потрібен) + #322 (маркетингова копія піде у 71.9)
- Type-check чистий по 11 зачеплених файлах; рестарт master чистий
- 71.7 (#364) DONE ✅ — заміна call sites notebooklm-bridge →
shared/rag.ts:shared/routes/chat.tsexecuteAskNotebooklmперенесено на нову платформу: паралельніragSearch(project, …)+ragSearch(_global_, …skill), merge за відстанню, fallback на локальний keyword-пошук коли top-hitd > 1.6або нуль результатів (покриває свіжі проєкти без embeddings). Назва інструмента збережена ("ask_notebooklm"), бо tool definitions ідуть downstream до Claude — перейменування зламало б розмови в польоті.shared/routes/skills.tshandleGenerateSkillперенесено з bridge-as-generator на Claude Sonnet із RAG-збагаченим house-style контекстом (top-5 хітів проєкту як приклади). Розділяє роль NotebookLM надвоє: retrieval ↔ generation.- Новий endpoint
GET /api/crm/projects/:name/rag/search?q=…&k=…&include_global=…&doc_types=…→shared/routes/rag-search.ts(паралельно project + global, тегований scope, сортування за відстанню). Підключено вrouter.ts. clients/lib/api.tssearchKnowledge(живитьarc kb search) перемкнуто: primary тепер б'є/rag/search, legacywiki/tree + filename-keywordвиживає як fallback для проєктів без embeddings.- Live VPS smoke: EN "Safari cookie auth bug" → issue#174 (auth/password reset) #1 d=1.00; UK "множинні тенанти" → issue#49 (Multi-Worker TG Topics Mode) #1 d=1.07 — крос-мовний retrieval цілий
Усі підфази відвантажено ✅
Усі 10 під-задач (#358–#367) закрито 2026-06-05. Повний soak-звіт: docs/architecture/PHASE_71_SOAK_2026-06-05.md. Архітектурний документ: docs/public/architecture/rag-architecture.md.
Phase 73: Meeting Transcription + Analysis (DONE ✅ — 9/9 під-задач)
Завантаження аудіо/відео зустрічі → транскрипція Groq whisper-large-v3 + Claude vision на кадрах зміни сцени + Claude summary → авто-вбудовується у RAG проєкту + лінк на задачу проєкту. Пряма кнопка завантаження на сторінці Transcripts. Місячна стеля на план (Starter=60 хв, Starter Cloud=300 хв). Фіча обмежена платними планами.
Parent: #379. Під-задачі #377/#378/#379/#380/#381/#382/#383/#384/#385.
Рішення CEO (D1-D6)
- D1 авто-embed у RAG з opt-out (прапорець
embed_to_ragза замовчуванням true) - D2 відкласти diarization (Phase 73+)
- D3 авто-summary так (Claude Sonnet)
- D4 видаляти вихідний файл коли
status=done - D5 макс завантаження 1 GB
- D6 скріпка в композері — основна точка входу; per-project вкладка Transcripts — другорядна
Що відвантажено
73.1 (#377) DONE ✅ — міграції 052 + 053 (
transcripts+transcript_jobs),POST /api/crm/projects/:name/transcripts/uploadз multipart + стелею 1 GB + MIME allow-list + атомарним записом на диск + insert обох рядків в одній tx. Гейт роутера через canAccessProject; зайву перевірку власника прибрано.73.2 (#378) DONE ✅ — фонова черга
master-bot/transcript-worker.ts. In-process булевий lock = макс 1 конкурентний job (whisper насичує 4 ядра з-t 4; два паралельно вдвічі сповільнюють обидва ТА голодом морять Bun event loop). State machine:queued → extracting_audio → transcribing → (відео: extracting_frames → frames_extracted) | (аудіо: transcribed). Підключено вmaster-bot/bot.ts.73.3 (#379) DONE ✅ — endpoints list/read/SSE:
GET /transcripts?limit=&cursor=,GET /transcripts/:id,GET /transcripts/job/:jobId/progressSSE-стрім із heartbeat-коментарями: keep-alive(10сidleTimeoutBun'а вбивав стрім під час тихих прогонів whisper). Auth браузерного EventSource через query?token=.73.7 (#383) DONE ✅ — інтеграція з композером.
Composer.jsx: детекціяisMediaFile,uploadMediaForTranscriptionPOST-ить multipart,trackTranscriptProgressвідкриває EventSource на/transcripts/job/:jobId/progress?token=…. Чіп-плейсхолдер → патчиться реальними id → SSE патчить status/progress_pct на місці.TRANSCRIPT_TERMINALоновлено до {summarized, done, failed} коли відвантажилася 73.5.hasPendingMediaгейтить кнопку Send.buildMessageWithAttachmentsвставляє--- TRANSCRIPT: <name> (<kind>) ---\n<text>\n--- END TRANSCRIPT ---, тож воркер читає зустрічі як будь-який inline-документ. File picker приймає mp4/mov/webm/mkv/m4v/mp3/wav/m4a/aac/ogg/opus/flac + audio/* + video/*.73.5 (#381) DONE ✅ —
master-bot/transcript-summary.tsвикликає Claude Sonnet із транскриптом (та описами кадрів, коли відвантажиться 73.4) і зберігає структурований JSON уsummary_json:{tldr, key_points[], action_items[{task, owner}], decisions[], topics[], model, generated_at}. Резолюція ключа дзеркалитьshared/worker-spawn.ts: BYOKaccount_settings.anthropic_key(дешифрується якщо зашифрований), fallbackPLATFORM_ANTHROPIC_KEYдля trial-mode власників. Збої summary нефатальні для транскрипта — статус відкочується до transcribed/frames_extracted, тож користувач може повторити після фіксу ключа. SSE TERMINAL set + frontendTRANSCRIPT_TERMINALоновлено:transcribed+frames_extractedтепер перехідні (далі йде summary). Smoke: JFK 11с → status=summarized, summary_json на 565 символів із tldr + 3 key_points + 4 topics; разом ~9с (3.4с warm whisper + ~5с Claude). Початковий model idclaude-sonnet-4-5-20250514дав 404 → замінено наclaude-sonnet-4-5за патерном workers.ts.73.4 (#380) DONE ✅ —
master-bot/transcript-vision.tsзапускає Claude Sonnet vision на кожен кадр зміни сцени. State machine вставляєvision_analyzing→vision_analyzedміжframes_extractedтаsummarizing. Per-frame промпт фокусується на слайдах/screen-shares/діаграмах і пропускає webcam-only кадри з "No informational content". Жорстка стеля MAX_FRAMES=50 (~$0.15 за типовими цінами Sonnet); послідовні виклики, щоб BYOK користувача не вибухав. Таймстемпи беруться з новогоtimestamps.json, який extractFrames пише, парсячи stderrshowinfo(n: <idx> pts_time: <sec>→frame_NNNN.jpg → ts_ms). Крок summary (73.5) тепер отримує vision-кадри як допоміжний контекст. Збій vision нефатальний: статус лишаєтьсяframes_extracted, summary продовжує transcript-only. Smoke: тестове відео з 3 склейками й текстовими накладками → 2 кадри проаналізовано на ts_ms=3000/6000 з коректними описами ("3 services" / "DECISION ship Q4"); end-to-end ~20с включно з 2 послідовними vision-викликами.73.6 (#382) DONE ✅ — RAG авто-embed після summary.
DocTypeрозширено"transcript". Післяstatus=summarizedворкер ставить статус jobembedding(95%), викликаєragUpsert(project, "transcript", String(transcript_id), ragText), деragText= сирий транскрипт + рядки[Xs] опис кадру+Summary: tldr / Key points: … / Decisions: … / Action items: ….embed_to_rag=0пропускає Cohere (opt-out користувача). Збій RAG нефатальний —doneвсе одно ставиться. Після embed:transcripts.status='done',completed_at, вихідний файл видалено (CEO D4), директорія кадрів вичищена. SSE TERMINAL оновлено до{done, failed}(прибраноsummarized— frontendTRANSCRIPT_TERMINALзберігаєsummarizedдля розгейтування кнопки send).rmdirSyncдодано доfs-імпортів; додані хелпериbuildRagText+cleanDir.73.8 (#384) DONE ✅ —
TranscriptsPage.jsxper-project сторінка Transcripts у CRM. Пункт навігації Sidebar ("Transcripts", іконка FileAudio). List view: усі транскрипти проєкту за created_at, кожен рядок показує filename/дату/тривалість/розмір + StatusBadge. Detail view: кнопка назад + 3 вкладки — Summary (tldr + key_points + decisions + чіпи action_items + теги topics), Frames (таймстемповані візуальні описи з Claude vision, webcam-only відфільтровані), Transcript (повний текст із inline-пошуком + підсвічуванням). i18n-рядки через макроси Trans/t, 8 локалей синхронізовано черезnpm run i18n:sync. Оновлено документацію: guides/voice-input.md + guides/meeting-transcription.md (новий), database-schema.md (міграції 052+053), rag-architecture.md (DocType transcript), api-reference.md (секція voice endpoint Phase 62).73.9 (#385) DONE ✅ — Post-processing UX + загартування інфраструктури. Міграція 054 (
linked_issue_idnullable FK наtranscripts).POST /transcripts/:id/link-issue(mode=new → створення задачі з summary, mode=append → збагачення тіла наявної задачі). Action bar у TranscriptDetail: "Create issue" / "Add to existing issue" / бейдж "Linked to #N". Пряма кнопка "Upload recording" на TranscriptsPage (FormData + поле filename).DELETE /transcripts/:id→ видаляє DB-рядки + RAG-чанки. Авто-опитування списку кожні 3с поки job у роботі. Groq whisper-large-v3 замінює локальний whisper.cpp ggml-base — драматично краща якість української/мультимовної, ~100× швидше за realtime, $0.111/година;GROQ_API_KEYкерується через Platform Settings (нова вкладка "Transcription"). Plan gate: free tier заблоковано (402), платні плани (Starter/Starter Cloud/beta) дозволені. Місячна стеля: Starter=60 хв, Starter Cloud=300 хв, Beta=1200 хв; progress bar використання в UI (бурштиновий @80%, червоний @100%). Фікс: Claude галюцинував імена з помилок Whisper — додано явне правило промпта "only use names that appear verbatim in transcript".
Phase 76: Project Channels — 1 бот на проєкт + Telegram Topics (DONE ✅ — 2026-06-06)
Крос-платформна абстракція каналів: один бот на проєкт замість одного бота на воркера. Telegram Supergroup + Topics для маршрутизації на воркера. Фундамент для Discord/Slack.
- 76A (#389) DONE ✅ — DB-міграція 055 (таблиці
project_channels+worker_channels).projectChannelQueriesуshared/db.ts(get/list/upsert/delete/resolveWorker/bindWorker/unbindWorker). 7 API-хендлерів уshared/routes/channels.ts: list, upsert Telegram, delete, list worker bindings, bind worker, unbind worker, verify (getMe + getChatMember + getForumTopics). Безпека: regex-валідація bot_token, валідація supergroup_id-100\d{9,}, allowlist config_json на платформу (Sentinel #5a), vault-ключproject:<name>:telegram:bot_token, deleteSecret перед DB-рядком при відключенні (Sentinel #4 no-orphan credentials). Роутер підключено уshared/routes/router.ts. - 76B (#389) DONE ✅ —
ChannelsSection.jsx3-кроковий візард у ProjectSettings: крок 1 (форма bot token + supergroup_id), крок 2 (verify → інфо про бота + статус адміна + список топіків), крок 3 (мапінг topic → worker дропдаун). Замінює per-worker поле Telegram-бота уніфікованою конфігурацією каналу на рівні проєкту. - 76C (#389) DONE ✅ — Topics-маршрутизація у child-боті + уніфіковані CLI-нотифікації.
message_thread_idдодано доTgMessage, параметрthreadIdуtgSend/tgTyping/tgSendMarkup. Ланцюг пріоритету токенів:project:<name>:telegram:bot_token→worker:<n>:<id>:bot_token. ПрапорецьUNIFIED_CHANNEL_MODE(!FORCED_WORKER_ID && !!PROJECT_CHANNEL_TOKEN). Маршрутизація:message_thread_id → projectChannelQueries.resolveWorker() → worker_id. Відповіді маршрутизуються назад у той самий topic-тред. Per-worker боти ставлятьBOT_TOKEN=nullколи канал налаштований (без конкуренції за токен). ВикликinitDb()додано при старті child-бота.spawnChannelBot()уshared/worker-spawn.ts(tmux socket/tmp/tmux-main, безFORCED_WORKER_ID). Watchdog виключає per-worker ботів коли канал існує.shared/tg-notify.tsnotifyWorker(): віддає перевагу channel-токену; резолвитьchat_id+message_thread_idіз vault-ключівworker:<project>:<id>:chat_id/worker:<project>:<id>:thread_id— CLI-нотифікації "finished turn" потрапляють у правильний Telegram-топік.handleBindWorkerChannelавто-зберігає vault-ключі при bind (використовуєworkspace_id, неchat_id). Авто-spawn channel-ботів при рестарті master. Зворотна сумісність із legacy маршрутизацією команд/c /d /w:. - #390 DONE ✅ — Користувачі cloud-плану використовують підписку Claude Code для Telegram-повідомлень.
resolveSpawn()уclaude-runner.tsперевіряєplan=cloud+ без BYOK → ставитьuseClaudeSubscription=true.spawnWorker()уcloud-spawn.tsпередає-e ANTHROPIC_API_KEY=уdocker exec— перекриває ключ із~/.bashrc, тож Claude CLI відкочується до OAuth-сесії зclaude login. Оновлено всі 4 call sitesspawnWorker.shared/worker-spawn.ts(3 spawn-функції) теж пропускає платформений ключ для cloud-плану.
#314: Worker Cards UX — Edit-іконка + чистка Preview drawer (DONE ✅ — 2026-06-07)
- WorkerTemplateCard: іконку Edit (Pencil) додано у верхній правий кут worker-варіанта. Кнопку
Previewприбрано — клік по картці відкриває drawer. Аліасui-designerдодано доROLE_META. - WorkerPreviewDrawer: іконку Edit додано до дій хедера для worker-варіанта (поруч із кнопкою Open).
- WorkersGlobalPage:
handleEditWorker→ відкриваєWorkerCreationWizardіз prefillinitialWorker.onSavedоновлює воркера на місці у списку.
#346: UI Atoms Library — впровадження Badge/Tag/Avatar (DONE ✅ — 2026-06-07)
Впровадження атомів Design System v2: inline color/style патерни винесені у перевикористовувані примітиви по всьому CRM.
- Badge впроваджено в: UserDropdown (key tier), BillingPage (Test Mode), ChannelsPage (статус), AdminLogsPage (лічильники fail/warn), CloudPage (private/archived), DiscoveryTab (count + overlapping skills), TranslationsDashboard (severity/status), GithubFeed (лічильник подій)
- Tag впроваджено в: DataList (чіпи активних фільтрів), IssuesRedesign (LabelsEditor)
- Avatar впроваджено в: UserDropdown (тригер + хедер), AccountSettingsDialog (AvatarUpload), IssuesRedesign (AssigneeAvatar)
- AvatarPackPicker: вкладку Upload прибрано — лише Role Icons.
ROLE_METAекспортовано для перевикористання. - AssigneeAvatar: рендерить SVG-іконку ролі через
ROLE_ICON_MAP(ті самі іконки що в сайдбарі). Аліасui-designerдодано доROLE_META+Avatar ROLE_COLOR. - Workers fetch у IssuesRedesign перемкнуто на глобальний
/api/crm/workers+ клієнтський фільтр заproject_name. - useOnboarding: гард
enabledзапобігає 401 при завантаженні сторінки без автентифікації.
Phase 78: Notes — Knowledge Collections (DONE ✅ 2026-06-08)
Нотатки в стилі NotebookLM на проєкт. Нота = колекція джерел (відео, аудіо, YouTube, веб, PDF, DOCX, TXT, зображення) з єдиним RAG-індексом і чатом. Прив'язується до задач — воркер бачить ноти коли бере issue в роботу.
Parent: #394 (закрито). Усі 10 під-задач відвантажено: #395–#404.
Що відвантажено
- 78.1 (#395) DONE ✅ — БД:
notes+note_sources+note_issue_links+note_chats(4 таблиці, міграції 049-050) - 78.2 (#396) DONE ✅ — Бекенд CRUD + upload-пайплайн: відео/аудіо (Groq Whisper), PDF (pdf-parse), DOCX (mammoth), TXT, зображення (Claude vision). Фонова черга обробки + SSE progress-події
- 78.3 (#397) DONE ✅ — YouTube: npm
youtube-transcript(каскад мов: en → en-US → en-GB → будь-яка) + fallback Supadata.ai (спершу пробуєlang=en, потім будь-яку мову). Виправляє регресію арабського транскрипта. - 78.4 (#398) DONE ✅ — Web scraping: Jina.ai
r.jina.ai/{url}→ чистий markdown, зберігає title + контент - 78.5 (#399) DONE ✅ — RAG:
doc_type='note_source'+ chat endpoint. RAG fallback: пряма ін'єкціяcontent_text(80K символів), коли sqlite-vec недоступний. Anti-hallucination попередження в system prompt для необроблених джерел. - 78.6 (#400) DONE ✅ — Сторінка Notes у CRM: список + деталі (панель джерел + чат). Sidebar: "Transcripts" → "Notes"
- 78.7 (#401) DONE ✅ — UI лінка на задачу + контекст воркера
- 78.8 (#402) DONE ✅ — Deprecated стара сторінка Transcripts, перейменування в сайдбарі, міграція даних
- 78.9 (#403) DONE ✅ — Чекбокси вибору джерел (за замовчуванням усі вибрані), inline-перейменування, бейджі аліасів S1/S2/... із кнопкою copy. 2-рядкова розкладка для елементів джерел. Endpoint
PATCH /notes/:id/sources/:sourceIdдля оновлення title. - 78.10 (#404) DONE ✅ — Tool use в чаті: Claude може створювати задачі проєкту прямо з чату (інструмент
create_issue), multi-turn SSE-стрімінг, компонентIssueCreatedCardв UI. Банер processing коли немає вибраних готових джерел.
Ключова архітектура
note-processor.ts— фоновий процесор: Whisper + vision + scraping + youtube-transcriptshared/routes/notes.ts— CRUD + чат + оновлення джерел + виконання tool usefrontend/src/crm/pages/NotesPage.jsx— повний Notes UI зSourceItem,ChatPanel,IssueCreatedCard- Tool use патерн:
create_issue→issueQueries.nextId()+issueQueries.insert()→ SSE-подіяtool_result→ стрім ходу 2
Phase 77: CEO Worker — Cross-Project Global Assistant ✅ DONE 2026-06-09 (#393)
Один CEO воркер на акаунт. Не прив'язаний до жодного проєкту — бачить всі проєкти юзера через інструменти. Стратегічна роль: аналіз, планування, cross-project огляд.
Відвантажено:
- Модель: Claude Opus 4.7, SSE agentic loop до 10 tool-ходів
- БД: міграція 058 — таблиці
ceo_sessions+ceo_messages - API: 6 маршрутів (
GET/POST /sessions,DELETE/GET/POST/DELETE /sessions/:id/messages-or-chat) - 6 CEO-інструментів (усі за гейтом
owner_id = JWT chatId):list_projects— читає воркерів ізworkers_registry.json(без DB-таблиціworkers)get_project_summary— інфо проєкту + воркери + відкриті задачі + недавня активністьget_issues— крос-проєктні задачі з фільтрами priority/status, JOIN-скоуп за власникомcreate_issue— створює задачу у власному проєктіget_worker_activity— недавні повідомлення чату + activity log на воркераsearch_knowledge— семантичний RAG-пошук (Cohere + sqlite-vec)
- CRM: сторінка
/ceo— сайдбар сесій + стрімінговий чат,BotMessageSquareу навігації Sidebar - CLI:
arc ceoREPL +arc ceo sessions+arc ceo clear+ прапорці--new/--session - Security P0 фікс: усі 6 інструментів фільтрують
WHERE owner_id = ?з JWT — запобігає крос-тенантному витоку даних - 77.5 (TG-бот на акаунт) → відкладено до #428 P2 backlog
Phase 75: Odoo CRM Integration (PLANNED, спочатку була Phase 70)
Воркери Arc OS стають повноцінними співробітниками всередині наявного Odoo клієнта — записи
hr.employee, користувачі з правами, виконавці задач, учасники чату Discuss. Тригериться З Odoo, розмова ВСЕРЕДИНІ Odoo Discuss. Користувач ніколи не покидає Odoo-воркфлоу. Перенумеровано з Phase 70 (яка стала Cloud Chat Routing) за комітом515f382.
Parent: #345 (P3 watchlist).
Стратегічне позиціонування
- CEO — 9 років Senior Odoo Developer — доменний авторитет
- Відкритий Python ORM, без API rate limits
- Odoo Apps marketplace = вбудована дистрибуція
- Модульно: інтегрувати по частинах (спершу HR + Project + Discuss)
- Вирівнювання з ринком UA/EU SMB
- Defensibility moat — Cursor/Claude Code/Accio не можуть легко відтворити глибоку ERP-інтеграцію
Референсна архітектура (валідована)
Патерн "Automated Bookkeeping Landscape": Odoo = System of Record · Claude Agents = Execution Layer · Human = Oversight. 8 спеціалізованих агентів (Revenue/AP/Payroll/Bank-Recon/Accruals/Reconciliation/Consolidation/Reporting). Та сама модель, що й наша спеціалізація воркерів. Див. docs/strategy/crm-integration-vision.md + docs/strategy/assets/odoo-claude-agents-bookkeeping-example.png.
Підфази (заплановано, не розпочато)
- 75.0 — Foundation: Odoo addon
arc_os_workers, мапінг воркер → Odoo user, ORM bridge (3-4 тиж) - 75.1 — HR identity: записи
hr.employee, відділи, email-аліаси, інтеграція Discuss (2-3 тиж) - 75.2 — Участь у воркфлоу: погодження, призначення задач, синхронізація статусів, TG-пінги (4-6 тиж)
- 75.3 — Marketplace + SDK для спільноти Odoo-розробників + revenue share (6-8 тиж)
- 75.4 — Production-запуск + лістинг в Odoo Apps store + ціновий tier (3-4 тиж)
- 75.5+ — Multi-CRM розширення: HubSpot → Pipedrive → monday.com → Notion → Salesforce
Жорсткі передумови (НЕ починаємо доки все не зелене)
- #293 multi-model wrapper відвантажено (enterprise-комфорт вимагає LLM-портабельності)
- Phase 71 RAG стабільний (~99% успіху синхронізації після міграції на sqlite-vec)
- #334 view primitives відвантажено (UI-фундамент для будь-яких конфіг-екранів на стороні Arc OS)
- #315 CLAUDE.md trim відвантажено (overhead ініціалізації сесії під контролем)
- Phase 67 worker UX завершено
- 20+ платних клієнтів Arc OS (довести основний продукт)
- Рев'ю Sentinel (модель безпеки для embedded enterprise-даних + AI-прав)
Реалістичний старт Phase 75: ~Q1 2027
Спочатку проєктувалося на вересень-жовтень 2026 як Phase 70, але слот Phase 70 зайняв Cloud Chat Routing, і передумови зсунулися праворуч.
Специфікації
- Стратегічне бачення:
docs/strategy/crm-integration-vision.md - Бриф розробника:
docs/strategy/phase70-odoo-developer-brief.md(назву файлу збережено для git-історії, контент уже оновлено з урахуванням перенумерації Phase 75)