diff --git a/.cursor/mcp.json b/.cursor/mcp.json
index 8c6715a151..21682bbfb0 100644
--- a/.cursor/mcp.json
+++ b/.cursor/mcp.json
@@ -1,11 +1,8 @@
{
- "mcpServers": {
- "laravel-boost": {
- "command": "php",
- "args": [
- "artisan",
- "boost:mcp"
- ]
- }
+ "mcpServers": {
+ "laravel-boost": {
+ "command": "php",
+ "args": ["artisan", "boost:mcp"]
}
-}
\ No newline at end of file
+ }
+}
diff --git a/.github/ISSUE_TEMPLATE/1-bug-report.yml b/.github/ISSUE_TEMPLATE/1-bug-report.yml
index 15cce4409b..1727fc5a8d 100644
--- a/.github/ISSUE_TEMPLATE/1-bug-report.yml
+++ b/.github/ISSUE_TEMPLATE/1-bug-report.yml
@@ -1,6 +1,6 @@
name: π Bug Report
description: File a bug report.
-title: "[Bug]: "
+title: '[Bug]: '
assignees:
- phanan
body:
diff --git a/.github/ISSUE_TEMPLATE/2-feature-request.yml b/.github/ISSUE_TEMPLATE/2-feature-request.yml
index 93052b603a..587cfd8b95 100644
--- a/.github/ISSUE_TEMPLATE/2-feature-request.yml
+++ b/.github/ISSUE_TEMPLATE/2-feature-request.yml
@@ -1,6 +1,6 @@
name: π‘Feature request
description: Request a new feature or improvement.
-title: "[FR]: "
+title: '[FR]: '
assignees:
- phanan
body:
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index 4435733435..d608b6f66f 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -6,6 +6,7 @@
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.20
@@ -23,46 +24,58 @@ This application is a Laravel application and its main Laravel ecosystems packag
- 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, 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 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 `pnpm run build`, `pnpm 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 when dealing with Laravel or Laravel ecosystem packages. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation 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.
@@ -71,6 +84,7 @@ This application is a Laravel application and its main Laravel ecosystems packag
- 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'.
@@ -86,11 +100,13 @@ This application is a Laravel application and its main Laravel ecosystems packag
- 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) { }
+ - public function __construct(public GitHub $github) { }
- Do not allow empty `__construct()` methods with zero parameters unless the constructor is private.
### Type Declarations
+
- Always use explicit return type declarations for methods and functions.
- Use appropriate PHP type hints for method parameters.
@@ -102,12 +118,15 @@ protected function isAccessible(User $user, ?string $path = null): bool
## Comments
+
- Prefer PHPDoc blocks over inline 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`.
=== tests rules ===
@@ -126,6 +145,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
- 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.
@@ -133,33 +153,42 @@ protected function isAccessible(User $user, ?string $path = null): bool
- 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] {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 `pnpm run build` or ask the user to run `pnpm run dev` or `composer run dev`.
=== laravel/v12 rules ===
@@ -170,6 +199,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
- Since Laravel 11, Laravel has a new streamlined file structure which this project uses.
### Laravel 12 Structure
+
- In Laravel 12, middleware are no longer registered in `app/Http/Kernel.php`.
- Middleware are configured declaratively in `bootstrap/app.php` using `Application::configure()->withMiddleware()`.
- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files.
@@ -178,10 +208,12 @@ protected function isAccessible(User $user, ?string $path = null): bool
- Console commands 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 12 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.
=== phpunit/core rules ===
@@ -196,6 +228,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
- 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.
### Running Tests
+
- Run the minimal number of tests, using an appropriate filter, before finalizing.
- To run all tests: `php artisan test --compact`.
- To run all tests in a file: `php artisan test --compact tests/Feature/ExampleTest.php`.
@@ -211,6 +244,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
- 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.
@@ -222,6 +256,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
### 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 ===
@@ -248,10 +283,11 @@ protected function isAccessible(User $user, ?string $path = null): bool
### Replaced Utilities
+
- Tailwind v4 removed deprecated utilities. Do not use the deprecated option; use the replacement.
- Opacity values are still numeric.
-| Deprecated | Replacement |
+| Deprecated | Replacement |
|------------+--------------|
| bg-opacity-* | bg-black/* |
| text-opacity-* | text-black/* |
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 74cf425789..ae8d93090c 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -3,14 +3,17 @@ Thank you for contributing to Koel! Please provide a clear description of your c
-->
## Description
+
## Motivation
+
## Screenshots (if applicable)
## Checklist
+
- [ ] I've tested my changes thoroughly and added tests where applicable
- [ ] I've updated relevant documentation (if any)
- [ ] My code follows the project's conventions
diff --git a/.github/workflows/lint-backend.yml b/.github/workflows/lint-backend.yml
index 5b9981cdbf..0dccc69633 100644
--- a/.github/workflows/lint-backend.yml
+++ b/.github/workflows/lint-backend.yml
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- php-version: [ 8.3 ]
+ php-version: [8.3]
steps:
- uses: actions/checkout@v6
- name: Set up PHP
diff --git a/.github/workflows/lint-frontend.yml b/.github/workflows/lint-frontend.yml
index b59d684540..17d40aa981 100644
--- a/.github/workflows/lint-frontend.yml
+++ b/.github/workflows/lint-frontend.yml
@@ -26,7 +26,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- node-version: [ 22 ]
+ node-version: [22]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 81ebb6f91a..d3c59f2fc1 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -23,7 +23,7 @@ jobs:
- name: Install PHP dependencies
uses: ramsey/composer-install@v2
with:
- composer-options: "--prefer-dist --no-dev --optimize-autoloader"
+ composer-options: '--prefer-dist --no-dev --optimize-autoloader'
- name: Set up Node
uses: actions/setup-node@v6
with:
diff --git a/.github/workflows/test-backend-mariadb.yml b/.github/workflows/test-backend-mariadb.yml
index bbf815f748..cb3a3fc33c 100644
--- a/.github/workflows/test-backend-mariadb.yml
+++ b/.github/workflows/test-backend-mariadb.yml
@@ -20,8 +20,8 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- php-version: [ 8.3 ]
- mariadb-version: [ 11.7 ]
+ php-version: [8.3]
+ mariadb-version: [11.7]
fail-fast: false
services:
mariadb:
diff --git a/.github/workflows/test-backend-pgsql.yml b/.github/workflows/test-backend-pgsql.yml
index bbfc8e350f..d8ba14d360 100644
--- a/.github/workflows/test-backend-pgsql.yml
+++ b/.github/workflows/test-backend-pgsql.yml
@@ -20,8 +20,8 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- php-version: [ 8.3 ]
- postgres-version: [ 15 ]
+ php-version: [8.3]
+ postgres-version: [15]
fail-fast: false
services:
postgres:
diff --git a/.github/workflows/test-backend-sqlite.yml b/.github/workflows/test-backend-sqlite.yml
index 357f1887a1..9974b0fefd 100644
--- a/.github/workflows/test-backend-sqlite.yml
+++ b/.github/workflows/test-backend-sqlite.yml
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- php-version: [ 8.3 ]
+ php-version: [8.3]
fail-fast: false
steps:
- uses: actions/checkout@v6
diff --git a/.github/workflows/unit-frontend.yml b/.github/workflows/unit-frontend.yml
index d159d6635a..8a3e28299e 100644
--- a/.github/workflows/unit-frontend.yml
+++ b/.github/workflows/unit-frontend.yml
@@ -26,8 +26,8 @@ jobs:
strategy:
fail-fast: false
matrix:
- node-version: [ 22 ]
- shard: [ 1/3, 2/3, 3/3 ]
+ node-version: [22]
+ shard: [1/3, 2/3, 3/3]
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
diff --git a/.junie/guidelines.md b/.junie/guidelines.md
index 4435733435..d608b6f66f 100644
--- a/.junie/guidelines.md
+++ b/.junie/guidelines.md
@@ -6,6 +6,7 @@
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.20
@@ -23,46 +24,58 @@ This application is a Laravel application and its main Laravel ecosystems packag
- 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, 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 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 `pnpm run build`, `pnpm 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 when dealing with Laravel or Laravel ecosystem packages. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation 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.
@@ -71,6 +84,7 @@ This application is a Laravel application and its main Laravel ecosystems packag
- 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'.
@@ -86,11 +100,13 @@ This application is a Laravel application and its main Laravel ecosystems packag
- 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) { }
+ - public function __construct(public GitHub $github) { }
- Do not allow empty `__construct()` methods with zero parameters unless the constructor is private.
### Type Declarations
+
- Always use explicit return type declarations for methods and functions.
- Use appropriate PHP type hints for method parameters.
@@ -102,12 +118,15 @@ protected function isAccessible(User $user, ?string $path = null): bool
## Comments
+
- Prefer PHPDoc blocks over inline 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`.
=== tests rules ===
@@ -126,6 +145,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
- 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.
@@ -133,33 +153,42 @@ protected function isAccessible(User $user, ?string $path = null): bool
- 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] {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 `pnpm run build` or ask the user to run `pnpm run dev` or `composer run dev`.
=== laravel/v12 rules ===
@@ -170,6 +199,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
- Since Laravel 11, Laravel has a new streamlined file structure which this project uses.
### Laravel 12 Structure
+
- In Laravel 12, middleware are no longer registered in `app/Http/Kernel.php`.
- Middleware are configured declaratively in `bootstrap/app.php` using `Application::configure()->withMiddleware()`.
- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files.
@@ -178,10 +208,12 @@ protected function isAccessible(User $user, ?string $path = null): bool
- Console commands 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 12 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.
=== phpunit/core rules ===
@@ -196,6 +228,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
- 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.
### Running Tests
+
- Run the minimal number of tests, using an appropriate filter, before finalizing.
- To run all tests: `php artisan test --compact`.
- To run all tests in a file: `php artisan test --compact tests/Feature/ExampleTest.php`.
@@ -211,6 +244,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
- 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.
@@ -222,6 +256,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
### 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 ===
@@ -248,10 +283,11 @@ protected function isAccessible(User $user, ?string $path = null): bool
### Replaced Utilities
+
- Tailwind v4 removed deprecated utilities. Do not use the deprecated option; use the replacement.
- Opacity values are still numeric.
-| Deprecated | Replacement |
+| Deprecated | Replacement |
|------------+--------------|
| bg-opacity-* | bg-black/* |
| text-opacity-* | text-black/* |
diff --git a/.junie/mcp/mcp.json b/.junie/mcp/mcp.json
index 334edc6fd5..3242e7b13c 100644
--- a/.junie/mcp/mcp.json
+++ b/.junie/mcp/mcp.json
@@ -1,11 +1,8 @@
{
- "mcpServers": {
- "laravel-boost": {
- "command": "/Users/an/Library/Application Support/Herd/bin/php83",
- "args": [
- "/Users/an/OSS/koel/koel/artisan",
- "boost:mcp"
- ]
- }
+ "mcpServers": {
+ "laravel-boost": {
+ "command": "/Users/an/Library/Application Support/Herd/bin/php83",
+ "args": ["/Users/an/OSS/koel/koel/artisan", "boost:mcp"]
}
-}
\ No newline at end of file
+ }
+}
diff --git a/.mcp.json b/.mcp.json
index 8c6715a151..21682bbfb0 100644
--- a/.mcp.json
+++ b/.mcp.json
@@ -1,11 +1,8 @@
{
- "mcpServers": {
- "laravel-boost": {
- "command": "php",
- "args": [
- "artisan",
- "boost:mcp"
- ]
- }
+ "mcpServers": {
+ "laravel-boost": {
+ "command": "php",
+ "args": ["artisan", "boost:mcp"]
}
-}
\ No newline at end of file
+ }
+}
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 0000000000..5a801366e4
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1,2 @@
+# vite-plus preview build registry bridge (auto-added by vp)
+registry=https://registry-bridge.viteplus.dev/
diff --git a/.vscode/mcp.json b/.vscode/mcp.json
index 5d3724c4ba..2189c2496b 100644
--- a/.vscode/mcp.json
+++ b/.vscode/mcp.json
@@ -1,11 +1,8 @@
{
- "servers": {
- "laravel-boost": {
- "command": "php",
- "args": [
- "artisan",
- "boost:mcp"
- ]
- }
+ "servers": {
+ "laravel-boost": {
+ "command": "php",
+ "args": ["artisan", "boost:mcp"]
}
-}
\ No newline at end of file
+ }
+}
diff --git a/AGENTS.md b/AGENTS.md
index 1b09c09e6c..bd96e9ecd8 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -6,6 +6,7 @@
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.20
@@ -23,46 +24,58 @@ This application is a Laravel application and its main Laravel ecosystems packag
- 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, 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 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 `pnpm run build`, `pnpm 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 when dealing with Laravel or Laravel ecosystem packages. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation 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.
@@ -71,6 +84,7 @@ This application is a Laravel application and its main Laravel ecosystems packag
- 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'.
@@ -86,11 +100,13 @@ This application is a Laravel application and its main Laravel ecosystems packag
- 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) { }
+ - public function __construct(public GitHub $github) { }
- Do not allow empty `__construct()` methods with zero parameters unless the constructor is private.
### Type Declarations
+
- Always use explicit return type declarations for methods and functions.
- Use appropriate PHP type hints for method parameters.
@@ -102,12 +118,15 @@ protected function isAccessible(User $user, ?string $path = null): bool
## Comments
+
- Prefer PHPDoc blocks over inline 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`.
=== tests rules ===
@@ -126,6 +145,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
- 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.
@@ -133,33 +153,42 @@ protected function isAccessible(User $user, ?string $path = null): bool
- 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] {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 `pnpm run build` or ask the user to run `pnpm run dev` or `composer run dev`.
=== laravel/v12 rules ===
@@ -170,6 +199,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
- Since Laravel 11, Laravel has a new streamlined file structure which this project uses.
### Laravel 12 Structure
+
- In Laravel 12, middleware are no longer registered in `app/Http/Kernel.php`.
- Middleware are configured declaratively in `bootstrap/app.php` using `Application::configure()->withMiddleware()`.
- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files.
@@ -178,10 +208,12 @@ protected function isAccessible(User $user, ?string $path = null): bool
- Console commands 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 12 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.
=== phpunit/core rules ===
@@ -196,6 +228,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
- 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.
### Running Tests
+
- Run the minimal number of tests, using an appropriate filter, before finalizing.
- To run all tests: `php artisan test --compact`.
- To run all tests in a file: `php artisan test --compact tests/Feature/ExampleTest.php`.
@@ -211,6 +244,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
- 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.
@@ -222,6 +256,7 @@ protected function isAccessible(User $user, ?string $path = null): bool
### 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 ===
@@ -248,10 +283,11 @@ protected function isAccessible(User $user, ?string $path = null): bool
### Replaced Utilities
+
- Tailwind v4 removed deprecated utilities. Do not use the deprecated option; use the replacement.
- Opacity values are still numeric.
-| Deprecated | Replacement |
+| Deprecated | Replacement |
|------------+--------------|
| bg-opacity-* | bg-black/* |
| text-opacity-* | text-black/* |
@@ -267,21 +303,26 @@ protected function isAccessible(User $user, ?string $path = null): bool
## Architecture
+
- Koel loads data progressively β there is no method to fetch all songs at once. Songs are loaded lazily per screen/context. This is by design for large libraries. Never assume the playable store vault contains all songs.
## Code Organization
+
- Traits must be placed in a `Concerns` subfolder (namespace) relative to their consumers (e.g. `App\Ai\Tools\Concerns\PlaysMusic`).
- Interfaces must be placed in a `Contracts` subfolder (namespace) relative to their consumers (e.g. `App\Ai\Tools\Contracts\SomeInterface`).
## Spelling
+
- Use US English spelling for all identifiers (PHP method/class/property names, TS/Vue variables and components), comments, docstrings, doc pages, and user-visible strings: `serialize` / `serializer` (not `serialise`), `color` (not `colour`), `initialize` (not `initialise`), `behavior` (not `behaviour`), `organize` / `organization`, `favorite`, `analyze`. Koel's codebase β and PHP's SPL (`JsonSerializable`) β is uniformly American; don't drift British by reflex.
## Self-Explanatory Code
+
- Code should read on its own. If a piece of code needs a comment to be understood, that's a signal the code is wrong, not that the comment is needed β refactor it: extract a named helper, rename a variable to encode intent, lift a condition into a named flag, pull a block into a small function. Use a comment only when refactoring genuinely can't carry the intent (a hidden invariant, a workaround tied to a specific external bug, behaviour a reader would otherwise misjudge). Never write comments that narrate the next line, summarise the surrounding block, or restate what well-named identifiers already say.
- Don't use single-letter variable names. The only allowed ones are `i` / `j` for loop counters, `h` for the test harness, and `$e` for the exception variable in `catch (Throwable|Exception|Error $e)` blocks (PHP's universal idiom β analogous to `e` for events in JS/TS event handlers). For everything else (callback params, destructured fields, lambda args, etc.) pick a name that says what it is.
- Never combine assignment with return. Always `$x = expr;` then `return $x;` on a separate line β `return $x = expr;` cramming two effects into one statement is forbidden in PHP, TS, and JS.
## PHP Conventions
+
- Always prefer Laravel's built-in helpers over custom implementations (e.g. `str()->plural()`, `Str::slug()`, `Arr::flatten()`, etc.). Do not reimplement what Laravel already provides.
- For guard clauses that throw on a condition, always reach for `throw_if($condition, ExceptionClass::class, ...$args)` / `throw_unless($condition, ExceptionClass::class, ...$args)` before writing `if (β¦) { throw new β¦; }`. The Laravel helpers read as a single declarative line, and the extra args are forwarded to the exception constructor. Plain `if`/`throw` is only correct when the throw branch has to do additional work (logging, side effects) before throwing.
- All methods must have explicit visibility (`public`, `protected`, or `private`). Never omit the visibility keyword, even on interface methods or static methods.
@@ -300,80 +341,96 @@ protected function isAccessible(User $user, ?string $path = null): bool
- Value objects in `app/Values/` must use a `final readonly class` with a `private __construct(...)` and a `public static function make(...): self` factory. Call sites construct them via `Foo::make(...)`, never `new Foo(...)`. The reference shape is `App\Values\Radio\RadioStationCreateData`.
## Environment Variables Documentation
+
- When adding, removing, or modifying environment variables in `.env.example`, always update `docs/environment-variables.md` to stay in sync.
## Documentation Pages
+
- Every doc page under `docs/` must have a `description` in its YAML frontmatter. When creating or editing a doc page, ensure the description accurately summarizes the page content.
- The docs use `vitepress-plugin-llms` to generate `llms.txt` and `llms-full.txt` on build; descriptions are surfaced there.
- Run `bash docs/.vitepress/check-frontmatter.sh` to verify all pages have descriptions.
-- **Write docs for users, not engineers.** Be concise, use simple words, be friendly. Lead with the action ("To upgrade: 1. Download. 2. Extract. 3. Restart."), not the rationale. Don't explain how launcher scripts or commands work internally β users want to know *what to do*, not *how the script reasons about it*. Cut corporate-speak ("turnkey path", "conceptually immutable", "provisions with the conventional layout"), nerdy parentheticals ("(`migrate` is idempotent β Laravel skips already-applied ones)"), and redundant warnings already covered elsewhere on the page.
-- **Don't inject your own judgment into docs.** No "isn't straightforward", "is usually easier", "you'd need to", "this is the recommended path", "for most users", "if you really want to". Don't editorialize difficulty, opinion-rate alternatives, or steer the reader toward what *you* think they should do. Users decided to read this section; just give them the steps.
+- **Write docs for users, not engineers.** Be concise, use simple words, be friendly. Lead with the action ("To upgrade: 1. Download. 2. Extract. 3. Restart."), not the rationale. Don't explain how launcher scripts or commands work internally β users want to know _what to do_, not _how the script reasons about it_. Cut corporate-speak ("turnkey path", "conceptually immutable", "provisions with the conventional layout"), nerdy parentheticals ("(`migrate` is idempotent β Laravel skips already-applied ones)"), and redundant warnings already covered elsewhere on the page.
+- **Don't inject your own judgment into docs.** No "isn't straightforward", "is usually easier", "you'd need to", "this is the recommended path", "for most users", "if you really want to". Don't editorialize difficulty, opinion-rate alternatives, or steer the reader toward what _you_ think they should do. Users decided to read this section; just give them the steps.
- **No clever bash one-liners for trivial tasks.** Don't reach for `diff <(grep -oE β¦ | sort -u) <(β¦)` when the instruction is "compare two files" β users can eyeball them. Process substitution, awk, sed pipelines, and similar are nerd-bait. If the task is "look at the difference between A and B", say that in English. Reserve shell snippets for things the user actually needs the exact incantation for.
## Git Commits
+
- Use [Conventional Commits](https://www.conventionalcommits.org/) for all commit messages (e.g. `fix:`, `feat:`, `chore:`, `test:`, `refactor:`, `docs:`, `ci:`, etc.).
- Focus on the feature/purpose, not implementation details. For example, prefer "feat: show current playing song during radio stream" over "feat: radio station ICY metadata now-playing". Same applies to PR titles.
- Never attribute work to AI in any artifact: no "Generated with Claude Code", "Assisted by AI", "Co-Authored-By: Claude/ChatGPT/Copilot/AI" lines, no AI-tool mentions in commits, PR titles, PR descriptions, issue comments, code comments, or doc pages. The author is the human running the tool.
- When the implementation of a PR changes (e.g. during code review), always update the PR title and description to reflect the current state of the changes.
## Releasing
+
- To release a new version, run `php artisan koel:release` (interactive) or `php artisan koel:release {patch|minor|major|vX.Y.Z}`. The command handles the version bump, commit, tag, `latest` tag move, and `release` branch sync.
- Do not bump `.version`, create release tags, or move the `latest` tag manually β always use `php artisan koel:release`.
- After the command finishes, the draft release is **not** immediately available on https://github.com/koel/koel/releases. The tag push triggers the `Upload Release Assets` GitHub Action (`.github/workflows/release.yml`), which sets up PHP/Node, builds assets, packages the zip/tarball, and only then creates the draft release. This typically takes several minutes.
- Wait for the workflow to finish before opening the releases page. Poll with `gh run list --workflow=release.yml --limit 1` or block on it with `gh run watch` (pick the most recent run). Once it's `completed/success`, the draft release exists and can be edited/published on GitHub.
- For minor/patch releases, you may be asked to write the release notes. Follow the convention of prior releases (e.g. v9.1.1, v9.1.0, v8.3.1):
- - Title: `vX.Y.Z` (no codename β codenames are reserved for major versions like "Beethoven" in v9.0.0, "Tchaikovsky" in v8.0.0).
- - Body matches GitHub's auto-generated format. Easiest way: `gh api repos/koel/koel/releases/generate-notes -F tag_name=vX.Y.Z -F previous_tag_name=vPREV --jq .body` to fetch the auto-generated body, then apply it with `gh release edit vX.Y.Z --repo koel/koel --notes-file -`.
- - Required structure: a `## What's Changed` section with bullets in the form `* by @ in `, optionally a `## New Contributors` section, and a trailing `**Full Changelog**: https://github.com/koel/koel/compare/vPREV...vX.Y.Z` line.
- - Do not rewrite or summarize commit subjects β keep them verbatim. Direct-to-master commits without PRs link to the commit SHA URL instead of a PR URL.
- - **Publish (un-draft) the release before tagging koel/franken or koel/docker.** Both downstream build scripts `curl https://github.com/koel/koel/releases/download/vX.Y.Z/koel-vX.Y.Z.tar.gz`, and that URL returns 404 for draft releases β the build fails. Apply notes and publish in one shot: `gh release edit vX.Y.Z --repo koel/koel --notes-file /tmp/notes.md --draft=false`. Only leave it as a draft if you're releasing koel/koel in isolation (no franken/docker companion).
+ - Title: `vX.Y.Z` (no codename β codenames are reserved for major versions like "Beethoven" in v9.0.0, "Tchaikovsky" in v8.0.0).
+ - Body matches GitHub's auto-generated format. Easiest way: `gh api repos/koel/koel/releases/generate-notes -F tag_name=vX.Y.Z -F previous_tag_name=vPREV --jq .body` to fetch the auto-generated body, then apply it with `gh release edit vX.Y.Z --repo koel/koel --notes-file -`.
+ - Required structure: a `## What's Changed` section with bullets in the form `* by @ in `, optionally a `## New Contributors` section, and a trailing `**Full Changelog**: https://github.com/koel/koel/compare/vPREV...vX.Y.Z` line.
+ - Do not rewrite or summarize commit subjects β keep them verbatim. Direct-to-master commits without PRs link to the commit SHA URL instead of a PR URL.
+ - **Publish (un-draft) the release before tagging koel/franken or koel/docker.** Both downstream build scripts `curl https://github.com/koel/koel/releases/download/vX.Y.Z/koel-vX.Y.Z.tar.gz`, and that URL returns 404 for draft releases β the build fails. Apply notes and publish in one shot: `gh release edit vX.Y.Z --repo koel/koel --notes-file /tmp/notes.md --draft=false`. Only leave it as a draft if you're releasing koel/koel in isolation (no franken/docker companion).
- If a downstream build fails because koel/koel was still a draft at the time, recover with `gh workflow run release.yml --repo koel/franken -f koel_version=vX.Y.Z` for franken. koel/docker has no such input β koel/docker#226 removed `workflow_dispatch` so a tag push is the only way to release β so recover there with `gh run rerun --repo koel/docker`, which replays the build against the tag that already exists.
## AI Assistant Tools
+
- When AI assistant tool capabilities change (added, removed, or updated), always update the sample prompts in `AiSamplePrompts.vue` to reflect the current abilities.
## Lucide Icons
+
- When importing icons from `lucide-vue-next`, always use the `Icon` suffix (e.g. `SparklesIcon`, not `Sparkles`; `SearchIcon`, not `Search`).
## TypeScript Conventions
+
- Always prefer generics over type casting when the API supports it (e.g. `container.querySelector('.foo')` instead of `container.querySelector('.foo') as HTMLElement`).
- Do not add explicit return types when they can be inferred by the compiler. Only annotate return types when inference is insufficient or ambiguous.
- When using `setTimeout`, `setInterval`, or `requestAnimationFrame`, always ensure they are cleaned up: on component unmount (`onBeforeUnmount`), on state transitions that invalidate them (e.g. drop cancels a pending expand), and when the operation completes. Treat every timer/rAF as a resource that must be explicitly released.
## Vue Template Conventions
+
- Always use Vue's same-name shorthand for bindings: `:foo` instead of `:foo="foo"`. This applies to props, components, and any v-bind where the attribute name matches the variable name.
## Vue Forms
+
- Any Vue surface that takes user input and commits it on submit must use the `useForm` composable from `@/composables/useForm` β including inline composers, popovers, and mini name-prompts that aren't named `*Form.vue`. Don't roll your own `ref('')` + manual submit handling.
- Pair it with the canonical wiring: `