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
|
## Tech stack
|
||||||
|
|
||||||
- Backend: PHP 8.2+, Laravel 12, Sanctum, Spatie Permission, MySQL 8, Redis
|
- 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)
|
- Testing: PHPUnit (backend), Vitest (frontend)
|
||||||
|
|
||||||
## Quality gates
|
## Quality gates
|
||||||
@@ -166,54 +166,47 @@ right tier per the decision tree there before adding new tests.
|
|||||||
|
|
||||||
## Frontend rules (strict)
|
## 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.
|
||||||
|
|
||||||
```
|
**Always read [`PRIMEVUE_COMPONENTS.md`](./dev-docs/PRIMEVUE_COMPONENTS.md)
|
||||||
resources/vuexy-admin-v10.11.1/vue-version/typescript-version/full-version/
|
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:
|
#### On migrated surfaces (target state)
|
||||||
- `javascript-version/` — wrong language
|
|
||||||
- `starter-kit/` — incomplete, missing components
|
|
||||||
- Any other variant or version
|
|
||||||
|
|
||||||
Before implementing any Vuexy-based page or component, read the reference implementation from this path first:
|
PrimeVue is the framework. Follow [`PRIMEVUE_COMPONENTS.md`](./dev-docs/PRIMEVUE_COMPONENTS.md):
|
||||||
```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"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 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.
|
#### On un-migrated surfaces (legacy, transient)
|
||||||
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.
|
|
||||||
|
|
||||||
Concrete component rules:
|
Vuetify + Vuexy `@core/` components remain in use until the surface's F4
|
||||||
- Tables: `v-data-table-server` with server-side pagination — never client-side for API data
|
sub-package lands. When extending these surfaces during the transition:
|
||||||
- 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
|
|
||||||
|
|
||||||
**Before ANY frontend task:** read `/dev-docs/VUEXY_COMPONENTS.md` to verify
|
- Match the surrounding code (`<VBtn>`, `<VTextField>`, `<v-data-table-server>`, etc.)
|
||||||
you are using available components rather than building custom ones.
|
- 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
|
### Vue components
|
||||||
|
|
||||||
@@ -240,7 +233,16 @@ you are using available components rather than building custom ones.
|
|||||||
|
|
||||||
### Forms
|
### 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
|
- `ref({ field: ... })` for form state
|
||||||
- `VForm` ref + per-field rules drawn from `@core/utils/validators`
|
- `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
|
- A separate `errors: Ref<Record<string, string>>` for server-validation
|
||||||
feedback (mapped from 422 responses)
|
feedback (mapped from 422 responses)
|
||||||
- **Zod** for runtime validation of API payloads/responses (in
|
- **Zod** for runtime validation of API payloads/responses (in
|
||||||
`apps/app/src/schemas/*.ts`) — Zod schemas mirror backend Form Requests
|
`apps/app/src/schemas/*.ts`) — schemas already mirror backend Form
|
||||||
(field names, required/optional, types) and are the canonical contract
|
Requests and carry forward unchanged into the target state
|
||||||
- No inline validation logic in components
|
- No inline validation logic in components
|
||||||
|
|
||||||
VeeValidate is **NOT** the form library here. It was previously listed
|
A single form is either fully Zod-resolver-validated (target) or fully
|
||||||
but never actually adopted in any page; it was removed in commit
|
`:rules`-validated (legacy) — never a hybrid. VeeValidate is **NOT** in
|
||||||
`<sha>` (Session 4 follow-up). Reference forms: `apps/app/src/components/sections/CreateShiftDialog.vue`,
|
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/components/timetable/AddPerformanceDialog.vue`,
|
||||||
`apps/app/src/pages/register/[public_token].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
|
### UI
|
||||||
|
|
||||||
- Always use Vuexy/Vuetify for layout, forms, tables, dialogs
|
- 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 Vuetify utility class exists
|
- 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
|
- 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)
|
- **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
|
||||||
- Use Vuetify responsive props (`cols`, `sm`, `md`, `lg`) — no fixed pixel widths
|
- 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 Vuetify utility exists
|
- Custom CSS via `<style scoped>` only as last resort when no framework utility / `pt` API / Aura token can do the job
|
||||||
|
|
||||||
## Forbidden patterns
|
## 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]/`
|
13. Vue page component in `src/pages/[module]/`
|
||||||
14. Add route in Vue Router
|
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
|
## Diagnostic discipline: audit before assume
|
||||||
|
|
||||||
When debugging or fixing any bug, the first action is to verify the
|
When debugging or fixing any bug, the first action is to verify the
|
||||||
|
|||||||
Reference in New Issue
Block a user