# Design — Crewli SPA GUI Redesign on the crewli-starter Design System | Field | Value | |---|---| | **Status** | Design approved (brainstorming) — pending spec review | | **Date** | 2026-05-15 | | **Author** | Brainstorming session (Bert + Claude Code) | | **Supersedes** | The F4a–F4d component-migration sub-packages of `dev-docs/RFC-WS-FRONTEND-PRIMEVUE.md` | | **Next artifact** | Implementation plan (writing-plans), then a new project RFC in `dev-docs/` | | **Source design system** | `crewli-starter/` (sibling working directory) | --- ## 1. Context & problem The Crewli SPA (`apps/app/`) is mid-migration from Vuetify+Vuexy to PrimeVue 4.5 (Aura) + Tailwind v4. F3 (PrimeVue foundation, parallel-mode) and F3.5 (a mockup-parity `AppShell`) have landed. Storybook 10 is wired (PrimeVue + Tailwind) but contains only two smoke stories. The original F4 plan was "translate existing Vuetify pages 1:1 to PrimeVue, preserve UX." A complete working prototype design system now exists in `crewli-starter/`: ~40 components, ~20 pages, a full app shell (sidebar / topbar / right drawer / workspace switcher), and several rich modules (Timetable, Cue editor, Section Builder). It already uses the **same stack**: PrimeVue 4.5, Aura preset via `@primeuix/themes`, the Crewli teal token set, Tailwind v4, Iconify-Tabler. It is pure JavaScript (no TypeScript). **Decision: pivot the redesign to use `crewli-starter` as the design source of truth**, building a new GUI in parallel with the existing one and migrating page-by-page, rather than translating legacy Vuetify pages. ## 2. Decisions taken (this session) 1. **Cohabitation:** parallel routes under `/v2/*`. Old pages stay on existing routes. Cutover is route-by-route. 2. **Fidelity rule:** PrimeVue-first. Default to a stock PrimeVue component styled with Tailwind + `pt` API + Aura tokens. Port custom CSS *only* when no PrimeVue primitive fits or the visual is genuinely bespoke. Generic elements (KPI cards, error/empty states, status badges, etc.) are **rebuilt on PrimeVue and accept the PrimeVue look** — restyle freely. Pixel-perfect 1:1 is reserved for the genuinely bespoke set only (see §7). 3. **Plan relationship:** a new project RFC supersedes F4a–F4d. The F4 *architectural* decisions (PrimeVue + Tailwind + Aura + FormField + DataTable conventions) all still stand; only the page-migration strategy and design source change. 4. **Shell strategy:** a new `AppShellV2.vue` (and `OrganizerLayoutV2.vue`) ports the crewli-starter shell 1:1. The existing `AppShell.vue` / `OrganizerLayout.vue` stay untouched until `/v2/` supersedes them. 5. **Folder convention:** `pages-v2/` + `components-v2/` mirror the existing structure. No per-file `V2` suffix inside those folders (the folder name carries the distinction); the suffix is only on the two shell/layout files that sit beside their v1 siblings. 6. **Sequencing approach:** Approach A — foundation-first vertical slice. Build the minimum end-to-end first, then iterate page-by-page. ## 3. Folder structure & routing ``` apps/app/src/ ├── pages-v2/ # NEW parallel page tree → /v2/* ├── components-v2/ │ ├── layout/ # AppSidebar, AppTopbar, SidebarNav, WorkspaceSwitcher, RightDrawer │ ├── shared/ # PageHead, StatCard, StatusTag, StateBlock, EnergyDots, EnergyPicker, TagsInput, DraggableBlock │ ├── templates/ # ListTemplate, FormTemplate, DetailTemplate, DashboardTemplate │ ├── filters/ # SmartFilterBar + chip + popover + 5 editors + SmartListsRow │ ├── timetable/ # (deferred — migrate with feature) │ └── music/ # (deferred — migrate with feature) │ # NOTE: no components-v2/forms/ — v2 reuses the existing │ # apps/app/src/components/forms/FormField.vue. This folder is │ # created ONLY if FormField provably forks (see §5). ├── layouts/ │ ├── OrganizerLayout.vue # EXISTING — untouched │ ├── OrganizerLayoutV2.vue # NEW — wraps AppShellV2 │ └── components/ │ ├── AppShell.vue # EXISTING — untouched │ └── AppShellV2.vue # NEW — ports crewli-starter shell 1:1 ├── stories/ # EXPANDED — see §6 ├── stores/ # + useWorkspaceStore ├── composables/ # + useRightDrawer └── types/v2/ # shared v2 types ``` **Routing:** `unplugin-vue-router` generates routes from `pages-v2/`; they are pinned under `/v2/*` (route prefix/meta). `vite-plugin-vue-meta-layouts` selects `OrganizerLayoutV2` for the `pages-v2/*` tree. No conditional logic inside layout files — each page tree picks its own layout. The old layout stays inert (zero regression risk on un-migrated pages). **Cutover convention (per page):** when a v2 page is approved to replace its v1 counterpart, move `pages-v2/X.vue` → `pages/X.vue` (overwrite), rewrite internal links `/v2/X` → `/X`, delete now-unused v1 components, commit. Router auto-updates. ## 4. AppShellV2 composition ``` layouts/components/AppShellV2.vue # Tailwind grid: sidebar | (topbar + content) | rightDrawer # (V2 suffix: sits beside v1 AppShell.vue) └── composes components-v2/layout/: ├── AppSidebar.vue # permanent rail (≥lg); PrimeVue Drawer overlay (` + Tailwind (custom) | Permanent rail; no PrimeVue primitive | | Sidebar mobile | PrimeVue `Drawer` | Correct off-canvas primitive | | Sidebar nav rows | `