/speckit-plan output for 004-product-knowledge: technical context and constitution gate check (all PASS), Phase 0 research (6 decisions: new-row-per-version instead of in-place overwrite to satisfy history retention, conditional-update-then-insert concurrency reusing 003-ticketing's optimistic-locking pattern, structured (non-semantic) filtered retrieval per doc 11 gap B1, known-issue lookup by error code, creating the ai-support module group for the first time with only its knowledge submodule populated, and admin auth consistent with prior features), Phase 1 data model (KnowledgeEntry/ErrorCode/ KnownIssue/Runbook, refining doc 06's conceptual schema with an explicit version-history mechanism), the admin CRUD + retrieval contract, and a 6-scenario quickstart. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
3.1 KiB
Phase 1 Data Model: Product Knowledge Management & Retrieval
All new models use cuid() ids. Refines docs/06-database-schema.md's conceptual
KnowledgeEntry/Runbook shapes with an explicit version-history mechanism (research.md).
KnowledgeEntry
| Field | Type | Notes |
|---|---|---|
| id | String @id @default(cuid()) | |
| code | String | KB-<PRODUCT>-<SEQ> style, e.g. KB-DQ-102 — logical identifier shared across versions |
| version | Int @default(1) | |
| isCurrentVersion | Boolean @default(true) | Exactly one true row per code at a time (research.md) |
| productId | String | FK → Product |
| feature | String? | |
| type | String | known_issue | faq | resolution_procedure | operations |
| problem | String? | |
| symptoms | String? | |
| errorCode | String? | Free-text reference for display; structured linkage is via ErrorCode/KnownIssue separately |
| cause | String? | |
| recommendedSolution | String? | |
| verificationSteps | String? | |
| escalationGuidance | String? | |
| status | String @default("draft") | draft | published | unpublished |
| effectiveDate | DateTime? | Null = effective immediately once published |
| categoryScope | String[] | |
| validationStatus | String @default("unvalidated") | unvalidated | validated |
| owner | String? | |
| lastReview | DateTime? | |
| source | String? | |
| createdAt | DateTime @default(now()) |
Constraints: @@unique([code, version]). Index on (productId, isCurrentVersion, status, effectiveDate) — the exact shape retrieval queries on.
Retrieval eligibility rule (not a DB constraint, enforced in the repository's query):
isCurrentVersion = true AND status = 'published' AND (effectiveDate IS NULL OR effectiveDate <= now()).
ErrorCode
| Field | Type | Notes |
|---|---|---|
| id | String @id @default(cuid()) | |
| code | String | e.g. LAYOUT_PARSE_042 |
| productId | String | FK → Product |
| description | String |
Constraints: @@unique([productId, code]) — unique within a product, matching FR-006.
KnownIssue
| Field | Type | Notes |
|---|---|---|
| id | String @id @default(cuid()) | |
| productId | String | FK → Product |
| errorCodeId | String? | FK → ErrorCode |
| description | String | |
| status | String @default("open") |
Runbook
| Field | Type | Notes |
|---|---|---|
| id | String @id @default(cuid()) | |
| key | String | Logical identifier shared across versions, e.g. PDF_HTML_CONVERSION_FAILURE |
| version | Int @default(1) | |
| isCurrentVersion | Boolean @default(true) | Same version-history mechanism as KnowledgeEntry |
| productId | String | FK → Product |
| steps | Json | Ordered array — order preserved exactly as authored (FR-008) |
| active | Boolean @default(true) |
Constraints: @@unique([key, productId, version]). Lookup-by-key queries filter
isCurrentVersion = true AND active = true.
Product (relations added by this feature)
knowledgeEntries KnowledgeEntry[], errorCodes ErrorCode[], knownIssues KnownIssue[],
runbooks Runbook[] — the forward relations doc 06 already specified on Product but that
couldn't be added until these models existed.