feat(api): Knowledge Base Phase 1 後端四層架構
Some checks failed
CD Pipeline / build-and-deploy (push) Successful in 7m0s
E2E Health Check / e2e-health (push) Successful in 17s
Type Sync Check / check-type-sync (push) Failing after 30s

- models/knowledge.py: Pydantic Schema (EntryType/Source/Status/CRUD)
- db/models.py: KnowledgeEntryRecord ORM (PostgreSQL)
- repositories/interfaces.py: IKnowledgeRepository Protocol
- repositories/knowledge_repository.py: PostgreSQL CRUD 實作
- services/knowledge_service.py: 業務邏輯 (get_db_context 內部管理 session)
- api/v1/knowledge.py: REST Router (get_knowledge_service,無直接 DB 存取)
- main.py: 掛載 Knowledge Base Router
- k8s/jobs/migrate-knowledge-entries.yaml: DB Migration Job

API 端點: GET/POST / | GET/PATCH/DELETE /{id} | POST /{id}/approve
         GET /search | GET /categories

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
OG T
2026-04-02 00:55:56 +08:00
parent 077e1cd637
commit d8be78b135
8 changed files with 837 additions and 0 deletions

View File

@@ -30,6 +30,7 @@ from sqlalchemy.orm import Mapped, mapped_column
from src.db.base import Base
from src.models.approval import ApprovalStatus, RiskLevel
from src.models.incident import IncidentStatus, Severity
from src.models.knowledge import EntrySource, EntryStatus, EntryType
# =============================================================================
# Helper Functions
@@ -454,3 +455,100 @@ class IncidentRecord(Base):
Index("ix_incident_created_at", "created_at"),
Index("ix_incident_resolved_at", "resolved_at"),
)
# =============================================================================
# KnowledgeEntry - Knowledge Base Phase 1
# =============================================================================
class KnowledgeEntryRecord(Base):
"""
知識庫條目 - Knowledge Base Phase 1
兩層架構:
- KnowledgeEntry: 知識條目 (此表)
- Playbook: 獨立 Redis透過 related_playbook_id 關聯
建立時間: 2026-04-02 (台北時區)
建立者: Claude Code (Knowledge Base Phase 1)
"""
__tablename__ = "knowledge_entries"
# Primary Key
id: Mapped[str] = mapped_column(
String(36),
primary_key=True,
default=generate_uuid,
)
# Core Fields
title: Mapped[str] = mapped_column(String(255), nullable=False)
content: Mapped[str] = mapped_column(Text, nullable=False)
entry_type: Mapped[str] = mapped_column(
SQLEnum(EntryType),
nullable=False,
comment="incident_case / runbook / best_practice / postmortem",
)
category: Mapped[str] = mapped_column(
String(100),
nullable=False,
comment="分類樹節點 (基礎設施/應用層/AI系統/安全合規)",
)
tags: Mapped[list[dict[str, Any]]] = mapped_column(
JSON,
default=list,
nullable=False,
comment="標籤列表 (JSONB)",
)
# Source & Status
source: Mapped[str] = mapped_column(
SQLEnum(EntrySource),
nullable=False,
comment="ai_extracted / human",
)
status: Mapped[str] = mapped_column(
SQLEnum(EntryStatus),
default=EntryStatus.DRAFT,
nullable=False,
comment="draft / review / approved / archived",
)
# Relations (soft references, not FK)
related_incident_id: Mapped[str | None] = mapped_column(
String(30),
nullable=True,
comment="關聯 Incident ID",
)
related_playbook_id: Mapped[str | None] = mapped_column(
String(255),
nullable=True,
comment="關聯 Playbook Redis Key",
)
# Metrics
view_count: Mapped[int] = mapped_column(
Integer,
default=0,
nullable=False,
)
# Metadata
created_by: Mapped[str | None] = mapped_column(String(100), nullable=True)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
default=utc_now,
)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
default=utc_now,
onupdate=utc_now,
)
# Indexes
__table_args__ = (
Index("ix_knowledge_entry_type", "entry_type"),
Index("ix_knowledge_category", "category"),
Index("ix_knowledge_status", "status"),
Index("ix_knowledge_created_at", "created_at"),
)