Implements 26 of 28 tasks from specs/004-product-knowledge/tasks.md
across all three user stories -- Phase 3 of the roadmap. First
feature to populate src/modules/ai-support/ (doc 07 places
`knowledge` there; only that submodule is built, matching this
codebase's convention of not pre-building unneeded submodules).
Schema (prisma/schema.prisma + migration):
- KnowledgeEntry, ErrorCode, KnownIssue, Runbook per docs/06,
refining its conceptual flat `version` field into an explicit
version-history mechanism: each edit inserts a new row
(isCurrentVersion flag, compound unique on (code, version) /
(key, productId, version)) instead of overwriting in place -- the
only way "prior versions remain retrievable" (FR-004/FR-009) is
actually true rather than aspirational.
User Story 1 -- knowledge entry authoring/publish/version (P1, MVP):
- draft -> published -> unpublished lifecycle; publish only takes
effect from its effectiveDate.
- Editing uses the same conditional-update-then-insert optimistic
concurrency pattern as 003-ticketing's Ticket.version (409 on a
stale expectedVersion).
- Full version history readable via GET .../versions.
User Story 2 -- error codes, known issues, runbooks (P2):
- ErrorCode + KnownIssue with direct lookup-by-error-code.
- Runbook steps stored as an ordered JSON array, preserved exactly;
same version-on-edit mechanism as knowledge entries; inactive
runbooks are indistinguishable from nonexistent ones on lookup.
User Story 3 -- filtered retrieval (P3):
- GET /knowledge/retrieve: product-scoped, excludes draft/
unpublished/not-yet-effective entries, validated entries ranked
ahead of unvalidated. Deliberately NOT semantic/vector search --
doc 11 gap B1 explicitly defers embedding-model choice to the
future AI-support feature; this is real, usable structured
filtering a semantic layer can sit in front of later.
Found and fixed one real bug before it reached tests: the retrieval
endpoint initially queried by the raw external product id instead of
resolving it to the internal Product.id first (every other endpoint
in this feature does that resolution) -- would have silently
returned zero results for every caller. Fixed with a lenient
tryResolveProductId (empty array, not 404, for an unregistered
product -- matches the "no matches, never an error" contract).
Deliberately skipped (not forgotten, see checklist notes): the two
planned mock-repository unit-test tasks (T004, T019) -- unlike
003-ticketing's state machine, this feature has no pure-logic
surface to isolate from Prisma; coverage comes entirely from
integration tests instead.
All 13 integration test files in the repo (36 tests, spanning this
feature and every prior one) verified passing together against a
real Postgres/Redis/MinIO -- no regressions. Full quality gate
(typecheck/lint/format/architecture/unit tests) passes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
/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>
/speckit-specify output for 004-product-knowledge (roadmap Phase 3):
3 user stories (authoring/versioning/publishing knowledge entries,
structured error-code/known-issue/runbook records, filtered
retrieval), 14 functional requirements. Full semantic/vector
retrieval is explicitly deferred to the future AI-support feature
(doc 11 gap B1) -- this feature's retrieval is structured filtering,
a real usable contract rather than a placeholder. Quality checklist
passes with no NEEDS CLARIFICATION markers.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>