Set pagination_theme explicitly now that the package would otherwise take it over itself; boost:update refreshed the package's guideline and skill. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
278 lines
22 KiB
Markdown
278 lines
22 KiB
Markdown
<laravel-boost-guidelines>
|
||
=== 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 ensure the best experience when building Laravel applications.
|
||
|
||
## Foundational Context
|
||
|
||
This application is a Laravel application running on PHP 8.5. You are an expert with the Laravel ecosystem. Always use the APIs that match the installed major version of each package — do not assume a version.
|
||
|
||
Before relying on a package's API, confirm its installed version:
|
||
- PHP packages: run `composer show --direct` to list direct dependencies with versions, or `composer show <vendor/package>` for a single package.
|
||
- JS packages: check `package.json` for the installed versions.
|
||
|
||
## Skills Activation
|
||
|
||
This project has domain-specific skills available in `**/skills/**`. You MUST activate the relevant skill whenever you work in that domain—don't wait until you're stuck.
|
||
|
||
## 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, and 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 they work. 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 `npm run build`, `npm run dev`, or `composer run dev`. Ask them.
|
||
|
||
## Documentation Files
|
||
|
||
- You must only create documentation files if explicitly requested by the user.
|
||
|
||
## Replies
|
||
|
||
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
|
||
|
||
=== boost rules ===
|
||
|
||
# Laravel Boost
|
||
|
||
## Tools
|
||
|
||
- Laravel Boost is an MCP server with tools designed specifically for this application. Prefer Boost tools over manual alternatives like shell commands or file reads.
|
||
- Use `database-query` to run read-only queries against the database instead of writing raw SQL in tinker.
|
||
- Use `database-schema` to inspect table structure before writing migrations or models.
|
||
- Use `get-absolute-url` to resolve the correct scheme, domain, and port for project URLs. Always use this before sharing a URL with the user.
|
||
- Use `browser-logs` to read browser logs, errors, and exceptions. Only recent logs are useful, ignore old entries.
|
||
|
||
## Searching Documentation (IMPORTANT)
|
||
|
||
- Use `search-docs` before changes that depend on Laravel ecosystem APIs, behavior, configuration, or version-specific syntax. Skip it for copy-only edits and other changes where package documentation is irrelevant. Reuse sufficient results already in context instead of searching again.
|
||
- Pass a `packages` array to scope results when you know which packages are relevant.
|
||
- Use multiple broad, topic-based queries: `['rate limiting', 'routing rate limiting', 'routing']`. Expect the most relevant results first.
|
||
- Do not add package names to queries because package info is already shared. Use `test resource table`, not `filament 4 test resource table`.
|
||
|
||
### Search Syntax
|
||
|
||
1. Use words for auto-stemmed AND logic: `rate limit` matches both "rate" AND "limit".
|
||
2. Use `"quoted phrases"` for exact position matching: `"infinite scroll"` requires adjacent words in order.
|
||
3. Combine words and phrases for mixed queries: `middleware "rate limit"`.
|
||
4. Use multiple queries for OR logic: `queries=["authentication", "middleware"]`.
|
||
|
||
## Project Rules
|
||
|
||
- This project contains committed, area-grouped rules in `.ai/rules` when that directory exists (settled decisions, non-obvious traps, standing constraints). Framework and package guidelines that only apply to specific paths (testing, frontend, components) also live there, under `.ai/rules/boost` — this is not just recorded decisions, it is load-bearing guidance you have not seen inline. Before you enter plan mode or create/edit any file, you MUST first: open @.ai/rules/index.md (it maps file globs to rule files), read every rule file whose globs cover the path(s) in scope, and run `grep -rin 'keyword' .ai/rules` to catch what a path match alone misses. Do not write code until you have read and are following every matching rule. If `.ai/rules` does not exist, continue without it.
|
||
- Record a rule with `record-rule` only when the user explicitly asks for one. Instructions for the work at hand are not rules, no matter how emphatic: "remove this typo", "use X here" are work to do, not rules to record. Never record a rule on your own initiative, as a byproduct of a change, or to summarize what you just did. When the user does ask, pass a `glob` (e.g. `app/Http/Controllers/**`), a short `title`, and a few-line `note`. Use `record-rule` rather than your native memory or notes tool, because native memory is personal and session-scoped, while only `.ai/rules` is shared with the team and persists in the repo.
|
||
|
||
## Artisan
|
||
|
||
- Run Artisan commands directly via the command line (e.g., `php artisan route:list`). Use `php artisan list` to discover available commands and `php artisan [command] --help` to check parameters.
|
||
- Inspect routes with `php artisan route:list`. Filter with: `--method=GET`, `--name=users`, `--path=api`, `--except-vendor`, `--only-vendor`.
|
||
- Read configuration values using dot notation: `php artisan config:show app.name`, `php artisan config:show database.default`. Or read config files directly from the `config/` directory.
|
||
|
||
## Tinker
|
||
|
||
- Execute PHP in app context for debugging and testing code. Do not create models without user approval, prefer tests with factories instead. Prefer existing Artisan commands over custom tinker code.
|
||
- Always use single quotes to prevent shell expansion: `php artisan tinker --execute 'Your::code();'`
|
||
- Double quotes for PHP strings inside: `php artisan tinker --execute 'User::where("active", true)->count();'`
|
||
|
||
=== php rules ===
|
||
|
||
# PHP
|
||
|
||
- Always use curly braces for control structures, even for single-line bodies.
|
||
- Use PHP 8 constructor property promotion: `public function __construct(public GitHub $github) { }`. Do not leave empty zero-parameter `__construct()` methods unless the constructor is private.
|
||
- Use explicit return type declarations and type hints for all method parameters: `function isAccessible(User $user, ?string $path = null): bool`
|
||
- Use TitleCase for Enum keys: `FavoritePerson`, `BestLake`, `Monthly`.
|
||
- Prefer PHPDoc blocks over inline comments. Only add inline comments for exceptionally complex logic.
|
||
- Use array shape type definitions in PHPDoc blocks.
|
||
|
||
=== deployments rules ===
|
||
|
||
# Deployment
|
||
|
||
- Laravel can be deployed using [Laravel Cloud](https://cloud.laravel.com/), which is the fastest way to deploy and scale production Laravel applications.
|
||
- Activate the `deploying-to-cloud` skill whenever deploying to Laravel Cloud, configuring Cloud environments or resources, using the Cloud CLI, or troubleshooting Cloud deployments.
|
||
|
||
=== tests rules ===
|
||
|
||
# Test Enforcement
|
||
|
||
- Add or update tests for behavior and logic changes when a test provides meaningful regression coverage.
|
||
- Pure copy, styling, and layout-only changes do not require new or updated tests.
|
||
- When test coverage applies, run the affected tests and ensure they pass.
|
||
- Test the changed behavior and its important failure modes, but do not add tests beyond them.
|
||
- Read the `testing-best-practices` skill before writing tests.
|
||
|
||
=== 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 `php artisan list` and check their parameters with `php artisan [command] --help`.
|
||
- If you're creating a generic PHP class, use `php 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.
|
||
|
||
### Model Creation
|
||
|
||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `php artisan make:model --help` to check the available options.
|
||
|
||
## 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.
|
||
|
||
## URL Generation
|
||
|
||
- When generating links to other pages, prefer named routes and the `route()` function.
|
||
|
||
## 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.
|
||
|
||
## 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`.
|
||
|
||
=== laravel-octane/core rules ===
|
||
|
||
# Laravel Octane
|
||
|
||
This application uses Laravel Octane, a long-running PHP server. The application bootstraps once and handles many requests within the same process.
|
||
|
||
- Never store request-specific state in singletons or static properties, because it can leak across requests.
|
||
- Use `config('octane.server')` to detect the active driver (`swoole`, `roadrunner`, or `frankenphp`).
|
||
- Prefer scoped bindings (`$this->app->scoped()`) over singletons for per-request services.
|
||
|
||
When working on Octane-specific features (concurrency, shared tables, memory, driver configuration, testing), invoke `octane-development` for detailed rules.
|
||
|
||
=== livewire/core rules ===
|
||
|
||
# Livewire
|
||
|
||
- Livewire allows you to build dynamic, reactive interfaces in PHP without writing JavaScript.
|
||
- You can use Alpine.js for client-side interactions instead of JavaScript frameworks.
|
||
- Keep state server-side so the UI reflects it. Validate and authorize in actions as you would in HTTP requests.
|
||
|
||
=== pint/core rules ===
|
||
|
||
# Laravel Pint Code Formatter
|
||
|
||
- If you have modified any PHP files, you must run `vendor/bin/pint --dirty --format agent` before finalizing changes to ensure your code matches the project's expected style.
|
||
- Do not run `vendor/bin/pint --test --format agent`, simply run `vendor/bin/pint --format agent` to fix any formatting issues.
|
||
|
||
=== pest/core rules ===
|
||
|
||
# Pest
|
||
|
||
- This project uses Pest. Create tests with `php artisan make:test --pest {name}`.
|
||
- Do not include the test suite directory in `{name}`. Use `SomeFeatureTest`, not `Feature/SomeFeatureTest`.
|
||
- Read the `testing-best-practices` skill for guidance on coverage, naming, structure, dependency isolation, and review.
|
||
- Do not delete tests or test files without approval. They are part of the application.
|
||
|
||
## Running Tests
|
||
|
||
- Run the narrowest set of tests that covers the change. Pass a file path or `--filter=testName` to `php artisan test --compact`.
|
||
- Rerun a test after each change to it.
|
||
- Run `vendor/bin/pest` to call the test runner directly. It accepts the same file path and `--filter=testName` arguments.
|
||
- After the feature tests pass, ask the user to run the complete suite with `php artisan test --compact`.
|
||
|
||
=== nonameweb/livewire-material/core rules ===
|
||
|
||
## Livewire Material
|
||
|
||
This application uses `nonameweb/livewire-material`: Material 3 Expressive components for Laravel and Livewire, in plain CSS. No utility classes — Tailwind, daisyUI or any other — belong here: a class your CSS does not declare does nothing, and `DesignGuard` fails it.
|
||
|
||
- Components are anonymous Blade components, unprefixed unless `config/livewire-material.php` sets a `prefix`. Before writing or changing a view that uses them, activate the `livewire-material-development` skill for the props, slots and traps of each component.
|
||
- The CSS entry imports `foundation.css` first, then the stylesheet of each component the views render (or `all.css` for all of them). A component whose stylesheet is not imported renders unstyled; `DesignGuard::missingStylesheets()` names each missing `@import`.
|
||
- Every layout includes `<x-theme-script />` in `<head>` before `@vite`. The colour scheme is generated with `php artisan material:scheme` — never edit `resources/css/material-scheme.css` by hand. With colour profiles (`livewire-material.profiles`), run it without a seed after changing them; the active profile comes from `Scheme::resolveProfileUsing()`.
|
||
- While the application runs locally, every token and component renders in the application's own scheme at `/material` (the showcase).
|
||
- HTTP error pages and the Markdown mail theme come from the package. Change error wording by publishing `--tag=livewire-material-errors`; select the mail theme with `MAIL_MARKDOWN_THEME=livewire-material::mail.theme`.
|
||
|
||
=== nonameweb/livewire-material/material-3 rules ===
|
||
|
||
## Material 3
|
||
|
||
Every view in this application is Material 3 Expressive (m3.material.io), through `nonameweb/livewire-material`. These rules decide what to write; the `material-3-design` skill carries the tables, the numbers and Google's source pages behind each one — activate it before designing a screen.
|
||
|
||
The library is plain CSS on M3's tokens. No utility classes — Tailwind, daisyUI or any other — belong here: a class your CSS does not declare does nothing, and `DesignGuard` fails it. A view is written three ways:
|
||
- Components and their props: `<x-button variant="filled">`, and the layout components `<x-row>`, `<x-stack>`, `<x-grid>`, `<x-feed>`, `<x-surface>` and `<x-pane>`, whose `gap` and `padding` take a spacing token (`space200`) and whose `hide-below`, `hide-from` and `stack-below` take a window size class.
|
||
- A fixed set of classes for text and interaction on plain elements: `md-type-*`, `md-ink-*`, `md-text-*`, `md-truncate`, `md-tabular`, `md-visually-hidden`, `md-state-layer`, `md-focus-ring`, `md-touch-target` and `md-link`.
|
||
- The application's own CSS, named by the application, whose values are `--md-sys-*` custom properties.
|
||
|
||
### Colour
|
||
|
||
- A colour is always a role: `md-ink-variant` on text, `var(--md-sys-color-outline-variant)` in the application's CSS, `color="error"` on a component. Never a hex, a palette tone or an opacity.
|
||
- Pair a role only with its `on-` partner: a `primary` fill takes `on-primary` text, a `secondary-container` fill takes `on-secondary-container`. That pair is the one whose contrast is guaranteed at every contrast level; mixing pairs (`primary-container` under `on-surface`) is not.
|
||
- `primary` is the one key action on a screen (a filled button; the FAB in `primary-container`). `secondary-container` is the quiet fill (tonal buttons, selected navigation, selected chips). `tertiary` is a contrasting accent, used rarely. `error`, `success`, `warning`, `info` mean state and nothing else: the `-container` for a tinted panel, the role itself for its text and icon.
|
||
- Ink is `on-surface` (`md-ink`); lower emphasis is `on-surface-variant` (`md-ink-variant`); decoration is `outline` (`md-ink-quiet`). Never dim ink with an opacity: 38% means disabled.
|
||
- `outline` is a boundary that must be read (a text field, the edge of a target). `outline-variant` is a divider or a card edge (`<x-divider>`, `<x-surface outlined>`). Never `outline` on a divider.
|
||
- Fixed and dim roles (`primary-fixed`, `surface-dim`, …) are for a colour that must not change with the theme; if unsure, don't. Inverse roles only on an inverse surface (the snackbar).
|
||
- A link in running text is underlined (`md-link`, with `md-ink-primary`); colour alone signals nothing.
|
||
- Contrast: 4.5:1 for text, 3:1 for large text, icons and grouped controls; disabled is exempt. Three contrast levels exist (`<html data-contrast>`: standard, medium, high) and every role changes with them — which is why only roles are allowed.
|
||
|
||
### Surfaces and elevation
|
||
|
||
- The page is `surface`. Panels separate by tone first: `surface-container-lowest` … `surface-container-highest` is a hierarchy of emphasis, not of height (`<x-surface level="surface-container-high">`). Navigation chrome is `surface-container`; a dialog, a menu, the search bar are `surface-container-high`; a modal sheet is `surface-container-low`; a filled card is `surface-container-highest`. A region keeps its role at every width.
|
||
- Shadows (`var(--md-sys-elevation-1)` … `-5`) are for what floats or lifts: 1 for elevated cards, buttons and modal sheets; 2 for menus, the navigation bar, a scrolled app bar; 3 for the FAB, dialogs, pickers and search; one level more on hover; nothing rests above 3. Fewer shadows carry more meaning.
|
||
- A scrim is `scrim` at 32%: `color-mix(in srgb, var(--md-sys-color-scrim) 32%, transparent)`.
|
||
|
||
### Shape
|
||
|
||
- Corners come from the scale `var(--md-sys-shape-corner-{none|xs|sm|md|lg|lg-increased|xl|xl-increased|xxl|full})`, or `<x-surface corner="md">`; never a length of your own.
|
||
- By family: `full` buttons, icon buttons, chips' avatars, badges, switches, sliders, the search bar, navigation indicators; `xs` text fields, menus, snackbars, plain tooltips; `sm` chips; `md` cards, rich tooltips; `lg` the FAB and a side sheet's inner corners; `xl` dialogs, bottom sheets, the search view, pickers, carousel items; `xxl` large hero containers.
|
||
- Nested shapes: inner radius = outer radius − padding; never the same radius inside and out.
|
||
- A press squares a round shape (the components do it; nothing morphs on hover). The 35 `<x-shape>`s are decoration, never meaning, used sparingly.
|
||
|
||
### Type
|
||
|
||
- Every text element carries one `md-type-*` class: `display` for hero figures and short marketing lines; `headline` for page and section titles; `title` for card, dialog and list-section titles; `body` for paragraphs (`md-type-body-lg` for reading); `label` inside components (buttons, chips, tabs, captions). In the application's CSS a style is `font: var(--md-sys-typescale-body-md)` with its `-tracking`; never a size, weight, line height or letter spacing of your own.
|
||
- `md-type-emphasized-*` is opt-in: a selected item, a primary action, a headline, a badge — not decoration.
|
||
- 40–60 characters per line; `md-tabular` on figures that change; text must scale to 200% without loss (containers grow, rows wrap, no fixed heights on text, no ellipsis without a way to read the rest).
|
||
|
||
### Motion
|
||
|
||
- Position, size and shape move on the spatial springs (they overshoot): `transition: transform var(--md-sys-motion-spatial-default-duration) var(--md-sys-motion-spatial-default)` — `fast` for small elements, `slow` for large ones. Colour and opacity move on the effects springs (`--md-sys-motion-effects-*`), which never overshoot. Always pair an easing with its duration.
|
||
- Entering decelerates, a permanent exit accelerates, a temporary exit (a sheet, a drawer) takes the emphasized curve; exits are shorter than entrances.
|
||
- Everything that moves goes through these tokens, so reduced motion makes it instant; a literal duration is a bug.
|
||
|
||
### States and targets
|
||
|
||
- Interactive elements carry `md-state-layer md-focus-ring`: hover 8%, focus 10%, pressed 10%, dragged 16% (`data-md-dragged`) of the content colour. Disabled is content at 38% and a container at 12% of `on-surface` (`--md-sys-state-disabled-content-opacity`, `--md-sys-state-disabled-container-opacity`, through `color-mix()`), with no state layer. Every state shows two indicators: colour plus a shape, an outline, an icon or a word.
|
||
- Every target is at least 48×48px with 8px between targets (`md-touch-target` on anything drawn smaller); a denser layout is an opt-in prop, never a default.
|
||
- Keyboard: Tab between components, arrows within one, Enter and Space activate, Escape dismisses; a dialog takes focus and gives it back to what opened it.
|
||
|
||
### Layout and breakpoints
|
||
|
||
- Widths are M3's window size classes and only those: compact below 600px (the default), medium 600, expanded 840, large 1200, extra-large 1600. A layout component takes them as props (`<x-row stack-below="medium">`, `<x-stack hide-from="expanded">`, `<x-grid :columns="['compact' => 1, 'expanded' => 2]">`); the application's CSS writes `@media (width >= 840px)`; a script asks `from()` and `upTo()` from `resources/js/breakpoints.js`.
|
||
- What changes per class: compact — navigation bar, one pane, full-screen dialogs, a bottom sheet for choices; medium — collapsed rail, one pane; expanded — rail (collapsible), two panes, menus and basic dialogs; large and extra-large — the rail expanded, two panes, a third only at extra-large as a side sheet. `<x-scaffold>` does this; content lives in panes (`<x-pane>`, `<x-list-detail>` for a list's second pane), never beside the rail by hand.
|
||
- Margins are 16px below medium and 24px from it (`<x-pane>` draws them); spacing sits on the 4px grid as `space25` … `space900`, as padding and gaps on the parent, with margins only between layout regions. A fixed pane is 360px (expanded) or 412px (large); a side sheet at most 400px.
|
||
- Write logical properties (`padding-inline-start`, `inset-inline-end`, `md-text-start`); directional icons mirror in RTL; charts and media controls stay LTR. Keep controls inside the safe area (`--material-safe-*`).
|
||
|
||
### Accessibility
|
||
|
||
- Native elements first (`<button>`, `<dialog>`, `<input>`), then ARIA. One `main`, one `banner`, one `contentinfo`; every repeated `nav` labelled, without the word "navigation".
|
||
- Headings in order from a single H1; the level is structure, the `md-type-*` class is appearance.
|
||
- An icon-only control has an accessible name that does not include its role; decorative icons are hidden; an error is announced and tied to its field (`aria-describedby`); a toast uses a polite live region and never takes focus. A single-key shortcut needs a modifier or a focused component.
|
||
|
||
### Icons
|
||
|
||
- `<x-icon name="home">` is a Material Symbol Rounded: `filled` means active or selected, `optical="20"` when drawn at 20px or less, one weight per group, the size and colour of the text beside it.
|
||
|
||
### Don'ts
|
||
|
||
- No icon in a snackbar; no disabled FAB (hide it); no horizontal radio rows; no hover morph on cards; no `outline` on dividers; no hex colours; no utility classes, and no breakpoint, radius, shadow, type size or duration off M3's scales; no segmented buttons, navigation drawer or bottom app bar — use `<x-button-group connected>`, the expanded rail and `<x-toolbar>`.
|
||
|
||
</laravel-boost-guidelines>
|