spec: refine 057 + extend 058 #67
173
.ai/guidelines/filament-v5-blueprint.md
Normal file
173
.ai/guidelines/filament-v5-blueprint.md
Normal file
@ -0,0 +1,173 @@
|
||||
## Source of Truth
|
||||
If any Filament behavior is uncertain, lookup the exact section in:
|
||||
- docs/research/filament-v5-notes.md
|
||||
and prefer that over guesses.
|
||||
|
||||
# SECTION B — FILAMENT V5 BLUEPRINT (EXECUTABLE RULES)
|
||||
|
||||
# Filament Blueprint (v5)
|
||||
|
||||
## 1) Non-negotiables
|
||||
- Filament v5 requires Livewire v4.0+.
|
||||
- Laravel 11+: register panel providers in `bootstrap/providers.php` (never `bootstrap/app.php`).
|
||||
- Global search hard rule: If a Resource should appear in Global Search, it must have an Edit or View page; otherwise it will return no results.
|
||||
- Destructive actions must execute via `Action::make(...)->action(...)` and include `->requiresConfirmation()` (no exceptions).
|
||||
- Prefer render hooks + CSS hook classes over publishing Filament internal views.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/upgrade-guide
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
- https://filamentphp.com/docs/5.x/actions/modals
|
||||
- https://filamentphp.com/docs/5.x/advanced/render-hooks
|
||||
- https://filamentphp.com/docs/5.x/styling/css-hooks
|
||||
|
||||
## 2) Directory & naming conventions
|
||||
- Default to Filament discovery conventions for Resources/Pages/Widgets unless you adopt modular architecture.
|
||||
- Clusters: directory layout is recommended, not mandatory; functional behavior depends on `$cluster`.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/navigation/clusters
|
||||
- https://filamentphp.com/docs/5.x/advanced/modular-architecture
|
||||
|
||||
## 3) Panel setup defaults
|
||||
- Default to a single `/admin` panel unless multiple audiences/configs demand multiple panels.
|
||||
- Verify provider registration (Laravel 11+: `bootstrap/providers.php`) when adding a panel.
|
||||
- Use `path()` carefully; treat `path('')` as a high-risk change requiring route conflict review.
|
||||
- Assets policy:
|
||||
- Panel-only assets: register via panel config.
|
||||
- Shared/plugin assets: register via `FilamentAsset::register()`.
|
||||
- Deployment must include `php artisan filament:assets`.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
|
||||
## 4) Navigation & information architecture
|
||||
- Use nav groups + sort order intentionally; apply conditional visibility for clarity, but enforce authorization separately.
|
||||
- Use clusters to introduce hierarchy and sub-navigation when sidebar complexity grows.
|
||||
- Treat cluster code structure as a recommendation (organizational benefit), not a required rule.
|
||||
- User menu:
|
||||
- Configure via `userMenuItems()` with Action objects.
|
||||
- Never put destructive actions there without confirmation + authorization.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/navigation/overview
|
||||
- https://filamentphp.com/docs/5.x/navigation/clusters
|
||||
- https://filamentphp.com/docs/5.x/navigation/user-menu
|
||||
|
||||
## 5) Resource patterns
|
||||
- Default to Resources for CRUD; use custom pages for non-CRUD tools/workflows.
|
||||
- Global search:
|
||||
- If a resource is intended for global search: ensure Edit/View page exists.
|
||||
- Otherwise disable global search for that resource (don’t “expect it to work”).
|
||||
- If global search renders relationship-backed details: eager-load via global search query override.
|
||||
- For very large datasets: consider disabling term splitting (only when needed).
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/resources/overview
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
|
||||
## 6) Page lifecycle & query rules
|
||||
- Treat relationship-backed rendering in aggregate contexts (global search details, list summaries) as requiring eager loading.
|
||||
- Prefer render hooks for layout injection; avoid publishing internal views.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
- https://filamentphp.com/docs/5.x/advanced/render-hooks
|
||||
|
||||
## 7) Infolists vs RelationManagers (decision tree)
|
||||
- Interactive CRUD / attach / detach under owner record → RelationManager.
|
||||
- Pick existing related record(s) inside owner form → Select / CheckboxList relationship fields.
|
||||
- Inline CRUD inside owner form → Repeater.
|
||||
- Default performance stance: RelationManagers stay lazy-loaded unless explicit UX justification exists.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/resources/managing-relationships
|
||||
- https://filamentphp.com/docs/5.x/infolists/overview
|
||||
|
||||
## 8) Form patterns (validation, reactivity, state)
|
||||
- Default: minimize server-driven reactivity; only use it when schema/visibility/requirements must change server-side.
|
||||
- Prefer “on blur” semantics for chatty inputs when using reactive behavior (per docs patterns).
|
||||
- Custom field views must obey state binding modifiers.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/forms/overview
|
||||
- https://filamentphp.com/docs/5.x/forms/custom-fields
|
||||
|
||||
## 9) Table & action patterns
|
||||
- Tables: always define a meaningful empty state (and empty-state actions where appropriate).
|
||||
- Actions:
|
||||
- Execution actions use `->action(...)`.
|
||||
- Destructive actions add `->requiresConfirmation()`.
|
||||
- Navigation-only actions should use `->url(...)`.
|
||||
- UNVERIFIED: do not assert modal/confirmation behavior for URL-only actions unless verified.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/tables/empty-state
|
||||
- https://filamentphp.com/docs/5.x/actions/modals
|
||||
|
||||
## 10) Authorization & security
|
||||
- Enforce panel access in non-local environments as documented.
|
||||
- UI visibility is not security; enforce policies/access checks in addition to hiding UI.
|
||||
- Bulk operations: explicitly decide between “Any” policy methods vs per-record authorization.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/users/overview
|
||||
- https://filamentphp.com/docs/5.x/resources/deleting-records
|
||||
|
||||
## 11) Notifications & UX feedback
|
||||
- Default to explicit success/error notifications for user-triggered mutations that aren’t instantly obvious.
|
||||
- Treat polling as a cost; set intervals intentionally where polling is used.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/notifications/overview
|
||||
- https://filamentphp.com/docs/5.x/widgets/stats-overview
|
||||
|
||||
## 12) Performance defaults
|
||||
- Heavy assets: prefer on-demand loading (`loadedOnRequest()` + `x-load-css` / `x-load-js`) for heavy dependencies.
|
||||
- Styling overrides use CSS hook classes; layout injection uses render hooks; avoid view publishing.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
- https://filamentphp.com/docs/5.x/styling/css-hooks
|
||||
- https://filamentphp.com/docs/5.x/advanced/render-hooks
|
||||
|
||||
## 13) Testing requirements
|
||||
- Test pages/relation managers/widgets as Livewire components.
|
||||
- Test actions using Filament’s action testing guidance.
|
||||
- Do not mount non-Livewire classes in Livewire tests.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/testing/overview
|
||||
- https://filamentphp.com/docs/5.x/testing/testing-actions
|
||||
|
||||
## 14) Forbidden patterns
|
||||
- Mixing Filament v3/v4 APIs into v5 code.
|
||||
- Any mention of Livewire v3 for Filament v5.
|
||||
- Registering panel providers in `bootstrap/app.php` on Laravel 11+.
|
||||
- Destructive actions without `->requiresConfirmation()`.
|
||||
- Shipping heavy assets globally when on-demand loading fits.
|
||||
- Publishing Filament internal views as a default customization technique.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/upgrade-guide
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/actions/modals
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
|
||||
## 15) Agent output contract
|
||||
For any implementation request, the agent must explicitly state:
|
||||
1) Livewire v4.0+ compliance.
|
||||
2) Provider registration location (Laravel 11+: `bootstrap/providers.php`).
|
||||
3) For each globally searchable resource: whether it has Edit/View page (or global search is disabled).
|
||||
4) Which actions are destructive and how confirmation + authorization is handled.
|
||||
5) Asset strategy: global vs on-demand and where `filament:assets` runs in deploy.
|
||||
6) Testing plan: which pages/widgets/relation managers/actions are covered.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/upgrade-guide
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
- https://filamentphp.com/docs/5.x/testing/testing-actions
|
||||
79
.ai/guidelines/filament-v5-checklist.md
Normal file
79
.ai/guidelines/filament-v5-checklist.md
Normal file
@ -0,0 +1,79 @@
|
||||
# SECTION C — AI REVIEW CHECKLIST (STRICT CHECKBOXES)
|
||||
|
||||
## Version Safety
|
||||
- [ ] Filament v5 explicitly targets Livewire v4.0+ (no Livewire v3 references anywhere).
|
||||
- Source: https://filamentphp.com/docs/5.x/upgrade-guide — “Upgrading Livewire”
|
||||
- [ ] All references are Filament `/docs/5.x/` only (no v3/v4 docs, no legacy APIs).
|
||||
- [ ] Upgrade assumptions match the v5 upgrade guide requirements and steps.
|
||||
- Source: https://filamentphp.com/docs/5.x/upgrade-guide — “New requirements”
|
||||
|
||||
## Panel & Navigation
|
||||
- [ ] Laravel 11+: panel providers are registered in `bootstrap/providers.php` (not `bootstrap/app.php`).
|
||||
- Source: https://filamentphp.com/docs/5.x/panel-configuration — “Creating a new panel”
|
||||
- [ ] Panel `path()` choices are intentional and do not conflict with existing routes (especially `path('')`).
|
||||
- Source: https://filamentphp.com/docs/5.x/panel-configuration — “Changing the path”
|
||||
- [ ] Cluster usage is correctly configured (discovery + `$cluster` assignments).
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/clusters — “Creating a cluster”
|
||||
- [ ] Cluster semantics (sub-navigation + grouped navigation behavior) are understood and verified against the clusters docs.
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/clusters — “Introduction”
|
||||
- [ ] Cluster directory structure is treated as recommended, not mandatory.
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/clusters — “Code structure recommendations for panels using clusters”
|
||||
- [ ] User menu items are registered via `userMenuItems()` and permission-gated where needed.
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/user-menu — “Introduction”
|
||||
|
||||
## Resource Structure
|
||||
- [ ] `$recordTitleAttribute` is set for any resource intended for global search.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/overview — “Record titles”
|
||||
- [ ] Hard rule enforced: every globally searchable resource has an Edit or View page; otherwise global search is disabled for it.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/global-search — “Setting global search result titles”
|
||||
- [ ] Relationship-backed global search details are eager-loaded via the global search query override.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/global-search — “Adding extra details to global search results”
|
||||
|
||||
## Infolists & Relations
|
||||
- [ ] Each relationship uses the correct tool (RelationManager vs Select/CheckboxList vs Repeater) based on required interaction.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/managing-relationships — “Choosing the right tool for the job”
|
||||
- [ ] RelationManagers remain lazy-loaded by default unless there’s an explicit UX justification.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/managing-relationships — “Disabling lazy loading”
|
||||
|
||||
## Forms
|
||||
- [ ] Server-driven reactivity is minimal; chatty inputs do not trigger network requests unnecessarily.
|
||||
- Source: https://filamentphp.com/docs/5.x/forms/overview — “Reactive fields on blur”
|
||||
- [ ] Custom field views obey state binding modifiers (no hardcoded `wire:model` without modifiers).
|
||||
- Source: https://filamentphp.com/docs/5.x/forms/custom-fields — “Obeying state binding modifiers”
|
||||
|
||||
## Tables & Actions
|
||||
- [ ] Tables define a meaningful empty state (and empty-state actions where appropriate).
|
||||
- Source: https://filamentphp.com/docs/5.x/tables/empty-state — “Adding empty state actions”
|
||||
- [ ] All destructive actions execute via `->action(...)` and include `->requiresConfirmation()`.
|
||||
- Source: https://filamentphp.com/docs/5.x/actions/modals — “Confirmation modals”
|
||||
- [ ] No checklist rule assumes confirmation/modals for `->url(...)` actions unless verified in docs (UNVERIFIED behavior must not be asserted as fact).
|
||||
- Source: https://filamentphp.com/docs/5.x/actions/modals — “Confirmation modals”
|
||||
|
||||
## Authorization & Security
|
||||
- [ ] Panel access is enforced for non-local environments as documented.
|
||||
- Source: https://filamentphp.com/docs/5.x/users/overview — “Authorizing access to the panel”
|
||||
- [ ] UI visibility is not treated as authorization; policies/access checks still enforce boundaries.
|
||||
- [ ] Bulk operations intentionally choose between “Any” policy methods vs per-record authorization where required.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/deleting-records — “Authorization”
|
||||
|
||||
## UX & Notifications
|
||||
- [ ] User-triggered mutations provide explicit success/error notifications when outcomes aren’t instantly obvious.
|
||||
- Source: https://filamentphp.com/docs/5.x/notifications/overview — “Introduction”
|
||||
- [ ] Polling (widgets/notifications) is configured intentionally (interval set or disabled) to control load.
|
||||
- Source: https://filamentphp.com/docs/5.x/widgets/stats-overview — “Live updating stats (polling)”
|
||||
|
||||
## Performance
|
||||
- [ ] Heavy frontend assets are loaded on-demand using `loadedOnRequest()` + `x-load-css` / `x-load-js` where appropriate.
|
||||
- Source: https://filamentphp.com/docs/5.x/advanced/assets — “Lazy loading CSS” / “Lazy loading JavaScript”
|
||||
- [ ] Styling overrides use CSS hook classes discovered via DevTools (no brittle selectors by default).
|
||||
- Source: https://filamentphp.com/docs/5.x/styling/css-hooks — “Discovering hook classes”
|
||||
|
||||
## Testing
|
||||
- [ ] Livewire tests mount Filament pages/relation managers/widgets (Livewire components), not static resource classes.
|
||||
- Source: https://filamentphp.com/docs/5.x/testing/overview — “What is a Livewire component when using Filament?”
|
||||
- [ ] Actions that mutate data are covered using Filament’s action testing guidance.
|
||||
- Source: https://filamentphp.com/docs/5.x/testing/testing-actions — “Testing actions”
|
||||
|
||||
## Deployment / Ops
|
||||
- [ ] `php artisan filament:assets` is included in the deployment process when using registered assets.
|
||||
- Source: https://filamentphp.com/docs/5.x/advanced/assets — “The FilamentAsset facade”
|
||||
@ -1,5 +1,14 @@
|
||||
{
|
||||
"general": {
|
||||
"previewFeatures": false
|
||||
},
|
||||
"mcpServers": {
|
||||
"laravel-boost": {
|
||||
"command": "vendor/bin/sail",
|
||||
"args": [
|
||||
"artisan",
|
||||
"boost:mcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
5
.github/agents/copilot-instructions.md
vendored
5
.github/agents/copilot-instructions.md
vendored
@ -11,6 +11,7 @@ ## Active Technologies
|
||||
- PHP 8.4.x (Laravel 12) + Laravel 12, Filament v4, Livewire v3 (feat/047-inventory-foundations-nodes)
|
||||
- PostgreSQL (JSONB for `InventoryItem.meta_jsonb`) (feat/047-inventory-foundations-nodes)
|
||||
- PostgreSQL (JSONB in `operation_runs.context`, `operation_runs.summary_counts`) (056-remove-legacy-bulkops)
|
||||
- PHP 8.4.15 (Laravel 12.47.0) + Filament v5.0.0, Livewire v4.0.1 (058-tenant-ui-polish)
|
||||
|
||||
- PHP 8.4.15 (feat/005-bulk-operations)
|
||||
|
||||
@ -30,9 +31,9 @@ ## Code Style
|
||||
PHP 8.4.15: Follow standard conventions
|
||||
|
||||
## Recent Changes
|
||||
- 058-tenant-ui-polish: Added PHP 8.4.15 (Laravel 12.47.0) + Filament v5.0.0, Livewire v4.0.1
|
||||
- 058-tenant-ui-polish: Added [if applicable, e.g., PostgreSQL, CoreData, files or N/A]
|
||||
- 056-remove-legacy-bulkops: Added PHP 8.4.x + Laravel 12, Filament v4, Livewire v3
|
||||
- feat/047-inventory-foundations-nodes: Added PHP 8.4.x (Laravel 12) + Laravel 12, Filament v4, Livewire v3
|
||||
- feat/042-inventory-dependencies-graph: Added PHP 8.4.x + Laravel 12, Filament v4, Livewire v3
|
||||
|
||||
|
||||
<!-- MANUAL ADDITIONS START -->
|
||||
|
||||
683
.github/copilot-instructions.md
vendored
Normal file
683
.github/copilot-instructions.md
vendored
Normal file
@ -0,0 +1,683 @@
|
||||
<laravel-boost-guidelines>
|
||||
=== .ai/filament-v5-blueprint rules ===
|
||||
|
||||
## Source of Truth
|
||||
If any Filament behavior is uncertain, lookup the exact section in:
|
||||
- docs/research/filament-v5-notes.md
|
||||
and prefer that over guesses.
|
||||
|
||||
# SECTION B — FILAMENT V5 BLUEPRINT (EXECUTABLE RULES)
|
||||
|
||||
# Filament Blueprint (v5)
|
||||
|
||||
## 1) Non-negotiables
|
||||
- Filament v5 requires Livewire v4.0+.
|
||||
- Laravel 11+: register panel providers in `bootstrap/providers.php` (never `bootstrap/app.php`).
|
||||
- Global search hard rule: If a Resource should appear in Global Search, it must have an Edit or View page; otherwise it will return no results.
|
||||
- Destructive actions must execute via `Action::make(...)->action(...)` and include `->requiresConfirmation()` (no exceptions).
|
||||
- Prefer render hooks + CSS hook classes over publishing Filament internal views.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/upgrade-guide
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
- https://filamentphp.com/docs/5.x/actions/modals
|
||||
- https://filamentphp.com/docs/5.x/advanced/render-hooks
|
||||
- https://filamentphp.com/docs/5.x/styling/css-hooks
|
||||
|
||||
## 2) Directory & naming conventions
|
||||
- Default to Filament discovery conventions for Resources/Pages/Widgets unless you adopt modular architecture.
|
||||
- Clusters: directory layout is recommended, not mandatory; functional behavior depends on `$cluster`.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/navigation/clusters
|
||||
- https://filamentphp.com/docs/5.x/advanced/modular-architecture
|
||||
|
||||
## 3) Panel setup defaults
|
||||
- Default to a single `/admin` panel unless multiple audiences/configs demand multiple panels.
|
||||
- Verify provider registration (Laravel 11+: `bootstrap/providers.php`) when adding a panel.
|
||||
- Use `path()` carefully; treat `path('')` as a high-risk change requiring route conflict review.
|
||||
- Assets policy:
|
||||
- Panel-only assets: register via panel config.
|
||||
- Shared/plugin assets: register via `FilamentAsset::register()`.
|
||||
- Deployment must include `php artisan filament:assets`.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
|
||||
## 4) Navigation & information architecture
|
||||
- Use nav groups + sort order intentionally; apply conditional visibility for clarity, but enforce authorization separately.
|
||||
- Use clusters to introduce hierarchy and sub-navigation when sidebar complexity grows.
|
||||
- Treat cluster code structure as a recommendation (organizational benefit), not a required rule.
|
||||
- User menu:
|
||||
- Configure via `userMenuItems()` with Action objects.
|
||||
- Never put destructive actions there without confirmation + authorization.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/navigation/overview
|
||||
- https://filamentphp.com/docs/5.x/navigation/clusters
|
||||
- https://filamentphp.com/docs/5.x/navigation/user-menu
|
||||
|
||||
## 5) Resource patterns
|
||||
- Default to Resources for CRUD; use custom pages for non-CRUD tools/workflows.
|
||||
- Global search:
|
||||
- If a resource is intended for global search: ensure Edit/View page exists.
|
||||
- Otherwise disable global search for that resource (don’t “expect it to work”).
|
||||
- If global search renders relationship-backed details: eager-load via global search query override.
|
||||
- For very large datasets: consider disabling term splitting (only when needed).
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/resources/overview
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
|
||||
## 6) Page lifecycle & query rules
|
||||
- Treat relationship-backed rendering in aggregate contexts (global search details, list summaries) as requiring eager loading.
|
||||
- Prefer render hooks for layout injection; avoid publishing internal views.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
- https://filamentphp.com/docs/5.x/advanced/render-hooks
|
||||
|
||||
## 7) Infolists vs RelationManagers (decision tree)
|
||||
- Interactive CRUD / attach / detach under owner record → RelationManager.
|
||||
- Pick existing related record(s) inside owner form → Select / CheckboxList relationship fields.
|
||||
- Inline CRUD inside owner form → Repeater.
|
||||
- Default performance stance: RelationManagers stay lazy-loaded unless explicit UX justification exists.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/resources/managing-relationships
|
||||
- https://filamentphp.com/docs/5.x/infolists/overview
|
||||
|
||||
## 8) Form patterns (validation, reactivity, state)
|
||||
- Default: minimize server-driven reactivity; only use it when schema/visibility/requirements must change server-side.
|
||||
- Prefer “on blur” semantics for chatty inputs when using reactive behavior (per docs patterns).
|
||||
- Custom field views must obey state binding modifiers.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/forms/overview
|
||||
- https://filamentphp.com/docs/5.x/forms/custom-fields
|
||||
|
||||
## 9) Table & action patterns
|
||||
- Tables: always define a meaningful empty state (and empty-state actions where appropriate).
|
||||
- Actions:
|
||||
- Execution actions use `->action(...)`.
|
||||
- Destructive actions add `->requiresConfirmation()`.
|
||||
- Navigation-only actions should use `->url(...)`.
|
||||
- UNVERIFIED: do not assert modal/confirmation behavior for URL-only actions unless verified.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/tables/empty-state
|
||||
- https://filamentphp.com/docs/5.x/actions/modals
|
||||
|
||||
## 10) Authorization & security
|
||||
- Enforce panel access in non-local environments as documented.
|
||||
- UI visibility is not security; enforce policies/access checks in addition to hiding UI.
|
||||
- Bulk operations: explicitly decide between “Any” policy methods vs per-record authorization.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/users/overview
|
||||
- https://filamentphp.com/docs/5.x/resources/deleting-records
|
||||
|
||||
## 11) Notifications & UX feedback
|
||||
- Default to explicit success/error notifications for user-triggered mutations that aren’t instantly obvious.
|
||||
- Treat polling as a cost; set intervals intentionally where polling is used.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/notifications/overview
|
||||
- https://filamentphp.com/docs/5.x/widgets/stats-overview
|
||||
|
||||
## 12) Performance defaults
|
||||
- Heavy assets: prefer on-demand loading (`loadedOnRequest()` + `x-load-css` / `x-load-js`) for heavy dependencies.
|
||||
- Styling overrides use CSS hook classes; layout injection uses render hooks; avoid view publishing.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
- https://filamentphp.com/docs/5.x/styling/css-hooks
|
||||
- https://filamentphp.com/docs/5.x/advanced/render-hooks
|
||||
|
||||
## 13) Testing requirements
|
||||
- Test pages/relation managers/widgets as Livewire components.
|
||||
- Test actions using Filament’s action testing guidance.
|
||||
- Do not mount non-Livewire classes in Livewire tests.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/testing/overview
|
||||
- https://filamentphp.com/docs/5.x/testing/testing-actions
|
||||
|
||||
## 14) Forbidden patterns
|
||||
- Mixing Filament v3/v4 APIs into v5 code.
|
||||
- Any mention of Livewire v3 for Filament v5.
|
||||
- Registering panel providers in `bootstrap/app.php` on Laravel 11+.
|
||||
- Destructive actions without `->requiresConfirmation()`.
|
||||
- Shipping heavy assets globally when on-demand loading fits.
|
||||
- Publishing Filament internal views as a default customization technique.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/upgrade-guide
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/actions/modals
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
|
||||
## 15) Agent output contract
|
||||
For any implementation request, the agent must explicitly state:
|
||||
1) Livewire v4.0+ compliance.
|
||||
2) Provider registration location (Laravel 11+: `bootstrap/providers.php`).
|
||||
3) For each globally searchable resource: whether it has Edit/View page (or global search is disabled).
|
||||
4) Which actions are destructive and how confirmation + authorization is handled.
|
||||
5) Asset strategy: global vs on-demand and where `filament:assets` runs in deploy.
|
||||
6) Testing plan: which pages/widgets/relation managers/actions are covered.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/upgrade-guide
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
- https://filamentphp.com/docs/5.x/testing/testing-actions
|
||||
|
||||
|
||||
=== .ai/filament-v5-checklist rules ===
|
||||
|
||||
# SECTION C — AI REVIEW CHECKLIST (STRICT CHECKBOXES)
|
||||
|
||||
## Version Safety
|
||||
- [ ] Filament v5 explicitly targets Livewire v4.0+ (no Livewire v3 references anywhere).
|
||||
- Source: https://filamentphp.com/docs/5.x/upgrade-guide — “Upgrading Livewire”
|
||||
- [ ] All references are Filament `/docs/5.x/` only (no v3/v4 docs, no legacy APIs).
|
||||
- [ ] Upgrade assumptions match the v5 upgrade guide requirements and steps.
|
||||
- Source: https://filamentphp.com/docs/5.x/upgrade-guide — “New requirements”
|
||||
|
||||
## Panel & Navigation
|
||||
- [ ] Laravel 11+: panel providers are registered in `bootstrap/providers.php` (not `bootstrap/app.php`).
|
||||
- Source: https://filamentphp.com/docs/5.x/panel-configuration — “Creating a new panel”
|
||||
- [ ] Panel `path()` choices are intentional and do not conflict with existing routes (especially `path('')`).
|
||||
- Source: https://filamentphp.com/docs/5.x/panel-configuration — “Changing the path”
|
||||
- [ ] Cluster usage is correctly configured (discovery + `$cluster` assignments).
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/clusters — “Creating a cluster”
|
||||
- [ ] Cluster semantics (sub-navigation + grouped navigation behavior) are understood and verified against the clusters docs.
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/clusters — “Introduction”
|
||||
- [ ] Cluster directory structure is treated as recommended, not mandatory.
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/clusters — “Code structure recommendations for panels using clusters”
|
||||
- [ ] User menu items are registered via `userMenuItems()` and permission-gated where needed.
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/user-menu — “Introduction”
|
||||
|
||||
## Resource Structure
|
||||
- [ ] `$recordTitleAttribute` is set for any resource intended for global search.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/overview — “Record titles”
|
||||
- [ ] Hard rule enforced: every globally searchable resource has an Edit or View page; otherwise global search is disabled for it.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/global-search — “Setting global search result titles”
|
||||
- [ ] Relationship-backed global search details are eager-loaded via the global search query override.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/global-search — “Adding extra details to global search results”
|
||||
|
||||
## Infolists & Relations
|
||||
- [ ] Each relationship uses the correct tool (RelationManager vs Select/CheckboxList vs Repeater) based on required interaction.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/managing-relationships — “Choosing the right tool for the job”
|
||||
- [ ] RelationManagers remain lazy-loaded by default unless there’s an explicit UX justification.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/managing-relationships — “Disabling lazy loading”
|
||||
|
||||
## Forms
|
||||
- [ ] Server-driven reactivity is minimal; chatty inputs do not trigger network requests unnecessarily.
|
||||
- Source: https://filamentphp.com/docs/5.x/forms/overview — “Reactive fields on blur”
|
||||
- [ ] Custom field views obey state binding modifiers (no hardcoded `wire:model` without modifiers).
|
||||
- Source: https://filamentphp.com/docs/5.x/forms/custom-fields — “Obeying state binding modifiers”
|
||||
|
||||
## Tables & Actions
|
||||
- [ ] Tables define a meaningful empty state (and empty-state actions where appropriate).
|
||||
- Source: https://filamentphp.com/docs/5.x/tables/empty-state — “Adding empty state actions”
|
||||
- [ ] All destructive actions execute via `->action(...)` and include `->requiresConfirmation()`.
|
||||
- Source: https://filamentphp.com/docs/5.x/actions/modals — “Confirmation modals”
|
||||
- [ ] No checklist rule assumes confirmation/modals for `->url(...)` actions unless verified in docs (UNVERIFIED behavior must not be asserted as fact).
|
||||
- Source: https://filamentphp.com/docs/5.x/actions/modals — “Confirmation modals”
|
||||
|
||||
## Authorization & Security
|
||||
- [ ] Panel access is enforced for non-local environments as documented.
|
||||
- Source: https://filamentphp.com/docs/5.x/users/overview — “Authorizing access to the panel”
|
||||
- [ ] UI visibility is not treated as authorization; policies/access checks still enforce boundaries.
|
||||
- [ ] Bulk operations intentionally choose between “Any” policy methods vs per-record authorization where required.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/deleting-records — “Authorization”
|
||||
|
||||
## UX & Notifications
|
||||
- [ ] User-triggered mutations provide explicit success/error notifications when outcomes aren’t instantly obvious.
|
||||
- Source: https://filamentphp.com/docs/5.x/notifications/overview — “Introduction”
|
||||
- [ ] Polling (widgets/notifications) is configured intentionally (interval set or disabled) to control load.
|
||||
- Source: https://filamentphp.com/docs/5.x/widgets/stats-overview — “Live updating stats (polling)”
|
||||
|
||||
## Performance
|
||||
- [ ] Heavy frontend assets are loaded on-demand using `loadedOnRequest()` + `x-load-css` / `x-load-js` where appropriate.
|
||||
- Source: https://filamentphp.com/docs/5.x/advanced/assets — “Lazy loading CSS” / “Lazy loading JavaScript”
|
||||
- [ ] Styling overrides use CSS hook classes discovered via DevTools (no brittle selectors by default).
|
||||
- Source: https://filamentphp.com/docs/5.x/styling/css-hooks — “Discovering hook classes”
|
||||
|
||||
## Testing
|
||||
- [ ] Livewire tests mount Filament pages/relation managers/widgets (Livewire components), not static resource classes.
|
||||
- Source: https://filamentphp.com/docs/5.x/testing/overview — “What is a Livewire component when using Filament?”
|
||||
- [ ] Actions that mutate data are covered using Filament’s action testing guidance.
|
||||
- Source: https://filamentphp.com/docs/5.x/testing/testing-actions — “Testing actions”
|
||||
|
||||
## Deployment / Ops
|
||||
- [ ] `php artisan filament:assets` is included in the deployment process when using registered assets.
|
||||
- Source: https://filamentphp.com/docs/5.x/advanced/assets — “The FilamentAsset facade”
|
||||
|
||||
|
||||
=== foundation rules ===
|
||||
|
||||
# Laravel Boost Guidelines
|
||||
|
||||
The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to enhance the user's satisfaction building Laravel applications.
|
||||
|
||||
## Foundational Context
|
||||
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
|
||||
|
||||
- php - 8.4.15
|
||||
- filament/filament (FILAMENT) - v5
|
||||
- laravel/framework (LARAVEL) - v12
|
||||
- laravel/prompts (PROMPTS) - v0
|
||||
- livewire/livewire (LIVEWIRE) - v4
|
||||
- laravel/mcp (MCP) - v0
|
||||
- laravel/pint (PINT) - v1
|
||||
- laravel/sail (SAIL) - v1
|
||||
- pestphp/pest (PEST) - v4
|
||||
- phpunit/phpunit (PHPUNIT) - v12
|
||||
- tailwindcss (TAILWINDCSS) - v4
|
||||
|
||||
## Conventions
|
||||
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, naming.
|
||||
- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`.
|
||||
- Check for existing components to reuse before writing a new one.
|
||||
|
||||
## Verification Scripts
|
||||
- Do not create verification scripts or tinker when tests cover that functionality and prove it works. Unit and feature tests are more important.
|
||||
|
||||
## Application Structure & Architecture
|
||||
- Stick to existing directory structure - don't create new base folders without approval.
|
||||
- Do not change the application's dependencies without approval.
|
||||
|
||||
## Frontend Bundling
|
||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `vendor/bin/sail npm run build`, `vendor/bin/sail npm run dev`, or `vendor/bin/sail composer run dev`. Ask them.
|
||||
|
||||
## Replies
|
||||
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
|
||||
|
||||
## Documentation Files
|
||||
- You must only create documentation files if explicitly requested by the user.
|
||||
|
||||
|
||||
=== boost rules ===
|
||||
|
||||
## Laravel Boost
|
||||
- Laravel Boost is an MCP server that comes with powerful tools designed specifically for this application. Use them.
|
||||
|
||||
## Artisan
|
||||
- Use the `list-artisan-commands` tool when you need to call an Artisan command to double check the available parameters.
|
||||
|
||||
## URLs
|
||||
- Whenever you share a project URL with the user you should use the `get-absolute-url` tool to ensure you're using the correct scheme, domain / IP, and port.
|
||||
|
||||
## Tinker / Debugging
|
||||
- You should use the `tinker` tool when you need to execute PHP to debug code or query Eloquent models directly.
|
||||
- Use the `database-query` tool when you only need to read from the database.
|
||||
|
||||
## Reading Browser Logs With the `browser-logs` Tool
|
||||
- You can read browser logs, errors, and exceptions using the `browser-logs` tool from Boost.
|
||||
- Only recent browser logs will be useful - ignore old logs.
|
||||
|
||||
## Searching Documentation (Critically Important)
|
||||
- Boost comes with a powerful `search-docs` tool you should use before any other approaches. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation specific for the user's circumstance. You should pass an array of packages to filter on if you know you need docs for particular packages.
|
||||
- The 'search-docs' tool is perfect for all Laravel related packages, including Laravel, Inertia, Livewire, Filament, Tailwind, Pest, Nova, Nightwatch, etc.
|
||||
- You must use this tool to search for Laravel-ecosystem documentation before falling back to other approaches.
|
||||
- Search the documentation before making code changes to ensure we are taking the correct approach.
|
||||
- Use multiple, broad, simple, topic based queries to start. For example: `['rate limiting', 'routing rate limiting', 'routing']`.
|
||||
- Do not add package names to queries - package information is already shared. For example, use `test resource table`, not `filament 4 test resource table`.
|
||||
|
||||
### Available Search Syntax
|
||||
- You can and should pass multiple queries at once. The most relevant results will be returned first.
|
||||
|
||||
1. Simple Word Searches with auto-stemming - query=authentication - finds 'authenticate' and 'auth'
|
||||
2. Multiple Words (AND Logic) - query=rate limit - finds knowledge containing both "rate" AND "limit"
|
||||
3. Quoted Phrases (Exact Position) - query="infinite scroll" - Words must be adjacent and in that order
|
||||
4. Mixed Queries - query=middleware "rate limit" - "middleware" AND exact phrase "rate limit"
|
||||
5. Multiple Queries - queries=["authentication", "middleware"] - ANY of these terms
|
||||
|
||||
|
||||
=== php rules ===
|
||||
|
||||
## PHP
|
||||
|
||||
- Always use curly braces for control structures, even if it has one line.
|
||||
|
||||
### Constructors
|
||||
- Use PHP 8 constructor property promotion in `__construct()`.
|
||||
- <code-snippet>public function __construct(public GitHub $github) { }</code-snippet>
|
||||
- Do not allow empty `__construct()` methods with zero parameters.
|
||||
|
||||
### Type Declarations
|
||||
- Always use explicit return type declarations for methods and functions.
|
||||
- Use appropriate PHP type hints for method parameters.
|
||||
|
||||
<code-snippet name="Explicit Return Types and Method Params" lang="php">
|
||||
protected function isAccessible(User $user, ?string $path = null): bool
|
||||
{
|
||||
...
|
||||
}
|
||||
</code-snippet>
|
||||
|
||||
## Comments
|
||||
- Prefer PHPDoc blocks over comments. Never use comments within the code itself unless there is something _very_ complex going on.
|
||||
|
||||
## PHPDoc Blocks
|
||||
- Add useful array shape type definitions for arrays when appropriate.
|
||||
|
||||
## Enums
|
||||
- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`.
|
||||
|
||||
|
||||
=== sail rules ===
|
||||
|
||||
## Laravel Sail
|
||||
|
||||
- This project runs inside Laravel Sail's Docker containers. You MUST execute all commands through Sail.
|
||||
- Start services using `vendor/bin/sail up -d` and stop them with `vendor/bin/sail stop`.
|
||||
- Open the application in the browser by running `vendor/bin/sail open`.
|
||||
- Always prefix PHP, Artisan, Composer, and Node commands** with `vendor/bin/sail`. Examples:
|
||||
- Run Artisan Commands: `vendor/bin/sail artisan migrate`
|
||||
- Install Composer packages: `vendor/bin/sail composer install`
|
||||
- Execute node commands: `vendor/bin/sail npm run dev`
|
||||
- Execute PHP scripts: `vendor/bin/sail php [script]`
|
||||
- View all available Sail commands by running `vendor/bin/sail` without arguments.
|
||||
|
||||
|
||||
=== tests rules ===
|
||||
|
||||
## Test Enforcement
|
||||
|
||||
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
|
||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `vendor/bin/sail artisan test` with a specific filename or filter.
|
||||
|
||||
|
||||
=== laravel/core rules ===
|
||||
|
||||
## Do Things the Laravel Way
|
||||
|
||||
- Use `vendor/bin/sail artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
||||
- If you're creating a generic PHP class, use `vendor/bin/sail artisan make:class`.
|
||||
- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior.
|
||||
|
||||
### Database
|
||||
- Always use proper Eloquent relationship methods with return type hints. Prefer relationship methods over raw queries or manual joins.
|
||||
- Use Eloquent models and relationships before suggesting raw database queries
|
||||
- Avoid `DB::`; prefer `Model::query()`. Generate code that leverages Laravel's ORM capabilities rather than bypassing them.
|
||||
- Generate code that prevents N+1 query problems by using eager loading.
|
||||
- Use Laravel's query builder for very complex database operations.
|
||||
|
||||
### Model Creation
|
||||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `vendor/bin/sail artisan make:model`.
|
||||
|
||||
### APIs & Eloquent Resources
|
||||
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
|
||||
|
||||
### Controllers & Validation
|
||||
- Always create Form Request classes for validation rather than inline validation in controllers. Include both validation rules and custom error messages.
|
||||
- Check sibling Form Requests to see if the application uses array or string based validation rules.
|
||||
|
||||
### Queues
|
||||
- Use queued jobs for time-consuming operations with the `ShouldQueue` interface.
|
||||
|
||||
### Authentication & Authorization
|
||||
- Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum, etc.).
|
||||
|
||||
### URL Generation
|
||||
- When generating links to other pages, prefer named routes and the `route()` function.
|
||||
|
||||
### Configuration
|
||||
- Use environment variables only in configuration files - never use the `env()` function directly outside of config files. Always use `config('app.name')`, not `env('APP_NAME')`.
|
||||
|
||||
### Testing
|
||||
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
|
||||
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
|
||||
- When creating tests, make use of `vendor/bin/sail artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
|
||||
|
||||
### Vite Error
|
||||
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `vendor/bin/sail npm run build` or ask the user to run `vendor/bin/sail npm run dev` or `vendor/bin/sail composer run dev`.
|
||||
|
||||
|
||||
=== laravel/v12 rules ===
|
||||
|
||||
## Laravel 12
|
||||
|
||||
- Use the `search-docs` tool to get version specific documentation.
|
||||
- Since Laravel 11, Laravel has a new streamlined file structure which this project uses.
|
||||
|
||||
### Laravel 12 Structure
|
||||
- No middleware files in `app/Http/Middleware/`.
|
||||
- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files.
|
||||
- `bootstrap/providers.php` contains application specific service providers.
|
||||
- **No app\Console\Kernel.php** - use `bootstrap/app.php` or `routes/console.php` for console configuration.
|
||||
- **Commands auto-register** - files in `app/Console/Commands/` are automatically available and do not require manual registration.
|
||||
|
||||
### Database
|
||||
- When modifying a column, the migration must include all of the attributes that were previously defined on the column. Otherwise, they will be dropped and lost.
|
||||
- Laravel 11 allows limiting eagerly loaded records natively, without external packages: `$query->latest()->limit(10);`.
|
||||
|
||||
### Models
|
||||
- Casts can and likely should be set in a `casts()` method on a model rather than the `$casts` property. Follow existing conventions from other models.
|
||||
|
||||
|
||||
=== livewire/core rules ===
|
||||
|
||||
## Livewire Core
|
||||
- Use the `search-docs` tool to find exact version specific documentation for how to write Livewire & Livewire tests.
|
||||
- Use the `vendor/bin/sail artisan make:livewire [Posts\CreatePost]` artisan command to create new components
|
||||
- State should live on the server, with the UI reflecting it.
|
||||
- All Livewire requests hit the Laravel backend, they're like regular HTTP requests. Always validate form data, and run authorization checks in Livewire actions.
|
||||
|
||||
## Livewire Best Practices
|
||||
- Livewire components require a single root element.
|
||||
- Use `wire:loading` and `wire:dirty` for delightful loading states.
|
||||
- Add `wire:key` in loops:
|
||||
|
||||
```blade
|
||||
@foreach ($items as $item)
|
||||
<div wire:key="item-{{ $item->id }}">
|
||||
{{ $item->name }}
|
||||
</div>
|
||||
@endforeach
|
||||
```
|
||||
|
||||
- Prefer lifecycle hooks like `mount()`, `updatedFoo()` for initialization and reactive side effects:
|
||||
|
||||
<code-snippet name="Lifecycle hook examples" lang="php">
|
||||
public function mount(User $user) { $this->user = $user; }
|
||||
public function updatedSearch() { $this->resetPage(); }
|
||||
</code-snippet>
|
||||
|
||||
|
||||
## Testing Livewire
|
||||
|
||||
<code-snippet name="Example Livewire component test" lang="php">
|
||||
Livewire::test(Counter::class)
|
||||
->assertSet('count', 0)
|
||||
->call('increment')
|
||||
->assertSet('count', 1)
|
||||
->assertSee(1)
|
||||
->assertStatus(200);
|
||||
</code-snippet>
|
||||
|
||||
|
||||
<code-snippet name="Testing a Livewire component exists within a page" lang="php">
|
||||
$this->get('/posts/create')
|
||||
->assertSeeLivewire(CreatePost::class);
|
||||
</code-snippet>
|
||||
|
||||
|
||||
=== pint/core rules ===
|
||||
|
||||
## Laravel Pint Code Formatter
|
||||
|
||||
- You must run `vendor/bin/sail bin pint --dirty` before finalizing changes to ensure your code matches the project's expected style.
|
||||
- Do not run `vendor/bin/sail bin pint --test`, simply run `vendor/bin/sail bin pint` to fix any formatting issues.
|
||||
|
||||
|
||||
=== pest/core rules ===
|
||||
|
||||
## Pest
|
||||
### Testing
|
||||
- If you need to verify a feature is working, write or update a Unit / Feature test.
|
||||
|
||||
### Pest Tests
|
||||
- All tests must be written using Pest. Use `vendor/bin/sail artisan make:test --pest {name}`.
|
||||
- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application.
|
||||
- Tests should test all of the happy paths, failure paths, and weird paths.
|
||||
- Tests live in the `tests/Feature` and `tests/Unit` directories.
|
||||
- Pest tests look and behave like this:
|
||||
<code-snippet name="Basic Pest Test Example" lang="php">
|
||||
it('is true', function () {
|
||||
expect(true)->toBeTrue();
|
||||
});
|
||||
</code-snippet>
|
||||
|
||||
### Running Tests
|
||||
- Run the minimal number of tests using an appropriate filter before finalizing code edits.
|
||||
- To run all tests: `vendor/bin/sail artisan test`.
|
||||
- To run all tests in a file: `vendor/bin/sail artisan test tests/Feature/ExampleTest.php`.
|
||||
- To filter on a particular test name: `vendor/bin/sail artisan test --filter=testName` (recommended after making a change to a related file).
|
||||
- When the tests relating to your changes are passing, ask the user if they would like to run the entire test suite to ensure everything is still passing.
|
||||
|
||||
### Pest Assertions
|
||||
- When asserting status codes on a response, use the specific method like `assertForbidden` and `assertNotFound` instead of using `assertStatus(403)` or similar, e.g.:
|
||||
<code-snippet name="Pest Example Asserting postJson Response" lang="php">
|
||||
it('returns all', function () {
|
||||
$response = $this->postJson('/api/docs', []);
|
||||
|
||||
$response->assertSuccessful();
|
||||
});
|
||||
</code-snippet>
|
||||
|
||||
### Mocking
|
||||
- Mocking can be very helpful when appropriate.
|
||||
- When mocking, you can use the `Pest\Laravel\mock` Pest function, but always import it via `use function Pest\Laravel\mock;` before using it. Alternatively, you can use `$this->mock()` if existing tests do.
|
||||
- You can also create partial mocks using the same import or self method.
|
||||
|
||||
### Datasets
|
||||
- Use datasets in Pest to simplify tests which have a lot of duplicated data. This is often the case when testing validation rules, so consider going with this solution when writing tests for validation rules.
|
||||
|
||||
<code-snippet name="Pest Dataset Example" lang="php">
|
||||
it('has emails', function (string $email) {
|
||||
expect($email)->not->toBeEmpty();
|
||||
})->with([
|
||||
'james' => 'james@laravel.com',
|
||||
'taylor' => 'taylor@laravel.com',
|
||||
]);
|
||||
</code-snippet>
|
||||
|
||||
|
||||
=== pest/v4 rules ===
|
||||
|
||||
## Pest 4
|
||||
|
||||
- Pest v4 is a huge upgrade to Pest and offers: browser testing, smoke testing, visual regression testing, test sharding, and faster type coverage.
|
||||
- Browser testing is incredibly powerful and useful for this project.
|
||||
- Browser tests should live in `tests/Browser/`.
|
||||
- Use the `search-docs` tool for detailed guidance on utilizing these features.
|
||||
|
||||
### Browser Testing
|
||||
- You can use Laravel features like `Event::fake()`, `assertAuthenticated()`, and model factories within Pest v4 browser tests, as well as `RefreshDatabase` (when needed) to ensure a clean state for each test.
|
||||
- Interact with the page (click, type, scroll, select, submit, drag-and-drop, touch gestures, etc.) when appropriate to complete the test.
|
||||
- If requested, test on multiple browsers (Chrome, Firefox, Safari).
|
||||
- If requested, test on different devices and viewports (like iPhone 14 Pro, tablets, or custom breakpoints).
|
||||
- Switch color schemes (light/dark mode) when appropriate.
|
||||
- Take screenshots or pause tests for debugging when appropriate.
|
||||
|
||||
### Example Tests
|
||||
|
||||
<code-snippet name="Pest Browser Test Example" lang="php">
|
||||
it('may reset the password', function () {
|
||||
Notification::fake();
|
||||
|
||||
$this->actingAs(User::factory()->create());
|
||||
|
||||
$page = visit('/sign-in'); // Visit on a real browser...
|
||||
|
||||
$page->assertSee('Sign In')
|
||||
->assertNoJavascriptErrors() // or ->assertNoConsoleLogs()
|
||||
->click('Forgot Password?')
|
||||
->fill('email', 'nuno@laravel.com')
|
||||
->click('Send Reset Link')
|
||||
->assertSee('We have emailed your password reset link!')
|
||||
|
||||
Notification::assertSent(ResetPassword::class);
|
||||
});
|
||||
</code-snippet>
|
||||
|
||||
<code-snippet name="Pest Smoke Testing Example" lang="php">
|
||||
$pages = visit(['/', '/about', '/contact']);
|
||||
|
||||
$pages->assertNoJavascriptErrors()->assertNoConsoleLogs();
|
||||
</code-snippet>
|
||||
|
||||
|
||||
=== tailwindcss/core rules ===
|
||||
|
||||
## Tailwind Core
|
||||
|
||||
- Use Tailwind CSS classes to style HTML, check and use existing tailwind conventions within the project before writing your own.
|
||||
- Offer to extract repeated patterns into components that match the project's conventions (i.e. Blade, JSX, Vue, etc..)
|
||||
- Think through class placement, order, priority, and defaults - remove redundant classes, add classes to parent or child carefully to limit repetition, group elements logically
|
||||
- You can use the `search-docs` tool to get exact examples from the official documentation when needed.
|
||||
|
||||
### Spacing
|
||||
- When listing items, use gap utilities for spacing, don't use margins.
|
||||
|
||||
<code-snippet name="Valid Flex Gap Spacing Example" lang="html">
|
||||
<div class="flex gap-8">
|
||||
<div>Superior</div>
|
||||
<div>Michigan</div>
|
||||
<div>Erie</div>
|
||||
</div>
|
||||
</code-snippet>
|
||||
|
||||
|
||||
### Dark Mode
|
||||
- If existing pages and components support dark mode, new pages and components must support dark mode in a similar way, typically using `dark:`.
|
||||
|
||||
|
||||
=== tailwindcss/v4 rules ===
|
||||
|
||||
## Tailwind 4
|
||||
|
||||
- Always use Tailwind CSS v4 - do not use the deprecated utilities.
|
||||
- `corePlugins` is not supported in Tailwind v4.
|
||||
- In Tailwind v4, configuration is CSS-first using the `@theme` directive — no separate `tailwind.config.js` file is needed.
|
||||
<code-snippet name="Extending Theme in CSS" lang="css">
|
||||
@theme {
|
||||
--color-brand: oklch(0.72 0.11 178);
|
||||
}
|
||||
</code-snippet>
|
||||
|
||||
- In Tailwind v4, you import Tailwind using a regular CSS `@import` statement, not using the `@tailwind` directives used in v3:
|
||||
|
||||
<code-snippet name="Tailwind v4 Import Tailwind Diff" lang="diff">
|
||||
- @tailwind base;
|
||||
- @tailwind components;
|
||||
- @tailwind utilities;
|
||||
+ @import "tailwindcss";
|
||||
</code-snippet>
|
||||
|
||||
|
||||
### Replaced Utilities
|
||||
- Tailwind v4 removed deprecated utilities. Do not use the deprecated option - use the replacement.
|
||||
- Opacity values are still numeric.
|
||||
|
||||
| Deprecated | Replacement |
|
||||
|------------+--------------|
|
||||
| bg-opacity-* | bg-black/* |
|
||||
| text-opacity-* | text-black/* |
|
||||
| border-opacity-* | border-black/* |
|
||||
| divide-opacity-* | divide-black/* |
|
||||
| ring-opacity-* | ring-black/* |
|
||||
| placeholder-opacity-* | placeholder-black/* |
|
||||
| flex-shrink-* | shrink-* |
|
||||
| flex-grow-* | grow-* |
|
||||
| overflow-ellipsis | text-ellipsis |
|
||||
| decoration-slice | box-decoration-slice |
|
||||
| decoration-clone | box-decoration-clone |
|
||||
</laravel-boost-guidelines>
|
||||
344
Agents.md
344
Agents.md
@ -386,6 +386,266 @@ ## Reference Materials
|
||||
===
|
||||
|
||||
<laravel-boost-guidelines>
|
||||
=== .ai/filament-v5-blueprint rules ===
|
||||
|
||||
## Source of Truth
|
||||
If any Filament behavior is uncertain, lookup the exact section in:
|
||||
- docs/research/filament-v5-notes.md
|
||||
and prefer that over guesses.
|
||||
|
||||
# SECTION B — FILAMENT V5 BLUEPRINT (EXECUTABLE RULES)
|
||||
|
||||
# Filament Blueprint (v5)
|
||||
|
||||
## 1) Non-negotiables
|
||||
- Filament v5 requires Livewire v4.0+.
|
||||
- Laravel 11+: register panel providers in `bootstrap/providers.php` (never `bootstrap/app.php`).
|
||||
- Global search hard rule: If a Resource should appear in Global Search, it must have an Edit or View page; otherwise it will return no results.
|
||||
- Destructive actions must execute via `Action::make(...)->action(...)` and include `->requiresConfirmation()` (no exceptions).
|
||||
- Prefer render hooks + CSS hook classes over publishing Filament internal views.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/upgrade-guide
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
- https://filamentphp.com/docs/5.x/actions/modals
|
||||
- https://filamentphp.com/docs/5.x/advanced/render-hooks
|
||||
- https://filamentphp.com/docs/5.x/styling/css-hooks
|
||||
|
||||
## 2) Directory & naming conventions
|
||||
- Default to Filament discovery conventions for Resources/Pages/Widgets unless you adopt modular architecture.
|
||||
- Clusters: directory layout is recommended, not mandatory; functional behavior depends on `$cluster`.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/navigation/clusters
|
||||
- https://filamentphp.com/docs/5.x/advanced/modular-architecture
|
||||
|
||||
## 3) Panel setup defaults
|
||||
- Default to a single `/admin` panel unless multiple audiences/configs demand multiple panels.
|
||||
- Verify provider registration (Laravel 11+: `bootstrap/providers.php`) when adding a panel.
|
||||
- Use `path()` carefully; treat `path('')` as a high-risk change requiring route conflict review.
|
||||
- Assets policy:
|
||||
- Panel-only assets: register via panel config.
|
||||
- Shared/plugin assets: register via `FilamentAsset::register()`.
|
||||
- Deployment must include `php artisan filament:assets`.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
|
||||
## 4) Navigation & information architecture
|
||||
- Use nav groups + sort order intentionally; apply conditional visibility for clarity, but enforce authorization separately.
|
||||
- Use clusters to introduce hierarchy and sub-navigation when sidebar complexity grows.
|
||||
- Treat cluster code structure as a recommendation (organizational benefit), not a required rule.
|
||||
- User menu:
|
||||
- Configure via `userMenuItems()` with Action objects.
|
||||
- Never put destructive actions there without confirmation + authorization.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/navigation/overview
|
||||
- https://filamentphp.com/docs/5.x/navigation/clusters
|
||||
- https://filamentphp.com/docs/5.x/navigation/user-menu
|
||||
|
||||
## 5) Resource patterns
|
||||
- Default to Resources for CRUD; use custom pages for non-CRUD tools/workflows.
|
||||
- Global search:
|
||||
- If a resource is intended for global search: ensure Edit/View page exists.
|
||||
- Otherwise disable global search for that resource (don’t “expect it to work”).
|
||||
- If global search renders relationship-backed details: eager-load via global search query override.
|
||||
- For very large datasets: consider disabling term splitting (only when needed).
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/resources/overview
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
|
||||
## 6) Page lifecycle & query rules
|
||||
- Treat relationship-backed rendering in aggregate contexts (global search details, list summaries) as requiring eager loading.
|
||||
- Prefer render hooks for layout injection; avoid publishing internal views.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
- https://filamentphp.com/docs/5.x/advanced/render-hooks
|
||||
|
||||
## 7) Infolists vs RelationManagers (decision tree)
|
||||
- Interactive CRUD / attach / detach under owner record → RelationManager.
|
||||
- Pick existing related record(s) inside owner form → Select / CheckboxList relationship fields.
|
||||
- Inline CRUD inside owner form → Repeater.
|
||||
- Default performance stance: RelationManagers stay lazy-loaded unless explicit UX justification exists.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/resources/managing-relationships
|
||||
- https://filamentphp.com/docs/5.x/infolists/overview
|
||||
|
||||
## 8) Form patterns (validation, reactivity, state)
|
||||
- Default: minimize server-driven reactivity; only use it when schema/visibility/requirements must change server-side.
|
||||
- Prefer “on blur” semantics for chatty inputs when using reactive behavior (per docs patterns).
|
||||
- Custom field views must obey state binding modifiers.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/forms/overview
|
||||
- https://filamentphp.com/docs/5.x/forms/custom-fields
|
||||
|
||||
## 9) Table & action patterns
|
||||
- Tables: always define a meaningful empty state (and empty-state actions where appropriate).
|
||||
- Actions:
|
||||
- Execution actions use `->action(...)`.
|
||||
- Destructive actions add `->requiresConfirmation()`.
|
||||
- Navigation-only actions should use `->url(...)`.
|
||||
- UNVERIFIED: do not assert modal/confirmation behavior for URL-only actions unless verified.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/tables/empty-state
|
||||
- https://filamentphp.com/docs/5.x/actions/modals
|
||||
|
||||
## 10) Authorization & security
|
||||
- Enforce panel access in non-local environments as documented.
|
||||
- UI visibility is not security; enforce policies/access checks in addition to hiding UI.
|
||||
- Bulk operations: explicitly decide between “Any” policy methods vs per-record authorization.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/users/overview
|
||||
- https://filamentphp.com/docs/5.x/resources/deleting-records
|
||||
|
||||
## 11) Notifications & UX feedback
|
||||
- Default to explicit success/error notifications for user-triggered mutations that aren’t instantly obvious.
|
||||
- Treat polling as a cost; set intervals intentionally where polling is used.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/notifications/overview
|
||||
- https://filamentphp.com/docs/5.x/widgets/stats-overview
|
||||
|
||||
## 12) Performance defaults
|
||||
- Heavy assets: prefer on-demand loading (`loadedOnRequest()` + `x-load-css` / `x-load-js`) for heavy dependencies.
|
||||
- Styling overrides use CSS hook classes; layout injection uses render hooks; avoid view publishing.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
- https://filamentphp.com/docs/5.x/styling/css-hooks
|
||||
- https://filamentphp.com/docs/5.x/advanced/render-hooks
|
||||
|
||||
## 13) Testing requirements
|
||||
- Test pages/relation managers/widgets as Livewire components.
|
||||
- Test actions using Filament’s action testing guidance.
|
||||
- Do not mount non-Livewire classes in Livewire tests.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/testing/overview
|
||||
- https://filamentphp.com/docs/5.x/testing/testing-actions
|
||||
|
||||
## 14) Forbidden patterns
|
||||
- Mixing Filament v3/v4 APIs into v5 code.
|
||||
- Any mention of Livewire v3 for Filament v5.
|
||||
- Registering panel providers in `bootstrap/app.php` on Laravel 11+.
|
||||
- Destructive actions without `->requiresConfirmation()`.
|
||||
- Shipping heavy assets globally when on-demand loading fits.
|
||||
- Publishing Filament internal views as a default customization technique.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/upgrade-guide
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/actions/modals
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
|
||||
## 15) Agent output contract
|
||||
For any implementation request, the agent must explicitly state:
|
||||
1) Livewire v4.0+ compliance.
|
||||
2) Provider registration location (Laravel 11+: `bootstrap/providers.php`).
|
||||
3) For each globally searchable resource: whether it has Edit/View page (or global search is disabled).
|
||||
4) Which actions are destructive and how confirmation + authorization is handled.
|
||||
5) Asset strategy: global vs on-demand and where `filament:assets` runs in deploy.
|
||||
6) Testing plan: which pages/widgets/relation managers/actions are covered.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/upgrade-guide
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
- https://filamentphp.com/docs/5.x/testing/testing-actions
|
||||
|
||||
|
||||
=== .ai/filament-v5-checklist rules ===
|
||||
|
||||
# SECTION C — AI REVIEW CHECKLIST (STRICT CHECKBOXES)
|
||||
|
||||
## Version Safety
|
||||
- [ ] Filament v5 explicitly targets Livewire v4.0+ (no Livewire v3 references anywhere).
|
||||
- Source: https://filamentphp.com/docs/5.x/upgrade-guide — “Upgrading Livewire”
|
||||
- [ ] All references are Filament `/docs/5.x/` only (no v3/v4 docs, no legacy APIs).
|
||||
- [ ] Upgrade assumptions match the v5 upgrade guide requirements and steps.
|
||||
- Source: https://filamentphp.com/docs/5.x/upgrade-guide — “New requirements”
|
||||
|
||||
## Panel & Navigation
|
||||
- [ ] Laravel 11+: panel providers are registered in `bootstrap/providers.php` (not `bootstrap/app.php`).
|
||||
- Source: https://filamentphp.com/docs/5.x/panel-configuration — “Creating a new panel”
|
||||
- [ ] Panel `path()` choices are intentional and do not conflict with existing routes (especially `path('')`).
|
||||
- Source: https://filamentphp.com/docs/5.x/panel-configuration — “Changing the path”
|
||||
- [ ] Cluster usage is correctly configured (discovery + `$cluster` assignments).
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/clusters — “Creating a cluster”
|
||||
- [ ] Cluster semantics (sub-navigation + grouped navigation behavior) are understood and verified against the clusters docs.
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/clusters — “Introduction”
|
||||
- [ ] Cluster directory structure is treated as recommended, not mandatory.
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/clusters — “Code structure recommendations for panels using clusters”
|
||||
- [ ] User menu items are registered via `userMenuItems()` and permission-gated where needed.
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/user-menu — “Introduction”
|
||||
|
||||
## Resource Structure
|
||||
- [ ] `$recordTitleAttribute` is set for any resource intended for global search.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/overview — “Record titles”
|
||||
- [ ] Hard rule enforced: every globally searchable resource has an Edit or View page; otherwise global search is disabled for it.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/global-search — “Setting global search result titles”
|
||||
- [ ] Relationship-backed global search details are eager-loaded via the global search query override.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/global-search — “Adding extra details to global search results”
|
||||
|
||||
## Infolists & Relations
|
||||
- [ ] Each relationship uses the correct tool (RelationManager vs Select/CheckboxList vs Repeater) based on required interaction.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/managing-relationships — “Choosing the right tool for the job”
|
||||
- [ ] RelationManagers remain lazy-loaded by default unless there’s an explicit UX justification.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/managing-relationships — “Disabling lazy loading”
|
||||
|
||||
## Forms
|
||||
- [ ] Server-driven reactivity is minimal; chatty inputs do not trigger network requests unnecessarily.
|
||||
- Source: https://filamentphp.com/docs/5.x/forms/overview — “Reactive fields on blur”
|
||||
- [ ] Custom field views obey state binding modifiers (no hardcoded `wire:model` without modifiers).
|
||||
- Source: https://filamentphp.com/docs/5.x/forms/custom-fields — “Obeying state binding modifiers”
|
||||
|
||||
## Tables & Actions
|
||||
- [ ] Tables define a meaningful empty state (and empty-state actions where appropriate).
|
||||
- Source: https://filamentphp.com/docs/5.x/tables/empty-state — “Adding empty state actions”
|
||||
- [ ] All destructive actions execute via `->action(...)` and include `->requiresConfirmation()`.
|
||||
- Source: https://filamentphp.com/docs/5.x/actions/modals — “Confirmation modals”
|
||||
- [ ] No checklist rule assumes confirmation/modals for `->url(...)` actions unless verified in docs (UNVERIFIED behavior must not be asserted as fact).
|
||||
- Source: https://filamentphp.com/docs/5.x/actions/modals — “Confirmation modals”
|
||||
|
||||
## Authorization & Security
|
||||
- [ ] Panel access is enforced for non-local environments as documented.
|
||||
- Source: https://filamentphp.com/docs/5.x/users/overview — “Authorizing access to the panel”
|
||||
- [ ] UI visibility is not treated as authorization; policies/access checks still enforce boundaries.
|
||||
- [ ] Bulk operations intentionally choose between “Any” policy methods vs per-record authorization where required.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/deleting-records — “Authorization”
|
||||
|
||||
## UX & Notifications
|
||||
- [ ] User-triggered mutations provide explicit success/error notifications when outcomes aren’t instantly obvious.
|
||||
- Source: https://filamentphp.com/docs/5.x/notifications/overview — “Introduction”
|
||||
- [ ] Polling (widgets/notifications) is configured intentionally (interval set or disabled) to control load.
|
||||
- Source: https://filamentphp.com/docs/5.x/widgets/stats-overview — “Live updating stats (polling)”
|
||||
|
||||
## Performance
|
||||
- [ ] Heavy frontend assets are loaded on-demand using `loadedOnRequest()` + `x-load-css` / `x-load-js` where appropriate.
|
||||
- Source: https://filamentphp.com/docs/5.x/advanced/assets — “Lazy loading CSS” / “Lazy loading JavaScript”
|
||||
- [ ] Styling overrides use CSS hook classes discovered via DevTools (no brittle selectors by default).
|
||||
- Source: https://filamentphp.com/docs/5.x/styling/css-hooks — “Discovering hook classes”
|
||||
|
||||
## Testing
|
||||
- [ ] Livewire tests mount Filament pages/relation managers/widgets (Livewire components), not static resource classes.
|
||||
- Source: https://filamentphp.com/docs/5.x/testing/overview — “What is a Livewire component when using Filament?”
|
||||
- [ ] Actions that mutate data are covered using Filament’s action testing guidance.
|
||||
- Source: https://filamentphp.com/docs/5.x/testing/testing-actions — “Testing actions”
|
||||
|
||||
## Deployment / Ops
|
||||
- [ ] `php artisan filament:assets` is included in the deployment process when using registered assets.
|
||||
- Source: https://filamentphp.com/docs/5.x/advanced/assets — “The FilamentAsset facade”
|
||||
|
||||
|
||||
=== foundation rules ===
|
||||
|
||||
# Laravel Boost Guidelines
|
||||
@ -396,10 +656,10 @@ ## Foundational Context
|
||||
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
|
||||
|
||||
- php - 8.4.15
|
||||
- filament/filament (FILAMENT) - v4
|
||||
- filament/filament (FILAMENT) - v5
|
||||
- laravel/framework (LARAVEL) - v12
|
||||
- laravel/prompts (PROMPTS) - v0
|
||||
- livewire/livewire (LIVEWIRE) - v3
|
||||
- livewire/livewire (LIVEWIRE) - v4
|
||||
- laravel/mcp (MCP) - v0
|
||||
- laravel/pint (PINT) - v1
|
||||
- laravel/sail (SAIL) - v1
|
||||
@ -411,7 +671,6 @@ ## Conventions
|
||||
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, naming.
|
||||
- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`.
|
||||
- Check for existing components to reuse before writing a new one.
|
||||
- UI consistency: Prefer Filament components (`<x-filament::section>`, infolist/table entries, etc.) over custom HTML/Tailwind for admin UI; only roll custom markup when Filament cannot express the UI.
|
||||
|
||||
## Verification Scripts
|
||||
- Do not create verification scripts or tinker when tests cover that functionality and prove it works. Unit and feature tests are more important.
|
||||
@ -421,7 +680,7 @@ ## Application Structure & Architecture
|
||||
- Do not change the application's dependencies without approval.
|
||||
|
||||
## Frontend Bundling
|
||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `npm run build`, `npm run dev`, or `composer run dev`. Ask them.
|
||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `vendor/bin/sail npm run build`, `vendor/bin/sail npm run dev`, or `vendor/bin/sail composer run dev`. Ask them.
|
||||
|
||||
## Replies
|
||||
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
|
||||
@ -499,20 +758,35 @@ ## Enums
|
||||
- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`.
|
||||
|
||||
|
||||
=== sail rules ===
|
||||
|
||||
## Laravel Sail
|
||||
|
||||
- This project runs inside Laravel Sail's Docker containers. You MUST execute all commands through Sail.
|
||||
- Start services using `vendor/bin/sail up -d` and stop them with `vendor/bin/sail stop`.
|
||||
- Open the application in the browser by running `vendor/bin/sail open`.
|
||||
- Always prefix PHP, Artisan, Composer, and Node commands** with `vendor/bin/sail`. Examples:
|
||||
- Run Artisan Commands: `vendor/bin/sail artisan migrate`
|
||||
- Install Composer packages: `vendor/bin/sail composer install`
|
||||
- Execute node commands: `vendor/bin/sail npm run dev`
|
||||
- Execute PHP scripts: `vendor/bin/sail php [script]`
|
||||
- View all available Sail commands by running `vendor/bin/sail` without arguments.
|
||||
|
||||
|
||||
=== tests rules ===
|
||||
|
||||
## Test Enforcement
|
||||
|
||||
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
|
||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test` with a specific filename or filter.
|
||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `vendor/bin/sail artisan test` with a specific filename or filter.
|
||||
|
||||
|
||||
=== laravel/core rules ===
|
||||
|
||||
## Do Things the Laravel Way
|
||||
|
||||
- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
||||
- If you're creating a generic PHP class, use `php artisan make:class`.
|
||||
- Use `vendor/bin/sail artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
||||
- If you're creating a generic PHP class, use `vendor/bin/sail artisan make:class`.
|
||||
- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior.
|
||||
|
||||
### Database
|
||||
@ -523,7 +797,7 @@ ### Database
|
||||
- Use Laravel's query builder for very complex database operations.
|
||||
|
||||
### Model Creation
|
||||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `php artisan make:model`.
|
||||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `vendor/bin/sail artisan make:model`.
|
||||
|
||||
### APIs & Eloquent Resources
|
||||
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
|
||||
@ -547,10 +821,10 @@ ### Configuration
|
||||
### Testing
|
||||
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
|
||||
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
|
||||
- When creating tests, make use of `php artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
|
||||
- When creating tests, make use of `vendor/bin/sail artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
|
||||
|
||||
### Vite Error
|
||||
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `npm run build` or ask the user to run `npm run dev` or `composer run dev`.
|
||||
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `vendor/bin/sail npm run build` or ask the user to run `vendor/bin/sail npm run dev` or `vendor/bin/sail composer run dev`.
|
||||
|
||||
|
||||
=== laravel/v12 rules ===
|
||||
@ -579,7 +853,7 @@ ### Models
|
||||
|
||||
## Livewire Core
|
||||
- Use the `search-docs` tool to find exact version specific documentation for how to write Livewire & Livewire tests.
|
||||
- Use the `php artisan make:livewire [Posts\CreatePost]` artisan command to create new components
|
||||
- Use the `vendor/bin/sail artisan make:livewire [Posts\CreatePost]` artisan command to create new components
|
||||
- State should live on the server, with the UI reflecting it.
|
||||
- All Livewire requests hit the Laravel backend, they're like regular HTTP requests. Always validate form data, and run authorization checks in Livewire actions.
|
||||
|
||||
@ -622,48 +896,12 @@ ## Testing Livewire
|
||||
</code-snippet>
|
||||
|
||||
|
||||
=== livewire/v3 rules ===
|
||||
|
||||
## Livewire 3
|
||||
|
||||
### Key Changes From Livewire 2
|
||||
- These things changed in Livewire 2, but may not have been updated in this application. Verify this application's setup to ensure you conform with application conventions.
|
||||
- Use `wire:model.live` for real-time updates, `wire:model` is now deferred by default.
|
||||
- Components now use the `App\Livewire` namespace (not `App\Http\Livewire`).
|
||||
- Use `$this->dispatch()` to dispatch events (not `emit` or `dispatchBrowserEvent`).
|
||||
- Use the `components.layouts.app` view as the typical layout path (not `layouts.app`).
|
||||
|
||||
### New Directives
|
||||
- `wire:show`, `wire:transition`, `wire:cloak`, `wire:offline`, `wire:target` are available for use. Use the documentation to find usage examples.
|
||||
|
||||
### Alpine
|
||||
- Alpine is now included with Livewire, don't manually include Alpine.js.
|
||||
- Plugins included with Alpine: persist, intersect, collapse, and focus.
|
||||
|
||||
### Lifecycle Hooks
|
||||
- You can listen for `livewire:init` to hook into Livewire initialization, and `fail.status === 419` for the page expiring:
|
||||
|
||||
<code-snippet name="livewire:load example" lang="js">
|
||||
document.addEventListener('livewire:init', function () {
|
||||
Livewire.hook('request', ({ fail }) => {
|
||||
if (fail && fail.status === 419) {
|
||||
alert('Your session expired');
|
||||
}
|
||||
});
|
||||
|
||||
Livewire.hook('message.failed', (message, component) => {
|
||||
console.error(message);
|
||||
});
|
||||
});
|
||||
</code-snippet>
|
||||
|
||||
|
||||
=== pint/core rules ===
|
||||
|
||||
## Laravel Pint Code Formatter
|
||||
|
||||
- You must run `vendor/bin/pint --dirty` before finalizing changes to ensure your code matches the project's expected style.
|
||||
- Do not run `vendor/bin/pint --test`, simply run `vendor/bin/pint` to fix any formatting issues.
|
||||
- You must run `vendor/bin/sail bin pint --dirty` before finalizing changes to ensure your code matches the project's expected style.
|
||||
- Do not run `vendor/bin/sail bin pint --test`, simply run `vendor/bin/sail bin pint` to fix any formatting issues.
|
||||
|
||||
|
||||
=== pest/core rules ===
|
||||
@ -673,7 +911,7 @@ ### Testing
|
||||
- If you need to verify a feature is working, write or update a Unit / Feature test.
|
||||
|
||||
### Pest Tests
|
||||
- All tests must be written using Pest. Use `php artisan make:test --pest {name}`.
|
||||
- All tests must be written using Pest. Use `vendor/bin/sail artisan make:test --pest {name}`.
|
||||
- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application.
|
||||
- Tests should test all of the happy paths, failure paths, and weird paths.
|
||||
- Tests live in the `tests/Feature` and `tests/Unit` directories.
|
||||
@ -686,9 +924,9 @@ ### Pest Tests
|
||||
|
||||
### Running Tests
|
||||
- Run the minimal number of tests using an appropriate filter before finalizing code edits.
|
||||
- To run all tests: `php artisan test`.
|
||||
- To run all tests in a file: `php artisan test tests/Feature/ExampleTest.php`.
|
||||
- To filter on a particular test name: `php artisan test --filter=testName` (recommended after making a change to a related file).
|
||||
- To run all tests: `vendor/bin/sail artisan test`.
|
||||
- To run all tests in a file: `vendor/bin/sail artisan test tests/Feature/ExampleTest.php`.
|
||||
- To filter on a particular test name: `vendor/bin/sail artisan test --filter=testName` (recommended after making a change to a related file).
|
||||
- When the tests relating to your changes are passing, ask the user if they would like to run the entire test suite to ensure everything is still passing.
|
||||
|
||||
### Pest Assertions
|
||||
|
||||
343
GEMINI.md
343
GEMINI.md
@ -226,6 +226,266 @@ ## Reference Materials
|
||||
===
|
||||
|
||||
<laravel-boost-guidelines>
|
||||
=== .ai/filament-v5-blueprint rules ===
|
||||
|
||||
## Source of Truth
|
||||
If any Filament behavior is uncertain, lookup the exact section in:
|
||||
- docs/research/filament-v5-notes.md
|
||||
and prefer that over guesses.
|
||||
|
||||
# SECTION B — FILAMENT V5 BLUEPRINT (EXECUTABLE RULES)
|
||||
|
||||
# Filament Blueprint (v5)
|
||||
|
||||
## 1) Non-negotiables
|
||||
- Filament v5 requires Livewire v4.0+.
|
||||
- Laravel 11+: register panel providers in `bootstrap/providers.php` (never `bootstrap/app.php`).
|
||||
- Global search hard rule: If a Resource should appear in Global Search, it must have an Edit or View page; otherwise it will return no results.
|
||||
- Destructive actions must execute via `Action::make(...)->action(...)` and include `->requiresConfirmation()` (no exceptions).
|
||||
- Prefer render hooks + CSS hook classes over publishing Filament internal views.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/upgrade-guide
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
- https://filamentphp.com/docs/5.x/actions/modals
|
||||
- https://filamentphp.com/docs/5.x/advanced/render-hooks
|
||||
- https://filamentphp.com/docs/5.x/styling/css-hooks
|
||||
|
||||
## 2) Directory & naming conventions
|
||||
- Default to Filament discovery conventions for Resources/Pages/Widgets unless you adopt modular architecture.
|
||||
- Clusters: directory layout is recommended, not mandatory; functional behavior depends on `$cluster`.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/navigation/clusters
|
||||
- https://filamentphp.com/docs/5.x/advanced/modular-architecture
|
||||
|
||||
## 3) Panel setup defaults
|
||||
- Default to a single `/admin` panel unless multiple audiences/configs demand multiple panels.
|
||||
- Verify provider registration (Laravel 11+: `bootstrap/providers.php`) when adding a panel.
|
||||
- Use `path()` carefully; treat `path('')` as a high-risk change requiring route conflict review.
|
||||
- Assets policy:
|
||||
- Panel-only assets: register via panel config.
|
||||
- Shared/plugin assets: register via `FilamentAsset::register()`.
|
||||
- Deployment must include `php artisan filament:assets`.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
|
||||
## 4) Navigation & information architecture
|
||||
- Use nav groups + sort order intentionally; apply conditional visibility for clarity, but enforce authorization separately.
|
||||
- Use clusters to introduce hierarchy and sub-navigation when sidebar complexity grows.
|
||||
- Treat cluster code structure as a recommendation (organizational benefit), not a required rule.
|
||||
- User menu:
|
||||
- Configure via `userMenuItems()` with Action objects.
|
||||
- Never put destructive actions there without confirmation + authorization.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/navigation/overview
|
||||
- https://filamentphp.com/docs/5.x/navigation/clusters
|
||||
- https://filamentphp.com/docs/5.x/navigation/user-menu
|
||||
|
||||
## 5) Resource patterns
|
||||
- Default to Resources for CRUD; use custom pages for non-CRUD tools/workflows.
|
||||
- Global search:
|
||||
- If a resource is intended for global search: ensure Edit/View page exists.
|
||||
- Otherwise disable global search for that resource (don’t “expect it to work”).
|
||||
- If global search renders relationship-backed details: eager-load via global search query override.
|
||||
- For very large datasets: consider disabling term splitting (only when needed).
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/resources/overview
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
|
||||
## 6) Page lifecycle & query rules
|
||||
- Treat relationship-backed rendering in aggregate contexts (global search details, list summaries) as requiring eager loading.
|
||||
- Prefer render hooks for layout injection; avoid publishing internal views.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
- https://filamentphp.com/docs/5.x/advanced/render-hooks
|
||||
|
||||
## 7) Infolists vs RelationManagers (decision tree)
|
||||
- Interactive CRUD / attach / detach under owner record → RelationManager.
|
||||
- Pick existing related record(s) inside owner form → Select / CheckboxList relationship fields.
|
||||
- Inline CRUD inside owner form → Repeater.
|
||||
- Default performance stance: RelationManagers stay lazy-loaded unless explicit UX justification exists.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/resources/managing-relationships
|
||||
- https://filamentphp.com/docs/5.x/infolists/overview
|
||||
|
||||
## 8) Form patterns (validation, reactivity, state)
|
||||
- Default: minimize server-driven reactivity; only use it when schema/visibility/requirements must change server-side.
|
||||
- Prefer “on blur” semantics for chatty inputs when using reactive behavior (per docs patterns).
|
||||
- Custom field views must obey state binding modifiers.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/forms/overview
|
||||
- https://filamentphp.com/docs/5.x/forms/custom-fields
|
||||
|
||||
## 9) Table & action patterns
|
||||
- Tables: always define a meaningful empty state (and empty-state actions where appropriate).
|
||||
- Actions:
|
||||
- Execution actions use `->action(...)`.
|
||||
- Destructive actions add `->requiresConfirmation()`.
|
||||
- Navigation-only actions should use `->url(...)`.
|
||||
- UNVERIFIED: do not assert modal/confirmation behavior for URL-only actions unless verified.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/tables/empty-state
|
||||
- https://filamentphp.com/docs/5.x/actions/modals
|
||||
|
||||
## 10) Authorization & security
|
||||
- Enforce panel access in non-local environments as documented.
|
||||
- UI visibility is not security; enforce policies/access checks in addition to hiding UI.
|
||||
- Bulk operations: explicitly decide between “Any” policy methods vs per-record authorization.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/users/overview
|
||||
- https://filamentphp.com/docs/5.x/resources/deleting-records
|
||||
|
||||
## 11) Notifications & UX feedback
|
||||
- Default to explicit success/error notifications for user-triggered mutations that aren’t instantly obvious.
|
||||
- Treat polling as a cost; set intervals intentionally where polling is used.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/notifications/overview
|
||||
- https://filamentphp.com/docs/5.x/widgets/stats-overview
|
||||
|
||||
## 12) Performance defaults
|
||||
- Heavy assets: prefer on-demand loading (`loadedOnRequest()` + `x-load-css` / `x-load-js`) for heavy dependencies.
|
||||
- Styling overrides use CSS hook classes; layout injection uses render hooks; avoid view publishing.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
- https://filamentphp.com/docs/5.x/styling/css-hooks
|
||||
- https://filamentphp.com/docs/5.x/advanced/render-hooks
|
||||
|
||||
## 13) Testing requirements
|
||||
- Test pages/relation managers/widgets as Livewire components.
|
||||
- Test actions using Filament’s action testing guidance.
|
||||
- Do not mount non-Livewire classes in Livewire tests.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/testing/overview
|
||||
- https://filamentphp.com/docs/5.x/testing/testing-actions
|
||||
|
||||
## 14) Forbidden patterns
|
||||
- Mixing Filament v3/v4 APIs into v5 code.
|
||||
- Any mention of Livewire v3 for Filament v5.
|
||||
- Registering panel providers in `bootstrap/app.php` on Laravel 11+.
|
||||
- Destructive actions without `->requiresConfirmation()`.
|
||||
- Shipping heavy assets globally when on-demand loading fits.
|
||||
- Publishing Filament internal views as a default customization technique.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/upgrade-guide
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/actions/modals
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
|
||||
## 15) Agent output contract
|
||||
For any implementation request, the agent must explicitly state:
|
||||
1) Livewire v4.0+ compliance.
|
||||
2) Provider registration location (Laravel 11+: `bootstrap/providers.php`).
|
||||
3) For each globally searchable resource: whether it has Edit/View page (or global search is disabled).
|
||||
4) Which actions are destructive and how confirmation + authorization is handled.
|
||||
5) Asset strategy: global vs on-demand and where `filament:assets` runs in deploy.
|
||||
6) Testing plan: which pages/widgets/relation managers/actions are covered.
|
||||
|
||||
Sources:
|
||||
- https://filamentphp.com/docs/5.x/upgrade-guide
|
||||
- https://filamentphp.com/docs/5.x/panel-configuration
|
||||
- https://filamentphp.com/docs/5.x/resources/global-search
|
||||
- https://filamentphp.com/docs/5.x/advanced/assets
|
||||
- https://filamentphp.com/docs/5.x/testing/testing-actions
|
||||
|
||||
|
||||
=== .ai/filament-v5-checklist rules ===
|
||||
|
||||
# SECTION C — AI REVIEW CHECKLIST (STRICT CHECKBOXES)
|
||||
|
||||
## Version Safety
|
||||
- [ ] Filament v5 explicitly targets Livewire v4.0+ (no Livewire v3 references anywhere).
|
||||
- Source: https://filamentphp.com/docs/5.x/upgrade-guide — “Upgrading Livewire”
|
||||
- [ ] All references are Filament `/docs/5.x/` only (no v3/v4 docs, no legacy APIs).
|
||||
- [ ] Upgrade assumptions match the v5 upgrade guide requirements and steps.
|
||||
- Source: https://filamentphp.com/docs/5.x/upgrade-guide — “New requirements”
|
||||
|
||||
## Panel & Navigation
|
||||
- [ ] Laravel 11+: panel providers are registered in `bootstrap/providers.php` (not `bootstrap/app.php`).
|
||||
- Source: https://filamentphp.com/docs/5.x/panel-configuration — “Creating a new panel”
|
||||
- [ ] Panel `path()` choices are intentional and do not conflict with existing routes (especially `path('')`).
|
||||
- Source: https://filamentphp.com/docs/5.x/panel-configuration — “Changing the path”
|
||||
- [ ] Cluster usage is correctly configured (discovery + `$cluster` assignments).
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/clusters — “Creating a cluster”
|
||||
- [ ] Cluster semantics (sub-navigation + grouped navigation behavior) are understood and verified against the clusters docs.
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/clusters — “Introduction”
|
||||
- [ ] Cluster directory structure is treated as recommended, not mandatory.
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/clusters — “Code structure recommendations for panels using clusters”
|
||||
- [ ] User menu items are registered via `userMenuItems()` and permission-gated where needed.
|
||||
- Source: https://filamentphp.com/docs/5.x/navigation/user-menu — “Introduction”
|
||||
|
||||
## Resource Structure
|
||||
- [ ] `$recordTitleAttribute` is set for any resource intended for global search.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/overview — “Record titles”
|
||||
- [ ] Hard rule enforced: every globally searchable resource has an Edit or View page; otherwise global search is disabled for it.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/global-search — “Setting global search result titles”
|
||||
- [ ] Relationship-backed global search details are eager-loaded via the global search query override.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/global-search — “Adding extra details to global search results”
|
||||
|
||||
## Infolists & Relations
|
||||
- [ ] Each relationship uses the correct tool (RelationManager vs Select/CheckboxList vs Repeater) based on required interaction.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/managing-relationships — “Choosing the right tool for the job”
|
||||
- [ ] RelationManagers remain lazy-loaded by default unless there’s an explicit UX justification.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/managing-relationships — “Disabling lazy loading”
|
||||
|
||||
## Forms
|
||||
- [ ] Server-driven reactivity is minimal; chatty inputs do not trigger network requests unnecessarily.
|
||||
- Source: https://filamentphp.com/docs/5.x/forms/overview — “Reactive fields on blur”
|
||||
- [ ] Custom field views obey state binding modifiers (no hardcoded `wire:model` without modifiers).
|
||||
- Source: https://filamentphp.com/docs/5.x/forms/custom-fields — “Obeying state binding modifiers”
|
||||
|
||||
## Tables & Actions
|
||||
- [ ] Tables define a meaningful empty state (and empty-state actions where appropriate).
|
||||
- Source: https://filamentphp.com/docs/5.x/tables/empty-state — “Adding empty state actions”
|
||||
- [ ] All destructive actions execute via `->action(...)` and include `->requiresConfirmation()`.
|
||||
- Source: https://filamentphp.com/docs/5.x/actions/modals — “Confirmation modals”
|
||||
- [ ] No checklist rule assumes confirmation/modals for `->url(...)` actions unless verified in docs (UNVERIFIED behavior must not be asserted as fact).
|
||||
- Source: https://filamentphp.com/docs/5.x/actions/modals — “Confirmation modals”
|
||||
|
||||
## Authorization & Security
|
||||
- [ ] Panel access is enforced for non-local environments as documented.
|
||||
- Source: https://filamentphp.com/docs/5.x/users/overview — “Authorizing access to the panel”
|
||||
- [ ] UI visibility is not treated as authorization; policies/access checks still enforce boundaries.
|
||||
- [ ] Bulk operations intentionally choose between “Any” policy methods vs per-record authorization where required.
|
||||
- Source: https://filamentphp.com/docs/5.x/resources/deleting-records — “Authorization”
|
||||
|
||||
## UX & Notifications
|
||||
- [ ] User-triggered mutations provide explicit success/error notifications when outcomes aren’t instantly obvious.
|
||||
- Source: https://filamentphp.com/docs/5.x/notifications/overview — “Introduction”
|
||||
- [ ] Polling (widgets/notifications) is configured intentionally (interval set or disabled) to control load.
|
||||
- Source: https://filamentphp.com/docs/5.x/widgets/stats-overview — “Live updating stats (polling)”
|
||||
|
||||
## Performance
|
||||
- [ ] Heavy frontend assets are loaded on-demand using `loadedOnRequest()` + `x-load-css` / `x-load-js` where appropriate.
|
||||
- Source: https://filamentphp.com/docs/5.x/advanced/assets — “Lazy loading CSS” / “Lazy loading JavaScript”
|
||||
- [ ] Styling overrides use CSS hook classes discovered via DevTools (no brittle selectors by default).
|
||||
- Source: https://filamentphp.com/docs/5.x/styling/css-hooks — “Discovering hook classes”
|
||||
|
||||
## Testing
|
||||
- [ ] Livewire tests mount Filament pages/relation managers/widgets (Livewire components), not static resource classes.
|
||||
- Source: https://filamentphp.com/docs/5.x/testing/overview — “What is a Livewire component when using Filament?”
|
||||
- [ ] Actions that mutate data are covered using Filament’s action testing guidance.
|
||||
- Source: https://filamentphp.com/docs/5.x/testing/testing-actions — “Testing actions”
|
||||
|
||||
## Deployment / Ops
|
||||
- [ ] `php artisan filament:assets` is included in the deployment process when using registered assets.
|
||||
- Source: https://filamentphp.com/docs/5.x/advanced/assets — “The FilamentAsset facade”
|
||||
|
||||
|
||||
=== foundation rules ===
|
||||
|
||||
# Laravel Boost Guidelines
|
||||
@ -236,10 +496,10 @@ ## Foundational Context
|
||||
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
|
||||
|
||||
- php - 8.4.15
|
||||
- filament/filament (FILAMENT) - v4
|
||||
- filament/filament (FILAMENT) - v5
|
||||
- laravel/framework (LARAVEL) - v12
|
||||
- laravel/prompts (PROMPTS) - v0
|
||||
- livewire/livewire (LIVEWIRE) - v3
|
||||
- livewire/livewire (LIVEWIRE) - v4
|
||||
- laravel/mcp (MCP) - v0
|
||||
- laravel/pint (PINT) - v1
|
||||
- laravel/sail (SAIL) - v1
|
||||
@ -260,7 +520,7 @@ ## Application Structure & Architecture
|
||||
- Do not change the application's dependencies without approval.
|
||||
|
||||
## Frontend Bundling
|
||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `npm run build`, `npm run dev`, or `composer run dev`. Ask them.
|
||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `vendor/bin/sail npm run build`, `vendor/bin/sail npm run dev`, or `vendor/bin/sail composer run dev`. Ask them.
|
||||
|
||||
## Replies
|
||||
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
|
||||
@ -338,20 +598,35 @@ ## Enums
|
||||
- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`.
|
||||
|
||||
|
||||
=== sail rules ===
|
||||
|
||||
## Laravel Sail
|
||||
|
||||
- This project runs inside Laravel Sail's Docker containers. You MUST execute all commands through Sail.
|
||||
- Start services using `vendor/bin/sail up -d` and stop them with `vendor/bin/sail stop`.
|
||||
- Open the application in the browser by running `vendor/bin/sail open`.
|
||||
- Always prefix PHP, Artisan, Composer, and Node commands** with `vendor/bin/sail`. Examples:
|
||||
- Run Artisan Commands: `vendor/bin/sail artisan migrate`
|
||||
- Install Composer packages: `vendor/bin/sail composer install`
|
||||
- Execute node commands: `vendor/bin/sail npm run dev`
|
||||
- Execute PHP scripts: `vendor/bin/sail php [script]`
|
||||
- View all available Sail commands by running `vendor/bin/sail` without arguments.
|
||||
|
||||
|
||||
=== tests rules ===
|
||||
|
||||
## Test Enforcement
|
||||
|
||||
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
|
||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test` with a specific filename or filter.
|
||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `vendor/bin/sail artisan test` with a specific filename or filter.
|
||||
|
||||
|
||||
=== laravel/core rules ===
|
||||
|
||||
## Do Things the Laravel Way
|
||||
|
||||
- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
||||
- If you're creating a generic PHP class, use `php artisan make:class`.
|
||||
- Use `vendor/bin/sail artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
||||
- If you're creating a generic PHP class, use `vendor/bin/sail artisan make:class`.
|
||||
- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior.
|
||||
|
||||
### Database
|
||||
@ -362,7 +637,7 @@ ### Database
|
||||
- Use Laravel's query builder for very complex database operations.
|
||||
|
||||
### Model Creation
|
||||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `php artisan make:model`.
|
||||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `vendor/bin/sail artisan make:model`.
|
||||
|
||||
### APIs & Eloquent Resources
|
||||
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
|
||||
@ -386,10 +661,10 @@ ### Configuration
|
||||
### Testing
|
||||
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
|
||||
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
|
||||
- When creating tests, make use of `php artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
|
||||
- When creating tests, make use of `vendor/bin/sail artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
|
||||
|
||||
### Vite Error
|
||||
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `npm run build` or ask the user to run `npm run dev` or `composer run dev`.
|
||||
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `vendor/bin/sail npm run build` or ask the user to run `vendor/bin/sail npm run dev` or `vendor/bin/sail composer run dev`.
|
||||
|
||||
|
||||
=== laravel/v12 rules ===
|
||||
@ -418,7 +693,7 @@ ### Models
|
||||
|
||||
## Livewire Core
|
||||
- Use the `search-docs` tool to find exact version specific documentation for how to write Livewire & Livewire tests.
|
||||
- Use the `php artisan make:livewire [Posts\CreatePost]` artisan command to create new components
|
||||
- Use the `vendor/bin/sail artisan make:livewire [Posts\CreatePost]` artisan command to create new components
|
||||
- State should live on the server, with the UI reflecting it.
|
||||
- All Livewire requests hit the Laravel backend, they're like regular HTTP requests. Always validate form data, and run authorization checks in Livewire actions.
|
||||
|
||||
@ -461,48 +736,12 @@ ## Testing Livewire
|
||||
</code-snippet>
|
||||
|
||||
|
||||
=== livewire/v3 rules ===
|
||||
|
||||
## Livewire 3
|
||||
|
||||
### Key Changes From Livewire 2
|
||||
- These things changed in Livewire 2, but may not have been updated in this application. Verify this application's setup to ensure you conform with application conventions.
|
||||
- Use `wire:model.live` for real-time updates, `wire:model` is now deferred by default.
|
||||
- Components now use the `App\Livewire` namespace (not `App\Http\Livewire`).
|
||||
- Use `$this->dispatch()` to dispatch events (not `emit` or `dispatchBrowserEvent`).
|
||||
- Use the `components.layouts.app` view as the typical layout path (not `layouts.app`).
|
||||
|
||||
### New Directives
|
||||
- `wire:show`, `wire:transition`, `wire:cloak`, `wire:offline`, `wire:target` are available for use. Use the documentation to find usage examples.
|
||||
|
||||
### Alpine
|
||||
- Alpine is now included with Livewire, don't manually include Alpine.js.
|
||||
- Plugins included with Alpine: persist, intersect, collapse, and focus.
|
||||
|
||||
### Lifecycle Hooks
|
||||
- You can listen for `livewire:init` to hook into Livewire initialization, and `fail.status === 419` for the page expiring:
|
||||
|
||||
<code-snippet name="livewire:load example" lang="js">
|
||||
document.addEventListener('livewire:init', function () {
|
||||
Livewire.hook('request', ({ fail }) => {
|
||||
if (fail && fail.status === 419) {
|
||||
alert('Your session expired');
|
||||
}
|
||||
});
|
||||
|
||||
Livewire.hook('message.failed', (message, component) => {
|
||||
console.error(message);
|
||||
});
|
||||
});
|
||||
</code-snippet>
|
||||
|
||||
|
||||
=== pint/core rules ===
|
||||
|
||||
## Laravel Pint Code Formatter
|
||||
|
||||
- You must run `vendor/bin/pint --dirty` before finalizing changes to ensure your code matches the project's expected style.
|
||||
- Do not run `vendor/bin/pint --test`, simply run `vendor/bin/pint` to fix any formatting issues.
|
||||
- You must run `vendor/bin/sail bin pint --dirty` before finalizing changes to ensure your code matches the project's expected style.
|
||||
- Do not run `vendor/bin/sail bin pint --test`, simply run `vendor/bin/sail bin pint` to fix any formatting issues.
|
||||
|
||||
|
||||
=== pest/core rules ===
|
||||
@ -512,7 +751,7 @@ ### Testing
|
||||
- If you need to verify a feature is working, write or update a Unit / Feature test.
|
||||
|
||||
### Pest Tests
|
||||
- All tests must be written using Pest. Use `php artisan make:test --pest {name}`.
|
||||
- All tests must be written using Pest. Use `vendor/bin/sail artisan make:test --pest {name}`.
|
||||
- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application.
|
||||
- Tests should test all of the happy paths, failure paths, and weird paths.
|
||||
- Tests live in the `tests/Feature` and `tests/Unit` directories.
|
||||
@ -525,9 +764,9 @@ ### Pest Tests
|
||||
|
||||
### Running Tests
|
||||
- Run the minimal number of tests using an appropriate filter before finalizing code edits.
|
||||
- To run all tests: `php artisan test`.
|
||||
- To run all tests in a file: `php artisan test tests/Feature/ExampleTest.php`.
|
||||
- To filter on a particular test name: `php artisan test --filter=testName` (recommended after making a change to a related file).
|
||||
- To run all tests: `vendor/bin/sail artisan test`.
|
||||
- To run all tests in a file: `vendor/bin/sail artisan test tests/Feature/ExampleTest.php`.
|
||||
- To filter on a particular test name: `vendor/bin/sail artisan test --filter=testName` (recommended after making a change to a related file).
|
||||
- When the tests relating to your changes are passing, ask the user if they would like to run the entire test suite to ensure everything is still passing.
|
||||
|
||||
### Pest Assertions
|
||||
|
||||
11
boost.json
11
boost.json
@ -1,7 +1,16 @@
|
||||
{
|
||||
"agents": [
|
||||
"codex",
|
||||
"copilot",
|
||||
"gemini",
|
||||
"opencode"
|
||||
],
|
||||
"guidelines": []
|
||||
"editors": [
|
||||
"codex",
|
||||
"gemini",
|
||||
"opencode",
|
||||
"vscode"
|
||||
],
|
||||
"guidelines": [],
|
||||
"sail": true
|
||||
}
|
||||
|
||||
114
docs/research/filament-v5-notes.md
Normal file
114
docs/research/filament-v5-notes.md
Normal file
@ -0,0 +1,114 @@
|
||||
# SECTION A — FILAMENT V5 NOTES (BULLETS + SOURCES)
|
||||
|
||||
## Versioning & Base Requirements
|
||||
- Rule: Filament v5 requires Livewire v4.0+.
|
||||
When: Always when installing/upgrading Filament v5. When NOT: Never target Livewire v3 in a v5 codebase.
|
||||
Source: https://filamentphp.com/docs/5.x/upgrade-guide — “Upgrading Livewire”
|
||||
|
||||
## Panels — Configuration
|
||||
- Rule: Panels are configured via dedicated panel providers; the default admin panel ships at `/admin`.
|
||||
When: Always—centralize panel setup (resources/pages/widgets/plugins) here. When NOT: Don’t scatter core panel configuration across unrelated providers.
|
||||
Source: https://filamentphp.com/docs/5.x/panel-configuration — “The default admin panel”
|
||||
- Rule: New panel providers must be registered in `bootstrap/providers.php` for Laravel 11+ (or `config/app.php` for Laravel 10 and below).
|
||||
When: When adding a new panel or if panel creation didn’t auto-register. When NOT: Don’t register panel providers in `bootstrap/app.php`.
|
||||
Source: https://filamentphp.com/docs/5.x/panel-configuration — “Creating a new panel”
|
||||
- Rule: Use `path()` to change a panel’s URL prefix; `path('')` mounts at `/` and can conflict with existing routes.
|
||||
When: When `/admin` is not desired. When NOT: Don’t set `path('')` if `/` is already routed in `routes/web.php`.
|
||||
Source: https://filamentphp.com/docs/5.x/panel-configuration — “Changing the path”
|
||||
- Rule: Use render hooks to inject Blade content into Filament layouts without publishing internal views.
|
||||
When: When inserting banners/scripts/partials into specific layout locations. When NOT: Don’t publish Filament views for small layout tweaks.
|
||||
Source: https://filamentphp.com/docs/5.x/advanced/render-hooks — “Registering render hooks”
|
||||
|
||||
## Navigation — Groups, Ordering, Visibility
|
||||
- Rule: Navigation is built from resources/pages/clusters and can be grouped, sorted, and conditionally shown/hidden.
|
||||
When: Always—use groups/sorting for predictable IA. When NOT: Don’t treat “hidden navigation” as authorization; still enforce policies/access checks.
|
||||
Source: https://filamentphp.com/docs/5.x/navigation/overview — “Introduction”
|
||||
- Rule: Clusters group resources/pages under a single nav item and provide sub-navigation.
|
||||
When: When the sidebar becomes too large and needs hierarchy. When NOT: Don’t cluster if it reduces discoverability for your users.
|
||||
Source: https://filamentphp.com/docs/5.x/navigation/clusters — “Introduction”
|
||||
- Rule: Cluster code structure (moving pages/resources into a cluster directory) is recommended, not required; behavior depends on `$cluster`.
|
||||
When: When you want consistent organization. When NOT: Don’t treat the directory layout as mandatory.
|
||||
Source: https://filamentphp.com/docs/5.x/navigation/clusters — “Code structure recommendations for panels using clusters”
|
||||
- Rule: The user menu is configured via `userMenuItems()` with Action objects and supports conditional visibility and sidebar placement.
|
||||
When: When adding account-related links/actions. When NOT: Don’t put destructive actions there without confirmation + authorization.
|
||||
Source: https://filamentphp.com/docs/5.x/navigation/user-menu — “Introduction”
|
||||
|
||||
## Theming & Branding — CSS Hooks, Colors, Icons
|
||||
- Rule: Filament exposes CSS hook classes (prefixed `fi-`) and recommends discovering them via browser DevTools.
|
||||
When: When styling core UI safely. When NOT: Don’t rely on brittle selectors; request/PR missing hooks instead of hacking around them.
|
||||
Source: https://filamentphp.com/docs/5.x/styling/css-hooks — “Discovering hook classes”
|
||||
- Rule: Apply styling by targeting hook classes (including Tailwind `@apply`) and use `!important` sparingly.
|
||||
When: When overriding default spacing/appearance in a maintainable way. When NOT: Don’t blanket `!important` your theme.
|
||||
Source: https://filamentphp.com/docs/5.x/styling/css-hooks — “Applying styles to hook classes”
|
||||
- Rule: Customize the default semantic color palettes via `FilamentColor::register()` (e.g., primary, danger, etc.).
|
||||
When: When aligning Filament semantics to your brand palette. When NOT: Don’t hardcode per-component hex values when semantics suffice.
|
||||
Source: https://filamentphp.com/docs/5.x/styling/colors — “Customizing the default colors”
|
||||
- Rule: Replace default UI icons globally via `FilamentIcon::register()` (icon aliases map to your chosen icons).
|
||||
When: When standardizing iconography or switching icon sets. When NOT: Don’t hardcode SVGs everywhere when aliases cover the UI.
|
||||
Source: https://filamentphp.com/docs/5.x/styling/icons — “Replacing the default icons”
|
||||
|
||||
## Asset System — Global + Lazy / On-Demand
|
||||
- Rule: Register shared assets via `FilamentAsset::register()`; assets are published into `/public` when `php artisan filament:assets` runs.
|
||||
When: For app/plugin assets loaded by Filament. When NOT: Don’t assume assets exist in production without the publish step.
|
||||
Source: https://filamentphp.com/docs/5.x/advanced/assets — “The FilamentAsset facade”
|
||||
- Rule: Lazy-load CSS with `x-load-css` and prevent auto-loading via `loadedOnRequest()` for page-specific styles.
|
||||
When: For heavy CSS used only on certain pages/components. When NOT: Don’t lazy-load tiny styles used everywhere.
|
||||
Source: https://filamentphp.com/docs/5.x/advanced/assets — “Lazy loading CSS”
|
||||
- Rule: Lazy-load JavaScript with `x-load-js` and prevent auto-loading via `loadedOnRequest()` for page-specific scripts.
|
||||
When: For heavy JS libraries used only on a subset of pages/widgets. When NOT: Don’t lazy-load scripts required for baseline panel behavior.
|
||||
Source: https://filamentphp.com/docs/5.x/advanced/assets — “Lazy loading JavaScript”
|
||||
|
||||
## Plugin System — Mechanics + Panel Scoping
|
||||
- Rule: Panel plugins integrate via a Plugin object; standalone plugins integrate via a service provider (no panel binding).
|
||||
When: When deciding whether a package needs panel-specific registration. When NOT: Don’t force a Plugin object for standalone-only components.
|
||||
Source: https://filamentphp.com/docs/5.x/plugins/getting-started — “The Plugin object”
|
||||
- Rule: Plugin assets should be registered in the plugin’s service provider so Filament can manage publishing/loading.
|
||||
When: When shipping CSS/JS/Alpine components with a package. When NOT: Don’t register package assets ad-hoc only in app panel providers.
|
||||
Source: https://filamentphp.com/docs/5.x/plugins/getting-started — “Registering assets”
|
||||
- Rule: Panel-scoped module/plugin registration can be centralized using `Panel::configureUsing()` for modular architectures.
|
||||
When: When modules should enable Filament artifacts only for specific panels. When NOT: Don’t register all modules globally if panels target different audiences.
|
||||
Source: https://filamentphp.com/docs/5.x/advanced/modular-architecture — “Registering plugins conditionally for specific panels”
|
||||
- Rule: Panel plugins are configurable per panel; treat “enabled in panel A” and “enabled in panel B” as independent configuration contexts.
|
||||
When: When the same app has multiple panels with different modules enabled. When NOT: Don’t assume a plugin is active across all panels.
|
||||
Source: https://filamentphp.com/docs/5.x/plugins/panel-plugins — “Introduction”
|
||||
|
||||
## Actions — Modals, Confirmation, Execution
|
||||
- Rule: Use `Action::make(...)->action(...)` to execute logic; use `requiresConfirmation()` for confirmation modals.
|
||||
When: For destructive or high-impact actions. When NOT: Don’t skip confirmation for destructive operations.
|
||||
Source: https://filamentphp.com/docs/5.x/actions/modals — “Confirmation modals”
|
||||
- Rule: Action modals can render a schema to collect input; submitted modal data is available to the action handler.
|
||||
When: When you need “form-in-action” workflows. When NOT: Don’t create bespoke modals when schema-in-modal is sufficient.
|
||||
Source: https://filamentphp.com/docs/5.x/actions/modals — “Rendering a form in a modal”
|
||||
|
||||
## Resources & Pages — Global Search, Queries
|
||||
- Rule: Global search returns results for a resource only if it has an Edit or View page; otherwise the resource returns no results.
|
||||
When: When enabling global search for a resource. When NOT: Don’t expect global search on resources without Edit/View pages.
|
||||
Source: https://filamentphp.com/docs/5.x/resources/global-search — “Setting global search result titles”
|
||||
- Rule: If global search result details access relationships, override the global search query to eager-load them to avoid N+1.
|
||||
When: Any time you return relationship-backed details. When NOT: Don’t lazy-load relationships in global search rendering.
|
||||
Source: https://filamentphp.com/docs/5.x/resources/global-search — “Adding extra details to global search results”
|
||||
- Rule: You can disable search term splitting for performance on large datasets.
|
||||
When: When global search becomes expensive. When NOT: Don’t disable if multi-word relevance is important.
|
||||
Source: https://filamentphp.com/docs/5.x/resources/global-search — “Disabling search term splitting”
|
||||
|
||||
## Tables — Empty States
|
||||
- Rule: Tables support empty-state content and can add empty-state actions to guide first-time users.
|
||||
When: Always—empty-state guidance improves “first run” UX. When NOT: Don’t leave empty lists without a clear next step when creation is expected.
|
||||
Source: https://filamentphp.com/docs/5.x/tables/empty-state — “Adding empty state actions”
|
||||
|
||||
## Testing
|
||||
- Rule: Filament testing distinguishes Livewire components (pages/relation managers/widgets) from non-Livewire classes (resources/actions/schema objects).
|
||||
When: When choosing what to mount with `Livewire::test()`. When NOT: Don’t try to Livewire-test non-Livewire classes directly.
|
||||
Source: https://filamentphp.com/docs/5.x/testing/overview — “What is a Livewire component when using Filament?”
|
||||
- Rule: Actions have dedicated testing guidance; follow it for asserting action execution and side effects.
|
||||
When: When actions drive critical business workflows. When NOT: Don’t leave actions untested if they mutate data or trigger external effects.
|
||||
Source: https://filamentphp.com/docs/5.x/testing/testing-actions — “Testing actions”
|
||||
|
||||
## OPINIONATED — best practices not explicitly mandated by docs
|
||||
- Rule: Standardize destructive actions: danger styling + requiresConfirmation() + policy authorization + success/error notification.
|
||||
When: For delete/force-delete/restore/bulk destructive ops. When NOT: For trivial, reversible toggles.
|
||||
|
||||
## UNVERIFIED — not explicitly stated in the cited v5 pages above
|
||||
- Rule: If you need confirmation or a modal, prefer `->action(...)` + `->requiresConfirmation()`; use `->url(...)` for navigation links.
|
||||
When: When deciding whether an action should execute vs navigate. When NOT: Don’t assume modal/confirmation behavior for URL-only actions without verifying in docs.
|
||||
Source: https://filamentphp.com/docs/5.x/actions/modals — “Confirmation modals”
|
||||
14
opencode.json
Normal file
14
opencode.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"mcp": {
|
||||
"laravel-boost": {
|
||||
"type": "local",
|
||||
"enabled": true,
|
||||
"command": [
|
||||
"vendor/bin/sail",
|
||||
"artisan",
|
||||
"boost:mcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -31,5 +31,5 @@ ## Feature Readiness
|
||||
|
||||
## Notes
|
||||
|
||||
- This is a technical upgrade, but the spec intentionally describes outcomes and guardrails rather than implementation steps.
|
||||
- Proceed to planning: identify concrete packages, versions, and migration steps in plan/tasks.
|
||||
- This is a technical upgrade, but the spec describes outcomes and guardrails rather than implementation steps.
|
||||
- Planning can capture concrete versions, dependency changes, and migration steps.
|
||||
|
||||
@ -3,7 +3,7 @@ # Feature Specification: Admin UI Stack Upgrade (Panel + Suite)
|
||||
**Feature Branch**: `057-filament-v5-upgrade`
|
||||
**Created**: 2026-01-20
|
||||
**Status**: Draft
|
||||
**Input**: Upgrade the existing admin UI stack to the next supported major release to maintain compatibility and support, and ensure no regressions for tenant isolation and Ops-UX/Monitoring guardrails.
|
||||
**Input**: Upgrade the existing admin UI stack to the next supported major release to maintain compatibility and support, and ensure no regressions for tenant isolation and Monitoring/Operations safety guardrails.
|
||||
|
||||
## Clarifications
|
||||
|
||||
@ -19,7 +19,7 @@ ## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Admin UI keeps working after upgrade (Priority: P1)
|
||||
|
||||
Administrators can sign in and use the admin panel (navigation, resources, forms, tables, actions) without runtime errors after the upgrade.
|
||||
Administrators can sign in and use the admin panel (navigation, lists, forms, actions) without runtime errors after the upgrade.
|
||||
|
||||
**Why this priority**: This is the minimum bar for the upgrade to be safe; if the admin UI is unstable, all operational work stops.
|
||||
|
||||
@ -75,18 +75,18 @@ ## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: The application MUST upgrade the admin panel stack to the next supported major release and its required compatible reactive UI layer.
|
||||
- **FR-002**: The application MUST continue to support the existing styling system without asset build failures.
|
||||
- **FR-003**: All existing Filament panels MUST load successfully for authorized users and preserve core interactions (navigation, tables, forms, actions, notifications, widgets).
|
||||
- **FR-004**: SPA-style navigation flows MUST continue to work, including global widget mounting and event delivery across navigation.
|
||||
- **FR-005**: Everything rendered under the Monitoring → Operations navigation section (including widgets/partials/tabs) MUST remain DB-only: no outbound HTTP requests are permitted during page render or during background/automatic Livewire requests (polling/auto-refresh/hydration).
|
||||
- **FR-010**: Any remote work initiated from Monitoring/Operations pages MUST be triggered only by explicit user actions (e.g., buttons) and MUST enqueue tracked operations (e.g., `OperationRun`-backed jobs) rather than performing outbound HTTP inline.
|
||||
- **FR-006**: Tenant isolation MUST be preserved across requests and Live UI interactions: all reads/writes/events/caches MUST scope to the active tenant.
|
||||
- **FR-007**: Compatibility risks MUST be managed by producing an explicit inventory of affected third-party packages and documenting upgrade/replacement decisions.
|
||||
- **FR-011**: If a third-party package is incompatible with the upgraded stack, the system MUST preserve equivalent functionality by upgrading or replacing the package; mixed-version pinning is not allowed. Any unavoidable feature loss MUST be handled as an explicit scope/decision change.
|
||||
- **FR-012**: Database migrations are allowed only if strictly required for compatibility; they MUST be reversible and non-destructive (no data loss). Migrations MUST include a safe `down()` path and avoid drops without an explicit plan, and MUST be mentioned in release notes.
|
||||
- **FR-001**: The system MUST upgrade the admin UI stack to the next supported major release and remain fully functional for all in-scope admin workflows.
|
||||
- **FR-002**: The system MUST continue to support the existing styling and asset pipeline without build failures.
|
||||
- **FR-003**: All existing admin pages MUST load successfully for authorized users and preserve core interactions (navigation, lists, forms, actions, notifications, and global UI elements).
|
||||
- **FR-004**: In-app navigation between admin pages MUST continue to work reliably, including any global progress indicators and event-driven UI behavior.
|
||||
- **FR-005**: Everything rendered under the Monitoring → Operations navigation section (including widgets/partials/tabs) MUST remain DB-only: no outbound HTTP requests are permitted during page render or during background/automatic requests (polling/auto-refresh/hydration).
|
||||
- **FR-006**: Tenant isolation MUST be preserved across requests and interactive UI behavior: all reads/writes/events/caches MUST scope to the active tenant.
|
||||
- **FR-007**: Compatibility risks MUST be managed by producing an explicit inventory of affected third-party dependencies and documenting upgrade/replacement decisions.
|
||||
- **FR-008**: The upgrade MUST not introduce new Microsoft Graph read/write behavior; if any Graph-touching behavior changes are required, they MUST be explicitly specified with safety gates and observability updates.
|
||||
- **FR-009**: The upgrade MUST include a documented rollback procedure that restores the previous working state.
|
||||
- **FR-010**: Any remote work initiated from Monitoring/Operations pages MUST be triggered only by explicit user actions and MUST enqueue a tracked operation (with an observable run record) rather than performing outbound HTTP inline.
|
||||
- **FR-011**: If a third-party dependency is incompatible with the upgraded stack, the system MUST preserve equivalent functionality by upgrading or replacing the dependency; mixed-version pinning is not allowed. Any unavoidable feature loss MUST be handled as an explicit scope/decision change.
|
||||
- **FR-012**: Database migrations are allowed only if strictly required for compatibility; they MUST be reversible and non-destructive (no data loss) and MUST be mentioned in release notes.
|
||||
|
||||
### Assumptions & Dependencies
|
||||
|
||||
@ -97,7 +97,7 @@ ### Assumptions & Dependencies
|
||||
### Key Entities *(include if feature involves data)*
|
||||
|
||||
- **Tenant**: The active tenant context that scopes all data access and UI state.
|
||||
- **OperationRun**: The persisted record of long-running operations shown in Monitoring/Operations views.
|
||||
- **Run Record**: The persisted record of long-running operations shown in Monitoring/Operations views.
|
||||
- **AuditLog**: The tenant-scoped audit trail used to retain accountability for sensitive actions.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
35
specs/058-tenant-ui-polish/checklists/requirements.md
Normal file
35
specs/058-tenant-ui-polish/checklists/requirements.md
Normal file
@ -0,0 +1,35 @@
|
||||
# Specification Quality Checklist: Tenant UI Polish (v1)
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2026-01-20
|
||||
**Feature**: [specs/058-tenant-ui-polish/spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- Validation run: 2026-01-20
|
||||
- Items marked incomplete require spec updates before `/speckit.clarify` or `/speckit.plan`
|
||||
22
specs/058-tenant-ui-polish/contracts/polling.md
Normal file
22
specs/058-tenant-ui-polish/contracts/polling.md
Normal file
@ -0,0 +1,22 @@
|
||||
# Polling Contract — Calm UI Rules
|
||||
|
||||
## Principle
|
||||
Polling is allowed only when it materially improves UX (active operations). It must be DB-only and must stop when no longer needed.
|
||||
|
||||
## Dashboard
|
||||
- Polling is enabled only while active runs exist (queued/running) for the current tenant.
|
||||
- Polling is disabled when:
|
||||
- No active runs exist.
|
||||
|
||||
## Operations index
|
||||
- Polling is enabled only while active runs exist.
|
||||
- Polling is disabled when:
|
||||
- No active runs exist.
|
||||
|
||||
## Modals
|
||||
- No polling inside modals.
|
||||
- When a modal is open, polling should not cause churn in the background.
|
||||
|
||||
## Technical approach
|
||||
- Widgets: use `$pollingInterval = null` to disable polling.
|
||||
- Tables: apply `$table->poll('10s')` only when active runs exist.
|
||||
28
specs/058-tenant-ui-polish/contracts/ui.md
Normal file
28
specs/058-tenant-ui-polish/contracts/ui.md
Normal file
@ -0,0 +1,28 @@
|
||||
# UI Contracts — Tenant UI Polish
|
||||
|
||||
This feature does not introduce HTTP APIs. These contracts describe UI routing, filters, and definitions that must remain stable.
|
||||
|
||||
## Routes (tenant-scoped)
|
||||
- Dashboard: tenant dashboard page (new custom page; replaces default dashboard entry).
|
||||
- Inventory hub: Inventory cluster root (routes to first page/resource in cluster).
|
||||
- Inventory items: Inventory items resource index, under cluster prefix.
|
||||
- Inventory sync runs: Inventory sync runs resource index, under cluster prefix.
|
||||
- Inventory coverage: Inventory coverage page, under cluster prefix.
|
||||
- Operations index: `OperationRunResource` index (`/operations`).
|
||||
- Operation run detail: `OperationRunResource` view page.
|
||||
|
||||
## Operations Tabs (FR-009)
|
||||
Tabs filter the Operations table by:
|
||||
- All: no extra constraints.
|
||||
- Active: `status IN ('queued','running')`
|
||||
- Succeeded: `status = 'completed' AND outcome = 'succeeded'`
|
||||
- Partial: `status = 'completed' AND outcome = 'partial'`
|
||||
- Failed: `status = 'completed' AND outcome = 'failed'`
|
||||
|
||||
## KPI Definitions
|
||||
- Inventory coverage % = Restorable / Total (Partial is separate, does not inflate %).
|
||||
- Drift stale threshold = 7 days.
|
||||
- “Recent” lists default size = 10.
|
||||
- “Active operations” shows two counts:
|
||||
- All active runs (queued + running)
|
||||
- Inventory-active runs (type = `inventory.sync`, queued + running)
|
||||
76
specs/058-tenant-ui-polish/data-model.md
Normal file
76
specs/058-tenant-ui-polish/data-model.md
Normal file
@ -0,0 +1,76 @@
|
||||
# Data Model — Tenant UI Polish
|
||||
|
||||
This feature is read-only. It introduces no schema changes.
|
||||
|
||||
## Entities
|
||||
|
||||
### Tenant
|
||||
- **Role**: scope boundary for all queries.
|
||||
- **Source**: `Tenant::current()` (Filament tenancy).
|
||||
|
||||
### OperationRun
|
||||
- **Role**: operations feed, KPIs, and canonical “View run” destinations.
|
||||
- **Key fields used** (existing):
|
||||
- `tenant_id`
|
||||
- `type`
|
||||
- `status` (`queued|running|completed`)
|
||||
- `outcome` (`succeeded|partial|failed|...`)
|
||||
- `created_at`, `started_at`, `completed_at`
|
||||
- `summary_counts`, `failure_summary` (JSONB)
|
||||
|
||||
**Derived values**:
|
||||
- **Active**: `status IN ('queued','running')`
|
||||
- **Terminal**: `status = 'completed'`
|
||||
- **Avg duration (7 days)**: only terminal runs with `started_at` and `completed_at`.
|
||||
|
||||
### InventoryItem
|
||||
- **Role**: inventory totals and coverage chips.
|
||||
- **Key fields used** (existing, inferred from resources):
|
||||
- `tenant_id`
|
||||
- coverage-related flags / fields used to categorize: Restorable, Partial, Risk, Dependencies
|
||||
|
||||
**Derived values**:
|
||||
- Total items
|
||||
- Coverage % = `restorable / total` (if total > 0)
|
||||
- Chip counts: Restorable, Partial, Risk, Dependencies
|
||||
|
||||
### InventorySyncRun
|
||||
- **Role**: “Last Inventory Sync” and “Sync Runs” list.
|
||||
- **Key fields used**:
|
||||
- `tenant_id`
|
||||
- status + timestamps
|
||||
- any “selection_hash / selection payload” metadata used for display
|
||||
|
||||
### Finding (Drift Finding)
|
||||
- **Role**: drift KPIs and “Needs Attention”.
|
||||
- **Key fields used** (existing migration):
|
||||
- `tenant_id`
|
||||
- `severity` (enum-like string)
|
||||
- `status` (open/closed)
|
||||
- timestamps
|
||||
- `scope_key` for grouping
|
||||
|
||||
**Derived values**:
|
||||
- Open findings by severity
|
||||
- Staleness: last drift scan older than 7 days
|
||||
|
||||
## KPI Queries (read-only)
|
||||
|
||||
### Dashboard
|
||||
- Drift KPIs: counts of open findings by severity + stale drift indicator.
|
||||
- Operations health: counts of active runs + failed/partial recent.
|
||||
- Recent lists: latest 10 findings + latest 10 operation runs.
|
||||
|
||||
### Inventory hub
|
||||
- Total items
|
||||
- Coverage % (restorable/total)
|
||||
- Last inventory sync (status + timestamp)
|
||||
- Active operations: (all active runs) + (inventory.sync active runs)
|
||||
|
||||
### Operations index
|
||||
- Total runs (30d)
|
||||
- Active runs (queued + running)
|
||||
- Failed/partial (7d)
|
||||
- Avg duration (7d, terminal runs only)
|
||||
|
||||
All queries must be tenant-scoped.
|
||||
164
specs/058-tenant-ui-polish/plan.md
Normal file
164
specs/058-tenant-ui-polish/plan.md
Normal file
@ -0,0 +1,164 @@
|
||||
# Implementation Plan: Tenant UI Polish (Dashboard + Inventory Hub + Operations)
|
||||
|
||||
**Branch**: `058-tenant-ui-polish` | **Date**: 2026-01-20 | **Spec**: `specs/058-tenant-ui-polish/spec.md`
|
||||
**Input**: Feature specification from `specs/058-tenant-ui-polish/spec.md`
|
||||
|
||||
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts.
|
||||
|
||||
## Summary
|
||||
|
||||
- Build a drift-first, tenant-scoped dashboard with “Needs Attention” and recent lists.
|
||||
- Make Inventory a hub using a Filament cluster to provide consistent left-side sub-navigation across Items / Sync Runs / Coverage.
|
||||
- Upgrade Operations index to “orders-style” with KPIs + status tabs filtering the existing `OperationRunResource` table.
|
||||
- Enforce DB-only renders (and DB-only polling) and a calm UI: polling only while active runs exist, and no polling churn in modals.
|
||||
|
||||
## Technical Context
|
||||
|
||||
<!--
|
||||
ACTION REQUIRED: Replace the content in this section with the technical details
|
||||
for the project. The structure here is presented in advisory capacity to guide
|
||||
the iteration process.
|
||||
-->
|
||||
|
||||
**Language/Version**: PHP 8.4.15 (Laravel 12.47.0)
|
||||
**Primary Dependencies**: Filament v5.0.0, Livewire v4.0.1
|
||||
**Storage**: PostgreSQL
|
||||
**Testing**: Pest v4 (+ PHPUnit v12 runtime)
|
||||
**Target Platform**: Web application (Filament admin panel)
|
||||
**Project Type**: Web (Laravel monolith)
|
||||
**Performance Goals**: Dashboard/Inventory/Operations render quickly (target <2s for typical tenants) with efficient tenant-scoped queries and no N+1.
|
||||
**Constraints**: DB-only for all page renders and any polling/auto-refresh; avoid UI churn in modals.
|
||||
**Scale/Scope**: Tenant-scoped surfaces; KPI math on existing `operation_runs`, `findings`, inventory tables.
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
- Inventory-first: clarify what is “last observed” vs snapshots/backups
|
||||
- Read/write separation: any writes require preview + confirmation + audit + tests
|
||||
- Graph contract path: Graph calls only via `GraphClientInterface` + `config/graph_contracts.php`
|
||||
- Deterministic capabilities: capability derivation is testable (snapshot/golden tests)
|
||||
- Tenant isolation: all reads/writes tenant-scoped; cross-tenant views are explicit and access-checked
|
||||
- Run observability: long-running/remote/queued work creates/reuses `OperationRun`; start surfaces enqueue-only; Monitoring is DB-only; DB-only <2s actions may skip runs but security-relevant ones still audit-log
|
||||
- Automation: queued/scheduled ops use locks + idempotency; handle 429/503 with backoff+jitter
|
||||
- Data minimization: Inventory stores metadata + whitelisted meta; logs contain no secrets/tokens
|
||||
|
||||
Status: ✅ No constitution violations for this feature (read-only, DB-only, tenant-scoped; no Graph calls added).
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/058-tenant-ui-polish/
|
||||
├── plan.md # This file (/speckit.plan command output)
|
||||
├── research.md # Phase 0 output (/speckit.plan command)
|
||||
├── data-model.md # Phase 1 output (/speckit.plan command)
|
||||
├── quickstart.md # Phase 1 output (/speckit.plan command)
|
||||
├── contracts/ # Phase 1 output (/speckit.plan command)
|
||||
└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
<!--
|
||||
ACTION REQUIRED: Replace the placeholder tree below with the concrete layout
|
||||
for this feature. Delete unused options and expand the chosen structure with
|
||||
real paths (e.g., apps/admin, packages/something). The delivered plan must
|
||||
not include Option labels.
|
||||
-->
|
||||
|
||||
```text
|
||||
app/
|
||||
├── Filament/
|
||||
│ ├── Clusters/ # New: Inventory cluster
|
||||
│ ├── Pages/ # New/updated: tenant dashboard, inventory landing, coverage
|
||||
│ ├── Resources/ # Updated: attach inventory resources to cluster; operations tabs/KPIs
|
||||
│ └── Widgets/ # New/updated: KPI header widgets
|
||||
├── Models/ # Existing: Tenant, OperationRun, Finding, InventoryItem, InventorySyncRun
|
||||
└── Providers/Filament/
|
||||
└── AdminPanelProvider.php # Update: discoverClusters(), dashboard page class
|
||||
|
||||
resources/
|
||||
└── views/ # Optional: partials/views for dashboard sections
|
||||
|
||||
tests/
|
||||
└── Feature/
|
||||
├── Monitoring/ # Existing: Operations DB-only + tenant scope tests
|
||||
└── Filament/ # Existing + new: Inventory/Dashboard page tests
|
||||
```
|
||||
|
||||
**Structure Decision**: Laravel monolith + Filament (v5) conventions. Implement UI changes via:
|
||||
- Filament Pages (dashboard + inventory pages)
|
||||
- Filament Clusters (inventory sub-navigation)
|
||||
- Filament Widgets (KPI headers / recent lists)
|
||||
- Filament Resource list tabs (operations index filtering)
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
> **Fill ONLY if Constitution Check has violations that must be justified**
|
||||
|
||||
None.
|
||||
|
||||
## Phase 0 — Outline & Research (complete)
|
||||
|
||||
- Output: `specs/058-tenant-ui-polish/research.md`
|
||||
- Key decisions captured:
|
||||
- Use Filament clusters for the Inventory hub sub-navigation.
|
||||
- Use Filament widgets for KPI headers.
|
||||
- Enable polling only while active runs exist.
|
||||
|
||||
## Phase 1 — Design & Contracts (complete)
|
||||
|
||||
### Data model
|
||||
- Output: `specs/058-tenant-ui-polish/data-model.md`
|
||||
- No schema changes required.
|
||||
|
||||
### UI contracts
|
||||
- Output: `specs/058-tenant-ui-polish/contracts/ui.md`
|
||||
- Output: `specs/058-tenant-ui-polish/contracts/polling.md`
|
||||
|
||||
### Provider registration (Laravel 11+)
|
||||
- Panel providers remain registered in `bootstrap/providers.php` (no changes required for this feature unless adding a new provider).
|
||||
|
||||
### Livewire / Filament version safety
|
||||
- Livewire v4.0+ (required by Filament v5) is in use.
|
||||
|
||||
### Asset strategy
|
||||
- Prefer existing Filament theme CSS and hook classes; avoid publishing Filament internal views.
|
||||
- No heavy assets expected; if any new panel assets are added, ensure deployment runs `php artisan filament:assets`.
|
||||
|
||||
### Destructive actions
|
||||
- None introduced in this feature.
|
||||
|
||||
### Constitution re-check (post-design)
|
||||
- ✅ Inventory-first: dashboard uses Inventory/Findings/OperationRun as last-observed state.
|
||||
- ✅ Read/write separation: this feature is read-only.
|
||||
- ✅ Graph contract path: no Graph calls added.
|
||||
- ✅ Tenant isolation: all queries remain tenant-scoped.
|
||||
- ✅ Run observability: only consumes existing `OperationRun` records; no new long-running work is introduced.
|
||||
- ✅ Data minimization: no new payload storage.
|
||||
|
||||
## Phase 2 — Implementation Plan (next)
|
||||
|
||||
### Story 1 (P1): Drift-first tenant dashboard
|
||||
- Create a custom Filament dashboard page (tenant-scoped) and wire it in `AdminPanelProvider` instead of the default `Dashboard::class`.
|
||||
- Implement drift + ops KPIs and “Needs Attention” + recent lists using DB-only Eloquent queries.
|
||||
- Implement conditional polling (only while active runs exist) using widget polling controls.
|
||||
- Tests:
|
||||
- Add DB-only coverage tests for the dashboard (no outbound HTTP; no queued jobs on render).
|
||||
- Add tenant scope tests for the dashboard.
|
||||
|
||||
### Story 2 (P2): Inventory becomes a hub
|
||||
- Add `discoverClusters()` to `AdminPanelProvider`.
|
||||
- Create `InventoryCluster` and assign `$cluster` on inventory pages/resources.
|
||||
- Add a shared inventory KPI header (widget) across the cluster surfaces.
|
||||
- Tests:
|
||||
- Extend existing inventory page tests to assert cluster pages load and remain tenant-scoped.
|
||||
|
||||
### Story 3 (P3): Operations index “orders-style”
|
||||
- Update `OperationRunResource` list page to:
|
||||
- Add KPI header widgets.
|
||||
- Add tabs: All / Active / Succeeded / Partial / Failed.
|
||||
- Enable table polling only while active runs exist.
|
||||
- Tests:
|
||||
- Extend operations tests to assert page renders with tabs and remains DB-only/tenant-scoped.
|
||||
27
specs/058-tenant-ui-polish/quickstart.md
Normal file
27
specs/058-tenant-ui-polish/quickstart.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Quickstart — Tenant UI Polish
|
||||
|
||||
## Prereqs
|
||||
- Run everything via Sail.
|
||||
|
||||
## Setup
|
||||
- `vendor/bin/sail up -d`
|
||||
- `vendor/bin/sail composer install`
|
||||
|
||||
## Run tests (targeted)
|
||||
- `vendor/bin/sail artisan test tests/Feature/Monitoring/OperationsDbOnlyTest.php`
|
||||
- `vendor/bin/sail artisan test tests/Feature/Monitoring/OperationsTenantScopeTest.php`
|
||||
- `vendor/bin/sail artisan test tests/Feature/Filament/InventoryPagesTest.php`
|
||||
|
||||
When the feature is implemented, add + run:
|
||||
- Dashboard DB-only + tenant scope tests (new).
|
||||
|
||||
## Manual QA (tenant-scoped)
|
||||
- Sign in, select a tenant.
|
||||
- Visit Dashboard: verify drift/ops KPIs, needs attention, and recent lists.
|
||||
- Visit Inventory cluster: Items / Sync Runs / Coverage share left sub-navigation and KPI header.
|
||||
- Visit Operations (`/operations`): KPI header + tabs filter table.
|
||||
|
||||
## Frontend assets
|
||||
If UI changes don’t show:
|
||||
- `vendor/bin/sail npm run dev`
|
||||
- or `vendor/bin/sail npm run build`
|
||||
66
specs/058-tenant-ui-polish/research.md
Normal file
66
specs/058-tenant-ui-polish/research.md
Normal file
@ -0,0 +1,66 @@
|
||||
# Research — Tenant UI Polish (Dashboard + Inventory Hub + Operations)
|
||||
|
||||
## Goal
|
||||
Deliver a drift-first, tenant-scoped UI polish pass that is:
|
||||
- DB-only on render and on any auto-refresh.
|
||||
- Calm (polling only when needed; no modal churn).
|
||||
- Consistent IA (Inventory hub sub-navigation; canonical Operations).
|
||||
|
||||
## Existing Code & Patterns (to reuse)
|
||||
|
||||
### Operations
|
||||
- Canonical list/detail already exist via `OperationRunResource` (`/operations`).
|
||||
- Tenant scoping already enforced in `OperationRunResource::getEloquentQuery()`.
|
||||
- Detail view already uses conditional polling with safeguards (tab hidden / modal open) via `RunDetailPolling`.
|
||||
|
||||
### Inventory
|
||||
- Inventory entry page exists as `InventoryLanding`.
|
||||
- Inventory “Items” and “Sync Runs” are currently resources (`InventoryItemResource`, `InventorySyncRunResource`).
|
||||
- Inventory sync “start surface” already follows constitution rules: authorize → create/reuse `OperationRun` → enqueue job → “View run”.
|
||||
|
||||
### Monitoring DB-only + Tenant isolation tests
|
||||
- Monitoring/Operations has DB-only tests and tenant scope tests.
|
||||
- Inventory landing + coverage have basic smoke tests.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
### Decision: Use Filament clusters to implement the Inventory “hub” navigation
|
||||
- **Decision**: Create an Inventory cluster and attach:
|
||||
- `InventoryLanding` (page)
|
||||
- Inventory items resource
|
||||
- Inventory sync runs resource
|
||||
- `InventoryCoverage` (page)
|
||||
- **Rationale**: Filament clusters are designed for “common sub-navigation between pages”, including mixing pages and resources.
|
||||
- **Notes**:
|
||||
- Requires enabling cluster discovery in the panel provider.
|
||||
- Sub-navigation position will be set to `Start` to achieve left-side navigation.
|
||||
|
||||
### Decision: Implement KPI headers as widgets (StatsOverviewWidget / TableWidget)
|
||||
- **Decision**: Use Filament widgets for KPI headers on:
|
||||
- Tenant dashboard (drift + ops)
|
||||
- Inventory hub (inventory KPIs)
|
||||
- Operations index (ops KPIs)
|
||||
- **Rationale**: Widgets are first-class, composable, and can optionally poll (with `$pollingInterval`) while remaining DB-only.
|
||||
|
||||
### Decision: “Calm UI” auto-refresh strategy
|
||||
- **Decision**:
|
||||
- Dashboard + Operations index: enable polling only while active runs exist.
|
||||
- Widgets/tables: polling is disabled when no active runs exist.
|
||||
- No polling inside modals.
|
||||
- **Rationale**: Matches FR-012 and avoids background churn.
|
||||
- **Implementation approach**:
|
||||
- Use Filament polling mechanisms:
|
||||
- Widgets: `$pollingInterval = null | '10s'` depending on “active runs exist”.
|
||||
- Tables: enable `$table->poll('10s')` only when “active runs exist”.
|
||||
|
||||
### Decision: No Graph / remote dependencies
|
||||
- **Decision**: All queries for this feature are Eloquent/PostgreSQL queries.
|
||||
- **Rationale**: Matches constitution and SC-005.
|
||||
|
||||
## Alternatives Considered
|
||||
- **Custom Blade layouts for hub navigation**: Rejected because clusters provide consistent sub-nav across resources/pages without fragile view overrides.
|
||||
- **Always-on polling**: Rejected to comply with calm UI rules and avoid waste.
|
||||
- **Keep `Monitoring/Operations` as canonical**: Rejected because `OperationRunResource` is already the canonical Operations surface with correct routing and detail pages.
|
||||
|
||||
## Open Questions
|
||||
None — all “NEEDS CLARIFICATION” items are resolved for planning.
|
||||
218
specs/058-tenant-ui-polish/spec.md
Normal file
218
specs/058-tenant-ui-polish/spec.md
Normal file
@ -0,0 +1,218 @@
|
||||
# Feature Specification: Tenant UI Polish (Dashboard + Inventory Hub + Operations)
|
||||
|
||||
**Feature Branch**: `058-tenant-ui-polish`
|
||||
**Created**: 2026-01-20
|
||||
**Status**: Draft
|
||||
**Input**: User description: "Feature 058 — Tenant UI Polish: Dashboard + Inventory Hub + Operations \"Orders-style\" (v1)"
|
||||
|
||||
## Clarifications
|
||||
|
||||
### Session 2026-01-20
|
||||
|
||||
- Q: Coverage % definition for Inventory KPI header? → A: Coverage % = Restorable / Total (Partial remains a separate chip/number; main % stays conservative)
|
||||
- Q: Drift stale threshold (last scan older than X days)? → A: 7 days
|
||||
- Q: Inventory KPI “Active Operations” definition? → A: Show both counts: All active runs (queued + running) and Inventory-active runs (queued + running)
|
||||
- Q: How many rows in “Recent” lists by default? → A: 10
|
||||
|
||||
### Session 2026-01-21
|
||||
|
||||
- Q: Operations index "Stuck" tab in v1? -> A: No "Stuck" tab in v1
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
<!--
|
||||
IMPORTANT: User stories should be PRIORITIZED as user journeys ordered by importance.
|
||||
Each user story/journey must be INDEPENDENTLY TESTABLE - meaning if you implement just ONE of them,
|
||||
you should still have a viable MVP (Minimum Viable Product) that delivers value.
|
||||
|
||||
Assign priorities (P1, P2, P3, etc.) to each story, where P1 is the most critical.
|
||||
Think of each story as a standalone slice of functionality that can be:
|
||||
- Developed independently
|
||||
- Tested independently
|
||||
- Deployed independently
|
||||
- Demonstrated to users independently
|
||||
-->
|
||||
|
||||
### User Story 1 - Drift-first tenant dashboard (Priority: P1)
|
||||
|
||||
As a tenant admin, I can open a tenant-scoped dashboard that immediately surfaces drift risk and operations health, without triggering any remote calls.
|
||||
|
||||
**Why this priority**: This is the primary entry point for day-to-day operations and should be actionable at a glance.
|
||||
|
||||
**Independent Test**: Visiting the dashboard shows drift + operations KPIs, a “needs attention” list with working CTAs, and recent lists, while confirming no outbound HTTP happens during render and any background UI updates.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** I am signed in to a tenant, **When** I open the Dashboard, **Then** I see tenant-scoped drift KPIs, operations health KPIs, and recent lists.
|
||||
2. **Given** there are urgent drift issues (e.g., high severity open findings), **When** I view the Dashboard, **Then** they appear in the “Needs Attention” section with a CTA that navigates to a filtered view.
|
||||
3. **Given** drift generation has a recent failed run, **When** I view the Dashboard, **Then** I can navigate from “Needs Attention” to the related operation run details.
|
||||
4. **Given** there is no drift data yet, **When** I view the Dashboard, **Then** the dashboard renders calmly with empty-state messaging and no errors.
|
||||
5. **Given** the last drift scan is older than 7 days, **When** I view the Dashboard, **Then** “Needs Attention” includes a “Drift stale” item with a CTA to investigate.
|
||||
6. **Given** there are more than 10 drift findings and operation runs, **When** I view the Dashboard, **Then** each “Recent” list shows the 10 most recent items.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Inventory becomes a hub module (Priority: P2)
|
||||
|
||||
As a tenant admin, I can use Inventory as a “hub” with consistent sub-navigation and a shared KPI header across Inventory subpages.
|
||||
|
||||
**Why this priority**: Inventory is a high-traffic area; a hub layout reduces cognitive load and makes it easier to find the right view quickly.
|
||||
|
||||
**Independent Test**: Navigating Inventory Items / Sync Runs / Coverage keeps the same shared KPI header, the left sub-navigation is consistent, and all data remains tenant-scoped and DB-only.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** I am signed in to a tenant, **When** I open Inventory, **Then** I see hub navigation (Items / Sync Runs / Coverage) and a shared KPI header.
|
||||
2. **Given** I switch between Inventory subpages, **When** I navigate Items → Sync Runs → Coverage, **Then** the KPI header remains visible and consistent.
|
||||
3. **Given** the tenant has an inventory sync run history, **When** I open “Sync Runs”, **Then** I see only sync runs relevant to inventory synchronization.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Operations index “Orders-style” (Priority: P3)
|
||||
|
||||
As a tenant admin, I can view Operations in an “orders-style” overview (KPIs + status tabs + table) to quickly assess activity and failures.
|
||||
|
||||
**Why this priority**: Operations is the canonical place to investigate work; better scanning and filtering reduces time-to-triage.
|
||||
|
||||
**Independent Test**: Visiting Operations index shows KPI cards and status tabs that correctly filter the table without introducing polling churn or any remote calls.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** I am signed in to a tenant, **When** I open Operations, **Then** I see KPIs, status tabs, and the operations table.
|
||||
2. **Given** there are active runs, **When** I click the “Active” tab, **Then** the table filters to queued + running runs only.
|
||||
3. **Given** there are failed runs, **When** I click the “Failed” tab, **Then** the table filters to failed runs only.
|
||||
4. **Given** I navigate away and back, **When** I return to Operations, **Then** the UI remains calm (no refresh loops) and loads quickly.
|
||||
|
||||
---
|
||||
|
||||
[Add more user stories as needed, each with an assigned priority]
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- No data yet: dashboard/inventory/operations render with empty states and helpful CTAs.
|
||||
- Large tenants: KPI calculations remain fast enough to keep pages responsive.
|
||||
- Mixed outcomes: partial/failed/succeeded runs are correctly categorized and discoverable via tabs/filters.
|
||||
- Tenant switching: no cross-tenant leakage of KPIs, lists, or links.
|
||||
- Time windows: KPI windows (e.g., last 7/30 days) handle timezones consistently.
|
||||
- “Unknown” states: missing duration/end time renders gracefully (e.g., avg duration excludes non-terminal runs).
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
**Constitution alignment (required):** If this feature introduces any Microsoft Graph calls, any write/change behavior,
|
||||
or any long-running/queued/scheduled work, the spec MUST describe contract registry updates, safety gates
|
||||
(preview/confirmation/audit), tenant isolation, run observability (`OperationRun` type/identity/visibility), and tests.
|
||||
If security-relevant DB-only actions intentionally skip `OperationRun`, the spec MUST describe `AuditLog` entries.
|
||||
|
||||
<!--
|
||||
ACTION REQUIRED: The content in this section represents placeholders.
|
||||
Fill them out with the right functional requirements.
|
||||
-->
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001 (Tenant scope)**: System MUST ensure the Dashboard, Inventory hub, and Operations views are tenant-scoped, with no cross-tenant visibility.
|
||||
- **FR-002 (DB-only surfaces)**: System MUST keep Dashboard, Inventory hub header, and Operations index DB-only during render and any background UI updates.
|
||||
- **FR-003 (Placement policy)**: System MUST show KPI cards only on these entry-point pages: Dashboard, Inventory hub (shared header), and Operations index.
|
||||
- **FR-004 (Inventory hub layout)**: System MUST provide an Inventory hub with left sub-navigation for Items, Sync Runs, and Coverage.
|
||||
- **FR-005 (Inventory KPIs)**: Inventory hub MUST show a shared KPI header across Inventory subpages with:
|
||||
- Total Items
|
||||
- Coverage % (restorable items / total items; partial shown separately)
|
||||
- Last Inventory Sync (status + timestamp)
|
||||
- Active Operations (queued + running), showing both:
|
||||
- All active runs
|
||||
- Inventory-active runs
|
||||
- **FR-006 (Inventory sync runs view)**: System MUST provide a “Sync Runs” view that lists only inventory synchronization runs.
|
||||
- **FR-007 (Coverage chips)**: System MUST standardize coverage chips to this set only: Restorable, Partial, Risk, Dependencies.
|
||||
- **FR-008 (Operations index KPIs)**: Operations index MUST show tenant-scoped KPIs:
|
||||
- Total Runs (30 days)
|
||||
- Active Runs (queued + running)
|
||||
- Failed/Partial (7 days)
|
||||
- Avg Duration (7 days, terminal runs only)
|
||||
- **FR-009 (Operations tabs)**: Operations index MUST provide status tabs that filter the operations table: All, Active, Succeeded, Partial, Failed. No "Stuck" tab in v1.
|
||||
- **FR-010 (Canonical terminology)**: System MUST use “Operations” as the canonical label (no legacy naming on these surfaces).
|
||||
- **FR-011 (Canonical links)**: “View run” links MUST always navigate to the canonical operation run detail view.
|
||||
- **FR-012 (Calm UI rules)**: System MUST avoid polling/churn in modals and avoid refresh loops; background updates should be used only where clearly necessary. Auto-refresh on Dashboard and Operations index is allowed only while active runs (queued/running) exist, and MUST stop when there are no active runs.
|
||||
- **FR-013 (Drift stale rule)**: System MUST flag drift as “stale” when the last drift scan is older than 7 days and surface it in “Needs Attention” with an investigation CTA.
|
||||
- **FR-014 (Recent list sizing)**: System MUST show 10 rows by default for “Recent Drift Findings” and “Recent Operations”.
|
||||
|
||||
### OperationRun status mapping (for tabs and KPIs)
|
||||
|
||||
OperationRun uses two canonical fields that drive UI filters:
|
||||
|
||||
- `status`: execution lifecycle (e.g., queued/running/completed)
|
||||
- `outcome`: terminal result (e.g., succeeded/partially_succeeded/failed/cancelled)
|
||||
|
||||
Tab filters MUST map exactly as:
|
||||
|
||||
- **All**: no status/outcome filter
|
||||
- **Active**: `status IN (queued, running)`
|
||||
- **Succeeded**: `status = completed AND outcome = succeeded`
|
||||
- **Partial**: `status = completed AND outcome = partially_succeeded`
|
||||
- **Failed**: `status = completed AND outcome = failed`
|
||||
|
||||
Notes:
|
||||
|
||||
- No “Stuck” tab in v1.
|
||||
- Runs with `outcome = cancelled` appear under **All** only (unless a future “Cancelled” tab is added).
|
||||
- Any legacy status/outcome values must already be normalized before reaching this UI (out of scope for this feature).
|
||||
|
||||
### KPI window definitions (timestamp basis)
|
||||
|
||||
All KPI windows are tenant-scoped and DB-only.
|
||||
|
||||
- **Total Runs (30 days)**: count OperationRuns by `created_at` within the last 30 days (includes all statuses/outcomes).
|
||||
- **Active Runs**: current count where `status IN (queued, running)` (no time window).
|
||||
- **Failed/Partial (7 days)**: count terminal runs where `status = completed AND outcome IN (failed, partially_succeeded)` and `completed_at` is within the last 7 days.
|
||||
- **Avg Duration (7 days)**: average of `(completed_at - started_at)` for runs where `status = completed`, `started_at` and `completed_at` are present, and `completed_at` is within the last 7 days.
|
||||
|
||||
### Inventory coverage classification (Restorable/Partial/Risk/Dependencies)
|
||||
|
||||
Coverage chips and KPI aggregation MUST derive from the existing “policy type meta” and dependency capability signals (DB-only):
|
||||
|
||||
- `inventory_items.policy_type`
|
||||
- `config('tenantpilot.supported_policy_types')` meta fields:
|
||||
- `restore` (e.g., enabled / preview-only)
|
||||
- `risk` (e.g., medium / medium-high / high)
|
||||
- Dependency support computed via the existing coverage dependency resolver (based on contracts/config).
|
||||
|
||||
Definitions:
|
||||
|
||||
- **Restorable**: inventory items whose policy type meta has `restore = enabled`
|
||||
- **Partial**: inventory items whose policy type meta has `restore = preview-only`
|
||||
- **Risk**: inventory items whose policy type meta has `risk IN (medium-high, high)`
|
||||
- **Dependencies**: inventory items whose policy type supports dependencies per the existing dependency capability resolver
|
||||
|
||||
Notes:
|
||||
|
||||
- This feature does not redefine coverage semantics; it standardizes UI rendering and KPI aggregation based on the existing policy type meta.
|
||||
- If a policy type is unknown/missing meta, it MUST be treated conservatively (non-restorable) for KPI aggregation.
|
||||
|
||||
**Assumptions**:
|
||||
- Drift findings, inventory items, and operation runs already exist as tenant-scoped data sources.
|
||||
- “Coverage %” is Restorable/Total; Partial is shown separately (e.g., chips/secondary metric). If total is 0, coverage shows as not available.
|
||||
- “Drift stale” default threshold is 7 days.
|
||||
- “Recent” list default size is 10.
|
||||
- Auto-refresh behavior (DB-only): Dashboard and Operations index auto-refresh only while active runs exist; otherwise it stops.
|
||||
- Creating/generating drift is out of scope unless it can be performed as an explicit, enqueue-only user action that results in an operation run.
|
||||
|
||||
### Key Entities *(include if feature involves data)*
|
||||
|
||||
- **Tenant**: The scope boundary for all dashboards and lists in this feature.
|
||||
- **Operation Run**: A tenant-scoped record of work execution, including status, timestamps, and outcomes used for Operations KPIs and recent lists.
|
||||
- **Drift Finding**: A tenant-scoped record representing detected drift, including severity and state (open/closed) used for Dashboard KPIs and “Needs Attention”.
|
||||
- **Inventory Item**: A tenant-scoped record representing inventory coverage and totals used in the Inventory hub.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
<!--
|
||||
ACTION REQUIRED: Define measurable success criteria.
|
||||
These must be technology-agnostic and measurable.
|
||||
-->
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001 (Task speed)**: A tenant admin can reach “what needs attention” (drift/ops) from the dashboard within 30 seconds.
|
||||
- **SC-002 (Discoverability)**: A tenant admin can find inventory sync runs within 2 clicks from Inventory.
|
||||
- **SC-003 (Triage efficiency)**: A tenant admin can filter Operations to “Active” or “Failed” within 1 click and identify a run to investigate within 60 seconds.
|
||||
- **SC-004 (Calm UI)**: No refresh loops are observed on Dashboard, Inventory hub pages, or Operations index during normal navigation.
|
||||
- **SC-005 (Safety)**: Viewing Dashboard, Inventory hub pages, and Operations index does not trigger any outbound HTTP.
|
||||
192
specs/058-tenant-ui-polish/tasks.md
Normal file
192
specs/058-tenant-ui-polish/tasks.md
Normal file
@ -0,0 +1,192 @@
|
||||
---
|
||||
description: "Task list for feature implementation"
|
||||
---
|
||||
|
||||
# Tasks: Tenant UI Polish (Dashboard + Inventory Hub + Operations)
|
||||
|
||||
**Input**: Design documents from `specs/058-tenant-ui-polish/`
|
||||
|
||||
**Tests**: Required (Pest) — this feature changes runtime UI behavior.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Setup (Shared Infrastructure)
|
||||
|
||||
- [ ] T001 Confirm feature inputs exist: specs/058-tenant-ui-polish/spec.md, specs/058-tenant-ui-polish/plan.md
|
||||
- [ ] T002 Confirm Phase 0/1 artifacts exist: specs/058-tenant-ui-polish/research.md, specs/058-tenant-ui-polish/data-model.md, specs/058-tenant-ui-polish/contracts/ui.md, specs/058-tenant-ui-polish/contracts/polling.md, specs/058-tenant-ui-polish/quickstart.md
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (Blocking Prerequisites)
|
||||
|
||||
- [ ] T003 Create shared helper to detect “active runs exist” for tenant polling in app/Support/OpsUx/ActiveRuns.php
|
||||
- [ ] T004 [P] Add focused tests for the helper in tests/Feature/OpsUx/ActiveRunsTest.php
|
||||
|
||||
**Checkpoint**: Shared polling predicate exists and is covered.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 — Drift-first tenant dashboard (Priority: P1) 🎯 MVP
|
||||
|
||||
**Goal**: Tenant-scoped dashboard that surfaces drift + ops KPIs and “Needs Attention”, DB-only.
|
||||
|
||||
**Independent Test**: Visiting the dashboard renders drift KPIs, ops KPIs, needs-attention CTAs, and recent lists (10 rows), with no outbound HTTP and no background work dispatched.
|
||||
|
||||
### Tests (US1)
|
||||
|
||||
- [ ] T005 [P] [US1] Add DB-only render test (no outbound HTTP, no background work) in tests/Feature/Filament/TenantDashboardDbOnlyTest.php
|
||||
- [ ] T006 [P] [US1] Add tenant isolation test (no cross-tenant leakage) in tests/Feature/Filament/TenantDashboardTenantScopeTest.php
|
||||
|
||||
### Implementation (US1)
|
||||
|
||||
- [ ] T007 [US1] Create tenant dashboard page in app/Filament/Pages/TenantDashboard.php
|
||||
- [ ] T008 [US1] Register the tenant dashboard page in app/Providers/Filament/AdminPanelProvider.php (replace default Dashboard page entry)
|
||||
- [ ] T009 [P] [US1] Create dashboard KPI widget(s) in app/Filament/Widgets/Dashboard/DashboardKpis.php
|
||||
- [ ] T010 [P] [US1] Create “Needs Attention” widget in app/Filament/Widgets/Dashboard/NeedsAttention.php
|
||||
- [ ] T011 [P] [US1] Create “Recent Drift Findings” widget (10 rows) in app/Filament/Widgets/Dashboard/RecentDriftFindings.php
|
||||
- [ ] T012 [P] [US1] Create “Recent Operations” widget (10 rows) in app/Filament/Widgets/Dashboard/RecentOperations.php
|
||||
- [ ] T013 [US1] Wire widgets into the dashboard page in app/Filament/Pages/TenantDashboard.php (header/sections) and implement conditional polling per specs/058-tenant-ui-polish/contracts/polling.md
|
||||
- [ ] T014 [US1] Implement drift stale rule (7 days) + CTA wiring in app/Filament/Widgets/Dashboard/NeedsAttention.php
|
||||
- [ ] T015 [US1] Ensure all dashboard queries are tenant-scoped + DB-only in app/Filament/Pages/TenantDashboard.php and app/Filament/Widgets/Dashboard/*.php
|
||||
|
||||
**Checkpoint**: US1 is shippable as an MVP.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 — Inventory becomes a hub module (Priority: P2)
|
||||
|
||||
**Goal**: Inventory becomes a cluster “hub” with consistent left sub-navigation and a shared KPI header across Items / Sync Runs / Coverage.
|
||||
|
||||
**Independent Test**: Navigating Items → Sync Runs → Coverage keeps consistent sub-navigation and shared KPI header, tenant-scoped and DB-only.
|
||||
|
||||
### Tests (US2)
|
||||
|
||||
- [ ] T016 [P] [US2] Add DB-only render test for Inventory hub surfaces in tests/Feature/Filament/InventoryHubDbOnlyTest.php
|
||||
- [ ] T017 [P] [US2] Extend/adjust inventory navigation smoke coverage in tests/Feature/Filament/InventoryPagesTest.php
|
||||
|
||||
### Implementation (US2)
|
||||
|
||||
- [ ] T018 [US2] Enable cluster discovery in app/Providers/Filament/AdminPanelProvider.php (add `discoverClusters(...)`)
|
||||
- [ ] T019 [US2] Create Inventory cluster class in app/Filament/Clusters/Inventory/InventoryCluster.php
|
||||
- [ ] T020 [US2] Assign Inventory cluster to inventory pages in app/Filament/Pages/InventoryLanding.php and app/Filament/Pages/InventoryCoverage.php
|
||||
- [ ] T021 [US2] Assign Inventory cluster to inventory resources in app/Filament/Resources/InventoryItemResource.php and app/Filament/Resources/InventorySyncRunResource.php
|
||||
- [ ] T022 [P] [US2] Create shared Inventory KPI header widget in app/Filament/Widgets/Inventory/InventoryKpiHeader.php
|
||||
- [ ] T023 [US2] Add Inventory KPI header widget to InventoryLanding in app/Filament/Pages/InventoryLanding.php
|
||||
- [ ] T024 [US2] Add Inventory KPI header widget to InventoryCoverage in app/Filament/Pages/InventoryCoverage.php
|
||||
- [ ] T025 [US2] Add Inventory KPI header widget to Inventory items list in app/Filament/Resources/InventoryItemResource.php (or its list page)
|
||||
- [ ] T026 [US2] Add Inventory KPI header widget to Inventory sync runs list in app/Filament/Resources/InventorySyncRunResource.php (or its list page)
|
||||
- [ ] T027 [US2] Ensure Inventory KPI definitions match specs/058-tenant-ui-polish/contracts/ui.md (coverage % restorable/total; partial separate; two active operations counts)
|
||||
- [ ] T041 [US2] Inventory coverage semantics reference (A2)
|
||||
- Identify and document the exact source-of-truth fields for Inventory KPI aggregation:
|
||||
- `inventory_items.policy_type`
|
||||
- `config('tenantpilot.supported_policy_types')` meta fields (`restore`, `risk`)
|
||||
- Dependency support via existing dependency capability resolver
|
||||
- Ensure KPI and chips read from this source only (DB-only).
|
||||
- DoD:
|
||||
- One canonical place documented and referenced by inventory KPIs.
|
||||
- No “magic” or duplicated classification logic across pages/widgets.
|
||||
- [ ] T028 [US2] Ensure “Sync Runs” view is inventory-only per spec in app/Filament/Resources/InventorySyncRunResource.php (query/filter by run type/intent if needed)
|
||||
- [ ] T029 [US2] Standardize coverage chips set on coverage-related surfaces in app/Filament/Pages/InventoryCoverage.php (Restorable, Partial, Risk, Dependencies only)
|
||||
|
||||
**Checkpoint**: Inventory hub behaves as a module with consistent sub-navigation + header.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 3 — Operations index “Orders-style” (Priority: P3)
|
||||
|
||||
**Goal**: Operations index shows KPIs + status tabs + table, with calm conditional polling.
|
||||
|
||||
**Independent Test**: Visiting Operations index shows KPIs and tabs that filter runs per specs/058-tenant-ui-polish/contracts/ui.md, DB-only, calm.
|
||||
|
||||
### Tests (US3)
|
||||
|
||||
- [ ] T030 [P] [US3] Extend Operations DB-only test assertions in tests/Feature/Monitoring/OperationsDbOnlyTest.php (assert tabs/KPI labels appear)
|
||||
- [ ] T031 [P] [US3] Extend Operations tenant isolation coverage in tests/Feature/Monitoring/OperationsTenantScopeTest.php (assert tab views don’t leak)
|
||||
|
||||
### Implementation (US3)
|
||||
|
||||
- [ ] T032 [P] [US3] Create Operations KPI header widget in app/Filament/Widgets/Operations/OperationsKpiHeader.php
|
||||
- [ ] T033 [US3] Add KPIs to the Operations list page in app/Filament/Resources/OperationRunResource/Pages/ListOperationRuns.php
|
||||
- [ ] T034 [US3] Implement status tabs (All/Active/Succeeded/Partial/Failed) on Operations list page in app/Filament/Resources/OperationRunResource/Pages/ListOperationRuns.php
|
||||
- [ ] T035 [US3] Ensure tab filter logic matches specs/058-tenant-ui-polish/contracts/ui.md by adjusting queries in app/Filament/Resources/OperationRunResource/Pages/ListOperationRuns.php
|
||||
- [ ] T036 [US3] Implement conditional polling for Operations list (only while active runs exist) by wiring table polling in app/Filament/Resources/OperationRunResource.php and/or app/Filament/Resources/OperationRunResource/Pages/ListOperationRuns.php
|
||||
- [ ] T037 [US3] Ensure canonical “View run” links still route to OperationRunResource view pages (no legacy routes)
|
||||
- Verify existing canonical link helper `App\Support\OperationRunLinks` is used consistently.
|
||||
- If no suitable helper exists for a given surface, add a minimal equivalent and use it everywhere.
|
||||
|
||||
- [ ] T042 [US3] Operations terminology sweep (FR-010)
|
||||
- Goal: The UI uses the canonical label “Operations” consistently; no legacy naming remains.
|
||||
- Audit + fix in:
|
||||
- Navigation label(s)
|
||||
- Page titles / breadcrumbs
|
||||
- Resource titles / headings
|
||||
- Any links mentioning “Bulk Operation Runs” or legacy run naming
|
||||
- DoD:
|
||||
- No occurrences of legacy labels remain in UI surfaces for Monitoring/Operations.
|
||||
- `rg -n "Bulk Operation|BulkOperationRun|Bulk Operation Runs" app resources` returns 0 matches (or matches only in tests explicitly allowed).
|
||||
- If ripgrep is unavailable, use `grep -R` with the same patterns.
|
||||
|
||||
**Checkpoint**: Operations index is “orders-style” with calm refresh behavior.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Polish & Cross-Cutting Concerns
|
||||
|
||||
- [ ] T038 [P] Run formatting on changed files in app/** and tests/** via `vendor/bin/sail bin pint --dirty`
|
||||
- [ ] T039 Run targeted tests from specs/058-tenant-ui-polish/quickstart.md and ensure green
|
||||
- [ ] T040 [P] Smoke-check key pages render for a tenant in tests/Feature/Filament/AdminSmokeTest.php (add assertions only if gaps are found)
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### User Story Dependencies
|
||||
|
||||
- US1 (P1) is standalone and can ship first.
|
||||
- US2 (P2) can be implemented after foundational polling helper; it touches the panel provider and inventory pages/resources.
|
||||
- US3 (P3) can be implemented after foundational polling helper; it touches the operations resource list page.
|
||||
|
||||
Suggested order (MVP-first): Phase 1 → Phase 2 → US1 → US2 → US3 → Polish.
|
||||
|
||||
### Parallel Opportunities (examples)
|
||||
|
||||
- US1: T009–T012 can be developed in parallel (different widget files).
|
||||
- US2: T022 can be developed in parallel while T018–T021 are in review.
|
||||
- US3: T032 can be developed in parallel with test updates (T030–T031).
|
||||
|
||||
---
|
||||
|
||||
## Parallel Execution Examples (per user story)
|
||||
|
||||
### US1
|
||||
- T005 [P] [US1] tests/Feature/Filament/TenantDashboardDbOnlyTest.php
|
||||
- T006 [P] [US1] tests/Feature/Filament/TenantDashboardTenantScopeTest.php
|
||||
- T009 [P] [US1] app/Filament/Widgets/Dashboard/DashboardKpis.php
|
||||
- T010 [P] [US1] app/Filament/Widgets/Dashboard/NeedsAttention.php
|
||||
- T011 [P] [US1] app/Filament/Widgets/Dashboard/RecentDriftFindings.php
|
||||
- T012 [P] [US1] app/Filament/Widgets/Dashboard/RecentOperations.php
|
||||
|
||||
### US2
|
||||
- T016 [P] [US2] tests/Feature/Filament/InventoryHubDbOnlyTest.php
|
||||
- T022 [P] [US2] app/Filament/Widgets/Inventory/InventoryKpiHeader.php
|
||||
|
||||
### US3
|
||||
- T030 [P] [US3] tests/Feature/Monitoring/OperationsDbOnlyTest.php
|
||||
- T031 [P] [US3] tests/Feature/Monitoring/OperationsTenantScopeTest.php
|
||||
- T032 [P] [US3] app/Filament/Widgets/Operations/OperationsKpiHeader.php
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### MVP First (US1 only)
|
||||
|
||||
1. Complete Phase 1 + Phase 2
|
||||
2. Implement US1 (dashboard)
|
||||
3. Run: `vendor/bin/sail artisan test tests/Feature/Filament/TenantDashboardDbOnlyTest.php`
|
||||
4. Run: `vendor/bin/sail artisan test tests/Feature/Filament/TenantDashboardTenantScopeTest.php`
|
||||
|
||||
### Incremental Delivery
|
||||
|
||||
- Add US2 next (Inventory hub), then US3 (Operations index).
|
||||
- After each story, run its targeted tests + the cross-cutting DB-only tests.
|
||||
Loading…
Reference in New Issue
Block a user