""" Knowledge Base Models ===================== Phase KB-1: 知識庫資料模型 兩層架構: - KnowledgeEntry: 知識條目 (incident_case / runbook / best_practice / postmortem) - Playbook: 獨立系統,透過 related_playbook_id 關聯 建立時間: 2026-04-02 (台北時區) 建立者: Claude Code (Knowledge Base Phase 1) 遵循 leWOOOgo 積木化原則: - Pydantic BaseModel 定義 - PostgreSQL Episodic Memory """ from datetime import datetime from enum import Enum from pydantic import BaseModel, Field from src.utils.timezone import now_taipei # ============================================================================= # Enums # ============================================================================= class EntryType(str, Enum): """知識條目類型""" INCIDENT_CASE = "incident_case" # AI 從 Incident 萃取的案例分析 RUNBOOK = "runbook" # 手動建立的操作手冊 BEST_PRACTICE = "best_practice" # 最佳實踐文章 POSTMORTEM = "postmortem" # 事後分析報告 # 2026-04-04 ogt: Phase 25 P1 — Knowledge Auto-Harvesting 新增類型 AUTO_RUNBOOK = "auto_runbook" # Nemotron 自動生成的 Runbook(DRAFT 待人工審核) ANTI_PATTERN = "anti_pattern" # 修復失敗案例(直接 PUBLISHED,阻斷後續重蹈覆轍) class EntrySource(str, Enum): """知識來源""" AI_EXTRACTED = "ai_extracted" # AI 自動萃取 HUMAN = "human" # 人工建立 class EntryStatus(str, Enum): """知識條目狀態""" DRAFT = "draft" # 草稿 REVIEW = "review" # 審核中 APPROVED = "approved" # 已批准 ARCHIVED = "archived" # 已封存 # 2026-04-04 Claude Code: Phase 25 P1 — ANTI_PATTERN 直接發布,無需審核 PUBLISHED = "published" # 已發布(ANTI_PATTERN 用,無需人工審核) # ============================================================================= # Pydantic Models # ============================================================================= class KnowledgeEntryCreate(BaseModel): """建立知識條目 Request""" title: str = Field(..., min_length=1, max_length=255) content: str = Field(..., min_length=1) entry_type: EntryType category: str = Field(..., min_length=1, max_length=100) tags: list[str] = Field(default_factory=list) source: EntrySource = EntrySource.HUMAN status: EntryStatus = EntryStatus.DRAFT related_incident_id: str | None = None related_playbook_id: str | None = None # P1-1 2026-04-28 ogt + Claude Sonnet 4.6: M4 補反查鏈 — approval → KM 關聯 # phase26_incident_km_integration.sql 已建立 related_approval_id 欄位與 partial index related_approval_id: str | None = None # P1-1 M3 2026-04-28 ogt + Claude Sonnet 4.6: 冪等 key(與 related_incident_id 組合) # migration: p1_1_km_idempotent_path_type.sql path_type: str | None = None # 2026-04-04 ogt: Phase 25 P1 — Anti-Pattern 閉環用症狀 hash symptoms_hash: str | None = None created_by: str | None = None class KnowledgeEntryUpdate(BaseModel): """更新知識條目 Request""" title: str | None = None content: str | None = None entry_type: EntryType | None = None category: str | None = None tags: list[str] | None = None status: EntryStatus | None = None class KnowledgeEntry(BaseModel): """知識條目完整模型""" id: str title: str content: str entry_type: EntryType category: str tags: list[str] = Field(default_factory=list) source: EntrySource status: EntryStatus = EntryStatus.DRAFT related_incident_id: str | None = None related_playbook_id: str | None = None # P1-1 2026-04-28 ogt + Claude Sonnet 4.6: M4 補反查鏈 related_approval_id: str | None = None # P1-1 M3 2026-04-28 ogt + Claude Sonnet 4.6: 冪等 key path_type: str | None = None # 2026-04-04 ogt: Phase 25 P1 — Anti-Pattern 閉環攔截用的症狀 hash(SymptomPattern.compute_hash()) symptoms_hash: str | None = None view_count: int = 0 created_by: str | None = None created_at: datetime = Field(default_factory=now_taipei) updated_at: datetime = Field(default_factory=now_taipei) model_config = {"from_attributes": True} class CategoryCount(BaseModel): """分類統計""" category: str count: int class KnowledgeListResponse(BaseModel): """列表回應""" items: list[KnowledgeEntry] total: int categories: list[CategoryCount] = Field(default_factory=list)