Files
support_backend/specs/004-product-knowledge/tasks.md
T
saqib mirandClaude Sonnet 5 e33d86081f feat: implement product knowledge management & retrieval (004)
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>
2026-09-02 15:55:18 +05:30

11 KiB

description
description
Task list for 004-product-knowledge

Tasks: Product Knowledge Management & Retrieval

Input: Design documents from specs/004-product-knowledge/

Prerequisites: plan.md, spec.md, research.md, data-model.md, contracts/knowledge-contract.md, quickstart.md

Tests: Included as first-class tasks (versioning and retrieval filtering are exactly the kind of "MUST" requirements regressions silently break), same approach as 002/003.

Organization: Tasks are grouped by user story (US1 = P1 knowledge entry authoring/publish/ version, US2 = P2 error codes/known issues/runbooks, US3 = P3 retrieval).

Format: [ID] [P?] [Story] Description

All file paths are relative to supporthub-api/ (repo root).


Phase 1: Setup

  • T001 Scaffold src/modules/ai-support/knowledge/ with the standard module shape (controller/, routes/, schema/, repository/, service/, types/, mapper/, constants/, index.ts), matching every other module's conventions (research.md "Module placement")

Phase 2: Foundational (Blocking Prerequisites)

Purpose: Schema for all four entities, shared by every user story.

⚠️ CRITICAL: No user-story stage work can begin until this phase is complete.

  • T002 Add KnowledgeEntry, ErrorCode, KnownIssue, Runbook models to prisma/schema.prisma per data-model.md (including isCurrentVersion and the (code, version) / (key, productId, version) compound unique constraints — NOT a bare unique on code/key), plus the four new back-relations on Product
  • T003 Run npm run prisma:generate and create the migration (npm run prisma:migrate) for T002 (depends on T002)

Checkpoint: Schema migrated. User stories can now be built.


Phase 3: User Story 1 - An admin authors, versions, and publishes knowledge entries (Priority: P1) 🎯 MVP

Goal: Full knowledge-entry lifecycle — create (draft) → publish → edit (new version) → validate → unpublish, with prior versions always retrievable.

Independent Test: Quickstart Scenarios 1, 2, 3.

Tests for User Story 1

  • [~] T004 [P] [US1] Unit tests for the version-on-edit logic — deliberately skipped, not forgotten: unlike 003-ticketing's state machine, there's no pure-logic surface here to isolate from Prisma (the concurrency behavior lives entirely inside the repository's own transaction) — see checklist Notes. Covered instead by T005's integration test, which exercises the real conflict path against a live database.
  • T005 [US1] Integration test covering Quickstart Scenarios 1, 2, 3 (draft invisible → publish makes retrievable, edit preserves history, stale-version edit rejected) against a real Postgres in tests/integration/knowledge-entries.test.ts

Implementation for User Story 1

  • T006 [US1] Add KnowledgeRepository (create; findCurrentByCode; findAllVersionsByCode (newest first); publish/unpublish/setValidationStatus (update the current-version row in place — these are metadata changes, not content edits, so they don't create a new version); createNewVersion implementing research.md's conditional-update-then-insert) in src/modules/ai-support/knowledge/repository/knowledge.repository.ts (depends on T003)
  • T007 [US1] Add KnowledgeService wrapping the repository with the FR-002/FR-004 rules (new entries default to status: draft, version: 1; edits always go through createNewVersion, never a raw update) in src/modules/ai-support/knowledge/service/knowledge.service.ts (depends on T006)
  • T008 [US1] Add Zod schemas for create/publish/unpublish/validate/edit request bodies in src/modules/ai-support/knowledge/schema/knowledge.schema.ts (depends on T001)
  • T009 [US1] Add routes: POST /admin/products/:externalProductId/knowledge, PATCH /admin/knowledge/:code/publish, PATCH /admin/knowledge/:code/unpublish, PATCH /admin/knowledge/:code/validate, PUT /admin/knowledge/:code, GET /admin/knowledge/:code/versions — all gated by fastify.authenticate — in src/modules/ai-support/knowledge/routes/knowledge.routes.ts, registered from src/api/routes.ts (depends on T007, T008)
  • T010 [US1] Run Quickstart Scenarios 1, 2, 3 locally and confirm all three pass

Checkpoint: User Story 1 is fully functional — knowledge entries can be authored, published, versioned, and validated, with full history preserved. This alone is a usable content-management surface even before error codes/runbooks/retrieval exist.


Phase 4: User Story 2 - Known issues, error codes, and runbooks are modeled as first-class, product-scoped records (Priority: P2)

Goal: ErrorCode/KnownIssue CRUD + lookup-by-error-code; Runbook CRUD with the same version-on-edit mechanism as User Story 1.

Independent Test: Quickstart Scenarios 4, 5.

Tests for User Story 2

  • T011 [P] [US2] Integration test covering Quickstart Scenario 4 (error code → known issue → lookup by error code) against a real Postgres in tests/integration/known-issues.test.ts
  • T012 [P] [US2] Integration test covering Quickstart Scenario 5 (runbook step order preserved; deactivate removes it from lookup) against a real Postgres in tests/integration/runbooks.test.ts

Implementation for User Story 2

  • T013 [P] [US2] Add ErrorCodesRepository/ErrorCodesService (create; findByCode) in src/modules/ai-support/knowledge/repository/error-codes.repository.ts + src/modules/ai-support/knowledge/service/error-codes.service.ts (depends on T003)
  • T014 [US2] Add KnownIssuesRepository/KnownIssuesService (create; findByErrorCode, joining through ErrorCodesRepository's lookup) in src/modules/ai-support/knowledge/repository/known-issues.repository.ts + src/modules/ai-support/knowledge/service/known-issues.service.ts (depends on T013)
  • T015 [P] [US2] Add RunbooksRepository (create; findCurrentByKey — filters isCurrentVersion: true, active: true, treating inactive the same as not-found per FR-010; createNewVersion reusing research.md's conditional-update-then-insert pattern; deactivate) in src/modules/ai-support/knowledge/repository/runbooks.repository.ts (depends on T003)
  • T016 [US2] Add RunbooksService in src/modules/ai-support/knowledge/service/runbooks.service.ts (depends on T015)
  • T017 [US2] Add routes: POST /admin/products/:externalProductId/error-codes, POST /admin/products/:externalProductId/known-issues, GET /admin/products/:externalProductId/known-issues/by-error-code/:code, POST /admin/products/:externalProductId/runbooks, PUT /admin/products/:externalProductId/runbooks/:key, PATCH /admin/products/:externalProductId/runbooks/:key/deactivate, GET /admin/products/:externalProductId/runbooks/:key — all gated by fastify.authenticate — added to src/modules/ai-support/knowledge/routes/knowledge.routes.ts (depends on T014, T016)
  • T018 [US2] Run Quickstart Scenarios 4, 5 locally and confirm both pass

Checkpoint: Both User Story 1 and 2 work together — the full structured knowledge catalog (entries, error codes, known issues, runbooks) exists.


Phase 5: User Story 3 - Retrieval returns only relevant, filtered, validation-aware knowledge (Priority: P3)

Goal: The filtered/ranked retrieval query (research.md), scoped to product/feature/category, excluding drafts and not-yet-effective entries, validated-first ordering.

Independent Test: Quickstart Scenario 6.

Tests for User Story 3

  • [~] T019 [P] [US3] Unit tests for the retrieval filter/ranking predicate — deliberately skipped for the same reason as T004: the filter/ranking predicate is a Prisma where/ orderBy clause, not an extractable pure function. Covered by T020's integration test.
  • T020 [US3] Integration test covering Quickstart Scenario 6 (cross-product isolation, validated-first ranking) against a real Postgres in tests/integration/knowledge-retrieval.test.ts

Implementation for User Story 3

  • T021 [US3] Add KnowledgeRepository.retrieve(productId, feature?, categoryScope?) implementing research.md's exact filter/order (depends on T006)
  • T022 [US3] Add KnowledgeService.retrieve(...) (depends on T021)
  • T023 [US3] Add route GET /knowledge/retrieve (no fastify.authenticate gate — this is a read path the future AI-support feature will call internally, not an admin surface; revisit once that feature defines its own internal-service-call convention) in src/modules/ai-support/knowledge/routes/knowledge.routes.ts, registered from src/api/routes.ts (depends on T022)
  • T024 [US3] Run Quickstart Scenario 6 locally and confirm it passes

Checkpoint: All three user stories work independently and together — knowledge can be authored, structured, and retrieved correctly.


Phase 6: Polish & Cross-Cutting Concerns

  • T025 [P] Add a "Product Knowledge" section to README.md describing the admin CRUD, versioning mechanism, and retrieval contract
  • T026 [P] Update specs/004-product-knowledge/checklists/requirements.md Notes with any implementation-time findings
  • T027 Run npx tsx scripts/check-architecture.ts and npm run lint/npm run typecheck
  • T028 Full regression: npm run test:unit (scoped to tests/unit) to confirm nothing broke elsewhere

Dependencies & Execution Order

Phase Dependencies

  • Setup (Phase 1): No dependencies
  • Foundational (Phase 2): Depends on Setup — BLOCKS all user stories
  • User Story 1 (Phase 3): Depends on Foundational — no dependency on US2/US3
  • User Story 2 (Phase 4): Depends on Foundational — independent of US1's own entities, though practically sequenced after since it reuses US1's version-on-edit pattern for runbooks
  • User Story 3 (Phase 5): Depends on US1's KnowledgeRepository existing (T006) — genuinely not implementable before US1, since retrieval queries the same table US1 creates
  • Polish (Phase 6): Depends on all three user stories

Parallel Opportunities

  • T004 alongside T006-T009 once T003 exists (unit test doesn't need the real implementation)
  • T011/T012 (independent integration test files)
  • T013/T015 (independent repositories)
  • T019 alongside US3's later tasks
  • T025/T026 in Polish

Implementation Strategy

MVP First (User Story 1 Only)

  1. Setup + Foundational (T001-T003)
  2. User Story 1 (T004-T010)
  3. STOP and VALIDATE: Quickstart Scenarios 1-3 pass — knowledge entries can be authored, published, and versioned correctly. Usable as a content-management surface even before structured error codes/runbooks/retrieval exist.

Incremental Delivery

  1. Setup + Foundational → schema migrated
  2. Add User Story 1 → knowledge entries work end to end (MVP)
  3. Add User Story 2 → error codes, known issues, runbooks
  4. Add User Story 3 → filtered retrieval, ready for the future AI-support feature to call
  5. Polish → docs and full regression