From 388e7e51117564b85b603f521d63b715611e3367 Mon Sep 17 00:00:00 2001 From: Alex Justesen Date: Tue, 18 Nov 2025 07:59:17 -0500 Subject: [PATCH 1/8] Just use Pint to lint (#2423) Co-authored-by: Alex Justesen <1144087+alexjustesen@users.noreply.github.com> --- .github/copilot-instructions.md | 8 ---- .github/workflows/ci.yml | 20 ++++++++-- CLAUDE.md | 12 ------ composer.json | 3 +- composer.lock | 70 +-------------------------------- 5 files changed, 19 insertions(+), 94 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c51b1a6c9..656e8ba4f 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -399,12 +399,4 @@ it('has emails', function (string $email) { - 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. - - -=== tightenco/duster rules === - -## Duster Code Formatter - -- You must run `vendor/bin/duster fix --dirty` before finalizing changes to ensure your code matches the project's expected style. -- Duster wraps Laravel Pint and other formatters, so never run Pint directly. Always prefer Duster for formatting tasks. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fcbf58101..16f5552d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,10 +16,24 @@ jobs: - name: Checkout uses: actions/checkout@v5 - - name: "duster" - uses: tighten/duster-action@v3 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + + - name: Cache Composer dependencies + uses: actions/cache@v4 with: - args: lint --using=pint -v + path: vendor + key: composer-${{ runner.os }}-${{ hashFiles('**/composer.lock') }} + restore-keys: | + composer-${{ runner.os }}- + + - name: Install Dependencies + run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist + + - name: Run Pint + run: vendor/bin/pint --test test-mariadb-11: needs: lint-app diff --git a/CLAUDE.md b/CLAUDE.md index 2a6120728..656e8ba4f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -34,10 +34,6 @@ This application is a Laravel application and its main Laravel ecosystems packag - Stick to existing directory structure - don't create new base folders without approval. - Do not change the application's dependencies without approval. -## Localization -- Only create or update language files in the `lang/en` directory. Do not create or modify language files for other locales. -- All translation strings should be added only to the English language files. - ## 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. @@ -403,12 +399,4 @@ it('has emails', function (string $email) { - 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. - - -=== tightenco/duster rules === - -## Duster Code Formatter - -- You must run `vendor/bin/duster fix --dirty` before finalizing changes to ensure your code matches the project's expected style. -- Duster wraps Laravel Pint and other formatters, so never run Pint directly. Always prefer Duster for formatting tasks. diff --git a/composer.json b/composer.json index 362dc3a78..2b38b1ec7 100644 --- a/composer.json +++ b/composer.json @@ -47,8 +47,7 @@ "nunomaduro/collision": "^8.8.2", "pestphp/pest": "^3.8.4", "pestphp/pest-plugin-laravel": "^3.2", - "spatie/laravel-ignition": "^2.9.1", - "tightenco/duster": "^3.3.0" + "spatie/laravel-ignition": "^2.9.1" }, "autoload": { "files": [ diff --git a/composer.lock b/composer.lock index fd19a1301..b5d427f75 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ef4555e79a9a20191d718ae6b212ca2c", + "content-hash": "39020dcee9d9965e781ef550aca663ac", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -13643,74 +13643,6 @@ ], "time": "2025-11-13T13:44:09+00:00" }, - { - "name": "tightenco/duster", - "version": "v3.3.0", - "source": { - "type": "git", - "url": "https://github.com/tighten/duster.git", - "reference": "0260abaaecabd9655a0836e4038238e6585a8b45" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/tighten/duster/zipball/0260abaaecabd9655a0836e4038238e6585a8b45", - "reference": "0260abaaecabd9655a0836e4038238e6585a8b45", - "shasum": "" - }, - "require": { - "php": "^8.2.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.73", - "laravel-zero/framework": "^11.36", - "laravel/pint": "^1.21", - "nunomaduro/termwind": "^2.0", - "spatie/invade": "^1.1", - "squizlabs/php_codesniffer": "^3.12", - "tightenco/tlint": "^9.5" - }, - "bin": [ - "builds/duster" - ], - "type": "project", - "autoload": { - "psr-4": { - "App\\": "app/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Matt Stauffer", - "email": "matt@tighten.com", - "homepage": "https://tighten.com", - "role": "Developer" - }, - { - "name": "Anthony Clark", - "email": "anthony@tighten.com", - "homepage": "https://tighten.com", - "role": "Developer" - } - ], - "description": "Automatic configuration for Laravel apps to apply Tighten's standard linting & code standards.", - "homepage": "https://github.com/tighten/duster", - "keywords": [ - "Code style", - "duster", - "laravel", - "php", - "tightenco" - ], - "support": { - "issues": "https://github.com/tighten/duster/issues", - "source": "https://github.com/tighten/duster" - }, - "time": "2025-11-07T15:00:12+00:00" - }, { "name": "webmozart/assert", "version": "1.12.1", From 99a26bc343f72b99e93cba8aabf2b4d310bc5739 Mon Sep 17 00:00:00 2001 From: Alex Justesen Date: Tue, 18 Nov 2025 12:35:17 -0500 Subject: [PATCH 2/8] Increase default session lifetime to 1 week (#2425) --- config/session.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/session.php b/config/session.php index 13d86a4ac..d9dbaea98 100644 --- a/config/session.php +++ b/config/session.php @@ -32,7 +32,7 @@ | */ - 'lifetime' => (int) env('SESSION_LIFETIME', 120), + 'lifetime' => (int) env('SESSION_LIFETIME', 10800), # 1 week 'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false), From 1f9c9c4cdd23efcf25fd95a406696da3441c2a1e Mon Sep 17 00:00:00 2001 From: Alex Justesen Date: Thu, 20 Nov 2025 12:46:26 -0500 Subject: [PATCH 3/8] Remove generated Boost files and related configurations (#2428) Co-authored-by: Alex Justesen <1144087+alexjustesen@users.noreply.github.com> --- .github/copilot-instructions.md | 402 -------------------------------- .gitignore | 8 + .mcp.json | 11 - CLAUDE.md | 402 -------------------------------- boost.json | 12 - 5 files changed, 8 insertions(+), 827 deletions(-) delete mode 100644 .github/copilot-instructions.md delete mode 100644 .mcp.json delete mode 100644 CLAUDE.md delete mode 100644 boost.json diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md deleted file mode 100644 index 656e8ba4f..000000000 --- a/.github/copilot-instructions.md +++ /dev/null @@ -1,402 +0,0 @@ - -=== 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.14 -- filament/filament (FILAMENT) - v4 -- laravel/framework (LARAVEL) - v12 -- laravel/prompts (PROMPTS) - v0 -- laravel/sanctum (SANCTUM) - v4 -- livewire/livewire (LIVEWIRE) - v3 -- laravel/mcp (MCP) - v0 -- laravel/pint (PINT) - v1 -- laravel/sail (SAIL) - v1 -- laravel/telescope (TELESCOPE) - v5 -- pestphp/pest (PEST) - v3 -- phpunit/phpunit (PHPUNIT) - v11 -- 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 `npm run build`, `npm run dev`, or `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()`. - - public function __construct(public GitHub $github) { } -- 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. - - -protected function isAccessible(User $user, ?string $path = null): bool -{ - ... -} - - -## 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`. - - -=== 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 `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 `php 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 `php artisan make:test [options] ` 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/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 `php 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) -
- {{ $item->name }} -
- @endforeach - ``` - -- Prefer lifecycle hooks like `mount()`, `updatedFoo()` for initialization and reactive side effects: - - - public function mount(User $user) { $this->user = $user; } - public function updatedSearch() { $this->resetPage(); } - - - -## Testing Livewire - - - Livewire::test(Counter::class) - ->assertSet('count', 0) - ->call('increment') - ->assertSet('count', 1) - ->assertSee(1) - ->assertStatus(200); - - - - - $this->get('/posts/create') - ->assertSeeLivewire(CreatePost::class); - - - -=== 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: - - -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); - }); -}); - - - -=== 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. - - -=== 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 `php artisan make:test --pest `. -- 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: - -it('is true', function () { - expect(true)->toBeTrue(); -}); - - -### 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). -- 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.: - -it('returns all', function () { - $response = $this->postJson('/api/docs', []); - - $response->assertSuccessful(); -}); - - -### 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. - - -it('has emails', function (string $email) { - expect($email)->not->toBeEmpty(); -})->with([ - 'james' => 'james@laravel.com', - 'taylor' => 'taylor@laravel.com', -]); - - - -=== 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. - - -
-
Superior
-
Michigan
-
Erie
-
-
- - -### 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. - -@theme { - --color-brand: oklch(0.72 0.11 178); -} - - -- In Tailwind v4, you import Tailwind using a regular CSS `@import` statement, not using the `@tailwind` directives used in v3: - - - - @tailwind base; - - @tailwind components; - - @tailwind utilities; - + @import "tailwindcss"; - - - -### 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 | - - -=== 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. -
diff --git a/.gitignore b/.gitignore index d4c8d324e..e86852207 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,11 @@ yarn-error.log /.nova /.phpunit.cache /.vscode + +# AI and Boost assets +/.claude +/.github/copilot-instructions.md +/.mcp.json +/boost.json +/AGENTS.md +/CLAUDE.md diff --git a/.mcp.json b/.mcp.json deleted file mode 100644 index fd4766a41..000000000 --- a/.mcp.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "mcpServers": { - "laravel-boost": { - "command": "./vendor/bin/sail", - "args": [ - "artisan", - "boost:mcp" - ] - } - } -} \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 656e8ba4f..000000000 --- a/CLAUDE.md +++ /dev/null @@ -1,402 +0,0 @@ - -=== 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.14 -- filament/filament (FILAMENT) - v4 -- laravel/framework (LARAVEL) - v12 -- laravel/prompts (PROMPTS) - v0 -- laravel/sanctum (SANCTUM) - v4 -- livewire/livewire (LIVEWIRE) - v3 -- laravel/mcp (MCP) - v0 -- laravel/pint (PINT) - v1 -- laravel/sail (SAIL) - v1 -- laravel/telescope (TELESCOPE) - v5 -- pestphp/pest (PEST) - v3 -- phpunit/phpunit (PHPUNIT) - v11 -- 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 `npm run build`, `npm run dev`, or `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()`. - - public function __construct(public GitHub $github) { } -- 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. - - -protected function isAccessible(User $user, ?string $path = null): bool -{ - ... -} - - -## 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`. - - -=== 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 `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 `php 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 `php artisan make:test [options] ` 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/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 `php 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) -
- {{ $item->name }} -
- @endforeach - ``` - -- Prefer lifecycle hooks like `mount()`, `updatedFoo()` for initialization and reactive side effects: - - - public function mount(User $user) { $this->user = $user; } - public function updatedSearch() { $this->resetPage(); } - - - -## Testing Livewire - - - Livewire::test(Counter::class) - ->assertSet('count', 0) - ->call('increment') - ->assertSet('count', 1) - ->assertSee(1) - ->assertStatus(200); - - - - - $this->get('/posts/create') - ->assertSeeLivewire(CreatePost::class); - - - -=== 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: - - -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); - }); -}); - - - -=== 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. - - -=== 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 `php artisan make:test --pest `. -- 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: - -it('is true', function () { - expect(true)->toBeTrue(); -}); - - -### 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). -- 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.: - -it('returns all', function () { - $response = $this->postJson('/api/docs', []); - - $response->assertSuccessful(); -}); - - -### 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. - - -it('has emails', function (string $email) { - expect($email)->not->toBeEmpty(); -})->with([ - 'james' => 'james@laravel.com', - 'taylor' => 'taylor@laravel.com', -]); - - - -=== 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. - - -
-
Superior
-
Michigan
-
Erie
-
-
- - -### 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. - -@theme { - --color-brand: oklch(0.72 0.11 178); -} - - -- In Tailwind v4, you import Tailwind using a regular CSS `@import` statement, not using the `@tailwind` directives used in v3: - - - - @tailwind base; - - @tailwind components; - - @tailwind utilities; - + @import "tailwindcss"; - - - -### 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 | - - -=== 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. -
diff --git a/boost.json b/boost.json deleted file mode 100644 index 34f823756..000000000 --- a/boost.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "agents": [ - "claude_code", - "copilot" - ], - "editors": [ - "claude_code", - "vscode" - ], - "guidelines": [], - "sail": true -} From 07a2ada82e1919626e0c1b28d3b95bf6be11ee16 Mon Sep 17 00:00:00 2001 From: Alex Justesen Date: Thu, 20 Nov 2025 12:51:51 -0500 Subject: [PATCH 4/8] Replace translation label with chore label in Crowdin config (#2429) Co-authored-by: Alex Justesen <1144087+alexjustesen@users.noreply.github.com> --- crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crowdin.yml b/crowdin.yml index 453c3fe81..510736be9 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,7 +1,7 @@ base_path: /lang preserve_hierarchy: true pull_request_labels: - - ":earth_africa: Translations" + - "chore" files: # PHP language files - root level From f751def2fdb974bd59eda6778e7382b85c76ec67 Mon Sep 17 00:00:00 2001 From: Alex Justesen Date: Mon, 24 Nov 2025 10:30:49 -0500 Subject: [PATCH 5/8] Add dispatched_by field to results and update related logic (#2431) Co-authored-by: Alex Justesen <1144087+alexjustesen@users.noreply.github.com> --- app/Actions/Ookla/RunSpeedtest.php | 3 ++- .../Controllers/Api/V1/SpeedtestController.php | 1 + app/Http/Resources/V1/ResultResource.php | 1 + app/Livewire/Topbar/RunSpeedtestAction.php | 1 + app/Models/Result.php | 9 +++++++++ ...1719_add_dispatched_by_to_results_table.php | 18 ++++++++++++++++++ 6 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 database/migrations/2025_11_24_151719_add_dispatched_by_to_results_table.php diff --git a/app/Actions/Ookla/RunSpeedtest.php b/app/Actions/Ookla/RunSpeedtest.php index 0d6a87a87..c3814310e 100644 --- a/app/Actions/Ookla/RunSpeedtest.php +++ b/app/Actions/Ookla/RunSpeedtest.php @@ -23,13 +23,14 @@ class RunSpeedtest { use AsAction; - public function handle(bool $scheduled = false, ?int $serverId = null): mixed + public function handle(bool $scheduled = false, ?int $serverId = null, ?int $dispatchedBy = null): mixed { $result = Result::create([ 'data->server->id' => $serverId, 'service' => ResultService::Ookla, 'status' => ResultStatus::Waiting, 'scheduled' => $scheduled, + 'dispatched_by' => $dispatchedBy, ]); SpeedtestWaiting::dispatch($result); diff --git a/app/Http/Controllers/Api/V1/SpeedtestController.php b/app/Http/Controllers/Api/V1/SpeedtestController.php index a0b00a37a..19519f61e 100644 --- a/app/Http/Controllers/Api/V1/SpeedtestController.php +++ b/app/Http/Controllers/Api/V1/SpeedtestController.php @@ -38,6 +38,7 @@ public function __invoke(Request $request) $result = RunSpeedtestAction::run( serverId: $request->input('server_id'), + dispatchedBy: $request->user()->id, ); return $this->sendResponse( diff --git a/app/Http/Resources/V1/ResultResource.php b/app/Http/Resources/V1/ResultResource.php index e00710297..069a90e71 100644 --- a/app/Http/Resources/V1/ResultResource.php +++ b/app/Http/Resources/V1/ResultResource.php @@ -34,6 +34,7 @@ public function toArray(Request $request): array 'healthy' => $this->healthy, 'status' => $this->status, 'scheduled' => $this->scheduled, + 'dispatched_by' => $this->dispatched_by, 'comments' => $this->comments, 'data' => $this->data, 'created_at' => $this->created_at->toDateTimestring(), diff --git a/app/Livewire/Topbar/RunSpeedtestAction.php b/app/Livewire/Topbar/RunSpeedtestAction.php index b6e77b292..ad8c05271 100644 --- a/app/Livewire/Topbar/RunSpeedtestAction.php +++ b/app/Livewire/Topbar/RunSpeedtestAction.php @@ -53,6 +53,7 @@ public function speedtestAction(): Action RunSpeedtest::run( serverId: $serverId, + dispatchedBy: Auth::id(), ); Notification::make() diff --git a/app/Models/Result.php b/app/Models/Result.php index 3ac4caa77..bba1a37d9 100644 --- a/app/Models/Result.php +++ b/app/Models/Result.php @@ -9,6 +9,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Prunable; +use Illuminate\Database\Eloquent\Relations\BelongsTo; class Result extends Model { @@ -45,4 +46,12 @@ public function prunable(): Builder { return static::where('created_at', '<=', now()->subDays(config('speedtest.prune_results_older_than'))); } + + /** + * Get the user who dispatched this speedtest. + */ + public function dispatchedBy(): BelongsTo + { + return $this->belongsTo(User::class, 'dispatched_by'); + } } diff --git a/database/migrations/2025_11_24_151719_add_dispatched_by_to_results_table.php b/database/migrations/2025_11_24_151719_add_dispatched_by_to_results_table.php new file mode 100644 index 000000000..473c9b776 --- /dev/null +++ b/database/migrations/2025_11_24_151719_add_dispatched_by_to_results_table.php @@ -0,0 +1,18 @@ +foreignId('dispatched_by')->nullable()->constrained('users')->nullOnDelete(); + }); + } +}; From 596f1523406493a70b1e8e6e84b4fb52e522ead1 Mon Sep 17 00:00:00 2001 From: Alex Justesen Date: Mon, 24 Nov 2025 11:35:38 -0500 Subject: [PATCH 6/8] Add user database notifications for completed and failed speedtests (#2432) Co-authored-by: Alex Justesen <1144087+alexjustesen@users.noreply.github.com> --- app/Listeners/ProcessCompletedSpeedtest.php | 44 +++++++++++++++++++++ app/Listeners/ProcessFailedSpeedtest.php | 44 +++++++++++++++++++++ lang/en/general.php | 1 + lang/en/results.php | 1 + 4 files changed, 90 insertions(+) create mode 100644 app/Listeners/ProcessCompletedSpeedtest.php create mode 100644 app/Listeners/ProcessFailedSpeedtest.php diff --git a/app/Listeners/ProcessCompletedSpeedtest.php b/app/Listeners/ProcessCompletedSpeedtest.php new file mode 100644 index 000000000..01bf317e6 --- /dev/null +++ b/app/Listeners/ProcessCompletedSpeedtest.php @@ -0,0 +1,44 @@ +result; + + if ($result->dispatched_by && ! $result->scheduled) { + $this->notifyDispatchingUser($result); + } + } + + /** + * Notify the user who dispatched the speedtest. + */ + private function notifyDispatchingUser(Result $result): void + { + $user = User::find($result->dispatched_by); + + $user->notify( + Notification::make() + ->title(__('results.speedtest_completed')) + ->actions([ + Action::make('view') + ->label(__('general.view')) + ->url(route('filament.admin.resources.results.index')), + ]) + ->success() + ->toDatabase(), + ); + } +} diff --git a/app/Listeners/ProcessFailedSpeedtest.php b/app/Listeners/ProcessFailedSpeedtest.php new file mode 100644 index 000000000..d11e5e7a0 --- /dev/null +++ b/app/Listeners/ProcessFailedSpeedtest.php @@ -0,0 +1,44 @@ +result; + + if ($result->dispatched_by && ! $result->scheduled) { + $this->notifyDispatchingUser($result); + } + } + + /** + * Notify the user who dispatched the speedtest. + */ + private function notifyDispatchingUser(Result $result): void + { + $user = User::find($result->dispatched_by); + + $user->notify( + Notification::make() + ->title(__('results.speedtest_failed')) + ->actions([ + Action::make('view') + ->label(__('general.view')) + ->url(route('filament.admin.resources.results.index')), + ]) + ->warning() + ->toDatabase(), + ); + } +} diff --git a/lang/en/general.php b/lang/en/general.php index 41f3add2c..c29e775d1 100644 --- a/lang/en/general.php +++ b/lang/en/general.php @@ -16,6 +16,7 @@ 'no' => 'No', 'options' => 'Options', 'details' => 'Details', + 'view' => 'View', // Common labels 'name' => 'Name', diff --git a/lang/en/results.php b/lang/en/results.php index 1cd083492..f59df96d8 100644 --- a/lang/en/results.php +++ b/lang/en/results.php @@ -63,6 +63,7 @@ // Notifications 'speedtest_started' => 'Speedtest started', 'speedtest_completed' => 'Speedtest completed', + 'speedtest_failed' => 'Speedtest failed', 'download_threshold_breached' => 'Download threshold breached!', 'upload_threshold_breached' => 'Upload threshold breached!', 'ping_threshold_breached' => 'Ping threshold breached!', From 80dc3e010c93f8cb3c44607137c311dea90fda4c Mon Sep 17 00:00:00 2001 From: Alex Justesen Date: Mon, 24 Nov 2025 12:15:23 -0500 Subject: [PATCH 7/8] New Crowdin updates (#2422) --- lang/de_DE/results.php | 4 ++-- lang/fr_FR/results.php | 12 ++++++------ lang/nl_NL/results.php | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lang/de_DE/results.php b/lang/de_DE/results.php index e14106acf..31a3d2317 100644 --- a/lang/de_DE/results.php +++ b/lang/de_DE/results.php @@ -3,7 +3,7 @@ return [ 'title' => 'Ergebnisse', 'result_overview' => 'Ergebnisübersicht', - 'error_message_title' => 'Error message', + 'error_message_title' => 'Fehlermeldung', // Metrics 'download' => 'Download', @@ -74,6 +74,6 @@ 'select_server_helper' => 'Leer lassen, um den Speedtest auszuführen, ohne einen Server anzugeben. Blockierte Server werden übersprungen.', 'manual_servers' => 'Manuelle Server', 'closest_servers' => 'Closest Server', - 'run_speedtest' => 'Run Speedtest', + 'run_speedtest' => 'Speedtest ausführen', 'start' => 'Start', ]; diff --git a/lang/fr_FR/results.php b/lang/fr_FR/results.php index 79ffac786..d0bb17353 100644 --- a/lang/fr_FR/results.php +++ b/lang/fr_FR/results.php @@ -3,22 +3,22 @@ return [ 'title' => 'Résultats', 'result_overview' => 'Aperçu des résultats', - 'error_message_title' => 'Error message', + 'error_message_title' => 'Message d\'erreur', // Metrics - 'download' => 'Download', + 'download' => 'Téléchargement', 'download_latency_high' => 'Latence de téléchargement élevée', 'download_latency_low' => 'Latence de téléchargement bas', 'download_latency_iqm' => 'Latence de téléchargement MIQ', 'download_latency_jitter' => 'Latence de téléchargement gigue', - 'upload' => 'Upload', + 'upload' => 'Envoi', 'upload_latency_high' => 'Latence d\'envoi élevée', 'upload_latency_low' => 'Latence d\'envoi faible', 'upload_latency_iqm' => 'Latence d\'envoi MIQ', 'upload_latency_jitter' => 'Latence d\'envoi gigue', - 'ping' => 'Ping', + 'ping' => 'Latence', 'ping_details' => 'Détails des latences', 'ping_jitter' => 'Latence gigue', 'ping_high' => 'Latence élevée', @@ -74,6 +74,6 @@ 'select_server_helper' => 'Laisser vide pour exécuter le test de vitesse sans spécifier de serveur. Les serveurs bloqués seront ignorés.', 'manual_servers' => 'Serveurs manuels', 'closest_servers' => 'Serveurs les plus proches', - 'run_speedtest' => 'Run Speedtest', - 'start' => 'Start', + 'run_speedtest' => 'Lancer le test de vitesse', + 'start' => 'Démarrer', ]; diff --git a/lang/nl_NL/results.php b/lang/nl_NL/results.php index 353be80ab..e1bb7b7b6 100644 --- a/lang/nl_NL/results.php +++ b/lang/nl_NL/results.php @@ -3,7 +3,7 @@ return [ 'title' => 'Resultaten', 'result_overview' => 'Overzicht van resultaten', - 'error_message_title' => 'Error message', + 'error_message_title' => 'Fout melding', // Metrics 'download' => 'Download', From 7ebd8f9f365bb76b71730569e0883f06fca7e3ed Mon Sep 17 00:00:00 2001 From: Alex Justesen Date: Mon, 24 Nov 2025 12:19:05 -0500 Subject: [PATCH 8/8] Release v1.9.0 (#2433) Co-authored-by: Alex Justesen <1144087+alexjustesen@users.noreply.github.com> --- config/speedtest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/speedtest.php b/config/speedtest.php index e58c75a47..263729a5f 100644 --- a/config/speedtest.php +++ b/config/speedtest.php @@ -6,9 +6,9 @@ /** * General settings. */ - 'build_date' => Carbon::parse('2025-11-17'), + 'build_date' => Carbon::parse('2025-11-24'), - 'build_version' => 'v1.8.0', + 'build_version' => 'v1.9.0', 'content_width' => env('CONTENT_WIDTH', '7xl'),