2.1.1 Issue-type metadata + the kind→type mapping
Estimate: 12m · Depends on: 1.4.2
Story 1.4's work_item.kind column already holds epic/story/task/bug/subtask. This Subtask adds the product-facing type layer: a single source of truth (a typed module, e.g. lib/issues/issueTypes.ts) mapping each user-facing issue type to its metadata — display label, icon, color token, and the set of allowed child types. The five v1 issue types are epic, story, task, bug, subtask — the same five Jira ships by default, and exactly the five values Story 1.4's WorkItemKind enum + DB triggers already enforce, so the metadata map stays total over the kind enum (a subtask row is a legal DB state, so any picker/icon/validation lookup must resolve for it). (Amended after Subtask 2.1.1 review — the original card under-scoped this to four and excluded subtask; corrected to five.) (The planning-side type column — code/design/copy/legal — is a separate axis owned by the AI layer and is NOT what this Subtask touches.)
Why a metadata module, not a DB table: the type set is small, fixed for v1, and read on nearly every render (icons, pickers, validation). A typed in-code map gives compile-time safety and zero query cost. If per-project custom issue types become a requirement later, this module is the single place that grows into a table-backed lookup — but YAGNI for v1 (durable shape: a typed constant, not a premature config table).
Acceptance criteria
- A typed module exports the five issue types with: label, icon (lucide component ref), color token (from the design system), and
allowedChildTypes. - The allowed-children map encodes: epic → [story, task, bug]; story → [task, bug, subtask]; task → [bug, subtask]; bug → [subtask]; subtask → []. (Inverts Story 1.4's
kind-parent constraint incl.subtask.parent ∈ {story, task, bug}; this is the product-readable form of it. Note bug is NOT a leaf — subtask is the single leaf.) - A helper
canParent(parentType, childType): booleanthe service layer uses for validation. - Unit tests over
canParentfor every legal + illegal pair.
Context refs
prisma/schema.prisma— thework_itemmodel +kindenum from Story 1.4motir-core/CLAUDE.md— 4-layer rule- Design-system color tokens + icon set (Story 1.0.5)