Skip to main content
Glama
schema.sql49.2 kB
-- WorkflowMCP SQLite Database Schema -- Phase 2.5: JSON to SQLite Migration -- Created: 2025-09-05 -- Enable foreign key constraints PRAGMA foreign_keys = ON; -- ============================================= -- Core Tables -- ============================================= -- Projects (Phase 3 addition) CREATE TABLE IF NOT EXISTS projects ( id TEXT PRIMARY KEY, name TEXT NOT NULL, description TEXT, status TEXT CHECK(status IN ('planning', 'active', 'on_hold', 'completed')) DEFAULT 'planning', priority TEXT CHECK(priority IN ('High', 'Medium', 'Low')) DEFAULT 'Medium', start_date TEXT, -- ISO string end_date TEXT, -- ISO string created_at TEXT NOT NULL, updated_at TEXT, created_by TEXT DEFAULT 'system', manager TEXT, -- Project manager tags TEXT, -- JSON array as text progress INTEGER DEFAULT 0, -- 0-100% notes TEXT ); -- PRDs (Product Requirements Documents) CREATE TABLE IF NOT EXISTS prds ( id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT, requirements TEXT, -- JSON array as text priority TEXT CHECK(priority IN ('High', 'Medium', 'Low')) DEFAULT 'Medium', status TEXT CHECK(status IN ('draft', 'review', 'approved', 'archived')) DEFAULT 'draft', created_at TEXT NOT NULL, updated_at TEXT, -- Project relationship project_id TEXT REFERENCES projects(id), -- Metadata version INTEGER DEFAULT 1, created_by TEXT, tags TEXT -- JSON array as text ); -- Tasks CREATE TABLE IF NOT EXISTS tasks ( id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT, status TEXT CHECK(status IN ('pending', 'in_progress', 'done', 'blocked')) DEFAULT 'pending', priority TEXT CHECK(priority IN ('High', 'Medium', 'Low')) DEFAULT 'Medium', assignee TEXT, estimated_hours INTEGER, actual_hours INTEGER, due_date TEXT, -- ISO string created_at TEXT NOT NULL, updated_at TEXT, -- Phase 2 additions plan_id TEXT, -- Foreign key to plans prd_id TEXT, -- Foreign key to PRDs (직접 연결) -- Project relationship project_id TEXT REFERENCES projects(id), -- Metadata version INTEGER DEFAULT 1, created_by TEXT, tags TEXT, -- JSON array as text notes TEXT, FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE SET NULL ); -- Plans CREATE TABLE IF NOT EXISTS plans ( id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT, status TEXT CHECK(status IN ('active', 'completed', 'paused', 'cancelled')) DEFAULT 'active', start_date TEXT, -- ISO string end_date TEXT, -- ISO string created_at TEXT NOT NULL, updated_at TEXT, -- Phase 2 additions prd_id TEXT, -- Foreign key to prds -- Progress tracking (calculated fields) total_tasks INTEGER DEFAULT 0, completed_tasks INTEGER DEFAULT 0, in_progress_tasks INTEGER DEFAULT 0, todo_tasks INTEGER DEFAULT 0, blocked_tasks INTEGER DEFAULT 0, progress_percentage REAL DEFAULT 0.0, last_sync_at TEXT, estimated_completion_date TEXT, -- Metadata version INTEGER DEFAULT 1, created_by TEXT, tags TEXT, -- JSON array as text FOREIGN KEY (prd_id) REFERENCES prds(id) ON DELETE SET NULL ); -- Milestones (separated from plans for better normalization) CREATE TABLE IF NOT EXISTS milestones ( id TEXT PRIMARY KEY, plan_id TEXT NOT NULL, title TEXT NOT NULL, description TEXT, due_date TEXT, -- ISO string completed BOOLEAN DEFAULT FALSE, completed_at TEXT, -- ISO string created_at TEXT NOT NULL, updated_at TEXT, sort_order INTEGER DEFAULT 0, FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE ); -- ============================================= -- Relationship Tables (Many-to-Many) -- ============================================= -- Task Dependencies (self-referencing many-to-many) CREATE TABLE IF NOT EXISTS task_dependencies ( id INTEGER PRIMARY KEY AUTOINCREMENT, dependent_task_id TEXT NOT NULL, -- The task that depends on another prerequisite_task_id TEXT NOT NULL, -- The task that must be completed first created_at TEXT NOT NULL, created_by TEXT, UNIQUE(dependent_task_id, prerequisite_task_id), FOREIGN KEY (dependent_task_id) REFERENCES tasks(id) ON DELETE CASCADE, FOREIGN KEY (prerequisite_task_id) REFERENCES tasks(id) ON DELETE CASCADE, -- Prevent self-dependency CHECK (dependent_task_id != prerequisite_task_id) ); -- PRD-Plan connections (many-to-many, though typically one-to-many) CREATE TABLE IF NOT EXISTS prd_plan_links ( id INTEGER PRIMARY KEY AUTOINCREMENT, prd_id TEXT NOT NULL, plan_id TEXT NOT NULL, created_at TEXT NOT NULL, created_by TEXT, UNIQUE(prd_id, plan_id), FOREIGN KEY (prd_id) REFERENCES prds(id) ON DELETE CASCADE, FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE ); -- Plan-Task connections (many-to-many) CREATE TABLE IF NOT EXISTS plan_task_links ( id INTEGER PRIMARY KEY AUTOINCREMENT, plan_id TEXT NOT NULL, task_id TEXT NOT NULL, created_at TEXT NOT NULL, created_by TEXT, UNIQUE(plan_id, task_id), FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE, FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE ); -- PRD-Task direct connections (many-to-many) CREATE TABLE IF NOT EXISTS prd_task_links ( id INTEGER PRIMARY KEY AUTOINCREMENT, prd_id TEXT NOT NULL, task_id TEXT NOT NULL, link_type TEXT CHECK(link_type IN ('direct', 'derived', 'related')) DEFAULT 'direct', created_at TEXT NOT NULL, created_by TEXT, notes TEXT, -- Optional notes about the connection UNIQUE(prd_id, task_id), FOREIGN KEY (prd_id) REFERENCES prds(id) ON DELETE CASCADE, FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE ); -- ============================================= -- Indexes for Performance -- ============================================= -- Core entity indexes CREATE INDEX IF NOT EXISTS idx_prds_status ON prds(status); CREATE INDEX IF NOT EXISTS idx_prds_priority ON prds(priority); CREATE INDEX IF NOT EXISTS idx_prds_created_at ON prds(created_at); CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); CREATE INDEX IF NOT EXISTS idx_tasks_priority ON tasks(priority); CREATE INDEX IF NOT EXISTS idx_tasks_assignee ON tasks(assignee); CREATE INDEX IF NOT EXISTS idx_tasks_plan_id ON tasks(plan_id); CREATE INDEX IF NOT EXISTS idx_tasks_due_date ON tasks(due_date); CREATE INDEX IF NOT EXISTS idx_tasks_created_at ON tasks(created_at); CREATE INDEX IF NOT EXISTS idx_plans_status ON plans(status); CREATE INDEX IF NOT EXISTS idx_plans_prd_id ON plans(prd_id); CREATE INDEX IF NOT EXISTS idx_plans_created_at ON plans(created_at); CREATE INDEX IF NOT EXISTS idx_milestones_plan_id ON milestones(plan_id); CREATE INDEX IF NOT EXISTS idx_milestones_due_date ON milestones(due_date); -- Relationship indexes CREATE INDEX IF NOT EXISTS idx_task_deps_dependent ON task_dependencies(dependent_task_id); CREATE INDEX IF NOT EXISTS idx_task_deps_prerequisite ON task_dependencies(prerequisite_task_id); CREATE INDEX IF NOT EXISTS idx_prd_plan_prd ON prd_plan_links(prd_id); CREATE INDEX IF NOT EXISTS idx_prd_plan_plan ON prd_plan_links(plan_id); CREATE INDEX IF NOT EXISTS idx_plan_task_plan ON plan_task_links(plan_id); CREATE INDEX IF NOT EXISTS idx_plan_task_task ON plan_task_links(task_id); CREATE INDEX IF NOT EXISTS idx_prd_task_prd ON prd_task_links(prd_id); CREATE INDEX IF NOT EXISTS idx_prd_task_task ON prd_task_links(task_id); CREATE INDEX IF NOT EXISTS idx_prd_task_type ON prd_task_links(link_type); -- ============================================= -- Views for Common Queries -- ============================================= -- Tasks with their plan and PRD information CREATE VIEW IF NOT EXISTS tasks_with_context AS SELECT t.*, p.title AS plan_title, p.status AS plan_status, pr.title AS prd_title, pr.status AS prd_status FROM tasks t LEFT JOIN plans p ON t.plan_id = p.id LEFT JOIN prds pr ON p.prd_id = pr.id; -- Plans with progress summary CREATE VIEW IF NOT EXISTS plans_with_progress AS SELECT p.*, pr.title AS prd_title, pr.status AS prd_status, COUNT(t.id) AS actual_total_tasks, COUNT(CASE WHEN t.status = 'done' THEN 1 END) AS actual_completed_tasks, COUNT(CASE WHEN t.status = 'in_progress' THEN 1 END) AS actual_in_progress_tasks, COUNT(CASE WHEN t.status = 'pending' THEN 1 END) AS actual_todo_tasks, COUNT(CASE WHEN t.status = 'blocked' THEN 1 END) AS actual_blocked_tasks, CASE WHEN COUNT(t.id) > 0 THEN ROUND((COUNT(CASE WHEN t.status = 'done' THEN 1 END) * 100.0) / COUNT(t.id), 2) ELSE 0 END AS actual_progress_percentage FROM plans p LEFT JOIN prds pr ON p.prd_id = pr.id LEFT JOIN tasks t ON t.plan_id = p.id GROUP BY p.id; -- Task dependency chain view CREATE VIEW IF NOT EXISTS task_dependency_chain AS SELECT td.dependent_task_id, td.prerequisite_task_id, t1.title AS dependent_task_title, t1.status AS dependent_task_status, t2.title AS prerequisite_task_title, t2.status AS prerequisite_task_status, td.created_at FROM task_dependencies td JOIN tasks t1 ON td.dependent_task_id = t1.id JOIN tasks t2 ON td.prerequisite_task_id = t2.id; -- Dashboard summary view CREATE VIEW IF NOT EXISTS dashboard_summary AS SELECT 'overview' AS section, COUNT(DISTINCT pr.id) AS total_prds, COUNT(DISTINCT p.id) AS total_plans, COUNT(DISTINCT t.id) AS total_tasks, COUNT(DISTINCT m.id) AS total_milestones, COUNT(DISTINCT CASE WHEN pr.status = 'approved' THEN pr.id END) AS approved_prds, COUNT(DISTINCT CASE WHEN p.status = 'active' THEN p.id END) AS active_plans, COUNT(DISTINCT CASE WHEN t.status = 'done' THEN t.id END) AS completed_tasks, COUNT(DISTINCT CASE WHEN t.status = 'blocked' THEN t.id END) AS blocked_tasks, COUNT(DISTINCT CASE WHEN m.completed = 1 THEN m.id END) AS completed_milestones FROM prds pr, plans p, tasks t, milestones m; -- ============================================= -- Triggers for Data Integrity and Automation -- ============================================= -- Update plans.updated_at when tasks are modified CREATE TRIGGER IF NOT EXISTS update_plan_timestamp_on_task_change AFTER UPDATE ON tasks WHEN OLD.plan_id IS NOT NULL OR NEW.plan_id IS NOT NULL BEGIN UPDATE plans SET updated_at = datetime('now') WHERE id = COALESCE(NEW.plan_id, OLD.plan_id); END; -- Update plan progress when task status changes CREATE TRIGGER IF NOT EXISTS update_plan_progress_on_task_status_change AFTER UPDATE ON tasks WHEN OLD.status != NEW.status AND NEW.plan_id IS NOT NULL BEGIN UPDATE plans SET total_tasks = ( SELECT COUNT(*) FROM tasks WHERE plan_id = NEW.plan_id ), completed_tasks = ( SELECT COUNT(*) FROM tasks WHERE plan_id = NEW.plan_id AND status = 'done' ), in_progress_tasks = ( SELECT COUNT(*) FROM tasks WHERE plan_id = NEW.plan_id AND status = 'in_progress' ), todo_tasks = ( SELECT COUNT(*) FROM tasks WHERE plan_id = NEW.plan_id AND status = 'pending' ), blocked_tasks = ( SELECT COUNT(*) FROM tasks WHERE plan_id = NEW.plan_id AND status = 'blocked' ), progress_percentage = ( SELECT CASE WHEN COUNT(*) > 0 THEN ROUND((COUNT(CASE WHEN status = 'done' THEN 1 END) * 100.0) / COUNT(*), 2) ELSE 0 END FROM tasks WHERE plan_id = NEW.plan_id ), last_sync_at = datetime('now'), updated_at = datetime('now') WHERE id = NEW.plan_id; END; -- Prevent circular dependencies CREATE TRIGGER IF NOT EXISTS prevent_circular_dependency BEFORE INSERT ON task_dependencies BEGIN SELECT CASE WHEN EXISTS ( WITH RECURSIVE dependency_chain(task_id, level) AS ( SELECT NEW.prerequisite_task_id, 0 UNION ALL SELECT td.prerequisite_task_id, level + 1 FROM task_dependencies td JOIN dependency_chain dc ON td.dependent_task_id = dc.task_id WHERE level < 100 -- Prevent infinite recursion ) SELECT 1 FROM dependency_chain WHERE task_id = NEW.dependent_task_id ) THEN RAISE(ABORT, '순환 의존성이 감지되었습니다. 이 의존성을 추가할 수 없습니다.') END; END; -- ============================================= -- Initial Data and Configuration -- ============================================= -- Create system configuration table CREATE TABLE IF NOT EXISTS system_config ( key TEXT PRIMARY KEY, value TEXT NOT NULL, description TEXT, updated_at TEXT NOT NULL ); -- Insert initial configuration INSERT OR IGNORE INTO system_config (key, value, description, updated_at) VALUES ('schema_version', '2.5.0', 'Database schema version', datetime('now')), ('migration_from', 'json_files', 'Original data source', datetime('now')), ('created_at', datetime('now'), 'Database creation timestamp', datetime('now')), ('last_backup', '', 'Last backup timestamp', datetime('now')); -- ============================================= -- Analysis and Reporting Functions -- ============================================= -- Note: SQLite doesn't support stored procedures, but we can create views for common analyses -- Blocked tasks analysis CREATE VIEW IF NOT EXISTS blocked_tasks_analysis AS SELECT t.id, t.title, t.assignee, t.plan_id, p.title AS plan_title, GROUP_CONCAT(t2.title, '; ') AS blocking_tasks, COUNT(td.prerequisite_task_id) AS blocking_count FROM tasks t LEFT JOIN plans p ON t.plan_id = p.id LEFT JOIN task_dependencies td ON t.id = td.dependent_task_id LEFT JOIN tasks t2 ON td.prerequisite_task_id = t2.id AND t2.status != 'done' WHERE t.status = 'blocked' GROUP BY t.id; -- Project velocity analysis (tasks completed per time period) CREATE VIEW IF NOT EXISTS project_velocity AS SELECT DATE(t.updated_at) AS completion_date, COUNT(*) AS tasks_completed, AVG(t.actual_hours) AS avg_hours_per_task, SUM(t.actual_hours) AS total_hours FROM tasks t WHERE t.status = 'done' AND t.updated_at >= date('now', '-30 days') GROUP BY DATE(t.updated_at) ORDER BY completion_date DESC; -- ============================================= -- Document Management System (Phase 2.7) -- ============================================= -- Documents table for storing all project documents CREATE TABLE IF NOT EXISTS documents ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, content TEXT NOT NULL, doc_type TEXT NOT NULL CHECK(doc_type IN ('test_guide', 'test_results', 'analysis', 'report', 'checklist', 'specification', 'meeting_notes', 'decision_log')), category TEXT, -- 'phase_2.6', 'testing', 'development', etc. file_path TEXT, -- Original file path if imported from file created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, -- Project relationship project_id TEXT REFERENCES projects(id), -- Metadata version INTEGER DEFAULT 1, created_by TEXT, tags TEXT, -- JSON array: ["testing", "sveltekit", "phase_2.6"] summary TEXT, -- Brief summary for quick reference status TEXT CHECK(status IN ('draft', 'review', 'approved', 'archived')) DEFAULT 'draft' ); -- Document Relations - for linking documents to each other CREATE TABLE IF NOT EXISTS document_relations ( id INTEGER PRIMARY KEY AUTOINCREMENT, parent_doc_id INTEGER NOT NULL, child_doc_id INTEGER NOT NULL, relation_type TEXT NOT NULL CHECK(relation_type IN ('reference', 'supersedes', 'related', 'follow_up', 'implements')), notes TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (parent_doc_id) REFERENCES documents(id) ON DELETE CASCADE, FOREIGN KEY (child_doc_id) REFERENCES documents(id) ON DELETE CASCADE, -- Prevent self-references and duplicate relations UNIQUE(parent_doc_id, child_doc_id, relation_type), CHECK(parent_doc_id != child_doc_id) ); -- Document Links - for linking documents to PRDs, Tasks, Plans CREATE TABLE IF NOT EXISTS document_links ( id INTEGER PRIMARY KEY AUTOINCREMENT, document_id INTEGER NOT NULL, linked_entity_type TEXT NOT NULL CHECK(linked_entity_type IN ('prd', 'task', 'plan')), linked_entity_id TEXT NOT NULL, link_type TEXT CHECK(link_type IN ('specification', 'test_plan', 'result', 'analysis', 'notes')) DEFAULT 'notes', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE CASCADE, -- Ensure unique links UNIQUE(document_id, linked_entity_type, linked_entity_id, link_type) ); -- Document Search Index for full-text search CREATE VIRTUAL TABLE IF NOT EXISTS documents_fts USING fts5( title, content, summary, tags, content=documents, content_rowid=id ); -- Triggers to maintain FTS index CREATE TRIGGER IF NOT EXISTS documents_fts_insert AFTER INSERT ON documents BEGIN INSERT INTO documents_fts(rowid, title, content, summary, tags) VALUES (new.id, new.title, new.content, new.summary, new.tags); END; CREATE TRIGGER IF NOT EXISTS documents_fts_update AFTER UPDATE ON documents BEGIN UPDATE documents_fts SET title = new.title, content = new.content, summary = new.summary, tags = new.tags WHERE rowid = new.id; END; CREATE TRIGGER IF NOT EXISTS documents_fts_delete AFTER DELETE ON documents BEGIN DELETE FROM documents_fts WHERE rowid = old.id; END; -- Document management views CREATE VIEW IF NOT EXISTS document_overview AS SELECT d.id, d.title, d.doc_type, d.category, d.summary, d.status, d.created_at, d.updated_at, COUNT(DISTINCT dr1.child_doc_id) as related_docs_count, COUNT(DISTINCT dl.linked_entity_id) as linked_entities_count, GROUP_CONCAT(DISTINCT json_extract(d.tags, '$[*]')) as tag_list FROM documents d LEFT JOIN document_relations dr1 ON d.id = dr1.parent_doc_id LEFT JOIN document_links dl ON d.id = dl.document_id GROUP BY d.id ORDER BY d.updated_at DESC; -- ============================================= -- Test Management System (Phase 3.0) -- ============================================= -- Test Cases Table CREATE TABLE IF NOT EXISTS test_cases ( id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT, type TEXT CHECK(type IN ('unit', 'integration', 'system', 'acceptance', 'regression')) DEFAULT 'unit', status TEXT CHECK(status IN ('draft', 'ready', 'active', 'deprecated')) DEFAULT 'draft', priority TEXT CHECK(priority IN ('High', 'Medium', 'Low')) DEFAULT 'Medium', -- Connection relationships task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL, design_id TEXT REFERENCES designs(id) ON DELETE SET NULL, prd_id TEXT REFERENCES prds(id) ON DELETE SET NULL, -- Project relationship project_id TEXT REFERENCES projects(id), -- Test details preconditions TEXT, test_steps TEXT, -- JSON array of steps expected_result TEXT, test_data TEXT, -- JSON object for test data -- Metadata created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')), created_by TEXT DEFAULT 'system', version INTEGER DEFAULT 1, tags TEXT, -- JSON array -- Execution info estimated_duration INTEGER DEFAULT 0, -- minutes complexity TEXT CHECK(complexity IN ('Low', 'Medium', 'High')) DEFAULT 'Medium', automation_status TEXT CHECK(automation_status IN ('manual', 'automated', 'semi_automated')) DEFAULT 'manual' ); -- Test Executions Table CREATE TABLE IF NOT EXISTS test_executions ( id TEXT PRIMARY KEY, test_case_id TEXT NOT NULL REFERENCES test_cases(id) ON DELETE CASCADE, -- Execution info execution_date TEXT DEFAULT (datetime('now')), executed_by TEXT DEFAULT 'system', environment TEXT DEFAULT 'development', -- development, staging, production -- Result info status TEXT CHECK(status IN ('pass', 'fail', 'blocked', 'skipped', 'pending')) NOT NULL, actual_result TEXT, notes TEXT, defects_found TEXT, -- JSON array of defect IDs -- Time tracking actual_duration INTEGER, -- minutes started_at TEXT, completed_at TEXT, -- Attachments (screenshots, logs, etc.) attachments TEXT, -- JSON array created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')) ); -- Test Defects/Issues Table CREATE TABLE IF NOT EXISTS test_defects ( id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT, severity TEXT CHECK(severity IN ('Critical', 'High', 'Medium', 'Low')) DEFAULT 'Medium', status TEXT CHECK(status IN ('open', 'in_progress', 'resolved', 'closed', 'deferred')) DEFAULT 'open', -- Connection relationships test_case_id TEXT REFERENCES test_cases(id) ON DELETE SET NULL, test_execution_id TEXT REFERENCES test_executions(id) ON DELETE SET NULL, related_task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL, -- Task for fixing this defect -- Metadata created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')), created_by TEXT DEFAULT 'system', assigned_to TEXT, resolved_at TEXT, -- Additional info steps_to_reproduce TEXT, expected_behavior TEXT, actual_behavior TEXT, workaround TEXT, tags TEXT -- JSON array ); -- Test Case Dependencies (similar to task dependencies) CREATE TABLE IF NOT EXISTS test_case_dependencies ( id TEXT PRIMARY KEY, test_case_id TEXT NOT NULL REFERENCES test_cases(id) ON DELETE CASCADE, depends_on_test_case_id TEXT NOT NULL REFERENCES test_cases(id) ON DELETE CASCADE, dependency_type TEXT CHECK(dependency_type IN ('prerequisite', 'blocks', 'related')) DEFAULT 'prerequisite', created_at TEXT DEFAULT (datetime('now')), -- Prevent self-dependency CHECK (test_case_id != depends_on_test_case_id), UNIQUE(test_case_id, depends_on_test_case_id) ); -- Test Suites (groups of test cases) CREATE TABLE IF NOT EXISTS test_suites ( id TEXT PRIMARY KEY, name TEXT NOT NULL, description TEXT, type TEXT CHECK(type IN ('smoke', 'regression', 'integration', 'acceptance')) DEFAULT 'regression', created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')), created_by TEXT DEFAULT 'system' ); -- Test Suite-Case relationships CREATE TABLE IF NOT EXISTS test_suite_cases ( id TEXT PRIMARY KEY, test_suite_id TEXT NOT NULL REFERENCES test_suites(id) ON DELETE CASCADE, test_case_id TEXT NOT NULL REFERENCES test_cases(id) ON DELETE CASCADE, execution_order INTEGER DEFAULT 0, created_at TEXT DEFAULT (datetime('now')), UNIQUE(test_suite_id, test_case_id) ); -- ============================================= -- Test Management Indexes -- ============================================= -- Test cases indexes CREATE INDEX IF NOT EXISTS idx_test_cases_status ON test_cases(status); CREATE INDEX IF NOT EXISTS idx_test_cases_type ON test_cases(type); CREATE INDEX IF NOT EXISTS idx_test_cases_priority ON test_cases(priority); CREATE INDEX IF NOT EXISTS idx_test_cases_task_id ON test_cases(task_id); CREATE INDEX IF NOT EXISTS idx_test_cases_design_id ON test_cases(design_id); CREATE INDEX IF NOT EXISTS idx_test_cases_prd_id ON test_cases(prd_id); CREATE INDEX IF NOT EXISTS idx_test_cases_created_at ON test_cases(created_at); -- Test executions indexes CREATE INDEX IF NOT EXISTS idx_test_executions_test_case_id ON test_executions(test_case_id); CREATE INDEX IF NOT EXISTS idx_test_executions_status ON test_executions(status); CREATE INDEX IF NOT EXISTS idx_test_executions_execution_date ON test_executions(execution_date); CREATE INDEX IF NOT EXISTS idx_test_executions_environment ON test_executions(environment); -- Test defects indexes CREATE INDEX IF NOT EXISTS idx_test_defects_status ON test_defects(status); CREATE INDEX IF NOT EXISTS idx_test_defects_severity ON test_defects(severity); CREATE INDEX IF NOT EXISTS idx_test_defects_test_case_id ON test_defects(test_case_id); CREATE INDEX IF NOT EXISTS idx_test_defects_assigned_to ON test_defects(assigned_to); -- ============================================= -- Test Management Views -- ============================================= -- Test cases with execution summary CREATE VIEW IF NOT EXISTS test_cases_with_stats AS SELECT tc.*, COUNT(te.id) AS total_executions, COUNT(CASE WHEN te.status = 'pass' THEN 1 END) AS passed_executions, COUNT(CASE WHEN te.status = 'fail' THEN 1 END) AS failed_executions, COUNT(CASE WHEN te.status = 'blocked' THEN 1 END) AS blocked_executions, MAX(te.execution_date) AS last_execution_date, (SELECT status FROM test_executions WHERE test_case_id = tc.id ORDER BY execution_date DESC LIMIT 1) AS last_execution_status, CASE WHEN COUNT(te.id) > 0 THEN ROUND((COUNT(CASE WHEN te.status = 'pass' THEN 1 END) * 100.0) / COUNT(te.id), 2) ELSE 0 END AS pass_rate_percentage FROM test_cases tc LEFT JOIN test_executions te ON tc.id = te.test_case_id GROUP BY tc.id; -- Test execution summary by date CREATE VIEW IF NOT EXISTS test_execution_summary AS SELECT DATE(execution_date) AS execution_date, environment, COUNT(*) AS total_executions, COUNT(CASE WHEN status = 'pass' THEN 1 END) AS passed, COUNT(CASE WHEN status = 'fail' THEN 1 END) AS failed, COUNT(CASE WHEN status = 'blocked' THEN 1 END) AS blocked, COUNT(CASE WHEN status = 'skipped' THEN 1 END) AS skipped, ROUND((COUNT(CASE WHEN status = 'pass' THEN 1 END) * 100.0) / COUNT(*), 2) AS pass_rate FROM test_executions GROUP BY DATE(execution_date), environment ORDER BY execution_date DESC; -- Test coverage by task CREATE VIEW IF NOT EXISTS test_coverage_by_task AS SELECT t.id AS task_id, t.title AS task_title, t.status AS task_status, COUNT(tc.id) AS test_cases_count, COUNT(CASE WHEN tc.status = 'active' THEN 1 END) AS active_test_cases, COUNT(DISTINCT te.id) AS total_executions, COUNT(CASE WHEN te.status = 'pass' THEN 1 END) AS passed_executions, CASE WHEN COUNT(tc.id) > 0 THEN ROUND((COUNT(CASE WHEN tc.status = 'active' THEN 1 END) * 100.0) / COUNT(tc.id), 2) ELSE 0 END AS test_readiness_percentage FROM tasks t LEFT JOIN test_cases tc ON t.id = tc.task_id LEFT JOIN test_executions te ON tc.id = te.test_case_id GROUP BY t.id ORDER BY test_readiness_percentage DESC; -- Active defects summary CREATE VIEW IF NOT EXISTS active_defects_summary AS SELECT td.*, tc.title AS test_case_title, tc.type AS test_case_type, t.title AS related_task_title, t.assignee AS task_assignee FROM test_defects td LEFT JOIN test_cases tc ON td.test_case_id = tc.id LEFT JOIN tasks t ON td.related_task_id = t.id WHERE td.status IN ('open', 'in_progress') ORDER BY CASE td.severity WHEN 'Critical' THEN 1 WHEN 'High' THEN 2 WHEN 'Medium' THEN 3 WHEN 'Low' THEN 4 END, td.created_at DESC; -- ============================================= -- Test Management Triggers -- ============================================= -- Update test case timestamp when executions are added CREATE TRIGGER IF NOT EXISTS update_test_case_on_execution AFTER INSERT ON test_executions BEGIN UPDATE test_cases SET updated_at = datetime('now') WHERE id = NEW.test_case_id; END; -- Automatically resolve defects when related task is completed CREATE TRIGGER IF NOT EXISTS auto_resolve_defects_on_task_completion AFTER UPDATE ON tasks WHEN OLD.status != 'done' AND NEW.status = 'done' BEGIN UPDATE test_defects SET status = 'resolved', resolved_at = datetime('now'), updated_at = datetime('now') WHERE related_task_id = NEW.id AND status IN ('open', 'in_progress'); END; -- ============================================= -- Phase 2.9: Deployment & Operations Management -- ============================================= -- Deployments (배포 관리) CREATE TABLE IF NOT EXISTS deployments ( id TEXT PRIMARY KEY, name TEXT NOT NULL, description TEXT, status TEXT CHECK(status IN ('planned', 'in_progress', 'completed', 'failed', 'rolled_back')) DEFAULT 'planned', environment TEXT NOT NULL, -- dev, staging, prod version TEXT, -- 관련 엔티티 연결 project_id TEXT REFERENCES projects(id), task_id TEXT REFERENCES tasks(id), -- 배포 정보 deploy_strategy TEXT, -- blue_green, canary, rolling rollback_plan TEXT, approval_status TEXT CHECK(approval_status IN ('pending', 'approved', 'rejected')) DEFAULT 'pending', approved_by TEXT, approved_at TEXT, -- 실행 정보 started_at TEXT, completed_at TEXT, deployed_by TEXT, -- 메타데이터 created_at TEXT NOT NULL, updated_at TEXT, created_by TEXT DEFAULT 'system', notes TEXT, tags TEXT -- JSON array as text ); -- Incidents (장애 관리) CREATE TABLE IF NOT EXISTS incidents ( id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT, severity TEXT CHECK(severity IN ('critical', 'high', 'medium', 'low')) DEFAULT 'medium', status TEXT CHECK(status IN ('open', 'investigating', 'resolved', 'closed')) DEFAULT 'open', -- 영향 범위 affected_systems TEXT, -- JSON array environment TEXT NOT NULL, -- 담당자 정보 assigned_to TEXT, reporter TEXT, -- 시간 추적 detected_at TEXT, resolved_at TEXT, closed_at TEXT, -- 해결 정보 resolution TEXT, root_cause TEXT, prevention_actions TEXT, -- JSON array -- 메타데이터 created_at TEXT NOT NULL, updated_at TEXT, tags TEXT -- JSON array as text ); -- Performance Metrics (성능 메트릭) CREATE TABLE IF NOT EXISTS performance_metrics ( id TEXT PRIMARY KEY, metric_name TEXT NOT NULL, metric_value REAL NOT NULL, metric_unit TEXT, environment TEXT NOT NULL, system_component TEXT, -- 시간 정보 timestamp TEXT NOT NULL, collected_at TEXT, -- 메타데이터 created_at TEXT NOT NULL, metadata TEXT -- JSON object as text ); -- Alert Rules (알림 규칙) CREATE TABLE IF NOT EXISTS alert_rules ( id TEXT PRIMARY KEY, name TEXT NOT NULL, description TEXT, condition_expression TEXT NOT NULL, -- 예: "cpu_usage > 80" severity TEXT CHECK(severity IN ('critical', 'warning', 'info')) DEFAULT 'warning', -- 대상 정보 environment TEXT NOT NULL, system_component TEXT, -- 알림 설정 notification_channels TEXT, -- JSON array (email, slack, etc.) is_active BOOLEAN DEFAULT 1, -- 메타데이터 created_at TEXT NOT NULL, updated_at TEXT, created_by TEXT DEFAULT 'system' ); -- Maintenance Schedules (유지보수 계획) CREATE TABLE IF NOT EXISTS maintenance_schedules ( id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT, maintenance_type TEXT CHECK(maintenance_type IN ('planned', 'emergency', 'routine')) DEFAULT 'planned', status TEXT CHECK(status IN ('scheduled', 'in_progress', 'completed', 'cancelled')) DEFAULT 'scheduled', -- 시간 정보 scheduled_start TEXT, scheduled_end TEXT, actual_start TEXT, actual_end TEXT, -- 영향 범위 affected_systems TEXT, -- JSON array environment TEXT NOT NULL, -- 담당자 정보 responsible_team TEXT, contact_person TEXT, -- 메타데이터 created_at TEXT NOT NULL, updated_at TEXT, created_by TEXT DEFAULT 'system', notes TEXT ); -- Environments (환경 관리) CREATE TABLE IF NOT EXISTS environments ( id TEXT PRIMARY KEY, name TEXT NOT NULL UNIQUE, -- dev, staging, prod display_name TEXT NOT NULL, description TEXT, status TEXT CHECK(status IN ('active', 'maintenance', 'inactive')) DEFAULT 'active', -- 환경 정보 environment_type TEXT CHECK(environment_type IN ('development', 'staging', 'production')) NOT NULL, url TEXT, -- 환경 접속 URL -- 리소스 정보 resource_config TEXT, -- JSON object (CPU, Memory, Storage, etc.) -- 설정 정보 config_variables TEXT, -- JSON object (환경변수 등) secrets_count INTEGER DEFAULT 0, -- 보안상 실제 값은 외부 저장 -- 메타데이터 created_at TEXT NOT NULL, updated_at TEXT, created_by TEXT DEFAULT 'system', manager TEXT, -- 환경 관리자 tags TEXT -- JSON array as text ); -- Environment Configs (환경별 설정 변수) CREATE TABLE IF NOT EXISTS environment_configs ( id TEXT PRIMARY KEY, environment_id TEXT NOT NULL REFERENCES environments(id) ON DELETE CASCADE, config_key TEXT NOT NULL, config_value TEXT, config_type TEXT CHECK(config_type IN ('string', 'number', 'boolean', 'json')) DEFAULT 'string', is_secret BOOLEAN DEFAULT 0, -- secret인 경우 value는 null -- 메타데이터 created_at TEXT NOT NULL, updated_at TEXT, created_by TEXT DEFAULT 'system', description TEXT, UNIQUE(environment_id, config_key) ); -- System Health (시스템 상태 추적) CREATE TABLE IF NOT EXISTS system_health ( id TEXT PRIMARY KEY, environment TEXT NOT NULL, component TEXT NOT NULL, -- api, database, cache, etc. status TEXT CHECK(status IN ('healthy', 'warning', 'critical', 'unknown')) DEFAULT 'unknown', -- 상태 정보 response_time REAL, -- milliseconds uptime_percentage REAL, -- 0-100 error_rate REAL, -- 0-100 -- 메타데이터 checked_at TEXT NOT NULL, created_at TEXT NOT NULL, metadata TEXT -- JSON object as text ); -- ============================================= -- Phase 2.9: Indexes for Performance -- ============================================= -- Deployment indexes CREATE INDEX IF NOT EXISTS idx_deployments_environment ON deployments(environment); CREATE INDEX IF NOT EXISTS idx_deployments_status ON deployments(status); CREATE INDEX IF NOT EXISTS idx_deployments_project_id ON deployments(project_id); CREATE INDEX IF NOT EXISTS idx_deployments_created_at ON deployments(created_at); -- Incident indexes CREATE INDEX IF NOT EXISTS idx_incidents_severity ON incidents(severity); CREATE INDEX IF NOT EXISTS idx_incidents_status ON incidents(status); CREATE INDEX IF NOT EXISTS idx_incidents_environment ON incidents(environment); CREATE INDEX IF NOT EXISTS idx_incidents_detected_at ON incidents(detected_at); -- Performance metrics indexes CREATE INDEX IF NOT EXISTS idx_performance_metrics_name ON performance_metrics(metric_name); CREATE INDEX IF NOT EXISTS idx_performance_metrics_environment ON performance_metrics(environment); CREATE INDEX IF NOT EXISTS idx_performance_metrics_timestamp ON performance_metrics(timestamp); -- Environment indexes CREATE INDEX IF NOT EXISTS idx_environments_type ON environments(environment_type); CREATE INDEX IF NOT EXISTS idx_environments_status ON environments(status); -- System health indexes CREATE INDEX IF NOT EXISTS idx_system_health_environment ON system_health(environment); CREATE INDEX IF NOT EXISTS idx_system_health_component ON system_health(component); CREATE INDEX IF NOT EXISTS idx_system_health_checked_at ON system_health(checked_at); -- ============================================= -- Phase 2.9: Views for Dashboard -- ============================================= -- Deployment status summary CREATE VIEW IF NOT EXISTS deployment_status_summary AS SELECT environment, COUNT(*) as total_deployments, COUNT(CASE WHEN status = 'completed' THEN 1 END) as completed, COUNT(CASE WHEN status = 'failed' THEN 1 END) as failed, COUNT(CASE WHEN status = 'in_progress' THEN 1 END) as in_progress, COUNT(CASE WHEN status = 'rolled_back' THEN 1 END) as rolled_back, MAX(completed_at) as last_deployment FROM deployments GROUP BY environment; -- Active incidents by environment CREATE VIEW IF NOT EXISTS active_incidents_summary AS SELECT environment, COUNT(*) as total_incidents, COUNT(CASE WHEN severity = 'critical' THEN 1 END) as critical, COUNT(CASE WHEN severity = 'high' THEN 1 END) as high, COUNT(CASE WHEN severity = 'medium' THEN 1 END) as medium, COUNT(CASE WHEN severity = 'low' THEN 1 END) as low, MIN(detected_at) as oldest_incident FROM incidents WHERE status IN ('open', 'investigating') GROUP BY environment; -- System health overview CREATE VIEW IF NOT EXISTS system_health_overview AS SELECT environment, component, status, response_time, uptime_percentage, error_rate, checked_at, CASE WHEN checked_at < datetime('now', '-5 minutes') THEN 'stale' ELSE 'current' END as data_freshness FROM system_health sh1 WHERE checked_at = ( SELECT MAX(checked_at) FROM system_health sh2 WHERE sh2.environment = sh1.environment AND sh2.component = sh1.component ) ORDER BY environment, component; -- Environment resource summary CREATE VIEW IF NOT EXISTS environment_summary AS SELECT e.*, COUNT(ec.id) as config_count, COUNT(d.id) as deployment_count, COUNT(CASE WHEN d.status = 'completed' THEN 1 END) as successful_deployments, COUNT(i.id) as incident_count, COUNT(CASE WHEN i.status IN ('open', 'investigating') THEN 1 END) as active_incidents FROM environments e LEFT JOIN environment_configs ec ON e.id = ec.environment_id LEFT JOIN deployments d ON e.name = d.environment LEFT JOIN incidents i ON e.name = i.environment GROUP BY e.id; -- ============================================= -- Phase 2.9: Triggers -- ============================================= -- Update deployment timestamp CREATE TRIGGER IF NOT EXISTS update_deployment_timestamp AFTER UPDATE ON deployments FOR EACH ROW BEGIN UPDATE deployments SET updated_at = datetime('now') WHERE id = NEW.id; END; -- Update incident timestamp CREATE TRIGGER IF NOT EXISTS update_incident_timestamp AFTER UPDATE ON incidents FOR EACH ROW BEGIN UPDATE incidents SET updated_at = datetime('now') WHERE id = NEW.id; END; -- Auto-close resolved incidents after 24 hours CREATE TRIGGER IF NOT EXISTS auto_close_resolved_incidents AFTER UPDATE ON incidents WHEN OLD.status != 'resolved' AND NEW.status = 'resolved' BEGIN -- This would typically be handled by a background job -- For now, we just update the resolved_at timestamp UPDATE incidents SET resolved_at = datetime('now') WHERE id = NEW.id AND resolved_at IS NULL; END; -- Update environment timestamp CREATE TRIGGER IF NOT EXISTS update_environment_timestamp AFTER UPDATE ON environments FOR EACH ROW BEGIN UPDATE environments SET updated_at = datetime('now') WHERE id = NEW.id; END; -- Update environment config timestamp CREATE TRIGGER IF NOT EXISTS update_environment_config_timestamp AFTER UPDATE ON environment_configs FOR EACH ROW BEGIN UPDATE environment_configs SET updated_at = datetime('now') WHERE id = NEW.id; UPDATE environments SET updated_at = datetime('now') WHERE id = NEW.environment_id; END; -- ============================================= -- Phase 3.5: Advanced Development Tools -- ============================================= -- Executable Specs Table (SDD - Spec-Driven Development) CREATE TABLE IF NOT EXISTS executable_specs ( id INTEGER PRIMARY KEY AUTOINCREMENT, spec_type TEXT NOT NULL CHECK(spec_type IN ('constitution', 'feature_spec', 'implementation_plan', 'task_breakdown', 'implementation_report')), title TEXT NOT NULL, constitution TEXT, specification TEXT, implementation_plan TEXT, task_breakdown TEXT, implementation_report TEXT, project_id TEXT REFERENCES projects(id), parent_spec_id INTEGER REFERENCES executable_specs(id), constitution_id INTEGER REFERENCES executable_specs(id), specification_id INTEGER REFERENCES executable_specs(id), plan_id INTEGER REFERENCES executable_specs(id), created_by TEXT, status TEXT CHECK(status IN ('active', 'archived', 'draft')) DEFAULT 'active', completeness_score REAL DEFAULT 0.0, quality_score REAL DEFAULT 0.0, validated_by TEXT, approval_status TEXT CHECK(approval_status IN ('pending', 'approved', 'rejected')) DEFAULT 'pending', created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')) ); -- Knowledge Base Table CREATE TABLE IF NOT EXISTS knowledge_base ( id INTEGER PRIMARY KEY AUTOINCREMENT, knowledge_type TEXT NOT NULL CHECK(knowledge_type IN ('pattern', 'best_practice', 'guideline', 'reference', 'troubleshooting', 'architecture')), title TEXT NOT NULL, description TEXT, content TEXT NOT NULL, domain TEXT, -- e.g., 'frontend', 'backend', 'database', 'devops' subdomain TEXT, -- e.g., 'react', 'node.js', 'postgresql', 'docker' technology_stack TEXT, -- JSON array as text complexity_level TEXT CHECK(complexity_level IN ('beginner', 'intermediate', 'advanced', 'expert')) DEFAULT 'intermediate', auto_apply BOOLEAN DEFAULT 0, trigger_conditions TEXT, -- JSON array as text usage_contexts TEXT, -- JSON array as text confidence_level REAL DEFAULT 0.5, validation_status TEXT CHECK(validation_status IN ('unvalidated', 'validated', 'deprecated')) DEFAULT 'unvalidated', source_type TEXT CHECK(source_type IN ('internal', 'external', 'generated', 'imported')) DEFAULT 'internal', source_url TEXT, related_knowledge_ids TEXT, -- JSON array as text prerequisite_knowledge_ids TEXT, -- JSON array as text created_by TEXT, usage_count INTEGER DEFAULT 0, last_used_at TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')) ); -- Code Templates Table CREATE TABLE IF NOT EXISTS code_templates ( id INTEGER PRIMARY KEY AUTOINCREMENT, template_type TEXT NOT NULL CHECK(template_type IN ('component', 'function', 'class', 'snippet', 'boilerplate', 'pattern')), title TEXT NOT NULL, description TEXT, code_content TEXT NOT NULL, language TEXT NOT NULL, -- e.g., 'javascript', 'python', 'sql', 'html', 'css' framework TEXT, -- e.g., 'react', 'vue', 'express', 'django' version_compatibility TEXT, -- JSON object as text parameters TEXT, -- JSON array as text parameter_schema TEXT, -- JSON object as text (validation schema) usage_instructions TEXT, category TEXT, -- e.g., 'ui_components', 'api_endpoints', 'database_queries' subcategory TEXT, -- e.g., 'forms', 'navigation', 'authentication' complexity_level TEXT CHECK(complexity_level IN ('beginner', 'intermediate', 'advanced', 'expert')) DEFAULT 'intermediate', dependencies TEXT, -- JSON array as text environment_requirements TEXT, -- JSON object as text quality_score REAL DEFAULT 0.0, test_coverage REAL DEFAULT 0.0, security_validated BOOLEAN DEFAULT 0, performance_validated BOOLEAN DEFAULT 0, related_template_ids TEXT, -- JSON array as text parent_template_id INTEGER REFERENCES code_templates(id), tags TEXT, -- JSON array as text keywords TEXT, -- JSON array as text created_by TEXT, usage_count INTEGER DEFAULT 0, last_used_at TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')) ); -- Full-Text Search Indexes for Advanced Tools CREATE VIRTUAL TABLE IF NOT EXISTS executable_specs_fts USING fts5( title, constitution, specification, implementation_plan, task_breakdown, implementation_report, content='executable_specs', content_rowid='id' ); CREATE VIRTUAL TABLE IF NOT EXISTS knowledge_base_fts USING fts5( title, description, content, domain, subdomain, content='knowledge_base', content_rowid='id' ); CREATE VIRTUAL TABLE IF NOT EXISTS code_templates_fts USING fts5( title, description, code_content, usage_instructions, category, subcategory, language, framework, content='code_templates', content_rowid='id' ); -- FTS Triggers for Advanced Tools CREATE TRIGGER IF NOT EXISTS executable_specs_fts_insert AFTER INSERT ON executable_specs BEGIN INSERT INTO executable_specs_fts(rowid, title, constitution, specification, implementation_plan, task_breakdown, implementation_report) VALUES (new.id, new.title, new.constitution, new.specification, new.implementation_plan, new.task_breakdown, new.implementation_report); END; CREATE TRIGGER IF NOT EXISTS executable_specs_fts_delete AFTER DELETE ON executable_specs BEGIN DELETE FROM executable_specs_fts WHERE rowid = old.id; END; CREATE TRIGGER IF NOT EXISTS executable_specs_fts_update AFTER UPDATE ON executable_specs BEGIN DELETE FROM executable_specs_fts WHERE rowid = old.id; INSERT INTO executable_specs_fts(rowid, title, constitution, specification, implementation_plan, task_breakdown, implementation_report) VALUES (new.id, new.title, new.constitution, new.specification, new.implementation_plan, new.task_breakdown, new.implementation_report); END; CREATE TRIGGER IF NOT EXISTS knowledge_base_fts_insert AFTER INSERT ON knowledge_base BEGIN INSERT INTO knowledge_base_fts(rowid, title, description, content, domain, subdomain) VALUES (new.id, new.title, new.description, new.content, new.domain, new.subdomain); END; CREATE TRIGGER IF NOT EXISTS knowledge_base_fts_delete AFTER DELETE ON knowledge_base BEGIN DELETE FROM knowledge_base_fts WHERE rowid = old.id; END; CREATE TRIGGER IF NOT EXISTS knowledge_base_fts_update AFTER UPDATE ON knowledge_base BEGIN DELETE FROM knowledge_base_fts WHERE rowid = old.id; INSERT INTO knowledge_base_fts(rowid, title, description, content, domain, subdomain) VALUES (new.id, new.title, new.description, new.content, new.domain, new.subdomain); END; CREATE TRIGGER IF NOT EXISTS code_templates_fts_insert AFTER INSERT ON code_templates BEGIN INSERT INTO code_templates_fts(rowid, title, description, code_content, usage_instructions, category, subcategory, language, framework) VALUES (new.id, new.title, new.description, new.code_content, new.usage_instructions, new.category, new.subcategory, new.language, new.framework); END; CREATE TRIGGER IF NOT EXISTS code_templates_fts_delete AFTER DELETE ON code_templates BEGIN DELETE FROM code_templates_fts WHERE rowid = old.id; END; CREATE TRIGGER IF NOT EXISTS code_templates_fts_update AFTER UPDATE ON code_templates BEGIN DELETE FROM code_templates_fts WHERE rowid = old.id; INSERT INTO code_templates_fts(rowid, title, description, code_content, usage_instructions, category, subcategory, language, framework) VALUES (new.id, new.title, new.description, new.code_content, new.usage_instructions, new.category, new.subcategory, new.language, new.framework); END; -- Update Triggers for timestamp management CREATE TRIGGER IF NOT EXISTS executable_specs_update_timestamp AFTER UPDATE ON executable_specs BEGIN UPDATE executable_specs SET updated_at = datetime('now') WHERE id = NEW.id; END; CREATE TRIGGER IF NOT EXISTS knowledge_base_update_timestamp AFTER UPDATE ON knowledge_base BEGIN UPDATE knowledge_base SET updated_at = datetime('now') WHERE id = NEW.id; END; CREATE TRIGGER IF NOT EXISTS code_templates_update_timestamp AFTER UPDATE ON code_templates BEGIN UPDATE code_templates SET updated_at = datetime('now') WHERE id = NEW.id; END; -- Indexes for Advanced Tools CREATE INDEX IF NOT EXISTS idx_executable_specs_type ON executable_specs(spec_type); CREATE INDEX IF NOT EXISTS idx_executable_specs_status ON executable_specs(status); CREATE INDEX IF NOT EXISTS idx_executable_specs_project_id ON executable_specs(project_id); CREATE INDEX IF NOT EXISTS idx_executable_specs_created_at ON executable_specs(created_at); CREATE INDEX IF NOT EXISTS idx_knowledge_base_type ON knowledge_base(knowledge_type); CREATE INDEX IF NOT EXISTS idx_knowledge_base_domain ON knowledge_base(domain); CREATE INDEX IF NOT EXISTS idx_knowledge_base_subdomain ON knowledge_base(subdomain); CREATE INDEX IF NOT EXISTS idx_knowledge_base_validation_status ON knowledge_base(validation_status); CREATE INDEX IF NOT EXISTS idx_code_templates_type ON code_templates(template_type); CREATE INDEX IF NOT EXISTS idx_code_templates_language ON code_templates(language); CREATE INDEX IF NOT EXISTS idx_code_templates_framework ON code_templates(framework); CREATE INDEX IF NOT EXISTS idx_code_templates_category ON code_templates(category);

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/foswmine/workflow-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server