docs(plan-3): close out Plan 3 — BACKLOG entries, RFC status, primitives registry, tooling conventions

- BACKLOG: add 3 spawned follow-ups (EnergyDots NaN, DraggableBlock pointercancel, AD-3 Menubar a11y)
- RFC-WS-GUI-REDESIGN-CREWLI-STARTER: mark Plan 3 complete with commit refs + DoD ledger
- PRIMEVUE_COMPONENTS: v2 primitives registry (8 components), statusSeverity SoT, Menubar-wrap pattern
- ARCH-TESTING: mount-helper type convention (Plan 3 codified, Plan 4 carry-over)
- FRONTEND-TOOLING: scoped lint invocation note (DoD #13 root cause)
- AppDialog.stories.ts: rename title to 'Shared/AppDialog' for sibling consistency
This commit is contained in:
2026-05-19 01:41:19 +02:00
parent 0b19e7856b
commit 637d77b327
6 changed files with 216 additions and 1 deletions

View File

@@ -20,6 +20,61 @@ deprecation stub; deletion in F6).
---
## v2 primitives registry (Plan 3)
> Landed by Plan 3 of [RFC-WS-GUI-REDESIGN-CREWLI-STARTER.md](./RFC-WS-GUI-REDESIGN-CREWLI-STARTER.md)
> (commits `537ec098..0b19e785` on `main`). All eight live under
> `apps/app/src/components-v2/shared/`; each has a co-located
> `<Name>.stories.ts` (Storybook title `Shared/<Name>`) and a co-located
> `__tests__/<Name>.spec.ts`. PrimeVue-first per AD-G3; scoped CSS only
> where the spec justifies it (EnergyDots/EnergyPicker §8, DraggableBlock §7.1).
| Component | Purpose | Props (summary) |
|---|---|---|
| `StatusTag` | PrimeVue `Tag` whose `severity` is resolved from a status string via the SoT map (never inlined) | `status`, `label?`, `dot?` |
| `StatCard` | KPI tile (PrimeVue `Card` + `Icon` + optional trend) — replaces v1 `AppKpiCard` | `icon`, `label`, `value`, `trend?`, `trendDir?` |
| `PageHead` | Thin Tailwind flex page header (title / sub / `#actions` slot); no PrimeVue dependency | `title`, `sub?` (+ `#actions` slot) |
| `StateBlock` | Mandatory loading / error / empty three-state wrapper + success passthrough | `state`, `errorMessage?`, `emptyMessage?`, `actionLabel?`, `retryLabel?` (emits `retry`, `action`) |
| `TagsInput` | Multi-tag input — re-implementation on PrimeVue `AutoComplete` (multiple + typeahead); lowercase-dedupe, comma/Enter split, 5-suggestion cap | `modelValue?: string[]`, `suggestions?: string[]`, `placeholder?` |
| `EnergyDots` | Read-only 5-dot energy meter (scoped CSS, §8-justified) | `value?: number`, `lg?: boolean` |
| `EnergyPicker` | Interactive 5-step energy picker (clicking the current value resets to 0) | `modelValue?: number` |
| `DraggableBlock` | §7.1 canonical 2-line draggable block (PointerEvent drag; parent owns all positioning) | `line1Left`, `line1Right?`, `line2Left?`, `line2Right?`, `selected?`, `dragging?`, `density?` (emits `click`, `dragstart`, `dragend`) |
**`statusSeverity` — single source of truth.**
`apps/app/src/components-v2/shared/statusSeverity.ts` is the canonical
map from the five backend-mirrored status enums (`ShiftAssignmentStatus`,
`ArtistEngagementStatus`, `PaymentStatus`, `PersonStatus`, `MatchStatus`)
to PrimeVue `Tag` severity literals. `StatusTag` resolves through it and
never inlines a severity. The map is bidirectionally test-locked by
`apps/app/tests/unit/utils/statusSeverity.consistency.spec.ts` (every
enum value maps to a severity; every map key is reachable from an enum).
**Changes to the map are RFC-level** (design spec §8) — not an ad-hoc
per-component decision.
**AppTopbar `<Menubar>` chrome-wrap (Plan 3 Task 11, RFC AD-3).**
Convention: *wrap, don't rewrite*. The hand-rolled top-bar chrome is
wrapped in `<Menubar :model="[]">` with the breadcrumb in `#start` and
the search / notifications / user cluster in `#end`. Menubar carries no
menu items — it is the AD-3-mandated chrome shell only; its `pt` slots
inherit the original layout classes verbatim so the wrap is visually
identical to the pre-wrap (Plan-2) bar (human pixel-parity check at the
HITL gate). **Caveat:** `:model="[]"` renders an empty `<ul
role="menubar">` — tracked as `A11Y-AD3-MENUBAR-EMPTY-MODEL` in
[`BACKLOG.md`](./BACKLOG.md) § Technische schuld; resolve at the F5
a11y batch before reusing this pattern broadly.
**DraggableBlock drag-model contract.** The canonical PointerEvent drag
model — reconciled from the two crewli-starter consumers (TimetableGrid
+ CueTimelineEditor) — is fixed by the A2 contract doc
`dev-docs/superpowers/plans/2026-05-17-gui-redesign-tier1-primitives-DRAGGABLEBLOCK-CONTRACT.md`
(commit `dd45e899`). Component is presentational; the parent owns all
snap/lane/px math. **Known gap:** no `@pointercancel` handler — a
system-cancelled drag emits a spurious `dragend`. Tracked as
`FRONTEND-DRAGGABLEBLOCK-POINTERCANCEL` (blocked on an A2-contract
amendment first).
---
## 1. Purpose and scope
This document defines: