docs(claude): point UI-framework conventions to PRIMEVUE_COMPONENTS.md; document migration-phase guidance
CLAUDE.md updated for the Vuetify→PrimeVue migration phase per RFC-WS-FRONTEND-PRIMEVUE F2: - Stack line: notes PrimeVue + Tailwind v4 as target, Vuetify still present on un-migrated surfaces - Replaced "Vuexy reference source" + "Vuexy-first strategy" sections with a single "UI framework strategy (migration-aware)" section that splits guidance into migrated / un-migrated / new surfaces and forwards to PRIMEVUE_COMPONENTS.md - Forms section now documents both target (@primevue/forms + Zod resolver via FormField) and legacy (ref + VForm + :rules) patterns, with the surface-level-consistency rule - UI section reframed: PrimeVue + Tailwind on migrated surfaces, Vuetify utilities on legacy surfaces, three-state pattern preserved on both - Order of work: framework note added for new pages during F4 Framework-agnostic sections (database, multi-tenancy, ULID, controllers, models, security, testing) untouched. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
113
CLAUDE.md
113
CLAUDE.md
@@ -11,7 +11,7 @@ Design document: `/dev-docs/design-document.md`
|
||||
## Tech stack
|
||||
|
||||
- Backend: PHP 8.2+, Laravel 12, Sanctum, Spatie Permission, MySQL 8, Redis
|
||||
- Frontend: TypeScript, Vue 3 (Composition API), Vuexy/Vuetify, Pinia, TanStack Query
|
||||
- Frontend: TypeScript, Vue 3 (Composition API), PrimeVue + Tailwind v4 (target state, migration in progress per [RFC-WS-FRONTEND-PRIMEVUE](./dev-docs/RFC-WS-FRONTEND-PRIMEVUE.md)) — Vuetify/Vuexy still present on un-migrated surfaces during F4; see [`PRIMEVUE_COMPONENTS.md`](./dev-docs/PRIMEVUE_COMPONENTS.md). Pinia, TanStack Query.
|
||||
- Testing: PHPUnit (backend), Vitest (frontend)
|
||||
|
||||
## Quality gates
|
||||
@@ -166,54 +166,47 @@ right tier per the decision tree there before adding new tests.
|
||||
|
||||
## Frontend rules (strict)
|
||||
|
||||
### Vuexy reference source (mandatory)
|
||||
### UI framework strategy (migration-aware)
|
||||
|
||||
When referencing Vuexy demo pages, components, or patterns, ALWAYS use the TypeScript Vue version at:
|
||||
The SPA is migrating Vuetify/Vuexy → PrimeVue + Tailwind v4 per
|
||||
[RFC-WS-FRONTEND-PRIMEVUE](./dev-docs/RFC-WS-FRONTEND-PRIMEVUE.md).
|
||||
During F4 (sub-packages F4a–F4d), both frameworks ship in the same build
|
||||
on different surfaces. The component-selection rules depend on which side
|
||||
of the migration the surface is on.
|
||||
|
||||
```
|
||||
resources/vuexy-admin-v10.11.1/vue-version/typescript-version/full-version/
|
||||
```
|
||||
**Always read [`PRIMEVUE_COMPONENTS.md`](./dev-docs/PRIMEVUE_COMPONENTS.md)
|
||||
before any frontend task** — it is the authoritative reference for
|
||||
component selection, theming, forms, and DataTable conventions across
|
||||
both phases.
|
||||
|
||||
This is the **ONLY** valid reference path. Never use:
|
||||
- `javascript-version/` — wrong language
|
||||
- `starter-kit/` — incomplete, missing components
|
||||
- Any other variant or version
|
||||
#### On migrated surfaces (target state)
|
||||
|
||||
Before implementing any Vuexy-based page or component, read the reference implementation from this path first:
|
||||
```bash
|
||||
# Example: find auth page references
|
||||
find resources/vuexy-admin-v10.11.1/vue-version/typescript-version/full-version/src/pages -name "*.vue" | grep -i "login\|auth"
|
||||
```
|
||||
PrimeVue is the framework. Follow [`PRIMEVUE_COMPONENTS.md`](./dev-docs/PRIMEVUE_COMPONENTS.md):
|
||||
|
||||
### Vuexy-first strategy
|
||||
1. **Can a Tailwind utility do this?** (layout, spacing, typography) → use it.
|
||||
2. **Does PrimeVue provide a component?** → use it (see §3 component mapping).
|
||||
3. **Forms** → `@primevue/forms` + Zod resolver via `<FormField>` (§5; full API in [RFC Appendix A](./dev-docs/RFC-WS-FRONTEND-PRIMEVUE.md#appendix-a--formfield-api-specification)).
|
||||
4. **DataTables** → `<DataTable>` with `:lazy="true"` for server-side (§6).
|
||||
5. **None of the above?** → cross-reference https://primevue.org/ for the closest match. Add a note in `PRIMEVUE_COMPONENTS.md` §3 if it's a recurring need.
|
||||
|
||||
Before writing ANY frontend component, consult `/dev-docs/VUEXY_COMPONENTS.md` and follow this decision tree:
|
||||
Customization order: Tailwind utilities (layout) → `pt` API (component-internal) → Aura preset extension (brand-wide) → `<style scoped>` (last resort, with comment).
|
||||
|
||||
1. **Can a standard Vuetify component do this?** → Use it with default props.
|
||||
Do not wrap it in a custom component.
|
||||
2. **Does Vuexy provide an @core component for this?** → Use it. Check
|
||||
`/dev-docs/VUEXY_COMPONENTS.md` section 1 for the full registry.
|
||||
3. **Does an existing Crewli page already solve a similar UI pattern?** →
|
||||
Copy that pattern exactly. Check `/dev-docs/VUEXY_COMPONENTS.md` section 3
|
||||
for established patterns and their reference implementations.
|
||||
4. **None of the above?** → Only then write custom code. Add `<style scoped>`
|
||||
with a comment explaining why Vuexy/Vuetify couldn't handle it.
|
||||
#### On un-migrated surfaces (legacy, transient)
|
||||
|
||||
Concrete component rules:
|
||||
- Tables: `v-data-table-server` with server-side pagination — never client-side for API data
|
||||
- Cards: `v-card` directly, or `AppCardActions` when collapse/refresh/remove is needed
|
||||
- Forms in dialogs: `v-dialog` + `v-card` + `v-form` — follow the established dialog pattern
|
||||
- Detail panels: `v-navigation-drawer` with `temporary` and `location="end"` — follow ShiftDetailPanel pattern
|
||||
- Date/time pickers: `AppDateTimePicker` from @core — never raw input[type=date]
|
||||
- Status indicators: `v-chip` with color prop — never custom styled spans
|
||||
- Loading states: `v-skeleton-loader` — never custom spinners
|
||||
- Error states: `v-alert` with retry button — never custom error divs
|
||||
- Empty states: `v-card` with icon + message + action button
|
||||
- Notifications: `v-snackbar` — never custom toast components
|
||||
- Page layout: `v-row` + `v-col` with Vuetify breakpoint props — never CSS grid or custom flexbox
|
||||
Vuetify + Vuexy `@core/` components remain in use until the surface's F4
|
||||
sub-package lands. When extending these surfaces during the transition:
|
||||
|
||||
**Before ANY frontend task:** read `/dev-docs/VUEXY_COMPONENTS.md` to verify
|
||||
you are using available components rather than building custom ones.
|
||||
- Match the surrounding code (`<VBtn>`, `<VTextField>`, `<v-data-table-server>`, etc.)
|
||||
- Reference the pre-F2 Vuexy registry via git: `git show 1c449ff6204cae6371da08c34ea8934d6b2ffcb8:dev-docs/VUEXY_COMPONENTS.md`
|
||||
- Vuexy template reference (when needed): `resources/vuexy-admin-v10.11.1/vue-version/typescript-version/full-version/` — TypeScript Vue version is the only valid path
|
||||
|
||||
Do **not** introduce PrimeVue components inside an un-migrated surface
|
||||
("no back-porting" — see `PRIMEVUE_COMPONENTS.md` §9).
|
||||
|
||||
#### On new surfaces (created during or after F4)
|
||||
|
||||
Start in PrimeVue. The migration phase is not a license to add new
|
||||
Vuetify code.
|
||||
|
||||
### Vue components
|
||||
|
||||
@@ -240,7 +233,16 @@ you are using available components rather than building custom ones.
|
||||
|
||||
### Forms
|
||||
|
||||
Canonical form pattern (used everywhere in the SPA):
|
||||
The canonical form pattern depends on the migration phase of the surface:
|
||||
|
||||
**Target state (migrated surfaces, new surfaces):** `@primevue/forms` +
|
||||
Zod resolver via the `<FormField>` wrapper. Full API specification in
|
||||
[RFC-WS-FRONTEND-PRIMEVUE Appendix A](./dev-docs/RFC-WS-FRONTEND-PRIMEVUE.md#appendix-a--formfield-api-specification);
|
||||
Crewli conventions in [`PRIMEVUE_COMPONENTS.md` §5](./dev-docs/PRIMEVUE_COMPONENTS.md).
|
||||
One Zod schema per form, field names mirror backend Form Request keys
|
||||
(snake_case), 422 errors merge via `useFormError(formRef)`.
|
||||
|
||||
**Legacy state (un-migrated surfaces, transient until each F4 sub-package):**
|
||||
|
||||
- `ref({ field: ... })` for form state
|
||||
- `VForm` ref + per-field rules drawn from `@core/utils/validators`
|
||||
@@ -248,13 +250,16 @@ Canonical form pattern (used everywhere in the SPA):
|
||||
- A separate `errors: Ref<Record<string, string>>` for server-validation
|
||||
feedback (mapped from 422 responses)
|
||||
- **Zod** for runtime validation of API payloads/responses (in
|
||||
`apps/app/src/schemas/*.ts`) — Zod schemas mirror backend Form Requests
|
||||
(field names, required/optional, types) and are the canonical contract
|
||||
`apps/app/src/schemas/*.ts`) — schemas already mirror backend Form
|
||||
Requests and carry forward unchanged into the target state
|
||||
- No inline validation logic in components
|
||||
|
||||
VeeValidate is **NOT** the form library here. It was previously listed
|
||||
but never actually adopted in any page; it was removed in commit
|
||||
`<sha>` (Session 4 follow-up). Reference forms: `apps/app/src/components/sections/CreateShiftDialog.vue`,
|
||||
A single form is either fully Zod-resolver-validated (target) or fully
|
||||
`:rules`-validated (legacy) — never a hybrid. VeeValidate is **NOT** in
|
||||
the stack on either side of the migration.
|
||||
|
||||
Reference forms (legacy pattern, will migrate during F4):
|
||||
`apps/app/src/components/sections/CreateShiftDialog.vue`,
|
||||
`apps/app/src/components/timetable/AddPerformanceDialog.vue`,
|
||||
`apps/app/src/pages/register/[public_token].vue`.
|
||||
|
||||
@@ -268,12 +273,12 @@ but never actually adopted in any page; it was removed in commit
|
||||
|
||||
### UI
|
||||
|
||||
- Always use Vuexy/Vuetify for layout, forms, tables, dialogs
|
||||
- Do not write custom CSS when a Vuetify utility class exists
|
||||
- Component framework selection: see "UI framework strategy" above and [`PRIMEVUE_COMPONENTS.md`](./dev-docs/PRIMEVUE_COMPONENTS.md). PrimeVue + Tailwind v4 on migrated/new surfaces; Vuetify on un-migrated surfaces during F4
|
||||
- Do not write custom CSS when a framework utility (Tailwind on migrated surfaces, Vuetify utilities on legacy surfaces) exists
|
||||
- Responsive: mobile-first, usable from 375px width
|
||||
- **Three states per page:** every data-driven view must handle loading (skeleton/spinner), error (`v-alert` with retry button), and empty (helpful message with action button)
|
||||
- Use Vuetify responsive props (`cols`, `sm`, `md`, `lg`) — no fixed pixel widths
|
||||
- Custom CSS via `<style scoped>` only as last resort when no Vuetify utility exists
|
||||
- **Three states per page:** every data-driven view must handle loading (skeleton), error (`Message` / `v-alert` with retry button), and empty (helpful message with action button) — both frameworks support this pattern
|
||||
- Responsive layout: Tailwind grid (`grid grid-cols-12 gap-4` + `col-span-N md:col-span-M`) on migrated surfaces; Vuetify `v-row` + `v-col` with breakpoint props on legacy surfaces — no fixed pixel widths
|
||||
- Custom CSS via `<style scoped>` only as last resort when no framework utility / `pt` API / Aura token can do the job
|
||||
|
||||
## Forbidden patterns
|
||||
|
||||
@@ -321,6 +326,12 @@ allowed only with a `TODO TECH-*` reference to a backlog item.
|
||||
13. Vue page component in `src/pages/[module]/`
|
||||
14. Add route in Vue Router
|
||||
|
||||
> **Framework note for steps 13–14 during F4 migration:** new pages
|
||||
> follow the PrimeVue + Tailwind conventions in [`PRIMEVUE_COMPONENTS.md`](./dev-docs/PRIMEVUE_COMPONENTS.md).
|
||||
> If the new module is grafted onto a not-yet-migrated surface (rare),
|
||||
> match the surrounding Vuetify style and let the surface's F4
|
||||
> sub-package migrate it later.
|
||||
|
||||
## Diagnostic discipline: audit before assume
|
||||
|
||||
When debugging or fixing any bug, the first action is to verify the
|
||||
|
||||
Reference in New Issue
Block a user