The work_item table — the unit of tracked work in Motir's PM core. Every epic, story, task, bug, and subtask a team plans in a project is a row in this table. Self-referencing tree (parent_id) with DB-level kind-parent rules and a depth limit. Carries the two user-visible content axes — descriptionMd ("what to do") and explanationMd ("why this matters") — both Markdown-source, GFM-rendered, with explanation provenance tracked (user_authored / ai_draft / user_edited) so the UI can surface "AI-drafted, review me" hints to non-technical reviewers. Wires Story 1.3's per-project key counter to allocate human-readable identifiers (PROD-42). Ships the schema, repository, service, RLS, dependency join table (work_item_link), and revision-history audit trail that every PM-core Epic (2 through 6) and the AI Planning Layer (Epic 7) build on. Reframed from the May 2026 plan revision: this Story models the tracked work issue tree (Jira's domain), not the AI planning meta-tree (Epic 7's domain — see Scope).
Prerequisites: Story 1.3 (Projects) must be complete — work_item FKs against Project with onDelete: Cascade, the RLS policies key off the same app.workspace_id session GUC that 1.2.3 established, and the issue-key allocator (PROD-42) calls projectRepository.allocateWorkItemNumber shipped in 1.3.1. Story 1.2 (Workspaces)'s RLS pattern is the structural model this Story copies. Story 1.0.5 (Design system) must be complete before 1.4.1 (mockup) — the issue-detail view composes the canonical Button, Input, Textarea, Select, Card, Avatar, Badge primitives. All code follows motir-core/CLAUDE.md's 4-layer rule (Route → Service → Repository → Prisma).
Functional verification — run the data layer end-to-end through the test endpoint added in 1.4.8. No production UI yet (that's Epic 2); this recipe exercises the service via HTTP + Prisma Studio + inspection.
pnpm install && pnpm prisma migrate dev && pnpm dev.curl -X POST .../api/_test/work-items -d '{"kind":"epic","title":"Q3 launch","projectId":"..."}' --cookie session. Note the returned identifier (e.g. PROD-1).pnpm prisma studio); confirm the work_item row exists with the expected fields and that a work_item_revision row exists with changeKind = 'created'.IllegalParentTypeError.DepthLimitExceededError.{ title: { from: "Q3 launch", to: ... } }.{"explanationMd": "## Why this matters\n\nThis launch...", "explanationSource": "ai_draft"} (simulating Epic 7's AI-drafting endpoint). GET the epic — confirm both fields stored. PATCH again with only {"explanationMd": "## Updated\n\n..."} (no explicit source) — GET confirms explanationSource = user_edited auto-transitioned. Open Prisma Studio — confirm three revision rows for the epic with the right diffs.GET /api/_test/work-items/{id}?render=1 — response body's descriptionHtml + explanationHtml fields contain sanitized HTML; verify any <script> tags in the Markdown source are stripped from the HTML output. Open a code-block test fixture, confirm syntax highlighting markup is present.POST /api/_test/work-item-links {fromId: epic.id, toId: Y.id, kind: 'is_blocked_by'}. Hit GET /api/_test/work-item-links?workItemId=epic.id&ready=1 — expect {ready: false}. PATCH Y and Z to status="done". Re-hit the ready endpoint — expect {ready: true}.WI_LINK_CYCLE in the body.