База данных — SQLite Schema

Общая информация

ER Diagram (Phase 65)

erDiagram
    users ||--o{ projects : owns
    users ||--|| account_settings : has
    users ||--o{ recovery_keys : holds
    users ||--o{ subscriptions : pays
    users ||--o{ invites : creates
    users ||--o{ chat_messages : sends
    users ||--o{ trial_credits : claims
    users ||--o{ activity_log : generates

    projects ||--o{ project_phases : tracks
    projects ||--o{ pinned_notes : pins
    projects ||--o{ chat_messages : contains
    projects ||--o{ timeline_events : records
    projects ||--o{ github_links : links
    projects ||--o{ skill_benchmarks : runs
    projects ||--o{ marketplace_cache : caches

    github_links ||--o{ github_events : receives

    invites }o--|| users : "consumed by"
    subscriptions ||--o{ stripe_events : "logs idempotency"

    users {
        TEXT id PK
        TEXT email UK
        TEXT password_hash
        TEXT role "admin · user"
        TEXT google_id UK
        TEXT github_id UK
        INTEGER email_verified
        INTEGER two_factor_enabled
        TEXT last_login
    }

    projects {
        INTEGER id PK
        TEXT technical_name
        TEXT owner_id FK
        TEXT display_name
        INTEGER is_archived
    }

    chat_messages {
        INTEGER id PK
        TEXT project_name
        TEXT worker_id
        TEXT role "user · assistant · system"
        TEXT content "AES-256-GCM if encrypted=1"
        INTEGER encrypted
        TEXT timestamp
    }

    subscriptions {
        TEXT user_id PK
        TEXT plan "free · min · max · beta"
        TEXT stripe_customer_id
        TEXT status
    }

    invites {
        TEXT code PK "arc-XXXX-XXXX"
        TEXT created_by FK
        TEXT used_by FK
        TEXT parent_invite_code
        TEXT status "active · used · revoked"
    }

    recovery_keys {
        INTEGER id PK
        TEXT user_id FK
        TEXT encrypted_key
        TEXT key_hint "first 4 chars"
    }

    trial_credits {
        TEXT email PK
        INTEGER credits_used
        TEXT first_used_at
    }

23 таблицы в 24 миграциях. Auth + проекты + данные workspace + интеллект-слой + billing + бета-gating + аудит контекстного экспорта. Все FK-ограничения соблюдены.

Таблицы

users — Пользователи

Колонка Тип Описание
id TEXT PK UUID
email TEXT UNIQUE Email (обязательный)
password_hash TEXT Хеш пароля (bcrypt)
role TEXT 'admin' или 'user'
name TEXT Имя
avatar_url TEXT URL аватара
google_id TEXT UNIQUE Google OAuth ID
github_id TEXT UNIQUE GitHub OAuth ID
email_verified INTEGER 0/1
two_factor_enabled INTEGER 0/1
totp_secret TEXT TOTP-секрет (2FA)
last_login TEXT ISO 8601
created_at TEXT ISO 8601

projects — Проекты

Колонка Тип Описание
id INTEGER PK Auto
technical_name TEXT Техническое имя (уникальное per owner)
owner_id TEXT FK→users Владелец
display_name TEXT Отображаемое имя
description TEXT Описание
color TEXT Цвет (hex)
icon TEXT Иконка
is_archived INTEGER 0/1
sort_order INTEGER Порядок (default 999)
project_protocol TEXT Протокол проекта
created_at, updated_at TEXT Timestamps

UNIQUE(technical_name, owner_id)

account_settings — Настройки аккаунта

Колонка Тип Описание
user_id TEXT PK FK→users
anthropic_key TEXT Anthropic API ключ
openai_key TEXT OpenAI API ключ
name TEXT Имя
role TEXT Роль
auto_harvest INTEGER Автосбор навыков 0/1

chat_messages — История чатов

Колонка Тип Описание
id INTEGER PK Auto
project_name TEXT Проект
worker_id TEXT Воркер
role TEXT 'user', 'assistant', 'system'
content TEXT Текст сообщения (зашифровано AES-256-GCM если encrypted=1)
encrypted INTEGER 0=plaintext, 1=vault-encrypted (Phase 45.3)
attachments TEXT JSON-массив
timestamp TEXT ISO 8601
metadata TEXT JSON-объект

INDEX(project_name, worker_id, timestamp DESC)

recovery_keys — Ключи восстановления (Phase 45.4)

Колонка Тип Описание
id INTEGER PK Auto
user_id TEXT FK→users Владелец
encrypted_key TEXT Зашифрованный master key
key_hint TEXT Подсказка (первые 4 символа)
created_at TEXT ISO 8601
used_at TEXT Когда использован
revoked INTEGER 0=активный, 1=отозван

INDEX(user_id)

github_links — Привязки GitHub repo (Phase 49.3)

Колонка Тип Описание
id INTEGER PK Auto
project_name TEXT Arc OS project
owner TEXT GitHub repo owner
repo TEXT GitHub repo name
webhook_secret TEXT UNIQUE 32-байтный hex для HMAC-SHA256 validation
created_at TEXT ISO 8601
created_by TEXT FK→users Кто создал link

UNIQUE(project_name, owner, repo) — multi-repo per project allowed. INDEX(project_name), INDEX(webhook_secret)

github_events — Лог GitHub-событий (Phase 49.3.1)

Колонка Тип Описание
id INTEGER PK Auto
link_id INTEGER FK→github_links CASCADE on link delete
project_name TEXT Arc OS project (denormalized для query speed)
event_type TEXT push, pull_request, workflow_run, issues
action TEXT sub-action (opened/closed/success/failure)
summary TEXT Pre-formatted display string
url TEXT GitHub deep link
actor TEXT GitHub username
created_at TEXT ISO 8601

INDEX(project_name, created_at DESC), INDEX(link_id)

skills_global — Глобальные скилы

Колонка Тип Описание
id INTEGER PK Auto
name TEXT UNIQUE Название
description TEXT Описание
category TEXT Категория (default 'general')
content TEXT Содержимое скила (markdown)
triggers TEXT JSON-массив триггеров
keywords TEXT JSON-массив ключевых слов
eval_rules TEXT JSON-массив правил
tool_code_ts TEXT TypeScript-реализация
version INTEGER Версия (auto-increment)
status TEXT 'active', 'draft', 'deprecated', 'archived'

skills_project_forks — Форки скилов

Колонка Тип Описание
id INTEGER PK Auto
project_name TEXT Проект
skill_id INTEGER FK→skills_global Родительский скил (CASCADE)
content TEXT Кастомизированное содержимое
triggers, keywords, eval_rules, tool_code_ts TEXT Переопределения
version INTEGER Версия форка

UNIQUE(project_name, skill_id)

skill_evolution_logs — История изменений скилов

Колонка Тип Описание
id INTEGER PK
skill_id INTEGER FK CASCADE
project_name TEXT Проект (nullable)
action TEXT 'created', 'modified', 'applied', 'reverted'
diff_summary TEXT Описание изменений
author TEXT Автор (default 'system')
metadata TEXT JSON

skill_update_requests — PR скилов (Sage)

Колонка Тип Описание
id INTEGER PK
skill_id INTEGER FK CASCADE
proposed_by TEXT 'sage' (default)
status TEXT 'pending', 'approved', 'rejected', 'applied'
current_content TEXT Текущая версия
proposed_content TEXT Предложенная версия
reason TEXT Причина изменения

skill_benchmarks — A/B тесты скилов

Колонка Тип Описание
id INTEGER PK
request_id INTEGER FK→skill_update_requests CASCADE
test_scenario TEXT Сценарий теста
old_output, new_output TEXT Результаты
score_old, score_new REAL Оценки
judgment_reason TEXT Обоснование

pinned_notes — Закреплённые заметки

Колонка Тип Описание
id INTEGER PK
project_name TEXT Проект
worker_id TEXT Воркер
title TEXT Заголовок
body TEXT Текст
source_message_id INTEGER Ссылка на chat_messages

project_phases — Фазы Roadmap

Колонка Тип Описание
id INTEGER PK
project_name TEXT Проект
phase_id INTEGER Номер фазы
phase_title TEXT Название
status TEXT 'PLANNED', 'ACTIVE', 'COMPLETED', 'CANCELLED'
progress REAL 0.0–1.0
deadline TEXT ISO 8601

UNIQUE(project_name, phase_id)

activity_log — Журнал активности

Колонка Тип Описание
id INTEGER PK
project_name TEXT Проект
actor TEXT Воркер или пользователь
event_type TEXT Тип события
title TEXT Описание
metadata TEXT JSON
created_at TEXT ISO 8601

INDEX(created_at DESC), INDEX(project_name, created_at DESC), INDEX(event_type, created_at DESC), INDEX(actor, created_at DESC)

system_configs — Системные настройки

Колонка Тип Описание
key TEXT PK Ключ
value TEXT Значение
description TEXT Описание

marketplace_analysis_cache — Кеш marketplace

Кеш анализа совместимости скилов из marketplace.

ephemeral_tokens — Короткоживущие токены (issue #27)

Persistent-хранилище для одноразовых токенов: OAuth state, password reset, email verification. До миграции 022 эти токены жили в in-memory Map и терялись при каждом рестарте master, ломая Google/GitHub login (invalid_state).

Колонка Тип Описание
token TEXT PK 32-байтный hex (randomBytes(32))
type TEXT NOT NULL oauth_state | password_reset | email_verification
payload TEXT NOT NULL JSON: {provider} для oauth_state, {email} для остальных
expires_at INTEGER NOT NULL ms epoch — TTL: 10 мин (oauth) / 30 мин (reset) / 24 ч (verify)

INDEX(type), INDEX(expires_at). Одноразовое использование: consume() в одной транзакции читает payload и удаляет строку.

project_issues — Задачи per project (issue #53, Phase 53.14)

SQLite SSOT для задач вместо per-project issues/issues.json. Файл остаётся на диске как derived export (mirror), gitignored — DB авторитативна.

Колонка Тип Описание
project_name TEXT NOT NULL name из registry; составная PK вместе с id
id INTEGER NOT NULL 1-based per-project sequence (max+1 при insert)
title TEXT NOT NULL заголовок задачи
body TEXT NOT NULL DEFAULT '' описание, markdown
priority TEXT NOT NULL DEFAULT 'P2' P0 | P1 | P2 | P3
labels TEXT NOT NULL DEFAULT '[]' JSON array of strings
status TEXT NOT NULL DEFAULT 'open' draft | open | in_progress | blocked | deferred | closed (SQL default 'open' сохраняется — новые задачи форсятся в draft на уровне приложения)
assignee TEXT NULL worker id, взявший задачу (migration 036)
created_by TEXT NOT NULL DEFAULT 'legacy' worker id, кто создал задачу (migration 046 / #327) — для audit (кто, когда, на кого)
created_at TEXT NOT NULL ISO timestamp
updated_at TEXT NOT NULL ISO timestamp
closed_at TEXT NULL ISO timestamp при status=closed
activity TEXT NOT NULL DEFAULT '[]' JSON array {ts, type, author, text} — append-only audit

PK (project_name, id) — у каждого проекта свой независимый id-пространство. INDEX (project_name, status) — самый частый фильтр (open only). Operations live in issueQueries (shared/db.ts): list/get/nextId/insert/upsert/replaceAll/bulkImport. replaceAll — атомарная транзакция; bulkImportINSERT OR IGNORE для idempotent re-seed.

Migration 036 (#187, 2026-05-23): ALTER TABLE project_issues ADD COLUMN assignee TEXT. Новые статусы (in_progress, blocked, deferred) валидируются на уровне приложения (IssueStatus union в shared/db.ts), не CHECK constraint (SQLite не позволяет добавлять constraint через ALTER TABLE).

Migration 046 (#327, 2026-06-03): ALTER TABLE project_issues ADD COLUMN created_by TEXT NOT NULL DEFAULT 'legacy'. Lifecycle расширен новым статусом draft. handleCreateIssue форсит status='draft' когда assignee=null (иначе сразу 'open'), требует worker_id (body или auth fallback). handleUpdateIssue auto-promote draft → open при первом назначении assignee и reject close для never-assigned задачи (FR-ISS-101/102/103). Pre-existing rows backfill через DEFAULT как 'legacy'.

onboarding_progress — Состояние post-wizard чеклиста (issue #56, Phase 54.1)

Per-user derived cache над event stream из activity_log (SSOT). UI читает одним запросом вместо агрегации по событиям. Replayable: dismiss/replay не меняют state, только dismissed_at.

Колонка Тип Описание
chat_id TEXT PRIMARY KEY user id (registry chat id)
state TEXT NOT NULL DEFAULT '{}' JSON {workers, cli, skill, bot, issue}completed | skipped (отсутствующие ключи = pending)
completed_count INTEGER NOT NULL DEFAULT 0 derived cache count of completed steps (0–5)
started_at TEXT NOT NULL DEFAULT (datetime('now')) создание строки (первое событие/dismiss/replay)
completed_at TEXT NULL ISO timestamp когда все 5 steps completed
dismissed_at TEXT NULL ISO timestamp когда пользователь закрыл чеклист
source TEXT NOT NULL DEFAULT 'web' web | cli — для funnel attribution (#58 arc tour)
updated_at TEXT NOT NULL DEFAULT (datetime('now')) mutation timestamp

INDEX на completed_at для funnel-аналитики (#61 Phase 54.6). Operations live in onboardingQueries (shared/db.ts): getProgress/recordEvent/dismiss/replay. recordEvent идемпотентен на (chat_id, step, status) — повторный идентичный вызов возвращает changed=false и не пишет в activity_log. Whitelist: 5 steps × 2 statuses (completed, skipped). skipped НЕ инкрементирует completed_count. Переход skipped → completed добавляет к count. Все мутации эмитируют события в activity_log с event_type LIKE 'onboarding_%' — настоящий SSOT для funnel-метрик; колонки таблицы — derived cache.

platform_audit_log — Super-admin trail ротации секретов (Phase 57, Sentinel #103)

Append-only журнал мутаций platform-secrets через vault в Platform Settings UI. SSOT для post-incident forensics («какой admin ротировал Anthropic key в 03:14 UTC?»). Vault.json сам этого не пишет — только значения.

Колонка Тип Описание
id INTEGER PRIMARY KEY AUTOINCREMENT временной порядок даже при clock skew
ts TEXT NOT NULL DEFAULT (datetime('now')) server-side UTC; attacker не может backdating
user_chat_id TEXT NOT NULL admin, выполнивший действие
user_email TEXT NULL snapshot из таблицы users на момент действия
action TEXT NOT NULL list | view | rotate | test | restart
key_name TEXT NOT NULL имя vault-записи (allowlist в platform.ts); * для list-all
ip TEXT NULL из CF-Connecting-IP / X-Real-IP / XFF tail
result TEXT NOT NULL success или fail:<reason>
user_agent TEXT NULL UA-строка, truncated 200 chars

INDEXES: idx_platform_audit_ts (recent across keys), idx_platform_audit_user (per-admin trail), idx_platform_audit_key (история ротаций per key). Инвариант append-only: нет UPDATE/DELETE-обработчиков; UI предоставляет read-only recent() + lastRotated() через platformAuditQueries в shared/db.ts. Каждое действие (success+fail) записывает строку.

auth_events — Лог событий аутентификации пользователей (Migration 027, issue #130)

Append-only журнал auth-событий для security auditing и расследования инцидентов. Отдельная от platform_audit_log (admin-only vault) — эта таблица покрывает end-user auth flow с IP.

Колонка Тип Описание
id INTEGER PRIMARY KEY AUTOINCREMENT временной порядок
ts TEXT NOT NULL DEFAULT (datetime('now')) server-side UTC
event TEXT NOT NULL signup | login | oauth_login | magic_link | device_code_approve
provider TEXT NOT NULL DEFAULT 'password' password | google | github | magic_link | device_code
user_id TEXT NULL NULL для неудачных попыток, где user не идентифицирован
email TEXT NULL email, использованный в попытке
ip TEXT NOT NULL DEFAULT 'unknown' CF-Connecting-IP → X-Real-IP → XFF last segment
user_agent TEXT NULL UA-строка
result TEXT NOT NULL success | failed | rate_limited | invalid_invite | already_registered | 2fa_required | invalid_token
meta TEXT NULL JSON extra context (напр. {isNew: true} для OAuth)

INDEXES: idx_auth_events_ts (newest first), idx_auth_events_user (per-user history), idx_auth_events_ip (per-IP threat detection), idx_auth_events_event (фильтр event+result). authEventQueries.insert/recent в shared/db.ts. Логируется в master-bot/routes/auth.ts (register/login/oauth/magic-link) и master-bot/routes/cli.ts (device_code_approve).

Миграции

# Название Фаза Что добавляет
001 initial_schema Phase 40 users, projects, account_settings
002 project_protocol Phase 40.7 projects.project_protocol
003 chat_messages Phase 40.10 chat_messages
004 skill_system Phase 41 skills_global, skills_project_forks, skill_evolution_logs, skill_update_requests
005 skill_benchmarks Phase 40.11d skill_benchmarks
006 system_configs system_configs + FIGMA_CACHE_ROOT
007 marketplace_cache Phase 40.12.1 marketplace_analysis_cache
008 harvester Phase 40.13 +is_suggestion, +source_query, +auto_harvest
009 pinned_notes Phase 41.8 pinned_notes
010 project_phases Phase 44 project_phases
011 activity_log Phase 44.1 activity_log
012 performance_indexes Perf Audit +idx_activity_log_actor, +idx_chat_msg_role_ts
013 timeline_timestamps Phase 47 +timestamp на сообщениях воркеров
014 timeline_events Phase 47 таблица timeline_events
015 e2ee_chat Phase 45.3 +encrypted колонка в chat_messages
016 recovery_keys Phase 45.4 таблица recovery_keys
017 github_links Phase 49.3 таблица github_links (webhook bindings)
018 github_events Phase 49.3.1 таблица github_events (лог событий для UI feed)
019 trial_credits Phase 50.1 +users.trial_granted_at, +projects.trial_mode, +projects.trial_tokens_remaining
020 subscriptions Phase 51 таблица subscriptions (plan, stripe_customer_id, status, feature_flags) + stripe_events idempotency log
021 invites Phase 52.1 таблица invites (closed beta enrollment) — code, created_by, used_by, parent_invite_code, status, note
022 ephemeral_tokens issue #27 таблица ephemeral_tokens — persistent OAuth state / password reset / email verification, вместо in-memory Map (фикс invalid_state при рестарте master)
023 project_issues Phase 53.14 / issue #53 таблица project_issues (composite PK project_name+id, JSON labels/activity) — переносит хранение задач из issues/issues.json в SQLite SSOT, JSON становится derived mirror; устраняет text-merge drift при деплое
024 context_exports Phase 56.4 + 56.5 / issues #100 + #101 export_audit_log (id PK, project_name, owner_id, exported_at, sections JSON, findings_critical/high/medium/low INT, bytes) + export_preferences (project_name PK, always_include_emails BOOL, auto_redact_critical BOOL DEFAULT 1, notify_on_export BOOL DEFAULT 0, updated_at) — per-project история аудита для Project Context Export + per-project policy toggles; алерт при ≥3 exports/24h когда notify_on_export = true
025 onboarding_progress Phase 54.1 / issue #56 onboarding_progress (chat_id PK, JSON state per 5 steps, completed_count derived, started_at/completed_at/dismissed_at, source web|cli) — derived cache над event stream из activity_log; SSOT = события event_type LIKE 'onboarding_%'; recordEvent идемпотентен, dismiss/replay non-destructive
026 platform_audit_log Phase 57 / Sentinel #103 platform_audit_log (id PK AUTOINCREMENT, ts, user_chat_id, user_email, action, key_name, ip, result, user_agent) — append-only audit trail для super-admin Platform Settings UI мутаций vault secrets. 3 indexes: idx_platform_audit_ts/user/key. Нет UPDATE/DELETE — read-only через platformAuditQueries.recent + lastRotated
027 auth_events Issue #130 auth_events (id PK AUTOINCREMENT, ts, event, provider, user_id, email, ip, user_agent, result, meta JSON) — Append-only лог событий аутентификации + IP. События: signup/login/oauth_login/magic_link/device_code_approve. Результаты: success/failed/rate_limited/invalid_invite/already_registered/2fa_required/invalid_token. 4 индекса: ts/user_id/ip/event+result
028 managed_containers Phase 60 #135/#136 managed_containers (id TEXT PK (имя Docker-контейнера), user_id, status (provisioning|ready|paused|suspended|deleted), server_ip, internal_port INT, claude_authed INT, github_authed INT, created_at, last_active) — Реестр Docker-контейнеров 1-на-пользователя для Standard Cloud. managedContainerQueries.findByUser/insert/updateStatus/setAuthFlag/touch/listActive в shared/db.ts. Endpoints: POST /api/crm/cloud/provision, GET /status, POST /deprovision в shared/routes/cloud.ts
029 cloud_waitlist Phase 60 #134 cloud_waitlist (id INT PK AUTOINCREMENT, user_id TEXT UNIQUE, email, position INT, status (waiting|invited|activated|declined), notes, joined_at, invited_at, activated_at) — waitlist Early Access для Standard Cloud.
030 translation_feedback Phase 59.4 #122 translation_feedback (id INT PK AUTOINCREMENT, locale, message_id, original, current_translation, suggestion, user_id, status (pending|accepted|rejected), created_at, reviewed_at).
031 token_usage_log Phase 63 #148 token_usage_log (id INT PK AUTOINCREMENT, project_name, owner_id, worker_id, input_tokens, output_tokens, cache_tokens, total_tokens, created_at INT) — использование токенов Claude per-request. Заполняется claude-runner.ts через /api/internal/usage/log.
032 arc_help_usage Phase 61 #147 arc_help_usage (user_id, date PK composite) — дневной rate-limit счётчик для Arc Help (30 msg/day).
033 arc_help_messages Phase 61 #153 arc_help_messages (id PK AUTOINCREMENT, user_id, role, text, sources JSON, created_at) — персистентная история чата Arc Help per user (последние 60).
034 skills_owner_project #157 ALTER TABLE skills_global ADD COLUMN owner_project TEXT — NULL=глобальный, non-null=принадлежит проекту.
035 password_version Phase 64 #174 ALTER TABLE users ADD COLUMN password_version INTEGER DEFAULT 0 — инкрементируется при смене пароля; claim pv в JWT валидируется crmAuthMiddleware для инвалидации старых токенов.
036 issue_assignee #187 / 2026-05-23 ALTER TABLE project_issues ADD COLUMN assignee TEXT — nullable worker id. Включает arc issue take <id> + расширенные статусы in_progress/blocked/deferred (валидируются на уровне приложения).
046 issue_draft_and_created_by #327 / 2026-06-03 ALTER TABLE project_issues ADD COLUMN created_by TEXT NOT NULL DEFAULT 'legacy' — audit-поле «кто создал». Lifecycle += draft (app-level union). handleCreateIssue форсит draft без assignee; handleUpdateIssue auto-promote draft→open при assign + reject close never-assigned (FR-ISS-101/102/103).
037 waitlist #197 / 2026-05-25 waitlist (id INT PK AUTOINCREMENT, email TEXT UNIQUE, message, status DEFAULT 'pending', created_at, updated_at) — форма запроса раннего доступа на странице логина.
038 plata_billing Phase 65 #202 / 2026-05-26 Добавляет колонки Plata by mono в subscriptions: plata_card_token TEXT, plata_wallet_id TEXT, plata_masked_pan TEXT, next_billing_date TEXT, billing_failures INTEGER DEFAULT 0. Также создаёт idempotency-таблицу plata_events (invoice_id PK, status, processed_at).
039 skill_project_grants #201 / 2026-05-26 skill_project_grants (skill_id INT FK→skills_global.id CASCADE, project_name TEXT, granted_at, PK composite) — many-to-many доступ к скилам между проектами.
040 drop_stripe #205 / 2026-05-26 DROP колонки stripe_customer_id + DROP TABLE stripe_events. NB: колонка stripe_subscription_id пережила эту миграцию, потому что SQLite отказывает в DROP COLUMN на колонках с UNIQUE-constraint (молча перехвачено try/catch). См. migration 041.
041 rebuild_subscriptions #205 / 2026-05-26 Follow-up к 040 — пересобирает таблицу subscriptions без осиротевшей колонки stripe_subscription_id через паттерн CREATE TABLE … AS. Idempotent (пропускается, когда колонка уже отсутствует).
042 totp_backup_codes ALTER TABLE users ADD COLUMN totp_backup_codes TEXT — TOTP recovery codes.
043 worker_avatars Phase D #304 / 2026-05-30 worker_avatars (id PK AUTOINCREMENT, project_name, worker_id, file_path, mime_type, created_at; UNIQUE(project_name, worker_id)) — metadata store для загруженных аватаров воркеров. Файлы сохраняются в data/worker-avatars/. Отдаётся через GET /api/crm/projects/:name/workers/:id/avatar.
044 worker_templates Phase I #304 / 2026-05-30 worker_templates (id PK AUTOINCREMENT, owner_id, name, description, config JSON, is_public, created_at; UNIQUE(owner_id, name)) — пользовательские шаблоны воркеров. Endpoints: GET/POST /api/crm/workers/templates, DELETE /api/crm/workers/templates/:id.
045 workers_runtime_state Phase F #306 / 2026-05-31 workers_runtime_state (project_name, worker_id, status, status_started_at, current_skill, current_task_id, updated_at; PK(project_name, worker_id), idx по updated_at) — живое runtime-состояние per worker. Пишется handleSetActiveRole (инвариант одной активной роли на проект). Читается GET /api/crm/projects/:name/workers/:id/runtime со staleness fallback: status='working' + tmux мёртв + updated_at > 10 мин → принудительно idle (crash detection).
049 embeddings Phase 71.2 #359 / 2026-06-04 embeddings (id PK AUTOINCREMENT, project, doc_type wiki/issue/skill, doc_id, chunk_ix, text, created_at) + embeddings_vec (vec0 virtual table, embedding FLOAT[1024]). Разделение: vec0 не может эффективно хранить metadata; LIST/DELETE workflow выполняются обычным SQL. Расширение sqlite-vec авто-загружается в initDb до запуска миграции.
050 drop_notebook_id Phase 71.8 #365 / 2026-06-05 ALTER TABLE projects DROP COLUMN notebook_id. Выводит из схемы поле NotebookLM bridge; семантический поиск теперь работает через self-hosted RAG (Cohere + sqlite-vec). Idempotent через проверку PRAGMA table_info, чтобы свежие DB с текущей схемой 001 не спотыкались об отсутствующую колонку.
051 voice_usage Phase 62.4 #373 / 2026-06-05 voice_usage_log (user_id TEXT, date TEXT YYYY-MM-DD, seconds_used INTEGER DEFAULT 0, PRIMARY KEY(user_id, date)) — дневной счётчик квоты голосовой транскрипции, зеркалит форму migration 032 arc_help_usage. Приблизительные секунды (оценка по размеру загрузки в байтах при кодеке ~32 kbps); сравнивается с мягким лимитом 60 мин/день в handleVoiceTranscribe (shared/routes/voice.ts) перед каждой транскрипцией, чтобы один пользователь не монополизировал общий пул whisper-server на Contabo.
052 transcripts Phase 73.1 #377 / 2026-06-05 transcripts (id PK AUTOINCREMENT, project TEXT, owner_id TEXT, source_filename TEXT, source_bytes INTEGER, source_kind TEXT CHECK(audio|video), duration_seconds INTEGER, transcript_text TEXT, frames_json TEXT, summary_json TEXT, embed_to_rag INTEGER DEFAULT 1, status TEXT DEFAULT 'queued', error TEXT, created_at TEXT DEFAULT datetime('now'), completed_at TEXT) — одна строка на загруженный файл встречи. frames_json = JSON-массив {ts_ms, description} от Claude vision (Phase 73.4). summary_json = {tldr, key_points, action_items, decisions, topics, model, generated_at} от Claude Sonnet (Phase 73.5). Исходный файл удаляется с диска, как только status='done' (решение CEO D4). Индексы по (project, created_at DESC) и (owner_id, created_at DESC).
056 skill_usage #319 / 2026-06-07 skill_usage (skill_name TEXT, project_name TEXT DEFAULT '_global_', trigger_count INTEGER DEFAULT 0, install_count INTEGER DEFAULT 0, session_count INTEGER DEFAULT 0, last_triggered_at TEXT, updated_at TEXT, PRIMARY KEY(skill_name, project_name)) — кумулятивные счётчики per skill per project. trigger_count инкрементируется каждый раз, когда context router инжектит скил; install_count — при save/create; session_count — при появлении в уникальной сессии. Используется GET /api/crm/projects/:name/skills/usage.
057 notes Phase 78.1 #395 / 2026-06-07 4 таблицы: notes (id PK, project_name, title, description, created_by, created_at, updated_at) — заметка как контейнер источников. note_sources (id PK, note_id FK→notes, source_type CHECK(video|audio|youtube|web|pdf|docx|txt|image), filename, file_path, file_size, url, title, content_text, duration_seconds, status CHECK(queued|processing|done|error), error, processed_at, created_at) — один источник на строку, content_text = извлечённый текст для RAG. note_issue_links (note_id FK, issue_id, project_name, linked_at, PK(note_id,issue_id)) — связь заметка↔задача. note_chats (id PK, note_id FK→notes, role CHECK(user|assistant), content, created_at) — история чата с заметкой. Indexes: notes(project_name,created_at DESC), note_sources(note_id), note_sources(status), note_issue_links(project_name,issue_id), note_chats(note_id,created_at).
053 transcript_jobs Phase 73.1 #377 / 2026-06-05 transcript_jobs (job_id TEXT PK, transcript_id INTEGER, status TEXT DEFAULT 'queued', progress_pct INTEGER DEFAULT 0, step_label TEXT, error TEXT, started_at TEXT DEFAULT datetime('now'), updated_at TEXT DEFAULT datetime('now')) — high-churn трекер прогресса для фонового воркера. Изолирован от transcripts, чтобы частые UPDATE (каждые несколько секунд во время ffmpeg/whisper) не дёргали индексы основной таблицы. SSE endpoint стримит эту таблицу с опросом 1s. Lifecycle статусов: queued → extracting_audio → transcribing → (video: extracting_frames → frames_extracted → vision_analyzing → vision_analyzed) → summarizing → summarized → embedding → done (или failed на любом шаге). Индекс по (status, updated_at).

Связи (Foreign Keys)

Все CASCADE — удаление скила удаляет все форки, историю, PR и бенчмарки.

ER-диаграмма (текстовая)

users ─1:N──> projects
            ├── chat_messages
            ├── pinned_notes
            ├── project_phases
            └── skills_project_forks ──> skills_global
                                          ├── skill_evolution_logs
                                          ├── skill_update_requests
                                          │    └── skill_benchmarks
                                          └── (standalone tables)
                                               ├── activity_log
                                               ├── system_configs
                                               └── marketplace_analysis_cache