mirror of
https://github.com/HolgerHatGarKeineNode/einundzwanzig-app.git
synced 2026-03-14 02:13:17 +00:00
🔥 Remove Laravel Sail, Docker, and related setup, migrate to simplified local development environment
- **Removed:** `docker-compose.yml`, Sail-specific Dockerfiles, and related scripts for PHP 8.3 setup. - **Updated:** Documentation to reflect a shift from Docker to a direct PHP-based local development workflow. - **Removed:** `laravel/sail` dependency from `composer.lock`. - **Implemented:** `#[Locked]` Livewire attribute across components for read-only properties. - **Added:** Feature tests to ensure locked properties cannot be tampered with.
This commit is contained in:
@@ -67,7 +67,7 @@ The Laravel Boost guidelines are specifically curated by Laravel maintainers for
|
||||
## 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.3.29
|
||||
- php - 8.4.17
|
||||
- laravel/framework (LARAVEL) - v12
|
||||
- laravel/horizon (HORIZON) - v5
|
||||
- laravel/nightwatch (NIGHTWATCH) - v1
|
||||
@@ -78,7 +78,6 @@ This application is a Laravel application and its main Laravel ecosystems packag
|
||||
- livewire/livewire (LIVEWIRE) - v4
|
||||
- laravel/mcp (MCP) - v0
|
||||
- laravel/pint (PINT) - v1
|
||||
- laravel/sail (SAIL) - v1
|
||||
- pestphp/pest (PEST) - v4
|
||||
- phpunit/phpunit (PHPUNIT) - v12
|
||||
- tailwindcss (TAILWINDCSS) - v4
|
||||
@@ -96,7 +95,7 @@ This application is a Laravel application and its main Laravel ecosystems packag
|
||||
- Do not change the application's dependencies without approval.
|
||||
|
||||
## Frontend Bundling
|
||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `vendor/bin/sail yarn run build`, `vendor/bin/sail yarn run dev`, or `vendor/bin/sail composer run dev`. Ask them.
|
||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `yarn run build`, `yarn run dev`, or `composer run dev`. Ask them.
|
||||
|
||||
## Replies
|
||||
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
|
||||
@@ -171,33 +170,19 @@ protected function isAccessible(User $user, ?string $path = null): bool
|
||||
## Enums
|
||||
- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`.
|
||||
|
||||
=== sail rules ===
|
||||
|
||||
## Laravel Sail
|
||||
|
||||
- This project runs inside Laravel Sail's Docker containers. You MUST execute all commands through Sail.
|
||||
- Start services using `vendor/bin/sail up -d` and stop them with `vendor/bin/sail stop`.
|
||||
- Open the application in the browser by running `vendor/bin/sail open`.
|
||||
- Always prefix PHP, Artisan, Composer, and Node commands with `vendor/bin/sail`. Examples:
|
||||
- Run Artisan Commands: `vendor/bin/sail artisan migrate`
|
||||
- Install Composer packages: `vendor/bin/sail composer install`
|
||||
- Execute Node commands: `vendor/bin/sail yarn run dev`
|
||||
- Execute PHP scripts: `vendor/bin/sail php [script]`
|
||||
- View all available Sail commands by running `vendor/bin/sail` without arguments.
|
||||
|
||||
=== tests rules ===
|
||||
|
||||
## Test Enforcement
|
||||
|
||||
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
|
||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `vendor/bin/sail artisan test --compact` with a specific filename or filter.
|
||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test --compact` with a specific filename or filter.
|
||||
|
||||
=== laravel/core rules ===
|
||||
|
||||
## Do Things the Laravel Way
|
||||
|
||||
- Use `vendor/bin/sail artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
||||
- If you're creating a generic PHP class, use `vendor/bin/sail artisan make:class`.
|
||||
- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
||||
- If you're creating a generic PHP class, use `php artisan make:class`.
|
||||
- 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
|
||||
@@ -208,7 +193,7 @@ 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 `vendor/bin/sail artisan make:model`.
|
||||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `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.
|
||||
@@ -232,10 +217,10 @@ protected function isAccessible(User $user, ?string $path = null): bool
|
||||
### Testing
|
||||
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
|
||||
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
|
||||
- When creating tests, make use of `vendor/bin/sail artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
|
||||
- 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 `vendor/bin/sail yarn run build` or ask the user to run `vendor/bin/sail yarn run dev` or `vendor/bin/sail composer run dev`.
|
||||
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `yarn run build` or ask the user to run `yarn run dev` or `composer run dev`.
|
||||
|
||||
=== laravel/v12 rules ===
|
||||
|
||||
@@ -286,7 +271,7 @@ accordion, autocomplete, avatar, badge, brand, breadcrumbs, button, calendar, ca
|
||||
## Livewire
|
||||
|
||||
- Use the `search-docs` tool to find exact version-specific documentation for how to write Livewire and Livewire tests.
|
||||
- Use the `vendor/bin/sail artisan make:livewire [Posts\CreatePost]` Artisan command to create new components.
|
||||
- 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.
|
||||
|
||||
@@ -330,8 +315,8 @@ accordion, autocomplete, avatar, badge, brand, breadcrumbs, button, calendar, ca
|
||||
|
||||
## Laravel Pint Code Formatter
|
||||
|
||||
- You must run `vendor/bin/sail bin pint --dirty` before finalizing changes to ensure your code matches the project's expected style.
|
||||
- Do not run `vendor/bin/sail bin pint --test`, simply run `vendor/bin/sail bin pint` to fix any formatting issues.
|
||||
- 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 ===
|
||||
|
||||
@@ -340,7 +325,7 @@ accordion, autocomplete, avatar, badge, brand, breadcrumbs, button, calendar, ca
|
||||
- If you need to verify a feature is working, write or update a Unit / Feature test.
|
||||
|
||||
### Pest Tests
|
||||
- All tests must be written using Pest. Use `vendor/bin/sail artisan make:test --pest {name}`.
|
||||
- All tests must be written using Pest. Use `php artisan make:test --pest {name}`.
|
||||
- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application.
|
||||
- Tests should test all of the happy paths, failure paths, and weird paths.
|
||||
- Tests live in the `tests/Feature` and `tests/Unit` directories.
|
||||
@@ -353,9 +338,9 @@ it('is true', function () {
|
||||
|
||||
### Running Tests
|
||||
- Run the minimal number of tests using an appropriate filter before finalizing code edits.
|
||||
- To run all tests: `vendor/bin/sail artisan test --compact`.
|
||||
- To run all tests in a file: `vendor/bin/sail artisan test --compact tests/Feature/ExampleTest.php`.
|
||||
- To filter on a particular test name: `vendor/bin/sail artisan test --compact --filter=testName` (recommended after making a change to a related file).
|
||||
- To run all tests: `php artisan test --compact`.
|
||||
- To run all tests in a file: `php artisan test --compact tests/Feature/ExampleTest.php`.
|
||||
- To filter on a particular test name: `php artisan test --compact --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
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"laravel-boost": {
|
||||
"command": "vendor/bin/sail",
|
||||
"command": "/usr/bin/php",
|
||||
"args": [
|
||||
"artisan",
|
||||
"/var/home/user/Code/einundzwanzig-app/artisan",
|
||||
"boost:mcp"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"laravel-boost": {
|
||||
"command": "vendor/bin/sail",
|
||||
"command": "php",
|
||||
"args": [
|
||||
"artisan",
|
||||
"boost:mcp"
|
||||
|
||||
45
AGENTS.md
45
AGENTS.md
@@ -8,7 +8,7 @@ The Laravel Boost guidelines are specifically curated by Laravel maintainers for
|
||||
## 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.3.29
|
||||
- php - 8.4.17
|
||||
- laravel/framework (LARAVEL) - v12
|
||||
- laravel/horizon (HORIZON) - v5
|
||||
- laravel/nightwatch (NIGHTWATCH) - v1
|
||||
@@ -19,7 +19,6 @@ This application is a Laravel application and its main Laravel ecosystems packag
|
||||
- livewire/livewire (LIVEWIRE) - v4
|
||||
- laravel/mcp (MCP) - v0
|
||||
- laravel/pint (PINT) - v1
|
||||
- laravel/sail (SAIL) - v1
|
||||
- pestphp/pest (PEST) - v4
|
||||
- phpunit/phpunit (PHPUNIT) - v12
|
||||
- tailwindcss (TAILWINDCSS) - v4
|
||||
@@ -37,7 +36,7 @@ This application is a Laravel application and its main Laravel ecosystems packag
|
||||
- Do not change the application's dependencies without approval.
|
||||
|
||||
## Frontend Bundling
|
||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `vendor/bin/sail yarn run build`, `vendor/bin/sail yarn run dev`, or `vendor/bin/sail composer run dev`. Ask them.
|
||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `yarn run build`, `yarn run dev`, or `composer run dev`. Ask them.
|
||||
|
||||
## Replies
|
||||
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
|
||||
@@ -112,33 +111,19 @@ protected function isAccessible(User $user, ?string $path = null): bool
|
||||
## Enums
|
||||
- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`.
|
||||
|
||||
=== sail rules ===
|
||||
|
||||
## Laravel Sail
|
||||
|
||||
- This project runs inside Laravel Sail's Docker containers. You MUST execute all commands through Sail.
|
||||
- Start services using `vendor/bin/sail up -d` and stop them with `vendor/bin/sail stop`.
|
||||
- Open the application in the browser by running `vendor/bin/sail open`.
|
||||
- Always prefix PHP, Artisan, Composer, and Node commands with `vendor/bin/sail`. Examples:
|
||||
- Run Artisan Commands: `vendor/bin/sail artisan migrate`
|
||||
- Install Composer packages: `vendor/bin/sail composer install`
|
||||
- Execute Node commands: `vendor/bin/sail yarn run dev`
|
||||
- Execute PHP scripts: `vendor/bin/sail php [script]`
|
||||
- View all available Sail commands by running `vendor/bin/sail` without arguments.
|
||||
|
||||
=== tests rules ===
|
||||
|
||||
## Test Enforcement
|
||||
|
||||
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
|
||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `vendor/bin/sail artisan test --compact` with a specific filename or filter.
|
||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test --compact` with a specific filename or filter.
|
||||
|
||||
=== laravel/core rules ===
|
||||
|
||||
## Do Things the Laravel Way
|
||||
|
||||
- Use `vendor/bin/sail artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
||||
- If you're creating a generic PHP class, use `vendor/bin/sail artisan make:class`.
|
||||
- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
||||
- If you're creating a generic PHP class, use `php artisan make:class`.
|
||||
- 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
|
||||
@@ -149,7 +134,7 @@ 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 `vendor/bin/sail artisan make:model`.
|
||||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `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.
|
||||
@@ -173,10 +158,10 @@ protected function isAccessible(User $user, ?string $path = null): bool
|
||||
### Testing
|
||||
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
|
||||
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
|
||||
- When creating tests, make use of `vendor/bin/sail artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
|
||||
- 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 `vendor/bin/sail yarn run build` or ask the user to run `vendor/bin/sail yarn run dev` or `vendor/bin/sail composer run dev`.
|
||||
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `yarn run build` or ask the user to run `yarn run dev` or `composer run dev`.
|
||||
|
||||
=== laravel/v12 rules ===
|
||||
|
||||
@@ -227,7 +212,7 @@ accordion, autocomplete, avatar, badge, brand, breadcrumbs, button, calendar, ca
|
||||
## Livewire
|
||||
|
||||
- Use the `search-docs` tool to find exact version-specific documentation for how to write Livewire and Livewire tests.
|
||||
- Use the `vendor/bin/sail artisan make:livewire [Posts\CreatePost]` Artisan command to create new components.
|
||||
- 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.
|
||||
|
||||
@@ -271,8 +256,8 @@ accordion, autocomplete, avatar, badge, brand, breadcrumbs, button, calendar, ca
|
||||
|
||||
## Laravel Pint Code Formatter
|
||||
|
||||
- You must run `vendor/bin/sail bin pint --dirty` before finalizing changes to ensure your code matches the project's expected style.
|
||||
- Do not run `vendor/bin/sail bin pint --test`, simply run `vendor/bin/sail bin pint` to fix any formatting issues.
|
||||
- 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 ===
|
||||
|
||||
@@ -281,7 +266,7 @@ accordion, autocomplete, avatar, badge, brand, breadcrumbs, button, calendar, ca
|
||||
- If you need to verify a feature is working, write or update a Unit / Feature test.
|
||||
|
||||
### Pest Tests
|
||||
- All tests must be written using Pest. Use `vendor/bin/sail artisan make:test --pest {name}`.
|
||||
- All tests must be written using Pest. Use `php artisan make:test --pest {name}`.
|
||||
- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application.
|
||||
- Tests should test all of the happy paths, failure paths, and weird paths.
|
||||
- Tests live in the `tests/Feature` and `tests/Unit` directories.
|
||||
@@ -294,9 +279,9 @@ it('is true', function () {
|
||||
|
||||
### Running Tests
|
||||
- Run the minimal number of tests using an appropriate filter before finalizing code edits.
|
||||
- To run all tests: `vendor/bin/sail artisan test --compact`.
|
||||
- To run all tests in a file: `vendor/bin/sail artisan test --compact tests/Feature/ExampleTest.php`.
|
||||
- To filter on a particular test name: `vendor/bin/sail artisan test --compact --filter=testName` (recommended after making a change to a related file).
|
||||
- To run all tests: `php artisan test --compact`.
|
||||
- To run all tests in a file: `php artisan test --compact tests/Feature/ExampleTest.php`.
|
||||
- To filter on a particular test name: `php artisan test --compact --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
|
||||
|
||||
45
CLAUDE.md
45
CLAUDE.md
@@ -8,7 +8,7 @@ The Laravel Boost guidelines are specifically curated by Laravel maintainers for
|
||||
## 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.3.29
|
||||
- php - 8.4.17
|
||||
- laravel/framework (LARAVEL) - v12
|
||||
- laravel/horizon (HORIZON) - v5
|
||||
- laravel/nightwatch (NIGHTWATCH) - v1
|
||||
@@ -19,7 +19,6 @@ This application is a Laravel application and its main Laravel ecosystems packag
|
||||
- livewire/livewire (LIVEWIRE) - v4
|
||||
- laravel/mcp (MCP) - v0
|
||||
- laravel/pint (PINT) - v1
|
||||
- laravel/sail (SAIL) - v1
|
||||
- pestphp/pest (PEST) - v4
|
||||
- phpunit/phpunit (PHPUNIT) - v12
|
||||
- tailwindcss (TAILWINDCSS) - v4
|
||||
@@ -37,7 +36,7 @@ This application is a Laravel application and its main Laravel ecosystems packag
|
||||
- Do not change the application's dependencies without approval.
|
||||
|
||||
## Frontend Bundling
|
||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `vendor/bin/sail yarn run build`, `vendor/bin/sail yarn run dev`, or `vendor/bin/sail composer run dev`. Ask them.
|
||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `yarn run build`, `yarn run dev`, or `composer run dev`. Ask them.
|
||||
|
||||
## Replies
|
||||
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
|
||||
@@ -112,33 +111,19 @@ protected function isAccessible(User $user, ?string $path = null): bool
|
||||
## Enums
|
||||
- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`.
|
||||
|
||||
=== sail rules ===
|
||||
|
||||
## Laravel Sail
|
||||
|
||||
- This project runs inside Laravel Sail's Docker containers. You MUST execute all commands through Sail.
|
||||
- Start services using `vendor/bin/sail up -d` and stop them with `vendor/bin/sail stop`.
|
||||
- Open the application in the browser by running `vendor/bin/sail open`.
|
||||
- Always prefix PHP, Artisan, Composer, and Node commands with `vendor/bin/sail`. Examples:
|
||||
- Run Artisan Commands: `vendor/bin/sail artisan migrate`
|
||||
- Install Composer packages: `vendor/bin/sail composer install`
|
||||
- Execute Node commands: `vendor/bin/sail yarn run dev`
|
||||
- Execute PHP scripts: `vendor/bin/sail php [script]`
|
||||
- View all available Sail commands by running `vendor/bin/sail` without arguments.
|
||||
|
||||
=== tests rules ===
|
||||
|
||||
## Test Enforcement
|
||||
|
||||
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
|
||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `vendor/bin/sail artisan test --compact` with a specific filename or filter.
|
||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test --compact` with a specific filename or filter.
|
||||
|
||||
=== laravel/core rules ===
|
||||
|
||||
## Do Things the Laravel Way
|
||||
|
||||
- Use `vendor/bin/sail artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
||||
- If you're creating a generic PHP class, use `vendor/bin/sail artisan make:class`.
|
||||
- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
||||
- If you're creating a generic PHP class, use `php artisan make:class`.
|
||||
- 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
|
||||
@@ -149,7 +134,7 @@ 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 `vendor/bin/sail artisan make:model`.
|
||||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `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.
|
||||
@@ -173,10 +158,10 @@ protected function isAccessible(User $user, ?string $path = null): bool
|
||||
### Testing
|
||||
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
|
||||
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
|
||||
- When creating tests, make use of `vendor/bin/sail artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
|
||||
- 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 `vendor/bin/sail yarn run build` or ask the user to run `vendor/bin/sail yarn run dev` or `vendor/bin/sail composer run dev`.
|
||||
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `yarn run build` or ask the user to run `yarn run dev` or `composer run dev`.
|
||||
|
||||
=== laravel/v12 rules ===
|
||||
|
||||
@@ -227,7 +212,7 @@ accordion, autocomplete, avatar, badge, brand, breadcrumbs, button, calendar, ca
|
||||
## Livewire
|
||||
|
||||
- Use the `search-docs` tool to find exact version-specific documentation for how to write Livewire and Livewire tests.
|
||||
- Use the `vendor/bin/sail artisan make:livewire [Posts\CreatePost]` Artisan command to create new components.
|
||||
- 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.
|
||||
|
||||
@@ -271,8 +256,8 @@ accordion, autocomplete, avatar, badge, brand, breadcrumbs, button, calendar, ca
|
||||
|
||||
## Laravel Pint Code Formatter
|
||||
|
||||
- You must run `vendor/bin/sail bin pint --dirty` before finalizing changes to ensure your code matches the project's expected style.
|
||||
- Do not run `vendor/bin/sail bin pint --test`, simply run `vendor/bin/sail bin pint` to fix any formatting issues.
|
||||
- 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 ===
|
||||
|
||||
@@ -281,7 +266,7 @@ accordion, autocomplete, avatar, badge, brand, breadcrumbs, button, calendar, ca
|
||||
- If you need to verify a feature is working, write or update a Unit / Feature test.
|
||||
|
||||
### Pest Tests
|
||||
- All tests must be written using Pest. Use `vendor/bin/sail artisan make:test --pest {name}`.
|
||||
- All tests must be written using Pest. Use `php artisan make:test --pest {name}`.
|
||||
- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application.
|
||||
- Tests should test all of the happy paths, failure paths, and weird paths.
|
||||
- Tests live in the `tests/Feature` and `tests/Unit` directories.
|
||||
@@ -294,9 +279,9 @@ it('is true', function () {
|
||||
|
||||
### Running Tests
|
||||
- Run the minimal number of tests using an appropriate filter before finalizing code edits.
|
||||
- To run all tests: `vendor/bin/sail artisan test --compact`.
|
||||
- To run all tests in a file: `vendor/bin/sail artisan test --compact tests/Feature/ExampleTest.php`.
|
||||
- To filter on a particular test name: `vendor/bin/sail artisan test --compact --filter=testName` (recommended after making a change to a related file).
|
||||
- To run all tests: `php artisan test --compact`.
|
||||
- To run all tests in a file: `php artisan test --compact tests/Feature/ExampleTest.php`.
|
||||
- To filter on a particular test name: `php artisan test --compact --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
|
||||
|
||||
34
README.md
34
README.md
@@ -31,43 +31,41 @@ After setting up your CNAME, please notify the repository owner to refresh SSL c
|
||||
|
||||
## Development
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- PHP 8.3+
|
||||
- PostgreSQL (running locally or as a container)
|
||||
- Redis (running locally or as a container)
|
||||
- Node.js + Yarn
|
||||
|
||||
### Installation
|
||||
|
||||
```cp .env.example .env```
|
||||
|
||||
```
|
||||
docker run --rm \
|
||||
-u "$(id -u):$(id -g)" \
|
||||
-v $(pwd):/var/www/html \
|
||||
-w /var/www/html \
|
||||
laravelsail/php83-composer:latest \
|
||||
composer install --ignore-platform-reqs
|
||||
```
|
||||
```composer install```
|
||||
*(you need a valid Flux Pro license or send a message to [Nostr - The Ben](http://njump.me/npub1pt0kw36ue3w2g4haxq3wgm6a2fhtptmzsjlc2j2vphtcgle72qesgpjyc6))*
|
||||
|
||||
#### Start docker development containers
|
||||
|
||||
```vendor/bin/sail up -d```
|
||||
|
||||
### Migrate and seed the database
|
||||
|
||||
```./vendor/bin/sail artisan migrate:fresh --seed```
|
||||
```php artisan migrate:fresh --seed```
|
||||
|
||||
### Laravel storage link
|
||||
|
||||
```./vendor/bin/sail artisan storage:link```
|
||||
```php artisan storage:link```
|
||||
|
||||
#### Install node dependencies
|
||||
|
||||
```vendor/bin/sail yarn```
|
||||
```yarn```
|
||||
|
||||
#### Start just in time compiler
|
||||
#### Start development environment
|
||||
|
||||
```vendor/bin/sail yarn dev```
|
||||
```composer run dev```
|
||||
|
||||
This starts the PHP dev server, queue worker, Pail log viewer, and Vite concurrently.
|
||||
|
||||
#### Update dependencies
|
||||
|
||||
```vendor/bin/sail yarn```
|
||||
```yarn```
|
||||
|
||||
## Security Vulnerabilities
|
||||
|
||||
|
||||
@@ -4,11 +4,13 @@ namespace App\Livewire\Forms;
|
||||
|
||||
use App\Enums\SelfHostedServiceType;
|
||||
use App\Models\SelfHostedService;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Form;
|
||||
|
||||
class ServiceForm extends Form
|
||||
{
|
||||
#[Locked]
|
||||
public ?SelfHostedService $service = null;
|
||||
|
||||
#[Validate('required|string|max:255')]
|
||||
@@ -47,7 +49,7 @@ class ServiceForm extends Form
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'type' => [
|
||||
'required',
|
||||
'in:' . collect(SelfHostedServiceType::cases())->map(fn($c) => $c->value)->implode(',')
|
||||
'in:'.collect(SelfHostedServiceType::cases())->map(fn ($c) => $c->value)->implode(','),
|
||||
],
|
||||
'intro' => ['nullable', 'string'],
|
||||
'url_clearnet' => ['nullable', 'url', 'max:255'],
|
||||
|
||||
@@ -9,6 +9,5 @@
|
||||
"opencode",
|
||||
"phpstorm"
|
||||
],
|
||||
"guidelines": [],
|
||||
"sail": true
|
||||
"guidelines": []
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
"laravel/boost": "^1.8",
|
||||
"laravel/pail": "^1.2.2",
|
||||
"laravel/pint": "^1.18",
|
||||
"laravel/sail": "^1.43",
|
||||
"mockery/mockery": "^1.6",
|
||||
"nunomaduro/collision": "^8.6",
|
||||
"pestphp/pest": "^4.3",
|
||||
@@ -89,7 +88,7 @@
|
||||
],
|
||||
"dev": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"npx concurrently -c \"#c4b5fd,#fb7185,#fdba74\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite --kill-others"
|
||||
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite --kill-others"
|
||||
],
|
||||
"test": [
|
||||
"@php artisan config:clear --ansi",
|
||||
|
||||
65
composer.lock
generated
65
composer.lock
generated
@@ -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": "46e95f6250487f6e4f947386804ca205",
|
||||
"content-hash": "ad826718b1e72bed521d15e12e5ac92f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "akuechler/laravel-geoly",
|
||||
@@ -12113,69 +12113,6 @@
|
||||
},
|
||||
"time": "2025-10-20T09:56:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/sail",
|
||||
"version": "v1.52.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/sail.git",
|
||||
"reference": "64ac7d8abb2dbcf2b76e61289451bae79066b0b3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/sail/zipball/64ac7d8abb2dbcf2b76e61289451bae79066b0b3",
|
||||
"reference": "64ac7d8abb2dbcf2b76e61289451bae79066b0b3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/console": "^9.52.16|^10.0|^11.0|^12.0",
|
||||
"illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0",
|
||||
"illuminate/support": "^9.52.16|^10.0|^11.0|^12.0",
|
||||
"php": "^8.0",
|
||||
"symfony/console": "^6.0|^7.0",
|
||||
"symfony/yaml": "^6.0|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"orchestra/testbench": "^7.0|^8.0|^9.0|^10.0",
|
||||
"phpstan/phpstan": "^2.0"
|
||||
},
|
||||
"bin": [
|
||||
"bin/sail"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Laravel\\Sail\\SailServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laravel\\Sail\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "Docker files for running a basic Laravel application.",
|
||||
"keywords": [
|
||||
"docker",
|
||||
"laravel"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/sail/issues",
|
||||
"source": "https://github.com/laravel/sail"
|
||||
},
|
||||
"time": "2026-01-01T02:46:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mockery/mockery",
|
||||
"version": "1.6.12",
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
services:
|
||||
laravel.test:
|
||||
build:
|
||||
context: './docker/8.3'
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
WWWGROUP: '${WWWGROUP}'
|
||||
image: 'sail-8.3/einundzwanzig-app'
|
||||
extra_hosts:
|
||||
- 'host.docker.internal:host-gateway'
|
||||
ports:
|
||||
- '${APP_PORT:-80}:80'
|
||||
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
|
||||
environment:
|
||||
WWWUSER: '${WWWUSER}'
|
||||
LARAVEL_SAIL: 1
|
||||
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
|
||||
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
|
||||
IGNITION_LOCAL_SITES_PATH: '${PWD}'
|
||||
volumes:
|
||||
- '.:/var/www/html'
|
||||
networks:
|
||||
- sail
|
||||
depends_on:
|
||||
- pgsql
|
||||
- redis
|
||||
- mailpit
|
||||
pgsql:
|
||||
image: 'postgres:17'
|
||||
ports:
|
||||
- '${FORWARD_DB_PORT:-5432}:5432'
|
||||
environment:
|
||||
PGPASSWORD: '${DB_PASSWORD:-secret}'
|
||||
POSTGRES_DB: '${DB_DATABASE}'
|
||||
POSTGRES_USER: '${DB_USERNAME}'
|
||||
POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}'
|
||||
volumes:
|
||||
- 'sail-pgsql:/var/lib/postgresql/data'
|
||||
- './docker/pgsql/create-testing-database.sql:/docker-entrypoint-initdb.d/10-create-testing-database.sql'
|
||||
networks:
|
||||
- sail
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- pg_isready
|
||||
- '-q'
|
||||
- '-d'
|
||||
- '${DB_DATABASE}'
|
||||
- '-U'
|
||||
- '${DB_USERNAME}'
|
||||
retries: 3
|
||||
timeout: 5s
|
||||
redis:
|
||||
image: 'redis:alpine'
|
||||
ports:
|
||||
- '${FORWARD_REDIS_PORT:-6379}:6379'
|
||||
volumes:
|
||||
- 'sail-redis:/data'
|
||||
networks:
|
||||
- sail
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- redis-cli
|
||||
- ping
|
||||
retries: 3
|
||||
timeout: 5s
|
||||
mailpit:
|
||||
image: 'axllent/mailpit:latest'
|
||||
ports:
|
||||
- '${FORWARD_MAILPIT_PORT:-1025}:1025'
|
||||
- '${FORWARD_MAILPIT_DASHBOARD_PORT:-8025}:8025'
|
||||
networks:
|
||||
- sail
|
||||
networks:
|
||||
sail:
|
||||
driver: bridge
|
||||
volumes:
|
||||
sail-pgsql:
|
||||
driver: local
|
||||
sail-redis:
|
||||
driver: local
|
||||
@@ -1,75 +0,0 @@
|
||||
FROM ubuntu:24.04
|
||||
|
||||
LABEL maintainer="Taylor Otwell"
|
||||
|
||||
ARG WWWGROUP
|
||||
ARG NODE_VERSION=24
|
||||
ARG MYSQL_CLIENT="mysql-client"
|
||||
ARG POSTGRES_VERSION=18
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV TZ=UTC
|
||||
ENV SUPERVISOR_PHP_COMMAND="/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan serve --host=0.0.0.0 --port=80"
|
||||
ENV SUPERVISOR_PHP_USER="sail"
|
||||
ENV PLAYWRIGHT_BROWSERS_PATH=0
|
||||
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
RUN echo "Acquire::http::Pipeline-Depth 0;" > /etc/apt/apt.conf.d/99custom && \
|
||||
echo "Acquire::http::No-Cache true;" >> /etc/apt/apt.conf.d/99custom && \
|
||||
echo "Acquire::BrokenProxy true;" >> /etc/apt/apt.conf.d/99custom
|
||||
|
||||
RUN apt-get update && apt-get upgrade -y \
|
||||
&& mkdir -p /etc/apt/keyrings \
|
||||
&& apt-get install -y gnupg gosu curl ca-certificates zip unzip git supervisor sqlite3 libcap2-bin libpng-dev python3 dnsutils librsvg2-bin fswatch ffmpeg nano \
|
||||
&& curl -sS 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xb8dc7e53946656efbce4c1dd71daeaab4ad4cab6' | gpg --dearmor | tee /etc/apt/keyrings/ppa_ondrej_php.gpg > /dev/null \
|
||||
&& echo "deb [signed-by=/etc/apt/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu noble main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y php8.3-cli php8.3-dev \
|
||||
php8.3-pgsql php8.3-sqlite3 php8.3-gd \
|
||||
php8.3-curl php8.3-mongodb \
|
||||
php8.3-imap php8.3-mysql php8.3-mbstring \
|
||||
php8.3-xml php8.3-zip php8.3-bcmath php8.3-soap \
|
||||
php8.3-intl php8.3-readline \
|
||||
php8.3-ldap \
|
||||
php8.3-gmp \
|
||||
php8.3-msgpack php8.3-igbinary php8.3-redis \
|
||||
php8.3-memcached php8.3-pcov php8.3-imagick php8.3-xdebug php8.3-swoole \
|
||||
&& curl -sLS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer \
|
||||
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
|
||||
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_VERSION.x nodistro main" > /etc/apt/sources.list.d/nodesource.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y nodejs \
|
||||
&& npm install -g npm \
|
||||
&& npm install -g pnpm \
|
||||
&& npm install -g bun \
|
||||
&& npx playwright install-deps \
|
||||
&& curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /etc/apt/keyrings/yarn.gpg >/dev/null \
|
||||
&& echo "deb [signed-by=/etc/apt/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
|
||||
&& curl -sS https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /etc/apt/keyrings/pgdg.gpg >/dev/null \
|
||||
&& echo "deb [signed-by=/etc/apt/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt noble-pgdg main" > /etc/apt/sources.list.d/pgdg.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y yarn \
|
||||
&& apt-get install -y $MYSQL_CLIENT \
|
||||
&& apt-get install -y postgresql-client-$POSTGRES_VERSION \
|
||||
&& apt-get -y autoremove \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.3
|
||||
|
||||
RUN userdel -r ubuntu
|
||||
RUN groupadd --force -g $WWWGROUP sail
|
||||
RUN useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail
|
||||
RUN git config --global --add safe.directory /var/www/html
|
||||
|
||||
COPY start-container /usr/local/bin/start-container
|
||||
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
COPY php.ini /etc/php/8.3/cli/conf.d/99-sail.ini
|
||||
RUN chmod +x /usr/local/bin/start-container
|
||||
|
||||
EXPOSE 80/tcp
|
||||
|
||||
ENTRYPOINT ["start-container"]
|
||||
@@ -1,5 +0,0 @@
|
||||
[PHP]
|
||||
post_max_size = 100M
|
||||
upload_max_filesize = 100M
|
||||
variables_order = EGPCS
|
||||
pcov.directory = .
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ "$SUPERVISOR_PHP_USER" != "root" ] && [ "$SUPERVISOR_PHP_USER" != "sail" ]; then
|
||||
echo "You should set SUPERVISOR_PHP_USER to either 'sail' or 'root'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -z "$WWWUSER" ]; then
|
||||
usermod -u $WWWUSER sail
|
||||
fi
|
||||
|
||||
if [ ! -d /.composer ]; then
|
||||
mkdir /.composer
|
||||
fi
|
||||
|
||||
chmod -R ugo+rw /.composer
|
||||
|
||||
if [ $# -gt 0 ]; then
|
||||
if [ "$SUPERVISOR_PHP_USER" = "root" ]; then
|
||||
exec "$@"
|
||||
else
|
||||
exec gosu $WWWUSER "$@"
|
||||
fi
|
||||
else
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
fi
|
||||
@@ -1,14 +0,0 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
user=root
|
||||
logfile=/var/log/supervisor/supervisord.log
|
||||
pidfile=/var/run/supervisord.pid
|
||||
|
||||
[program:php]
|
||||
command=%(ENV_SUPERVISOR_PHP_COMMAND)s
|
||||
user=%(ENV_SUPERVISOR_PHP_USER)s
|
||||
environment=LARAVEL_SAIL="1"
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
@@ -1,2 +0,0 @@
|
||||
SELECT 'CREATE DATABASE testing'
|
||||
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'testing')\gexec
|
||||
@@ -5,7 +5,7 @@
|
||||
"type": "local",
|
||||
"enabled": true,
|
||||
"command": [
|
||||
"vendor/bin/sail",
|
||||
"php",
|
||||
"artisan",
|
||||
"boost:mcp"
|
||||
]
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
|
||||
<env name="BCRYPT_ROUNDS" value="4"/>
|
||||
<env name="CACHE_STORE" value="array"/>
|
||||
<env name="DB_DATABASE" value="testing"/>
|
||||
<env name="DB_DATABASE" value="einundzwanzig_app_testing"/>
|
||||
<env name="MAIL_MAILER" value="array"/>
|
||||
<env name="PULSE_ENABLED" value="false"/>
|
||||
<env name="QUEUE_CONNECTION" value="sync"/>
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Models\Course;
|
||||
use App\Models\CourseEvent;
|
||||
use App\Models\Venue;
|
||||
use App\Traits\SeoTrait;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -17,6 +18,7 @@ class extends Component {
|
||||
public Course $course;
|
||||
public ?CourseEvent $event = null;
|
||||
|
||||
#[Locked]
|
||||
public $country = 'de';
|
||||
|
||||
public string $fromDate = '';
|
||||
|
||||
@@ -5,6 +5,7 @@ use App\Models\Course;
|
||||
use App\Models\Lecturer;
|
||||
use App\Traits\SeoTrait;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithFileUploads;
|
||||
@@ -25,9 +26,14 @@ class extends Component {
|
||||
public ?int $lecturer_id = null;
|
||||
public ?string $description = null;
|
||||
|
||||
// System fields (read-only)
|
||||
// System fields (read-only) - locked to prevent client-side tampering
|
||||
#[Locked]
|
||||
public ?int $created_by = null;
|
||||
|
||||
#[Locked]
|
||||
public ?string $created_at = null;
|
||||
|
||||
#[Locked]
|
||||
public ?string $updated_at = null;
|
||||
|
||||
public function mount(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ use App\Attributes\SeoDataAttribute;
|
||||
use App\Models\Lecturer;
|
||||
use App\Traits\SeoTrait;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithFileUploads;
|
||||
@@ -34,9 +35,14 @@ class extends Component {
|
||||
public ?string $node_id = null;
|
||||
public ?string $paynym = null;
|
||||
|
||||
// System fields (read-only)
|
||||
// System fields (read-only) - locked to prevent client-side tampering
|
||||
#[Locked]
|
||||
public ?int $created_by = null;
|
||||
|
||||
#[Locked]
|
||||
public ?string $created_at = null;
|
||||
|
||||
#[Locked]
|
||||
public ?string $updated_at = null;
|
||||
|
||||
public function mount(): void
|
||||
|
||||
@@ -5,6 +5,7 @@ use App\Enums\RecurrenceType;
|
||||
use App\Models\Meetup;
|
||||
use App\Models\MeetupEvent;
|
||||
use App\Traits\SeoTrait;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -16,6 +17,7 @@ class extends Component {
|
||||
public Meetup $meetup;
|
||||
public ?MeetupEvent $event = null;
|
||||
|
||||
#[Locked]
|
||||
public $country = 'de';
|
||||
|
||||
public string $startDate = '';
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Models\Country;
|
||||
use App\Models\Meetup;
|
||||
use App\Traits\SeoTrait;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithFileUploads;
|
||||
@@ -42,9 +43,14 @@ class extends Component {
|
||||
public ?string $github_data = null;
|
||||
public bool $visible_on_map = false;
|
||||
|
||||
// System fields (read-only)
|
||||
// System fields (read-only) - locked to prevent client-side tampering
|
||||
#[Locked]
|
||||
public ?int $created_by = null;
|
||||
|
||||
#[Locked]
|
||||
public ?string $created_at = null;
|
||||
|
||||
#[Locked]
|
||||
public ?string $updated_at = null;
|
||||
|
||||
// New City Modal
|
||||
|
||||
@@ -4,6 +4,7 @@ use App\Attributes\SeoDataAttribute;
|
||||
use App\Enums\SelfHostedServiceType;
|
||||
use App\Livewire\Forms\ServiceForm;
|
||||
use App\Traits\SeoTrait;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithFileUploads;
|
||||
@@ -13,7 +14,9 @@ new
|
||||
class extends Component {
|
||||
use SeoTrait;
|
||||
|
||||
#[Locked]
|
||||
public string $country = 'de';
|
||||
|
||||
public ServiceForm $form;
|
||||
|
||||
public function mount(): void
|
||||
|
||||
132
tests/Feature/LivewireLockedPropertiesTest.php
Normal file
132
tests/Feature/LivewireLockedPropertiesTest.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
use App\Models\City;
|
||||
use App\Models\Country;
|
||||
use App\Models\Meetup;
|
||||
use App\Models\SelfHostedService;
|
||||
use App\Models\User;
|
||||
use Livewire\Features\SupportLockedProperties\CannotUpdateLockedPropertyException;
|
||||
use Livewire\Livewire;
|
||||
|
||||
beforeEach(function () {
|
||||
$this->user = User::factory()->create(['timezone' => 'Europe/Berlin']);
|
||||
$this->country = Country::factory()->create();
|
||||
$this->city = City::factory()->for($this->country)->create();
|
||||
});
|
||||
|
||||
describe('Meetup Edit Component', function () {
|
||||
beforeEach(function () {
|
||||
$this->meetup = Meetup::factory()->for($this->city)->create([
|
||||
'created_by' => $this->user->id,
|
||||
]);
|
||||
});
|
||||
|
||||
it('loads meetup edit page correctly with locked properties', function () {
|
||||
Livewire::actingAs($this->user)
|
||||
->test('meetups.edit', ['meetup' => $this->meetup])
|
||||
->assertSet('created_by', $this->meetup->created_by)
|
||||
->assertSet('created_at', $this->meetup->created_at->format('Y-m-d H:i:s'))
|
||||
->assertSet('updated_at', $this->meetup->updated_at->format('Y-m-d H:i:s'));
|
||||
});
|
||||
|
||||
it('throws exception when tampering with locked created_by property', function () {
|
||||
$this->expectException(CannotUpdateLockedPropertyException::class);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test('meetups.edit', ['meetup' => $this->meetup])
|
||||
->set('created_by', 999);
|
||||
});
|
||||
|
||||
it('throws exception when tampering with locked created_at property', function () {
|
||||
$this->expectException(CannotUpdateLockedPropertyException::class);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test('meetups.edit', ['meetup' => $this->meetup])
|
||||
->set('created_at', '2020-01-01 00:00:00');
|
||||
});
|
||||
|
||||
it('throws exception when tampering with locked updated_at property', function () {
|
||||
$this->expectException(CannotUpdateLockedPropertyException::class);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test('meetups.edit', ['meetup' => $this->meetup])
|
||||
->set('updated_at', '2020-01-01 00:00:00');
|
||||
});
|
||||
|
||||
it('can still update non-locked properties', function () {
|
||||
Livewire::actingAs($this->user)
|
||||
->test('meetups.edit', ['meetup' => $this->meetup])
|
||||
->set('name', 'Updated Meetup Name')
|
||||
->set('community', 'einundzwanzig')
|
||||
->call('updateMeetup')
|
||||
->assertHasNoErrors();
|
||||
|
||||
$this->meetup->refresh();
|
||||
expect($this->meetup->name)->toBe('Updated Meetup Name');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Meetup Create-Edit Events Component', function () {
|
||||
beforeEach(function () {
|
||||
$this->meetup = Meetup::factory()->for($this->city)->create();
|
||||
});
|
||||
|
||||
it('has locked country property', function () {
|
||||
Livewire::actingAs($this->user)
|
||||
->test('meetups.create-edit-events', ['meetup' => $this->meetup])
|
||||
->assertSet('country', 'de');
|
||||
});
|
||||
|
||||
it('throws exception when tampering with locked country property', function () {
|
||||
$this->expectException(CannotUpdateLockedPropertyException::class);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test('meetups.create-edit-events', ['meetup' => $this->meetup])
|
||||
->set('country', 'us');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Services Create Component', function () {
|
||||
it('has locked country property', function () {
|
||||
Livewire::actingAs($this->user)
|
||||
->test('services.create')
|
||||
->assertSet('country', 'de');
|
||||
});
|
||||
|
||||
it('throws exception when tampering with locked country property', function () {
|
||||
$this->expectException(CannotUpdateLockedPropertyException::class);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test('services.create')
|
||||
->set('country', 'us');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ServiceForm Locked Properties', function () {
|
||||
beforeEach(function () {
|
||||
// Create service with the current user as creator
|
||||
$this->service = SelfHostedService::factory()->create([
|
||||
'created_by' => $this->user->id,
|
||||
'anon' => false,
|
||||
]);
|
||||
});
|
||||
|
||||
it('has locked service property in edit component', function () {
|
||||
Livewire::actingAs($this->user)
|
||||
->test('services.edit', ['service' => $this->service])
|
||||
->assertSet('form.service.id', $this->service->id);
|
||||
});
|
||||
|
||||
it('throws exception when tampering with locked service model in form', function () {
|
||||
$anotherService = SelfHostedService::factory()->create([
|
||||
'created_by' => $this->user->id,
|
||||
'anon' => false,
|
||||
]);
|
||||
|
||||
$this->expectException(CannotUpdateLockedPropertyException::class);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test('services.edit', ['service' => $this->service])
|
||||
->set('form.service', $anotherService);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user