Follow-up to P5 (commit ac36dfe9). Vue warned about unresolved
AppBreadcrumb component in AppTopbar's #start slot — auto-import via
unplugin-vue-components did not register it because
components-v2/ is outside the scan path (Components({ dirs: [...] })
covers src/@core/components, src/views/demos, src/components only).
The original P5 edit did include this import line, but a formatter
pass appears to have pruned it as "unused" before runtime parsed the
template; the symbol was unresolved at render and the warning
surfaced. Restored explicitly so any future formatter pass keeps it.
Fix 2 (AppTopbar #start = AppBreadcrumb) now functions visually,
not just structurally. Manual smoke pending (Bert).
Follow-up backlog: AUTO-IMPORTS-V2-SCAN — extend Components({ dirs })
to include src/components-v2/ so the v2 chrome can rely on the same
auto-import ergonomics as v1. Not done here to keep the fix surgical.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per RFC-WS-PRIMEVUE-PLAN-2-5 §5.1–§5.5 plus the AD-2.5-W1 option-A
supersession (no sub on dropdown items either, accepted divergence).
Atomic changes:
- AppTopbar: brand block (gradient "C" mark + Crewli wordmark) removed
per Fix 1; the #start slot now renders <AppBreadcrumb /> per Fix 2.
Legacy meta-based useBreadcrumb consumption (breadcrumbModel computed,
vue-router useRouter import, command-based PrimeVue Breadcrumb model)
is gone; AppBreadcrumb owns the registry-driven path. Dead
topbar-mark-shadow scoped CSS rule deleted.
- AppBreadcrumb: import updated to the renamed useBreadcrumb.
- AppSidebar: docstring updated to make the Fix 3 vertical order
(Header → Nav → Switcher, switcher bottom-anchored) explicit. No
template change needed: SidebarNav's root <nav class="flex-1"> already
fills available column space, naturally pushing WorkspaceSwitcher to
the bottom (two flex-1 siblings would split the column 50/50 and
compress the nav — a separate spacer element is structurally wrong).
- WorkspaceSwitcher: dropdown panel restructured per crewli-starter
reference. Semantic class markers (.popover-head/.title/.link/.list/
.opt/.is-current/.ws-logo/.name/.check-mark/.foot) added alongside
Tailwind utilities so specs assert structure with stable selectors.
Footer buttons wired to placeholder createWorkspace / inviteUser
handlers (console.warn + TODO) until the flows ship. Manage link
stays a non-navigating label (no v2-workspaces-manage route yet).
No sub line on any dropdown row (AD-2.5-W1 option A).
Atomic legacy useBreadcrumb retirement (planned since P1):
- Legacy route-meta-driven useBreadcrumb + toBreadcrumbItems +
BreadcrumbRouteRecord types deleted entirely (only AppTopbar
consumed it, and that consumption is gone after Fix 2).
- useNavBreadcrumb → useBreadcrumb (single SoT for breadcrumb chain).
- NavBreadcrumbItem → BreadcrumbItem.
- AppBreadcrumb.vue import updated to the new name.
- SidebarNav.vue docstring reference scrubbed to the new name.
- useBreadcrumb.spec.ts: 10 legacy toBreadcrumbItems specs removed;
4 walkNavTree specs retained.
AppTopbar.spec.ts:
- vue-router mock simplified (route.matched no longer relevant).
- AppBreadcrumb stubbed in #start; legacy command-vs-route assertion
removed; new spec verifies AppBreadcrumb is rendered.
WorkspaceSwitcher.spec.ts: 5 new dropdown specs (header / row count /
current-row checkmark / footer buttons / no-sub on rows).
Suite delta: 557 → 552 (−5 net: −10 legacy toBreadcrumbItems specs,
+5 Fix 5 dropdown specs, −1 obsolete AppTopbar breadcrumb-model spec,
+1 new AppTopbar AppBreadcrumb-presence spec).
vue-tsc clean. Scoped ESLint clean (0 errors). All 3 re-grep checks
returned 0 hits (useNavBreadcrumb/NavBreadcrumbItem, topbar brand
selectors, standalone "sub" identifier in WorkspaceSwitcher — only
documentation comments referencing the no-sub state remain, which
describe absence by design).
Manual smoke skipped (Auto Mode); coverage from the post-edit specs
includes AppBreadcrumb-in-#start, dropdown structure, and trigger
no-sub. Recommend Bert run `pnpm --filter crewli-app dev` and verify
the 6 checks listed in the prompt before merging.
Known divergence from crewli-starter (accepted):
- Dropdown rows are ~16px shorter than crewli-starter (no sub line).
Tracked as WORKSPACE-DROPDOWN-SUB-CONTENT for a future RFC with
the required backend scope (organisations.type enum + metrics).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
P4 (Plan 2.5, AD-2.5-W1 + AD-2.5-B1) refactored SidebarNav to read
APP_NAVIGATION directly, retiring the OrganizerLayoutV2 → useV2Nav →
AppSidebar :groups → SidebarNav :groups props chain. Five artifacts
were deliberately left in place to keep the P4 diff focused — this
commit removes them.
Deleted:
- src/composables/useV2Nav.ts (+ spec) — v1→v2 nav fold adapter, no
production consumer post-P4
- src/types/v2/nav.ts — V2NavGroup / V2NavItem types, only consumed
by the deleted composables above. types/v2/ directory removed (empty)
- src/components-v2/layout/sidebarNavActive.ts (+ spec) — pure helper,
SidebarNav now uses inlined active check against NavItem.routeName
- navFixture export + V2NavGroup import from stories/v2/_helpers.ts
Also: stale "useV2Nav(orgNavItems)" reference scrubbed from
OrganizerLayoutV2.vue docstring (the function no longer exists; the
comment now describes the retired plumbing generically).
Suite delta: 575 → 557 (−18 specs). The drop is correct — the removed
specs tested deleted dead code (sidebarNavActive: 8 specs, useV2Nav:
10 specs), not contract behaviour.
vue-tsc clean. Scoped ESLint clean (0 errors). Final re-grep on all
deleted symbols (useV2Nav, V2NavGroup, V2NavItem, sidebarNavActive,
navFixture) returns zero hits across apps/app/src/.
Per zero-compromise gap 5 (delete > adapt): orphans don't stay.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per RFC-WS-PRIMEVUE-PLAN-2-5 §4 AD-2.5-W1 and AD-2.5-B1, §5.4 Fix 4.
Changes:
- WorkspaceSwitcher: sub field removed from template, WorkspaceDisplay
type, and buildDisplay derivation. Stories did not carry sub args
(auto-derived from seeded org.role); no WithSub story existed. New
regression spec (WorkspaceSwitcher.spec.ts) locks the no-sub render.
- SidebarNav: now consumes APP_NAVIGATION from src/config/navigation.ts
as the single source of truth (shared with breadcrumb derivation in
useNavBreadcrumb). The groups: V2NavGroup[] prop is removed; render
walks top-level NavItems (branch nodes render label-heading + children;
leaf nodes render as rows; items without routeName render as
non-clickable dormant placeholders). Previous nav data source:
groups prop fed by useV2Nav(orgNavItems) in OrganizerLayoutV2.
- APP_NAVIGATION expanded with 7 entries to preserve visual sidebar
continuity (Evenementen at top-level + Beheer branch with 5 children).
All new entries use routeName: undefined until the corresponding v2
page lands (TODOs noted per entry); only Dashboard maps to v2-dashboard.
- AppSidebar: groups prop removed; passes only :collapsed to SidebarNav.
- OrganizerLayoutV2: useV2Nav(orgNavItems) plumbing retired; the layout
now renders <AppSidebar /> with no nav-data wiring.
- Tests: AppSidebar.spec drops the "passes groups prop to SidebarNav"
assertion; OrganizerLayoutV2.spec drops the "forwards orgNavItems"
assertion. New WorkspaceSwitcher no-sub regression spec (+2 tests).
- Storybook: SidebarNav.stories and AppSidebar.stories updated to no
longer thread navFixture/groups; WithActiveItem pushes v2-dashboard.
Position of WorkspaceSwitcher (Fix 3), workspace dropdown panel (Fix 5),
and AppBreadcrumb wiring (Fix 2) remain unchanged in P4 — both lands in
P5. The legacy useBreadcrumb composable also remains untouched until P5
(atomic with AppTopbar refactor).
Orphans flagged for follow-up cleanup (intentionally not deleted in P4):
useV2Nav composable + spec, V2NavGroup/V2NavItem types, sidebarNavActive
helper + spec, navFixture in stories/v2/_helpers.ts.
Suite delta: 575 → 575 (+2 WorkspaceSwitcher no-sub spec, -1 AppSidebar
groups-prop assertion, -1 OrganizerLayoutV2 groups-forward assertion).
vue-tsc clean. Scoped ESLint clean (0 errors).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per RFC-WS-PRIMEVUE-PLAN-2-5 §4 AD-2.5-D1 and §5.6 Fix 6. Single class
on <html> drives both PrimeVue darkModeSelector and Tailwind v4
@custom-variant dark — one toggle, two ecosystems react.
Audit findings (pre-change):
- applyDomAttributes was writing BOTH data-theme="dark" AND .dark on
documentElement. The historic data-theme write is the design-doc §4
mechanism that AD-2.5-D1 supersedes; the .dark toggle was already
correct (and is already paired with PrimeVue darkModeSelector: '.dark'
in plugins/primevue/index.ts:31, verified in P1).
- tailwind.css had NO @custom-variant dark directive — Tailwind v4
default is `prefers-color-scheme` (OS-controlled), so utility
`dark:` variants would have ignored the topbar toggle entirely.
- One stray .dark subtree wrapper in AppTopbar.stories.ts:56
(DarkTheme story) — deliberate Storybook isolation per its comment,
but in violation of AD-2.5-D1's single-source-of-truth rule.
Changes:
- useShellUiStore.applyDomAttributes(): removed data-theme write,
kept .dark class toggle on document.documentElement, kept
data-density (P6 wires density-toggle UI; density is an
orthogonal axis and unaffected). File-header comment updated to
cite AD-2.5-D1 + reference the Tailwind & PrimeVue mirror sites.
- assets/styles/tailwind.css: added
`@custom-variant dark (&:where(.dark, .dark *))` so utility
`dark:` classes resolve via the same .dark trigger.
- components-v2/layout/AppTopbar.stories.ts: stripped class="dark"
from the DarkTheme story's render wrapper. Story comment updated
to flag that visual confirmation now comes via parity-batch
Playwright (after Plan 2.5 closes), not Storybook autodocs. A
proper documentElement-mutating decorator is a backlog item.
- stores/__tests__/useShellUiStore.spec.ts: updated the existing
applyDomAttributes assertion to drop the data-theme expectation
(the write is gone); added a new `describe('applyDomAttributes
— dark mode (AD-2.5-D1)', …)` block with 2 specs (class toggle
reactive, no data-theme attribute written).
Re-grep verification — all three return 0 hits:
- stray .dark in v2 (excluding `dark:` utility prefixes)
- data-theme setAttribute calls in stores/
- [data-theme=…] CSS selectors anywhere
Suite delta: 573 → 575 (+2). vue-tsc clean. Scoped ESLint clean.
Note: darkModeSelector: '.dark' was already set in
plugins/primevue/index.ts:31 (verified in P1 audit) — the config
dimension of AD-2.5-D1 was satisfied before this commit; P3 closes
the store-side, Tailwind-side, and stray-class dimensions.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Per RFC-WS-PRIMEVUE-PLAN-2-5 §4 AD-2.5-T1. Establishes Inter as the
canonical Crewli body font via @fontsource/inter (local package, no
Google Fonts CDN).
Audit findings (pre-change):
- No @fontsource/public-sans package was installed.
- No <link> tag in index.html loaded Public Sans.
- Only one Public Sans reference existed in source: the vendored
Vuexy SCSS variable $font-family-custom at
src/@core/scss/template/libs/vuetify/_variables.scss, which drives
Vuetify's $body-font-family on legacy surfaces during F4.
- No src/main.css exists; the Tailwind v4 entry lives at
src/assets/styles/tailwind.css with no @theme block yet.
Changes:
- @fontsource/inter@^5.2.8 added to dependencies; weights
400/500/600/700 imported at main.ts ahead of tailwind.css.
- src/assets/styles/tailwind.css: new @theme block declaring
--font-sans Inter-first, plus :root --crewli-font-family and
html/body font-family applying that variable cascade-wide.
- src/@core/scss/template/libs/vuetify/_variables.scss:
$font-family-custom switched from the historical body font to
Inter (vendored edit, narrowly scoped, F6 removes @core/ entirely).
- tests/unit/styles/typography.spec.ts: 3-spec regression lock
(Tailwind direct stacks, Vuexy SCSS variable, zero historical
references in either file). File-content inspection — jsdom does
not cascade from imported stylesheets, so getComputedStyle would
always pass.
Suite delta: 570 → 573 (+3; the prompt's template was +2 but the
audit revealed two distinct font-config files, so each gets its own
assertion per the prompt's "cover all sites" rule). vue-tsc clean.
Scoped ESLint clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Per RFC-WS-PRIMEVUE-PLAN-2-5 §8 step 1. Foundation scaffolding only —
no shell fixes, no Public Sans removal, no useShellUiStore changes
(P2–P6 scope).
Implements:
- theme darkModeSelector verified at '.dark' (already correct in
plugins/primevue/index.ts — config site is here, not theme.ts).
- src/config/navigation.ts: APP_NAVIGATION registry per AD-2.5-B1
(Dashboard entry only — v2-dashboard is the only v2 route today).
- src/composables/useBreadcrumb.ts: walkNavTree pure helper +
useNavBreadcrumb composable per AD-2.5-B1. The legacy meta-based
useBreadcrumb is preserved (consumed by AppTopbar, P1 may not
touch AppTopbar); P4 retires it and renames useNavBreadcrumb.
- src/components-v2/layout/AppBreadcrumb.vue: layout primitive
wrapping PrimeVue Breadcrumb, consuming useNavBreadcrumb.
- Tests: walkNavTree (4 specs, co-located), AppBreadcrumb mount
(2 specs, tests/component/layouts/).
Suite 564 → 570 (+6, all new specs green). vue-tsc clean. Scoped
ESLint clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Vitest hoists vi.mock()/vi.hoisted() above all imports, so the
component import can sit with the other imports (import/first satisfied)
without the eslint-disable-next-line directives — the mock factories
only deref their refs at mount time. Honors the no-eslint-disable rule.
28/28 affected specs green.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The project's no-unused-vars only ignores all-underscore names (/^_+$/u);
`_bp` in the @vueuse/core useBreakpoints mock failed it. Latent since
Task 3 — masked because the whole-codebase `pnpm lint` stylish formatter
OOMs (RangeError on the legacy-code message volume) and emitted no
results. Scoped errors-only lint surfaced it. 21/21 specs still green.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Code-review follow-up. AppTopbar DarkTheme mutated <html>.dark which
leaked into Default/CompactDensity stacked on the same autodocs page;
scope dark to the story subtree via a `.dark` wrapper (Aura
darkModeSelector is the `.dark` class) — verified isolated on the docs
page. Also factor the duplicated render scaffolds in AppDialog (shared
dialogStory factory) and WorkspaceSwitcher (meta-level render).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces the Plan-1 skeleton stubs: OrganizerLayoutV2 now fills
AppShellV2's #sidebar/#topbar/#drawer slots with the ported AppSidebar /
AppTopbar / RightDrawer and sources orgNavItems via useV2Nav() (legal
now that OrganizerLayoutV2.vue is the layouts-v2 zone). AppShellV2 is
unchanged; its contract test stays green. New component test locks the
composition (right component per slot, :groups forwarded, no skeleton).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
AD-G2 ("OrganizerLayoutV2 wraps AppShellV2") was in tension with AD-G5:
src/layouts/OrganizerLayoutV2.vue classified as the v1 `layouts` zone,
which is deliberately barred from components-v2. New `layouts-v2` zone
(src/layouts/*V2*.vue, mode:file) gets pages-v2-equivalent v2 capability;
the v1 `layouts` zone is unchanged so v2 isolation is preserved. RFC
AD-G5 amended; locked by 3 boundaries-v2.spec.ts regression tests (7/7).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
vue/no-reserved-component-names is error-level; <dialog> is native HTML.
Matching is via the stubs key + findComponent reference, not the stub's
own name, so the rename is behaviour-neutral (14/14 tests still pass).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces crewli-starter's hand-rolled Teleport/scrim/keydown Escape
pattern with a typed PrimeVue Dialog wrapper. v-model:open via writable
computed; slots #tabs/#footer gated; 12 unit tests all passing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds :key="component" to <component :is="Body"> so opening drawer B
while A is open fully remounts (A's instance/state can't leak into B) —
a real defect for a primary shell overlay. Same-name reopen still
relies on the body reacting to prop changes (documented inline).
Companion test asserts the cross-component switch swaps the body
cleanly (A unmounts, B mounts). Addresses the Task 5 code-review
Important finding.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
unplugin-auto-import scans src/composables/; the new drawerRegistry
exports added global + vue-module declarations. auto-imports.d.ts is
tracked — keep it in sync (same precedent as prior composable syncs).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds composables/drawerRegistry.ts (boundary-safe register-by-call map:
register/resolve, zero static component imports — composables zone may
not import components, RFC-WS-GUI-REDESIGN AD-G5). Extends useRightDrawer
with resolveDrawerComponent (thin facade, prior API/tests preserved).
RightDrawer.vue: PrimeVue <Drawer position=right>, v-model:visible via a
writable computed ↔ useRightDrawer isOpen/close; title/flush read from the
open() props object (A4); dynamic <component :is> via resolveDrawerComponent
with a graceful empty state on null; #actions header slot retained. 18
unit/component tests.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- FIX A (IMPORTANT): PrimeVue Breadcrumb ignores `route` key; map non-last
items with `command: () => router.push(item.to)` for real client-side nav
- FIX B: add type="button" to all 6 native <button> chrome elements
- FIX C: authStore.logout() bare call matches project no-void pattern
- FIX D: document param-route edge case in toBreadcrumbItems
- FIX E: regression test asserts command+push on non-last, no command on last,
no `route` key on any item
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- useBreadcrumb composable: pure toBreadcrumbItems() helper + thin
useRoute() wrapper; route-driven, no prop coupling
- AppTopbar: hamburger→setMobileOpen, theme/density toggles→shell store,
PrimeVue Breadcrumb/OverlayBadge/Popover/Avatar/Menu; replaces all
manual document.mousedown listeners with PrimeVue built-in dismissal;
notifications stubbed (useNotificationStore is a toast queue, not a
feed — TODO TECH-WS-GUI-REDESIGN); sign-out→authStore.logout()
- Unit tests: 10 breadcrumb + 6 AppTopbar assertions (16 total, all pass)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CRITICAL: replace `lg:hidden` on PrimeVue Drawer with `v-if="isMobile"` so the
teleported portal/overlay is never created on desktop viewports regardless of
mobileOpen state. Replace useMediaQuery raw string in SidebarHeader with
useBreakpoints(breakpointsTailwind).smaller('lg') shared by both components.
Add desktop/mobile comments; adapt tests to useBreakpoints mock; add
Drawer-absent-on-desktop and aside w-16/w-64 width-class assertions (21 tests).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Ports crewli-starter's monolithic AppSidebar.vue into two typed production
components: SidebarHeader (the .brand block) and AppSidebar (composing
SidebarHeader + SidebarNav + WorkspaceSwitcher). AppSidebar renders a
permanent <aside> on desktop (lg+) and a PrimeVue Drawer on mobile, both
wired to useShellUiStore for collapse/mobile state.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Ports crewli-starter WorkspaceSwitcher into the Crewli SPA as production
TypeScript: PrimeVue Popover replaces the manual click-outside listener,
data is derived from useAuthStore/useOrganisationStore (no new store), gradient
pairs are deterministic via a new pure util with full Vitest coverage.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- FIX 1: Replace <button @click="router.push"> with <RouterLink custom>
+ <a> for real link semantics (middle-click, ⌘-click, screen-reader);
custom isNavItemActive prefix-match stays the active source of truth;
adds :aria-current="page" on active items; drops useRouter/router.push.
RouterLink to prop cast via itemTo() helper (RouteLocationRaw from
unplugin-vue-router) to satisfy typed RouterLinkTyped<RouteNamedMap>.
- FIX 2: Align .nav-item comment to actual template values (py-[9px]
rounded-md, not CSS vars); replace inaccurate Tailwind v3/v4 before:
composability justification in <style scoped> with the real reason
(accent bar at left:-10px is clipped by the overflow-y-auto nav).
- FIX 3: text-left → text-start (logical property, RTL-safe).
- FIX 4: Document id=route-name assumption in useV2Nav.ts with a
one-line comment at the id: assignment.
- FIX 5: Reword misleading "dotted names" spec description to state
the real invariant (id = v1 route name, already kebab-case).
- FIX 6: Add 2 tests — useV2Nav wrapper .value equality, and
consecutive-headings edge case (empty-items group produced).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
unplugin-auto-import scans src/composables/, so the new useV2Nav added
a global + vue-module declaration. auto-imports.d.ts is tracked; keep
it in sync (same precedent as Plan 1's useRightDrawer sync).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Ports crewli-starter's sidebar nav into the SPA as production TS:
V2NavGroup/V2NavItem types, a pure toV2NavGroups adapter wrapped by
useV2Nav(items) (composables zone can't import @/navigation, so the
v1 nav array is passed in — the layout supplies orgNavItems in Task 7),
a pure isNavItemActive helper, and SidebarNav.vue (props-only,
router-driven nav, route-based active state, collapsed mode, main.css
translated to Tailwind inline). 16 unit tests. Icon import is
allowed via the components-foundation bridge (no eslint-disable).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Plan-1 Task-4 added { type:'components-foundation', pattern:
'src/components/Icon.vue' } without mode:'file'. eslint-plugin-boundaries
defaults to folder mode, so the single-file pattern never matched and
Icon.vue fell through to the generic `components` catch-all — breaking
the sanctioned components-v2 -> Icon bridge (RFC AD-G5) for every v2
shell component. Plan-1's boundary test only exercised the forms/**
folder-glob edge so the gap was latent. Adds mode:'file' + a regression
test locking the components-v2 -> Icon.vue edge.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Storybook failed to boot ("module does not provide an export named
'default'"): .storybook/preview.ts did a default import while the
PrimeVue installer is a named-only export (deliberate — f218ac6e
switched to named to stop Vuexy registerPlugins() double-registration).
That commit missed updating preview.ts, so Storybook has been broken on
main since. Align the consumer with the producer (named import, same as
main.ts) rather than re-adding a default export. Pre-existing bug,
unrelated to the GUI-redesign merge.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
unplugin-auto-import scans src/composables/, so the new useRightDrawer
(Task 7) added a global + vue-module declaration. auto-imports.d.ts is
tracked (committed for editor/CI type resolution without a build), so
keep it in sync — same precedent as committing typed-router.d.ts. No
new symbol from useShellUiStore: src/stores is not in the auto-import
dirs (stores are imported explicitly), which is correct.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces the Task 3 stub in pages-v2/dashboard.vue with the boot-proof
page (data-testid v2-dashboard, correct definePage meta). Adds the
Playwright CT smoke (appshell-boot.spec.ts) that mounts AppShellV2 in
Chromium and asserts both the shell root and slot content are visible;
uses page scope for the root-element assertion (CT component locator
only matches descendants, not the root itself). Full Plan-1 gate green:
typecheck 0 new errors, eslint clean, 5 vitest files / 21 tests + 2
component tests, vite build succeeded, typed-router has v2-dashboard.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The vite-plugin-vue-meta-layouts layout name is a hand-maintained union
in env.d.ts (not auto-generated). Task 8 created OrganizerLayoutV2 and
Task 3's boot-proof page sets meta.layout: 'OrganizerLayoutV2', but the
union lacked the v2 entries so a typed definePage failed vue-tsc.
Registers both v2 layouts (PortalLayoutV2 added now to pre-empt the same
gap when portal v2 lands). Completes Task 8 (RFC-WS-GUI-REDESIGN AD-G2).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>