Before you spend review time on the mockups taxonomy PRs, here is the whole picture: what the project is, what each PR touches, how it was built and verified, and previews for everything. At the end, a short feedback form (eight calls + an open field) so we set the review up right; answers submit straight from the page. Nothing assumed, everything linked.
Mockups get a real taxonomy: categories → use-cases → sub-use-cases (Apparel → T-Shirt, or Apparel → Hat → Cap), maintained by the content team in the CMS. This project brings it to both places people browse mockups, on one shared data layer:
Dashboard: the /mockups page moves from group-only navigation to the taxonomy: category chips → use-case lanes → drill-in grid with sub-use-case filter tags, search from anywhere. Ships first to the team for the dogfooding round.
Editor: the Mockups panel is rebuilt to match the Textures/Illustrations panel UX on the same taxonomy: one tab per category, expand-in-place lanes per use-case, sub-use-case filter, sort and search. Fully behind the mockups-taxonomy-panel feature flag; with the flag off everything behaves exactly as production today.
Already merged: the CMS taxonomy API (github.com/Kittl/cms/pull/1749, GET /api/mockups/taxonomy + /by-use-case) and the swimlane abstraction (github.com/Kittl/mono/pull/12582). Staging CMS is fully seeded (9 categories, 69 use-cases); production gets the endpoint with the next CMS release. That release gates the dashboard merge, not the flag-gated editor PRs.
@repo/mockups (one taxonomy client both surfaces use: query options, keys, types matching the CMS payload, plus a pagination fix) and the swimlane shell in @repo/elements-panel (a carried-over-lane guard and an opt-in persistentScrollbar, both regression-tested), plus the editor's data plumbing (panel store, query keys, feature flag). No user-visible change on its own; the one shared-code behavior change (a lane opened during a tab switch is no longer auto-closed by the shell reset) only triggers in the new mockups flows and is regression-tested for the existing panels.@repo/mockups; the types match the CMS payload exactly (verified against the live endpoint). Includes a pagination fix: feeds built on the shared options stop at the server total instead of firing a trailing empty request (the dashboard benefits today; the editor panel's multiplexed feed keeps its existing short-page stop, flagged in a self-review comment).Pick an answer per question, notes optional, then hit Send answers at the bottom.
Four PRs total instead of one giant review per surface. If you would cut it differently (coarser, finer, different boundaries, different order), say so before we go deep.
The editor work and the dashboard work each grew their own taxonomy fetch code; the foundation PR unifies them into one client in @repo/mockups before either merges, so there is a single contract and a single set of types. Each surface keeps its own UI state on top.
The panel store keeps the fetched tree and revalidates selections on refresh, following templatePanelStore / elementsPanelStore. The alternative is ids-only in the store with objects derived from React Query. If you would rather see ids-only, say so and we scope together whether that lands before merge or as a follow-up.
// as built (matches templatePanelStore precedent)
store = { taxonomy: {...full tree...},
filter: { expandedUseCase: {...object...} } }
// alternative (ids-only, artboard-creator shape)
store = { filter: { expandedUseCaseId: 201 } }
// objects derived from the React Query cache at render time
One deliberate wrinkle either way: a use-case opened from a mockup's tag can live outside the panel taxonomy and must survive refresh (its feed is fetched by id). Both cases have store tests.
The foundation touches the shared swimlane components used by Illustrations/Textures: (a) a guard so a lane opened by a navigation in the same render as a tab switch is not immediately auto-closed by the shell reset, and (b) an opt-in persistentScrollbar on the expanded feed. The guard is a real behavior change in shared code; only the new mockups flows change both inputs together, and the existing close path keeps its regression test.
The dashboard lane is a simple carousel with a View-all drill-in, not an expand-in-place feed, so it has a ~160-line presenter of its own rather than a further-generalized shared component. Unifying the lane implementations is a follow-up candidate, not part of this stack.
The editor panel body and the dashboard page component each own their surface's wiring: state machine, data hooks, navigation registration, selection, and mode switching. The actual UI is delegated to subcomponents, and both files carry the heaviest test coverage in their PRs. The repo guideline says to avoid multi-purpose components, so this is a conscious trade: splitting them now means refactoring verified code right before review. If you want them split, we would take it as a follow-up unless you feel strongly it should block.
src/stores next to its siblings, not src/features/mockups: fine?The editor guidelines say new feature code belongs under src/features/, but every existing panel store (templatePanelStore, elementsPanelStore) lives in src/stores/. We followed the sibling precedent so mockups is not the one panel store living somewhere else. Moving it is a mechanical rename if you prefer the guideline over the precedent.
Two deliberate short-term choices: (a) the mockup popover takes a legacy callback (tag click = text search, exactly production) and a new one (navigate to the use-case), the legacy one winning when present, collapsing to one after rollout. (b) ?mockups-taxonomy-panel=1 force-enables the panel even in production bundles because flags cannot be configured on ephemeral previews (same pattern as the monetisation override); until launch, anyone with the param can see the read-only panel.
Order preferences, missing context, things that look over- or under-engineered, anything else.