From 637d77b327294dddae9549490564ef693d3e4583 Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Tue, 19 May 2026 01:41:19 +0200 Subject: [PATCH] =?UTF-8?q?docs(plan-3):=20close=20out=20Plan=203=20?= =?UTF-8?q?=E2=80=94=20BACKLOG=20entries,=20RFC=20status,=20primitives=20r?= =?UTF-8?q?egistry,=20tooling=20conventions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- .../components-v2/shared/AppDialog.stories.ts | 2 +- dev-docs/ARCH-TESTING.md | 27 +++++++ dev-docs/BACKLOG.md | 78 +++++++++++++++++++ dev-docs/FRONTEND-TOOLING.md | 25 ++++++ dev-docs/PRIMEVUE_COMPONENTS.md | 55 +++++++++++++ .../RFC-WS-GUI-REDESIGN-CREWLI-STARTER.md | 30 +++++++ 6 files changed, 216 insertions(+), 1 deletion(-) diff --git a/apps/app/src/components-v2/shared/AppDialog.stories.ts b/apps/app/src/components-v2/shared/AppDialog.stories.ts index ad464564..52f710be 100644 --- a/apps/app/src/components-v2/shared/AppDialog.stories.ts +++ b/apps/app/src/components-v2/shared/AppDialog.stories.ts @@ -9,7 +9,7 @@ import AppDialog from '@/components-v2/shared/AppDialog.vue' * and renders the dialog open by default for autodocs visibility. */ const meta: Meta = { - title: 'v2 Shell/AppDialog', + title: 'Shared/AppDialog', component: AppDialog, tags: ['autodocs'], argTypes: { diff --git a/dev-docs/ARCH-TESTING.md b/dev-docs/ARCH-TESTING.md index ee2c3e9c..d5fc6da5 100644 --- a/dev-docs/ARCH-TESTING.md +++ b/dev-docs/ARCH-TESTING.md @@ -340,3 +340,30 @@ For Playwright tests to run, the host must have: for v1 per RFC §A.5. - Mobile viewport baselines — desktop 1440×900 only for v1. - Soketi / WebSocket testing infrastructure when ART-15 lands. + +--- + +## Mount-helper type convention (Plan 3 codified) + +Plan 3 hit this in 6+ tasks: a plan-doc test spec typed the `mount` +helper's props parameter as `Record`, which `vue-tsc` +strict mode rejects when the object is passed to +`mount(Component, { props })` — the component's generated prop type is +narrower than `Record`, so the assignment is a type +error (and widening it with `any` would violate the project zero-`any` +rule). + +**Convention:** type the helper parameter as `Partial<Props>`, +never `Record`: + +```ts +const mountX = (props: Partial = {}) => + mount(X, { props }) +``` + +Rationale: satisfies `vue-tsc` strict; behaviour-neutral; introduces no +`any`. Plan 3 used the equivalent explicit inline props shape per task +(the behaviour-neutral sanctioned deviation from the verbatim plan-doc); +**standardise on `Partial<Props>` from Plan 4 onward** so the +template-layer tests (List / Form / Detail / Dashboard / StateBlock) +share one idiom rather than re-deriving the shape each time. diff --git a/dev-docs/BACKLOG.md b/dev-docs/BACKLOG.md index c2b1811c..a534a0d7 100644 --- a/dev-docs/BACKLOG.md +++ b/dev-docs/BACKLOG.md @@ -1365,6 +1365,84 @@ deadline implementation). --- +### FRONTEND-ENERGYDOTS-NAN-ROBUSTNESS — EnergyDots/EnergyPicker NaN/Infinity input + +**Aanleiding:** `EnergyDots.vue` en `EnergyPicker.vue` renderen +`data-energy="NaN"` en 0 dots wanneer de input `NaN`/`Infinity` is; +`withDefaults` vervangt alleen `undefined`, niet `NaN`. Verbatim port +uit crewli-starter in Plan 3 (T7/T8); geen Plan-3 consumer, dus bewust +niet in-flight gewijzigd (buiten frozen scope, surfaced ipv silently +changed). + +**Wat:** +- Clamp/valideer de numerieke input op de prop-grens (niet-eindige + waarden → 0 of geclamped 0–5 bereik). +- Voeg `NaN`/`Infinity`-guard tests toe voor beide componenten in één + hardening-commit. + +**Trigger:** Eerste API-gevoede consumer in Plan 4+ (een pagina die +ongevalideerde numerieke API-data doorgeeft). + +**Prioriteit:** Laag — geen huidige consumer; cosmetische degradatie, +geen crash. + +--- + +### FRONTEND-DRAGGABLEBLOCK-POINTERCANCEL — DraggableBlock spurious dragend on system-cancel + +**Aanleiding:** `DraggableBlock.vue` heeft geen `@pointercancel` +handler. Een door het systeem geannuleerde drag (iOS home-gesture, +Android long-press, stylus out-of-range) vuurt via `lostpointercapture` +een spurieuze `dragend` met stale coördinaten terwijl `active` nog +`true` is — een parent (TimetableGrid/CueTimelineEditor) herpositioneert +dan onterecht een block. Beste vondst van de Plan 3 review; valt buiten +het A2-contract (`dd45e899`). + +**Geblokkeerd door:** A2-contract amendement eerst — het drag-model in +`dev-docs/superpowers/plans/2026-05-17-gui-redesign-tier1-primitives-DRAGGABLEBLOCK-CONTRACT.md` +moet `pointercancel`-semantiek expliciet specificeren vóór de +code-wijziging (frozen-artifact discipline, analoog aan constraint #1). + +**Wat:** +- Amend het A2-contract doc met `pointercancel` semantiek. +- Voeg een `@pointercancel` handler toe die de `@pointerup` cleanup + spiegelt (clear `active`, reset start-coördinaten; géén `dragend` + emit). +- Voeg een Vitest cancel-tijdens-drag test toe (geen `dragend`/`click`; + navolgende `lostpointercapture` is een no-op). + +**Trigger:** Tier-4 integratie-sprint (TimetableGrid / CueTimelineEditor). + +**Prioriteit:** Middel — echte correctheids-gap op touch/stylus zodra +een echte consumer DraggableBlock bedraadt. + +--- + +### A11Y-AD3-MENUBAR-EMPTY-MODEL — Empty role="menubar" from AD-3 Menubar-wrap + +**Aanleiding:** Het RFC AD-3 Menubar-wrap patroon +(``, Plan 3 Task 11 Step-4 design) produceert een +lege `
    ` in de DOM. Raakt elke consumer van het +chrome-shell patroon, te beginnen met `AppTopbar` (Task 11). +Plan-frozen Step-4 ontwerp; pattern-level beslissing, dus bewust niet +in-flight gewijzigd. + +**Wat (pattern-level beslissing):** +- Óf onderdruk de lege `ul` via een PT-slot override op het + Menubar-wrap patroon, +- óf vervang de Menubar-wrap door een dunnere chrome-primitive zonder + menubar-semantiek. +- Documenteer de gekozen lijn in `PRIMEVUE_COMPONENTS.md` (v2 + primitives registry — Menubar-wrap sectie). + +**Trigger:** F5 a11y-audit batch (per RFC-WS-FRONTEND-PRIMEVUE §A.7 +item 17). + +**Prioriteit:** Laag — niet user-blocking; a11y-hygiëne, op te lossen +in de geplande a11y-batch vóór brede herbruik van het patroon. + +--- + ## Opgeloste items (mei 2026) - ~~**WS-TOOLING-001**: Claude Code deterministic guard-rail layer (5 hooks, `crewli-reviewer` subagent op Opus 4.7, 3 slash commands `/sprint-status` `/review-multitenancy` `/sync-docs`, `dev-docs/CLAUDE_CODE_TOOLING.md`). 8/8 smoke tests groen, live integratie geverifieerd. Merge `ad36c06` op 2026-05-05. Follow-ups: TECH-HOOK-001, TECH-CMD-001, TECH-STYLE-001.~~ ✅ diff --git a/dev-docs/FRONTEND-TOOLING.md b/dev-docs/FRONTEND-TOOLING.md index bb8c9829..ae3181a8 100644 --- a/dev-docs/FRONTEND-TOOLING.md +++ b/dev-docs/FRONTEND-TOOLING.md @@ -60,6 +60,31 @@ never blanket-disable ts-reset. If a specific reset is genuinely wrong for the project, document it; the upstream issue is the backstop. +## ESLint + +### Scoped lint invocation + +`pnpm lint -- ` is **vacuous**: pnpm's `--` passthrough forwards +trailing args as workspace/script filters, not as ESLint targets, so +errors in the intended files are never surfaced. In Plan 3 this made +per-task lint report "clean" while real errors existed — the root +cause of the GUI-redesign DoD #13 miss (fixed in `0b19e785`). + +Correct scoped invocation — call the project's ESLint binary directly +with the paths: + +```bash +pnpm exec eslint +``` + +For per-task gates, pair a file-scoped run with a directory-scoped run +so project-level rule misconfigs surface too: + +```bash +pnpm exec eslint apps/app/src/components-v2/shared/Foo.vue +pnpm exec eslint apps/app/src/components-v2/shared +``` + ## Vitest Runs against `apps/portal/` and `apps/app/`. `apps/app/` has a diff --git a/dev-docs/PRIMEVUE_COMPONENTS.md b/dev-docs/PRIMEVUE_COMPONENTS.md index 748849a9..aee477ff 100644 --- a/dev-docs/PRIMEVUE_COMPONENTS.md +++ b/dev-docs/PRIMEVUE_COMPONENTS.md @@ -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 +> `.stories.ts` (Storybook title `Shared/`) and a co-located +> `__tests__/.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 `` chrome-wrap (Plan 3 Task 11, RFC AD-3).** +Convention: *wrap, don't rewrite*. The hand-rolled top-bar chrome is +wrapped in `` 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 `
      ` — 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: diff --git a/dev-docs/RFC-WS-GUI-REDESIGN-CREWLI-STARTER.md b/dev-docs/RFC-WS-GUI-REDESIGN-CREWLI-STARTER.md index e63a7b80..e2e51d07 100644 --- a/dev-docs/RFC-WS-GUI-REDESIGN-CREWLI-STARTER.md +++ b/dev-docs/RFC-WS-GUI-REDESIGN-CREWLI-STARTER.md @@ -7,6 +7,36 @@ | **Design spec** | `dev-docs/superpowers/specs/2026-05-15-crewli-starter-gui-redesign-design.md` | | **Impl plans** | `dev-docs/superpowers/plans/2026-05-16-gui-redesign-foundation.md` (Plan 1 of 5) | +## Status + +| Plan | State | Scope | +|---|---|---| +| Plan 1 — structural foundation | ✅ Done | bootable `/v2/` slice | +| Plan 2 — shell pieces | ✅ Done | AppSidebar/AppTopbar/SidebarNav/WorkspaceSwitcher/RightDrawer/AppDialog | +| Plan 3 — Tier-1 primitives + DraggableBlock + Storybook | ✅ Done (2026-05-18) | `537ec098..0b19e785` on `main`, 16 commits | +| Plan 4 — template layer | Next | List/Form/Detail/Dashboard/StateBlock | +| Plan 5 — catalog + theme/density toolbar | Pending | — | + +**Plan 3 closure (2026-05-18).** Per-task SHAs: A1 `1561024e` · A2 +`dd45e899` · T1 `20af2ebd` · T2 `9d1fd16f` · T3 `12cff8c0` · T4 +`b0d5e961` · T5 `284fdcc4` · T6 `b64b0241` · T7 `79650d0b` · T8 +`91d20d0d` · T9 `814d11c8` · T10 `183218ef` · T11 `f03a3f16` · +T11(b)-fix `237afc89` · T12 `1a66ac6e` · lint-fix `0b19e785`. + +- **Tests:** 527 → 564 (+37). `vue-tsc --noEmit` clean; scoped ESLint clean. +- **Bundle:** +35.9 kB raw / +0.82% (gzip overhead negligible) — within §11 "expected small". +- **DEFERRED-HITL (4, by design per AD-G6, not failures):** v2 parity + baselines for StatusTag, StatCard, PageHead, EnergyDots, EnergyPicker, + DraggableBlock (static states), TagsInput (criterion: Aura-coherent, + not pixel), and the AppTopbar `@visual` re-baseline. Per-component + criteria documented in the Plan 3 plan-doc; these are the human + parity-check gate. +- **Spawned BACKLOG follow-ups (3):** `FRONTEND-ENERGYDOTS-NAN-ROBUSTNESS`, + `FRONTEND-DRAGGABLEBLOCK-POINTERCANCEL` (blocked on an A2-contract + amendment), `A11Y-AD3-MENUBAR-EMPTY-MODEL` — see `dev-docs/BACKLOG.md` + § Technische schuld. +- Holistic review verdict: sound foundation for Plan 4. + ## 1. What changes vs RFC-WS-FRONTEND-PRIMEVUE The F4a–F4d strategy ("translate legacy Vuetify pages 1:1 to PrimeVue,