--- name: project-route-structure description: "Always apply in this project when creating, moving, or refactoring Laravel route definitions in routes/**/*.php; changing route prefixes, names, middleware, scoped bindings, or route files; or adding frontend-facing endpoints that Wayfinder generates. Documents the KanbanGit route-file layout and grouping conventions." --- # Project Route Structure ## When to Apply Activate this skill whenever work in this project changes: - `routes/**/*.php` - Route names, URI prefixes, middleware groups, scoped bindings, or controller route registrations - Frontend-facing endpoints that require regenerated Wayfinder output Use this together with `laravel-best-practices`. Also activate `wayfinder-development` when route changes affect generated frontend route/action imports. ## Route Files - `routes/web.php` is the web entry point only. Keep public shell routes here, such as `home` and `dashboard`, then require domain route files. - `routes/web/projects.php` owns the main `projects.*` structure. - `routes/web/admin.php` owns all `admin.*` routes. - `routes/web/teams.php` owns all `teams.*` routes. - `routes/web/settings.php` owns account settings routes, but keeps their existing route names such as `profile.edit`, `security.edit`, and `git-connections.edit`. - `routes/web/project/*.php` contains larger nested project route sections that would make `routes/web/projects.php` too deeply indented. Add a new route file only when a domain gets large enough to stand alone. Otherwise, extend the existing domain file. ## Grouping Pattern - Put shared middleware, URI prefixes, route name prefixes, and controller declarations on groups instead of repeating them on each route. - Prefer this nesting order when it reads naturally: `middleware(...)`, `prefix(...)`, `name(...)`, `controller(...)`, then `group(...)`. - Keep public route names stable unless the user explicitly asks for a public interface change. - Keep route URIs stable when reorganizing route files; this kind of change should be structural. - Use `function (): void` for route group closures. - For large nested sections, keep the structural group in the parent file and `require` a child file from inside the group. For example, keep `Route::prefix('tickets')->name('tickets.')->group(...)` in `routes/web/projects.php`, then require `routes/web/project/tickets.php` inside it. ## Project Routes Project routes should follow this shape: - Top-level group: `middleware(['auth', 'verified'])`, `prefix('projects')`, `name('projects.')`. - Project create/store routes live under `can:create-project`. - Routes under `{project}` use project gates by capability: - Read pages: `can:view-project,project` - Mutations: `can:write-project,project` - Project settings and access management: `can:admin-project,project` - Project delete: `can:access-admin` - `projects/{project}/permissions/...` must not be inside `Route::scopeBindings()`, because `Project` does not define `users()` or `teams()` child relationships. - Use `Route::scopeBindings()` only around nested project resources that should bind through project-owned relationships, such as tickets and project settings children. - Keep the outer `{project}` group in `routes/web/projects.php`; it is part of the main project structure. - Keep compact view routes, such as show, board, and backlog, directly in `routes/web/projects.php`. - Keep ticket subroutes grouped under `tickets.` in `routes/web/projects.php`, with the route contents in `routes/web/project/tickets.php`. - Keep settings subroutes grouped under `settings.` in `routes/web/projects.php`, with the route contents in `routes/web/project/settings.php`. - Split dense settings subsections further under `routes/web/project/settings/`, such as `board.php`, `metadata.php`, and `repositories.php`. ## Settings Routes - Keep the `settings` URI prefix grouped. - Keep profile edit/update behind `auth` only. - Keep profile deletion, security, git connections, and appearance behind `auth` plus `verified`. - Do not rename settings routes to a `settings.*` namespace unless the frontend/tests are intentionally updated. ## Verification After changing route files: 1. Run `php artisan route:list --except-vendor`. 2. Run `php artisan wayfinder:generate --with-form --no-interaction` when any route signature, name, method, or controller action changed. 3. Run `vendor/bin/pint --dirty --format agent` for PHP route formatting. 4. Run the affected feature tests, usually `php artisan test --compact tests/Feature/Projects tests/Feature/Teams tests/Feature/Admin tests/Feature/Settings`. 5. Run `git diff --check` before finalizing.