Skip to content

Commit e383976

Browse files
committed
feat: many new features
fix #2, fix #3, fix #5, fix #6
1 parent d9cef53 commit e383976

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2348
-260
lines changed

.github/copilot-instructions.md

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
<laravel-boost-guidelines>
2+
=== boost rules ===
3+
4+
## Laravel Boost
5+
- Laravel Boost is an MCP server that comes with powerful tools designed specifically for this application. Use them.
6+
7+
## Artisan
8+
- Use the `list-artisan-commands` tool when you need to call an Artisan command to double check the available parameters.
9+
10+
## URLs
11+
- 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.
12+
13+
## Tinker / Debugging
14+
- You should use the `tinker` tool when you need to execute PHP to debug code or query Eloquent models directly.
15+
- Use the `database-query` tool when you only need to read from the database.
16+
17+
## Reading Browser Logs With the `browser-logs` Tool
18+
- You can read browser logs, errors, and exceptions using the `browser-logs` tool from Boost.
19+
- Only recent browser logs will be useful - ignore old logs.
20+
21+
## Searching Documentation (Critically Important)
22+
- Boost comes with a powerful `search-docs` tool you should use before any other approaches. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation specific for the user's circumstance. You should pass an array of packages to filter on if you know you need docs for particular packages.
23+
- The 'search-docs' tool is perfect for all Laravel related packages, including Laravel, Inertia, Livewire, Filament, Tailwind, Pest, Nova, Nightwatch, etc.
24+
- You must use this tool to search for Laravel-ecosystem documentation before falling back to other approaches.
25+
- Search the documentation before making code changes to ensure we are taking the correct approach.
26+
- Use multiple, broad, simple, topic based queries to start. For example: `['rate limiting', 'routing rate limiting', 'routing']`.
27+
28+
### Available Search Syntax
29+
- You can and should pass multiple queries at once. The most relevant results will be returned first.
30+
31+
1. Simple Word Searches with auto-stemming - query=authentication - finds 'authenticate' and 'auth'
32+
2. Multiple Words (AND Logic) - query=rate limit - finds knowledge containing both "rate" AND "limit"
33+
3. Quoted Phrases (Exact Position) - query="infinite scroll - Words must be adjacent and in that order
34+
4. Mixed Queries - query=middleware "rate limit" - "middleware" AND exact phrase "rate limit"
35+
5. Multiple Queries - queries=["authentication", "middleware"] - ANY of these terms
36+
37+
=== inertia-laravel/core rules ===
38+
39+
## Inertia Core
40+
41+
- Inertia.js components should be placed in the `resources/js/Pages` directory unless specified differently in the JS bundler (vite.config.js).
42+
- Use `Inertia::render()` for server-side routing instead of traditional Blade views.
43+
44+
<code-snippet lang="php" name="Inertia::render Example">
45+
// routes/web.php example
46+
Route::get('/users', function () {
47+
return Inertia::render('Users/Index', [
48+
'users' => User::all()
49+
]);
50+
});
51+
</code-snippet>
52+
53+
=== inertia-laravel/v2 rules ===
54+
55+
## Inertia v2
56+
57+
- Make use of all Inertia features from v1 & v2. Check the documentation before making any changes to ensure we are taking the correct approach.
58+
59+
### Inertia v2 New Features
60+
- Polling
61+
- Prefetching
62+
- Deferred props
63+
- Infinite scrolling using merging props and `WhenVisible`
64+
- Lazy loading data on scroll
65+
66+
### Deferred Props & Empty States
67+
- When using deferred props on the frontend, you should add a nice empty state with pulsing / animated skeleton.
68+
69+
=== laravel/core rules ===
70+
71+
## Do Things the Laravel Way
72+
73+
- 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.
74+
- If you're creating a generic PHP class, use `artisan make:class`.
75+
- 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.
76+
77+
### Database
78+
- Always use proper Eloquent relationship methods with return type hints. Prefer relationship methods over raw queries or manual joins.
79+
- Use Eloquent models and relationships before suggesting raw database queries
80+
- Avoid `DB::`; prefer `Model::query()`. Generate code that leverages Laravel's ORM capabilities rather than bypassing them.
81+
- Generate code that prevents N+1 query problems by using eager loading.
82+
- Use Laravel's query builder for very complex database operations.
83+
84+
### Model Creation
85+
- 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`.
86+
87+
### APIs & Eloquent Resources
88+
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
89+
90+
### Controllers & Validation
91+
- Always create Form Request classes for validation rather than inline validation in controllers. Include both validation rules and custom error messages.
92+
- Check sibling Form Requests to see if the application uses array or string based validation rules.
93+
94+
### Queues
95+
- Use queued jobs for time-consuming operations with the `ShouldQueue` interface.
96+
97+
### Authentication & Authorization
98+
- Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum, etc.).
99+
100+
### URL Generation
101+
- When generating links to other pages, prefer named routes and the `route()` function.
102+
103+
### Configuration
104+
- 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')`.
105+
106+
### Testing
107+
- 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.
108+
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
109+
- 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.
110+
111+
### Vite Error
112+
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `npm run build` or ask the user to run `npm run dev` or `composer run dev`.
113+
114+
=== laravel/v12 rules ===
115+
116+
## Laravel 12
117+
118+
- Use the `search-docs` tool to get version specific documentation.
119+
- Since Laravel 11, Laravel has a new streamlined file structure which this project uses.
120+
121+
### Laravel 12 Structure
122+
- No middleware files in `app/Http/Middleware/`.
123+
- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files.
124+
- `bootstrap/providers.php` contains application specific service providers.
125+
- **No app\Console\Kernel.php** - use `bootstrap/app.php` or `routes/console.php` for console configuration.
126+
- **Commands auto-register** - files in `app/Console/Commands/` are automatically available and do not require manual registration.
127+
128+
### Database
129+
- 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.
130+
- Laravel 11 allows limiting eagerly loaded records natively, without external packages: `$query->latest()->limit(10);`.
131+
132+
### Models
133+
- 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.
134+
135+
=== pint/core rules ===
136+
137+
## Laravel Pint Code Formatter
138+
139+
- You must run `vendor/bin/pint --dirty` before finalizing changes to ensure your code matches the project's expected style.
140+
- Do not run `vendor/bin/pint --test`, simply run `vendor/bin/pint` to fix any formatting issues.
141+
142+
=== pest/core rules ===
143+
144+
## Pest
145+
146+
### Testing
147+
- If you need to verify a feature is working, write or update a Unit / Feature test.
148+
149+
### Pest Tests
150+
- All tests must be written using Pest. Use `php artisan make:test --pest <name>`.
151+
- 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.
152+
- Tests should test all of the happy paths, failure paths, and weird paths.
153+
- Tests live in the `tests/Feature` and `tests/Unit` directories.
154+
- Pest tests look and behave like this:
155+
<code-snippet name="Basic Pest Test Example" lang="php">
156+
it('is true', function () {
157+
expect(true)->toBeTrue();
158+
});
159+
</code-snippet>
160+
161+
### Running Tests
162+
- Run the minimal number of tests using an appropriate filter before finalizing code edits.
163+
- To run all tests: `php artisan test`.
164+
- To run all tests in a file: `php artisan test tests/Feature/ExampleTest.php`.
165+
- To filter on a particular test name: `php artisan test --filter=testName` (recommended after making a change to a related file).
166+
- 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.
167+
168+
### Pest Assertions
169+
- When asserting status codes on a response, use the specific method like `assertForbidden` and `assertNotFound` instead of using `assertStatus(403)` or similar, e.g.:
170+
<code-snippet name="Pest Example Asserting postJson Response" lang="php">
171+
it('returns all', function () {
172+
$response = $this->postJson('/api/docs', []);
173+
174+
$response->assertSuccessful();
175+
});
176+
</code-snippet>
177+
178+
### Mocking
179+
- Mocking can be very helpful when appropriate.
180+
- When mocking, you can use the `Pest\Laravel\mock` Pest function, but always import it via `use function Pest\Laravel\mock;` before using it. Alternatively, you can use `$this->mock()` if existing tests do.
181+
- You can also create partial mocks using the same import or self method.
182+
183+
### Datasets
184+
- Use datasets in Pest to simplify tests which have a lot of duplicated data. This is often the case when testing validation rules, so consider going with this solutionwhen writing tests for validation rules.
185+
186+
<code-snippet name="Pest Dataset Example" lang="php">
187+
it('has emails', function (string $email) {
188+
expect($email)->not->toBeEmpty();
189+
})->with([
190+
'james' => 'james@laravel.com',
191+
'taylor' => 'taylor@laravel.com',
192+
]);
193+
</code-snippet>
194+
195+
=== inertia-vue/core rules ===
196+
197+
## Inertia + Vue
198+
199+
- Vue components must have a single root element.
200+
- Use `router.visit()` or `<Link>` for navigation instead of traditional links.
201+
202+
<code-snippet lang="vue" name="Inertia Client Navigation">
203+
import { Link } from '@inertiajs/vue3'
204+
205+
<Link href="/">Home</Link>
206+
</code-snippet>
207+
208+
- For form handling, use `router.post` and related methods. Do not use regular forms.
209+
210+
<code-snippet lang="vue" name="Inertia Vue Form Example">
211+
<script setup>
212+
import { reactive } from 'vue'
213+
import { router } from '@inertiajs/vue3'
214+
import { usePage } from '@inertiajs/vue3'
215+
216+
const page = usePage()
217+
218+
const form = reactive({
219+
first_name: null,
220+
last_name: null,
221+
email: null,
222+
})
223+
224+
function submit() {
225+
router.post('/users', form)
226+
}
227+
</script>
228+
229+
<template>
230+
<h1>Create {{ page.modelName }}</h1>
231+
<form @submit.prevent="submit">
232+
<label for="first_name">First name:</label>
233+
<input id="first_name" v-model="form.first_name" />
234+
<label for="last_name">Last name:</label>
235+
<input id="last_name" v-model="form.last_name" />
236+
<label for="email">Email:</label>
237+
<input id="email" v-model="form.email" />
238+
<button type="submit">Submit</button>
239+
</form>
240+
</template>
241+
</code-snippet>
242+
</laravel-boost-guidelines>

.gitignore

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
/.idea
1010
/.nova
1111
/.phpunit.cache
12-
/.vscode
1312
/.zed
1413
/auth.json
1514
/node_modules
@@ -24,5 +23,6 @@ Homestead.yaml
2423
Thumbs.db
2524
auto-imports.d.ts
2625
components.d.ts
27-
routes
28-
wayfinder
26+
resources/js/routes
27+
resources/js/actions
28+
resources/js/wayfinder

.vscode/mcp.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"servers": {
3+
"laravel-boost": {
4+
"command": "php",
5+
"args": [
6+
"./artisan",
7+
"boost:mcp"
8+
],
9+
"type": "stdio"
10+
}
11+
},
12+
"inputs": []
13+
}

.vscode/settings.json

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
// Disable the default formatter, use eslint instead
3+
"prettier.enable": false,
4+
"editor.formatOnSave": false,
5+
6+
// Auto fix
7+
"editor.codeActionsOnSave": {
8+
"source.fixAll.eslint": "explicit",
9+
"source.organizeImports": "never"
10+
},
11+
12+
// Silent the stylistic rules in you IDE, but still auto fix them
13+
"eslint.rules.customizations": [
14+
{ "rule": "style/*", "severity": "off", "fixable": true },
15+
{ "rule": "format/*", "severity": "off", "fixable": true },
16+
{ "rule": "*-indent", "severity": "off", "fixable": true },
17+
{ "rule": "*-spacing", "severity": "off", "fixable": true },
18+
{ "rule": "*-spaces", "severity": "off", "fixable": true },
19+
{ "rule": "*-order", "severity": "off", "fixable": true },
20+
{ "rule": "*-dangle", "severity": "off", "fixable": true },
21+
{ "rule": "*-newline", "severity": "off", "fixable": true },
22+
{ "rule": "*quotes", "severity": "off", "fixable": true },
23+
{ "rule": "*semi", "severity": "off", "fixable": true }
24+
],
25+
26+
// Enable eslint for all supported languages
27+
"eslint.validate": [
28+
"javascript",
29+
"javascriptreact",
30+
"typescript",
31+
"typescriptreact",
32+
"vue",
33+
"html",
34+
"markdown",
35+
"json",
36+
"json5",
37+
"jsonc",
38+
"yaml",
39+
"toml",
40+
"xml",
41+
"gql",
42+
"graphql",
43+
"astro",
44+
"svelte",
45+
"css",
46+
"less",
47+
"scss",
48+
"pcss",
49+
"postcss"
50+
],
51+
"files.associations": {
52+
"*.css": "tailwindcss"
53+
},
54+
"editor.quickSuggestions": {
55+
"strings": "on"
56+
},
57+
"tailwindCSS.classAttributes": [
58+
"class",
59+
"ui"
60+
],
61+
"tailwindCSS.experimental.classRegex": [
62+
[
63+
"ui:\\s*{([^)]*)\\s*}",
64+
"(?:'|\"|`)([^']*)(?:'|\"|`)"
65+
]
66+
]
67+
}

app/Actions/Fortify/UpdateUserProfileInformation.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Models\User;
66
use Illuminate\Contracts\Auth\MustVerifyEmail;
7+
use Illuminate\Http\UploadedFile;
78
use Illuminate\Support\Facades\Validator;
89
use Illuminate\Validation\Rule;
910
use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
@@ -27,8 +28,13 @@ public function update(User $user, array $input): void
2728
'max:255',
2829
Rule::unique('users')->ignore($user->id),
2930
],
31+
'photo' => ['nullable', 'mimes:jpg,jpeg,png', 'max:1024'],
3032
])->validateWithBag('updateProfileInformation');
3133

34+
if (isset($input['photo']) && $input['photo'] instanceof UploadedFile) {
35+
$user->updateProfilePhoto($input['photo']);
36+
}
37+
3238
if ($input['email'] !== $user->email &&
3339
$user instanceof MustVerifyEmail) {
3440
$this->updateVerifiedUser($user, $input);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace App\Http\Controllers;
4+
5+
use Illuminate\Http\Request;
6+
use Illuminate\Support\Facades\Auth;
7+
8+
class CurrentUserController extends Controller
9+
{
10+
/**
11+
* Delete the authenticated user's account.
12+
*/
13+
public function destroy(Request $request): void
14+
{
15+
$request->validate([
16+
'password' => ['required', 'current_password'],
17+
]);
18+
19+
$user = $request->user();
20+
21+
Auth::logout();
22+
23+
$user->delete();
24+
25+
$request->session()->invalidate();
26+
$request->session()->regenerateToken();
27+
}
28+
}

0 commit comments

Comments
 (0)