From d7491705d97259f900c4701cbe8b0bdceec6fb37 Mon Sep 17 00:00:00 2001 From: johnfrum1234 Date: Sun, 15 Mar 2026 13:12:54 +0200 Subject: [PATCH] =?UTF-8?q?Add=20core/db.py=20=E2=80=94=20SQLite=20schema?= =?UTF-8?q?=20with=20all=209=20tables=20from=20DESIGN.md=203.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tables: projects, tasks, decisions, agent_logs, modules, pipelines, project_links, support_tickets, support_bot_config. WAL mode, foreign keys enabled, idempotent init. Co-Authored-By: Claude Opus 4.6 (1M context) --- core/__init__.py | 0 core/db.py | 181 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 core/__init__.py create mode 100644 core/db.py diff --git a/core/__init__.py b/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/db.py b/core/db.py new file mode 100644 index 0000000..32ae5ef --- /dev/null +++ b/core/db.py @@ -0,0 +1,181 @@ +""" +Kin — SQLite database schema and connection management. +All tables from DESIGN.md section 3.5 State Management. +""" + +import sqlite3 +from pathlib import Path + +DB_PATH = Path(__file__).parent.parent / "kin.db" + +SCHEMA = """ +-- Проекты (центральный реестр) +CREATE TABLE IF NOT EXISTS projects ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + path TEXT NOT NULL, + tech_stack JSON, + status TEXT DEFAULT 'active', + priority INTEGER DEFAULT 5, + pm_prompt TEXT, + claude_md_path TEXT, + forgejo_repo TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP +); + +-- Задачи (привязаны к проекту) +CREATE TABLE IF NOT EXISTS tasks ( + id TEXT PRIMARY KEY, + project_id TEXT NOT NULL REFERENCES projects(id), + title TEXT NOT NULL, + status TEXT DEFAULT 'pending', + priority INTEGER DEFAULT 5, + assigned_role TEXT, + parent_task_id TEXT REFERENCES tasks(id), + brief JSON, + spec JSON, + review JSON, + test_result JSON, + security_result JSON, + forgejo_issue_id INTEGER, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP +); + +-- Решения и грабли (внешняя память PM-агента) +CREATE TABLE IF NOT EXISTS decisions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + project_id TEXT NOT NULL REFERENCES projects(id), + task_id TEXT REFERENCES tasks(id), + type TEXT NOT NULL, + category TEXT, + title TEXT NOT NULL, + description TEXT NOT NULL, + tags JSON, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP +); + +-- Логи агентов (дебаг, обучение, cost tracking) +CREATE TABLE IF NOT EXISTS agent_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + project_id TEXT NOT NULL REFERENCES projects(id), + task_id TEXT REFERENCES tasks(id), + agent_role TEXT NOT NULL, + session_id TEXT, + action TEXT NOT NULL, + input_summary TEXT, + output_summary TEXT, + tokens_used INTEGER, + model TEXT, + cost_usd REAL, + success BOOLEAN, + error_message TEXT, + duration_seconds INTEGER, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP +); + +-- Модули проекта (карта для PM) +CREATE TABLE IF NOT EXISTS modules ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + project_id TEXT NOT NULL REFERENCES projects(id), + name TEXT NOT NULL, + type TEXT NOT NULL, + path TEXT NOT NULL, + description TEXT, + owner_role TEXT, + dependencies JSON, + UNIQUE(project_id, name) +); + +-- Pipelines (история запусков) +CREATE TABLE IF NOT EXISTS pipelines ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + task_id TEXT NOT NULL REFERENCES tasks(id), + project_id TEXT NOT NULL REFERENCES projects(id), + route_type TEXT NOT NULL, + steps JSON NOT NULL, + status TEXT DEFAULT 'running', + total_cost_usd REAL, + total_tokens INTEGER, + total_duration_seconds INTEGER, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + completed_at DATETIME +); + +-- Кросс-проектные зависимости +CREATE TABLE IF NOT EXISTS project_links ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + from_project TEXT NOT NULL REFERENCES projects(id), + to_project TEXT NOT NULL REFERENCES projects(id), + type TEXT NOT NULL, + description TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP +); + +-- Тикеты от пользователей +CREATE TABLE IF NOT EXISTS support_tickets ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + project_id TEXT NOT NULL REFERENCES projects(id), + source TEXT NOT NULL, + client_id TEXT, + client_message TEXT NOT NULL, + classification TEXT, + guard_result TEXT, + guard_reason TEXT, + anamnesis JSON, + task_id TEXT REFERENCES tasks(id), + response TEXT, + response_approved BOOLEAN DEFAULT FALSE, + status TEXT DEFAULT 'new', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + resolved_at DATETIME +); + +-- Настройки бота для каждого проекта +CREATE TABLE IF NOT EXISTS support_bot_config ( + project_id TEXT PRIMARY KEY REFERENCES projects(id), + telegram_bot_token TEXT, + welcome_message TEXT, + faq JSON, + auto_reply BOOLEAN DEFAULT FALSE, + require_approval BOOLEAN DEFAULT TRUE, + brand_voice TEXT, + forbidden_topics JSON, + escalation_keywords JSON +); + +-- Индексы +CREATE INDEX IF NOT EXISTS idx_tasks_project_status ON tasks(project_id, status); +CREATE INDEX IF NOT EXISTS idx_decisions_project ON decisions(project_id); +CREATE INDEX IF NOT EXISTS idx_decisions_tags ON decisions(tags); +CREATE INDEX IF NOT EXISTS idx_agent_logs_project ON agent_logs(project_id, created_at); +CREATE INDEX IF NOT EXISTS idx_agent_logs_cost ON agent_logs(project_id, cost_usd); +CREATE INDEX IF NOT EXISTS idx_tickets_project ON support_tickets(project_id, status); +CREATE INDEX IF NOT EXISTS idx_tickets_client ON support_tickets(client_id); +""" + + +def get_connection(db_path: Path = DB_PATH) -> sqlite3.Connection: + conn = sqlite3.connect(str(db_path)) + conn.execute("PRAGMA journal_mode=WAL") + conn.execute("PRAGMA foreign_keys=ON") + conn.row_factory = sqlite3.Row + return conn + + +def init_db(db_path: Path = DB_PATH) -> sqlite3.Connection: + conn = get_connection(db_path) + conn.executescript(SCHEMA) + conn.commit() + return conn + + +if __name__ == "__main__": + conn = init_db() + tables = conn.execute( + "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name" + ).fetchall() + print(f"Initialized {len(tables)} tables:") + for t in tables: + print(f" - {t['name']}") + conn.close()