Merge pull request 'Organize web routes by domain' (#32) from codex/organize-routes into main
Reviewed-on: OpenSource/KanbanGit#32 Reviewed-by: Eric <eric-peters6@gmx.de>
This commit was merged in pull request #32.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
---
|
||||
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.
|
||||
@@ -34,6 +34,7 @@ This project has domain-specific skills available. You MUST activate the relevan
|
||||
|
||||
- `fortify-development` — ACTIVATE when the user works on authentication in Laravel. This includes login, registration, password reset, email verification, two-factor authentication (2FA/TOTP/QR codes/recovery codes), profile updates, password confirmation, or any auth-related routes and controllers. Activate when the user mentions Fortify, auth, authentication, login, register, signup, forgot password, verify email, 2FA, or references app/Actions/Fortify/, CreateNewUser, UpdateUserProfileInformation, FortifyServiceProvider, config/fortify.php, or auth guards. Fortify is the frontend-agnostic authentication backend for Laravel that registers all auth routes and controllers. Also activate when building SPA or headless authentication, customizing login redirects, overriding response contracts like LoginResponse, or configuring login throttling. Do NOT activate for Laravel Passport (OAuth2 API tokens), Socialite (OAuth social login), or non-auth Laravel features.
|
||||
- `laravel-best-practices` — Apply this skill whenever writing, reviewing, or refactoring Laravel PHP code. This includes creating or modifying controllers, models, migrations, form requests, policies, jobs, scheduled commands, service classes, and Eloquent queries. Triggers for N+1 and query performance issues, caching strategies, authorization and security patterns, validation, error handling, queue and job configuration, route definitions, and architectural decisions. Also use for Laravel code reviews and refactoring existing Laravel code to follow best practices. Covers any task involving Laravel backend PHP code patterns.
|
||||
- `project-route-structure` — 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.
|
||||
- `wayfinder-development` — Use this skill for Laravel Wayfinder which auto-generates typed functions for Laravel controllers and routes. ALWAYS use this skill when frontend code needs to call backend routes or controller actions. Trigger when: connecting any React/Vue/Svelte/Inertia frontend to Laravel controllers, routes, building end-to-end features with both frontend and backend, wiring up forms or links to backend endpoints, fixing route-related TypeScript errors, importing from @/actions or @/routes, or running wayfinder:generate. Use Wayfinder route functions instead of hardcoded URLs. Covers: wayfinder() vite plugin, .url()/.get()/.post()/.form(), query params, route model binding, tree-shaking. Do not use for backend-only task
|
||||
- `inertia-vue-development` — Develops Inertia.js v2 Vue client-side applications. Activates when creating Vue pages, forms, or navigation; using <Link>, <Form>, useForm, or router; working with deferred props, prefetching, or polling; or when user mentions Vue with Inertia, Vue pages, Vue forms, or Vue navigation.
|
||||
- `tailwindcss-development` — Always invoke when the user's message includes 'tailwind' in any form. Also invoke for: building responsive grid layouts (multi-column card grids, product grids), flex/grid page structures (dashboards with sidebars, fixed topbars, mobile-toggle navs), styling UI components (cards, tables, navbars, pricing sections, forms, inputs, badges), adding dark mode variants, fixing spacing or typography, and Tailwind v3/v4 work. The core use case: writing or fixing Tailwind utility classes in HTML templates (Blade, JSX, Vue). Skip for backend PHP logic, database queries, API routes, JavaScript with no HTML/CSS component, CSS file audits, build tool configuration, and vanilla CSS.
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ use Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets;
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
web: __DIR__.'/../routes/web.php',
|
||||
commands: __DIR__.'/../routes/console.php',
|
||||
commands: __DIR__ . '/../routes/console.php',
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware): void {
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
- resources benutzen
|
||||
- Für jedes Model / Route, resources benutzen, kein mapping/feste arrays mehr in den controller.
|
||||
- kein 'model' => $model (bspw. 'project' => $project) mehr.
|
||||
- niemals das model in reponse return. für jedes model deshalb eine resource und diese benutzen.
|
||||
- niemals das model in response return. für jedes model deshalb eine resource und diese benutzen.
|
||||
- in der resource niemals mit only oder manuel die props übergeben.
|
||||
- Ziel: neue attribute von model sollen nicht ausversehen in responses auftauchen & responses kleiner, falls manche attr nicht gebraucht werden
|
||||
- Ziel:
|
||||
- neue attribute von model sollen nicht ausversehen in responses auftauchen & responses kleiner, falls manche attr nicht gebraucht werden
|
||||
- für spätere api routes die selben ressourcen für responses
|
||||
- folgende actions löschen und durch resource benutzen:
|
||||
- app/Actions/Projects/BuildProjectBacklogPageProps.php
|
||||
- app/Actions/Projects/BuildProjectBoardPageProps.php
|
||||
|
||||
@@ -1,8 +1 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Foundation\Inspiring;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
|
||||
Artisan::command('inspire', function () {
|
||||
$this->comment(Inspiring::quote());
|
||||
})->purpose('Display an inspiring quote');
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\Settings\GitConnectionController;
|
||||
use App\Http\Controllers\Settings\ProfileController;
|
||||
use App\Http\Controllers\Settings\SecurityController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
Route::redirect('settings', '/settings/profile');
|
||||
|
||||
Route::get('settings/profile', [ProfileController::class, 'edit'])->name('profile.edit');
|
||||
Route::patch('settings/profile', [ProfileController::class, 'update'])->name('profile.update');
|
||||
});
|
||||
|
||||
Route::middleware(['auth', 'verified'])->group(function () {
|
||||
Route::delete('settings/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
|
||||
|
||||
Route::get('settings/security', [SecurityController::class, 'edit'])->name('security.edit');
|
||||
|
||||
Route::put('settings/password', [SecurityController::class, 'update'])
|
||||
->middleware('throttle:6,1')
|
||||
->name('user-password.update');
|
||||
|
||||
Route::get('settings/git-connections', [GitConnectionController::class, 'edit'])
|
||||
->name('git-connections.edit');
|
||||
Route::post('settings/git-connections', [GitConnectionController::class, 'store'])
|
||||
->name('git-connections.store');
|
||||
Route::patch('settings/git-connections/{gitConnection}', [GitConnectionController::class, 'update'])
|
||||
->name('git-connections.update');
|
||||
Route::delete('settings/git-connections/{gitConnection}', [GitConnectionController::class, 'destroy'])
|
||||
->name('git-connections.destroy');
|
||||
|
||||
Route::inertia('settings/appearance', 'settings/Appearance')->name('appearance.edit');
|
||||
});
|
||||
+4
-173
@@ -1,15 +1,5 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\Admin\UserManagementController;
|
||||
use App\Http\Controllers\ProjectBoardController;
|
||||
use App\Http\Controllers\ProjectBoardSettingsController;
|
||||
use App\Http\Controllers\ProjectController;
|
||||
use App\Http\Controllers\ProjectRepositorySettingsController;
|
||||
use App\Http\Controllers\ProjectTicketBranchController;
|
||||
use App\Http\Controllers\ProjectTicketController;
|
||||
use App\Http\Controllers\ProjectTicketLinkController;
|
||||
use App\Http\Controllers\ProjectTicketMetadataSettingsController;
|
||||
use App\Http\Controllers\TeamController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Laravel\Fortify\Features;
|
||||
|
||||
@@ -20,168 +10,9 @@ Route::inertia('/', 'Welcome', [
|
||||
Route::middleware(['auth', 'verified'])->group(function () {
|
||||
Route::inertia('dashboard', 'Dashboard')->name('dashboard');
|
||||
|
||||
Route::get('projects', [ProjectController::class, 'index'])
|
||||
->name('projects.index');
|
||||
Route::get('projects/create', [ProjectController::class, 'create'])
|
||||
->middleware('can:create-project')
|
||||
->name('projects.create');
|
||||
Route::post('projects', [ProjectController::class, 'store'])
|
||||
->middleware('can:create-project')
|
||||
->name('projects.store');
|
||||
Route::get('projects/{project}', [ProjectController::class, 'show'])
|
||||
->middleware('can:view-project,project')
|
||||
->name('projects.show');
|
||||
|
||||
Route::delete('projects/{project}', [ProjectController::class, 'destroy'])
|
||||
->middleware('can:access-admin')
|
||||
->name('projects.destroy');
|
||||
|
||||
Route::get('projects/{project}/access', [ProjectController::class, 'access'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.access');
|
||||
Route::patch('projects/{project}/permissions/users/{user}', [ProjectController::class, 'updateUserPermissions'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.permissions.users.update');
|
||||
Route::patch('projects/{project}/permissions/teams/{team}', [ProjectController::class, 'updateTeamPermissions'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.permissions.teams.update');
|
||||
|
||||
Route::scopeBindings()->group(function (): void {
|
||||
Route::get('projects/{project}/board', [ProjectBoardController::class, 'index'])
|
||||
->middleware('can:view-project,project')
|
||||
->name('projects.board.index');
|
||||
Route::get('projects/{project}/backlog', [ProjectController::class, 'backlog'])
|
||||
->middleware('can:view-project,project')
|
||||
->name('projects.backlog.index');
|
||||
Route::get('projects/{project}/tickets/create', [ProjectTicketController::class, 'create'])
|
||||
->middleware('can:write-project,project')
|
||||
->name('projects.tickets.create');
|
||||
Route::post('projects/{project}/tickets', [ProjectTicketController::class, 'store'])
|
||||
->middleware('can:write-project,project')
|
||||
->name('projects.tickets.store');
|
||||
Route::get('projects/{project}/tickets/{ticket}', [ProjectTicketController::class, 'show'])
|
||||
->middleware('can:view-project,project')
|
||||
->name('projects.tickets.show');
|
||||
Route::patch('projects/{project}/tickets/{ticket}', [ProjectTicketController::class, 'update'])
|
||||
->middleware('can:write-project,project')
|
||||
->name('projects.tickets.update');
|
||||
Route::get('projects/{project}/tickets/{ticket}/branches/validate', [ProjectTicketBranchController::class, 'validate'])
|
||||
->middleware('can:write-project,project')
|
||||
->name('projects.tickets.branches.validate');
|
||||
Route::post('projects/{project}/tickets/{ticket}/branches', [ProjectTicketBranchController::class, 'store'])
|
||||
->middleware('can:write-project,project')
|
||||
->name('projects.tickets.branches.store');
|
||||
Route::post('projects/{project}/tickets/{ticket}/links', [ProjectTicketLinkController::class, 'store'])
|
||||
->middleware('can:write-project,project')
|
||||
->name('projects.tickets.links.store');
|
||||
Route::delete('projects/{project}/tickets/{ticket}/links/{ticketLink}', [ProjectTicketLinkController::class, 'destroy'])
|
||||
->middleware('can:write-project,project')
|
||||
->withoutScopedBindings()
|
||||
->name('projects.tickets.links.destroy');
|
||||
Route::patch('projects/{project}/tickets/{ticket}/status', [ProjectBoardController::class, 'move'])
|
||||
->middleware('can:write-project,project')
|
||||
->name('projects.tickets.status.update');
|
||||
Route::get('projects/{project}/settings/general', [ProjectController::class, 'general'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.general');
|
||||
Route::get('projects/{project}/settings/board', [ProjectBoardSettingsController::class, 'show'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.board');
|
||||
Route::post('projects/{project}/settings/board/columns', [ProjectBoardSettingsController::class, 'store'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.board.columns.store');
|
||||
Route::patch('projects/{project}/settings/board/columns/{boardColumn}', [ProjectBoardSettingsController::class, 'update'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.board.columns.update');
|
||||
Route::delete('projects/{project}/settings/board/columns/{boardColumn}', [ProjectBoardSettingsController::class, 'destroy'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.board.columns.destroy');
|
||||
Route::post('projects/{project}/settings/board/statuses', [ProjectBoardSettingsController::class, 'storeStatus'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.board.statuses.store');
|
||||
Route::patch('projects/{project}/settings/board/statuses/{ticketStatus}', [ProjectBoardSettingsController::class, 'updateStatus'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.board.statuses.update');
|
||||
Route::delete('projects/{project}/settings/board/statuses/{ticketStatus}', [ProjectBoardSettingsController::class, 'destroyStatus'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.board.statuses.destroy');
|
||||
Route::patch('projects/{project}/settings/board/statuses/{ticketStatus}/transitions', [ProjectBoardSettingsController::class, 'updateStatusTransitions'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.board.statuses.transitions.update');
|
||||
Route::get('projects/{project}/settings/metadata', [ProjectTicketMetadataSettingsController::class, 'show'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.metadata');
|
||||
Route::get('projects/{project}/settings/repositories', [ProjectRepositorySettingsController::class, 'show'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.repositories');
|
||||
Route::post('projects/{project}/settings/repositories', [ProjectRepositorySettingsController::class, 'store'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.repositories.store');
|
||||
Route::patch('projects/{project}/settings/repositories/{repositoryConnection}', [ProjectRepositorySettingsController::class, 'update'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.repositories.update');
|
||||
Route::delete('projects/{project}/settings/repositories/{repositoryConnection}', [ProjectRepositorySettingsController::class, 'destroy'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.repositories.destroy');
|
||||
Route::post('projects/{project}/settings/metadata/types', [ProjectTicketMetadataSettingsController::class, 'storeType'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.metadata.types.store');
|
||||
Route::patch('projects/{project}/settings/metadata/types/{ticketType}', [ProjectTicketMetadataSettingsController::class, 'updateType'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.metadata.types.update');
|
||||
Route::patch('projects/{project}/settings/metadata', [ProjectTicketMetadataSettingsController::class, 'update'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.metadata.update');
|
||||
Route::delete('projects/{project}/settings/metadata/types/{ticketType}', [ProjectTicketMetadataSettingsController::class, 'destroyType'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.metadata.types.destroy');
|
||||
Route::post('projects/{project}/settings/metadata/priorities', [ProjectTicketMetadataSettingsController::class, 'storePriority'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.metadata.priorities.store');
|
||||
Route::patch('projects/{project}/settings/metadata/priorities/{ticketPriority}', [ProjectTicketMetadataSettingsController::class, 'updatePriority'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.metadata.priorities.update');
|
||||
Route::delete('projects/{project}/settings/metadata/priorities/{ticketPriority}', [ProjectTicketMetadataSettingsController::class, 'destroyPriority'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.metadata.priorities.destroy');
|
||||
Route::post('projects/{project}/settings/metadata/fields', [ProjectTicketMetadataSettingsController::class, 'storeFieldDefinition'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.metadata.fields.store');
|
||||
Route::patch('projects/{project}/settings/metadata/fields/{ticketFieldDefinition}', [ProjectTicketMetadataSettingsController::class, 'updateFieldDefinition'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.metadata.fields.update');
|
||||
Route::delete('projects/{project}/settings/metadata/fields/{ticketFieldDefinition}', [ProjectTicketMetadataSettingsController::class, 'destroyFieldDefinition'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.metadata.fields.destroy');
|
||||
Route::post('projects/{project}/settings/metadata/link-types', [ProjectTicketMetadataSettingsController::class, 'storeLinkType'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.metadata.link-types.store');
|
||||
Route::patch('projects/{project}/settings/metadata/link-types/{ticketLinkType}', [ProjectTicketMetadataSettingsController::class, 'updateLinkType'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.metadata.link-types.update');
|
||||
Route::delete('projects/{project}/settings/metadata/link-types/{ticketLinkType}', [ProjectTicketMetadataSettingsController::class, 'destroyLinkType'])
|
||||
->middleware('can:admin-project,project')
|
||||
->name('projects.settings.metadata.link-types.destroy');
|
||||
});
|
||||
|
||||
Route::get('teams', [TeamController::class, 'index'])
|
||||
->middleware('can:view-teams')
|
||||
->name('teams.index');
|
||||
Route::post('teams', [TeamController::class, 'store'])
|
||||
->middleware('can:create-team')
|
||||
->name('teams.store');
|
||||
Route::patch('teams/{team}/members', [TeamController::class, 'updateMembers'])
|
||||
->name('teams.members.update');
|
||||
Route::patch('teams/{team}/permissions/users/{user}', [TeamController::class, 'updateUserPermissions'])
|
||||
->name('teams.permissions.users.update');
|
||||
require __DIR__.'/web/admin.php';
|
||||
require __DIR__.'/web/projects.php';
|
||||
require __DIR__.'/web/teams.php';
|
||||
});
|
||||
|
||||
Route::middleware(['auth', 'verified', 'can:access-admin'])
|
||||
->prefix('admin')
|
||||
->name('admin.')
|
||||
->group(function () {
|
||||
Route::get('users', [UserManagementController::class, 'index'])->name('users.index');
|
||||
Route::patch('users/{user}/permissions', [UserManagementController::class, 'update'])->name('users.update');
|
||||
});
|
||||
|
||||
require __DIR__.'/settings.php';
|
||||
require __DIR__.'/web/settings.php';
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\Admin\UserManagementController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::middleware('can:access-admin')
|
||||
->prefix('admin')
|
||||
->name('admin.')
|
||||
->group(function (): void {
|
||||
Route::prefix('users')
|
||||
->name('users.')
|
||||
->controller(UserManagementController::class)
|
||||
->group(function (): void {
|
||||
Route::get('/', 'index')->name('index');
|
||||
Route::patch('{user}/permissions', 'update')->name('update');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\ProjectBoardSettingsController;
|
||||
use App\Http\Controllers\ProjectController;
|
||||
use App\Http\Controllers\ProjectRepositorySettingsController;
|
||||
use App\Http\Controllers\ProjectTicketMetadataSettingsController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('general', [ProjectController::class, 'general'])->name('general');
|
||||
|
||||
Route::get('board', [ProjectBoardSettingsController::class, 'show'])->name('board');
|
||||
|
||||
Route::prefix('board')
|
||||
->name('board.')
|
||||
->controller(ProjectBoardSettingsController::class)
|
||||
->group(function (): void {
|
||||
require __DIR__.'/settings/board.php';
|
||||
});
|
||||
|
||||
Route::get('metadata', [ProjectTicketMetadataSettingsController::class, 'show'])->name('metadata');
|
||||
Route::patch('metadata', [ProjectTicketMetadataSettingsController::class, 'update'])->name('metadata.update');
|
||||
|
||||
Route::prefix('metadata')
|
||||
->name('metadata.')
|
||||
->controller(ProjectTicketMetadataSettingsController::class)
|
||||
->group(function (): void {
|
||||
require __DIR__.'/settings/metadata.php';
|
||||
});
|
||||
|
||||
Route::get('repositories', [ProjectRepositorySettingsController::class, 'show'])->name('repositories');
|
||||
|
||||
Route::prefix('repositories')
|
||||
->name('repositories.')
|
||||
->controller(ProjectRepositorySettingsController::class)
|
||||
->group(function (): void {
|
||||
require __DIR__.'/settings/repositories.php';
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::prefix('columns')->name('columns.')->group(function (): void {
|
||||
Route::post('/', 'store')->name('store');
|
||||
Route::patch('{boardColumn}', 'update')->name('update');
|
||||
Route::delete('{boardColumn}', 'destroy')->name('destroy');
|
||||
});
|
||||
|
||||
Route::prefix('statuses')->name('statuses.')->group(function (): void {
|
||||
Route::post('/', 'storeStatus')->name('store');
|
||||
Route::patch('{ticketStatus}', 'updateStatus')->name('update');
|
||||
Route::delete('{ticketStatus}', 'destroyStatus')->name('destroy');
|
||||
Route::patch('{ticketStatus}/transitions', 'updateStatusTransitions')->name('transitions.update');
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::prefix('types')->name('types.')->group(function (): void {
|
||||
Route::post('/', 'storeType')->name('store');
|
||||
Route::patch('{ticketType}', 'updateType')->name('update');
|
||||
Route::delete('{ticketType}', 'destroyType')->name('destroy');
|
||||
});
|
||||
|
||||
Route::prefix('priorities')->name('priorities.')->group(function (): void {
|
||||
Route::post('/', 'storePriority')->name('store');
|
||||
Route::patch('{ticketPriority}', 'updatePriority')->name('update');
|
||||
Route::delete('{ticketPriority}', 'destroyPriority')->name('destroy');
|
||||
});
|
||||
|
||||
Route::prefix('fields')->name('fields.')->group(function (): void {
|
||||
Route::post('/', 'storeFieldDefinition')->name('store');
|
||||
Route::patch('{ticketFieldDefinition}', 'updateFieldDefinition')->name('update');
|
||||
Route::delete('{ticketFieldDefinition}', 'destroyFieldDefinition')->name('destroy');
|
||||
});
|
||||
|
||||
Route::prefix('link-types')->name('link-types.')->group(function (): void {
|
||||
Route::post('/', 'storeLinkType')->name('store');
|
||||
Route::patch('{ticketLinkType}', 'updateLinkType')->name('update');
|
||||
Route::delete('{ticketLinkType}', 'destroyLinkType')->name('destroy');
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::post('/', 'store')->name('store');
|
||||
Route::patch('{repositoryConnection}', 'update')->name('update');
|
||||
Route::delete('{repositoryConnection}', 'destroy')->name('destroy');
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\ProjectBoardController;
|
||||
use App\Http\Controllers\ProjectTicketBranchController;
|
||||
use App\Http\Controllers\ProjectTicketController;
|
||||
use App\Http\Controllers\ProjectTicketLinkController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::middleware('can:write-project,project')->group(function (): void {
|
||||
Route::get('create', [ProjectTicketController::class, 'create'])->name('create');
|
||||
Route::post('/', [ProjectTicketController::class, 'store'])->name('store');
|
||||
});
|
||||
|
||||
Route::prefix('{ticket}')->group(function (): void {
|
||||
Route::get('/', [ProjectTicketController::class, 'show'])
|
||||
->middleware('can:view-project,project')
|
||||
->name('show');
|
||||
|
||||
Route::middleware('can:write-project,project')->group(function (): void {
|
||||
Route::patch('/', [ProjectTicketController::class, 'update'])->name('update');
|
||||
Route::patch('status', [ProjectBoardController::class, 'move'])->name('status.update');
|
||||
|
||||
Route::prefix('branches')
|
||||
->name('branches.')
|
||||
->controller(ProjectTicketBranchController::class)
|
||||
->group(function (): void {
|
||||
Route::get('validate', 'validate')->name('validate');
|
||||
Route::post('/', 'store')->name('store');
|
||||
});
|
||||
|
||||
Route::prefix('links')
|
||||
->name('links.')
|
||||
->controller(ProjectTicketLinkController::class)
|
||||
->group(function (): void {
|
||||
Route::post('/', 'store')->name('store');
|
||||
Route::delete('{ticketLink}', 'destroy')
|
||||
->withoutScopedBindings()
|
||||
->name('destroy');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\ProjectBoardController;
|
||||
use App\Http\Controllers\ProjectController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::prefix('projects')->name('projects.')->group(function (): void {
|
||||
Route::get('/', [ProjectController::class, 'index'])->name('index');
|
||||
|
||||
Route::middleware('can:create-project')->group(function (): void {
|
||||
Route::get('create', [ProjectController::class, 'create'])->name('create');
|
||||
Route::post('/', [ProjectController::class, 'store'])->name('store');
|
||||
});
|
||||
|
||||
Route::prefix('{project}')
|
||||
->group(function (): void {
|
||||
Route::middleware('can:view-project,project')->group(function (): void {
|
||||
Route::get('/', [ProjectController::class, 'show'])->name('show');
|
||||
Route::get('board', [ProjectBoardController::class, 'index'])->name('board.index');
|
||||
Route::get('backlog', [ProjectController::class, 'backlog'])->name('backlog.index');
|
||||
});
|
||||
|
||||
Route::delete('/', [ProjectController::class, 'destroy'])
|
||||
->middleware('can:access-admin')
|
||||
->name('destroy');
|
||||
|
||||
Route::middleware('can:admin-project,project')->group(function (): void {
|
||||
Route::get('access', [ProjectController::class, 'access'])->name('access');
|
||||
|
||||
Route::prefix('permissions')->name('permissions.')->group(function (): void {
|
||||
Route::patch('users/{user}', [ProjectController::class, 'updateUserPermissions'])
|
||||
->name('users.update');
|
||||
Route::patch('teams/{team}', [ProjectController::class, 'updateTeamPermissions'])
|
||||
->name('teams.update');
|
||||
});
|
||||
});
|
||||
|
||||
Route::scopeBindings()->group(function (): void {
|
||||
Route::prefix('tickets')
|
||||
->name('tickets.')
|
||||
->group(function (): void {
|
||||
require __DIR__.'/project/tickets.php';
|
||||
});
|
||||
|
||||
Route::prefix('settings')
|
||||
->name('settings.')
|
||||
->middleware('can:admin-project,project')
|
||||
->group(function (): void {
|
||||
require __DIR__.'/project/settings.php';
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\Settings\GitConnectionController;
|
||||
use App\Http\Controllers\Settings\ProfileController;
|
||||
use App\Http\Controllers\Settings\SecurityController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::middleware('auth')
|
||||
->prefix('settings')
|
||||
->group(function (): void {
|
||||
Route::redirect('/', '/settings/profile');
|
||||
|
||||
Route::controller(ProfileController::class)
|
||||
->prefix('profile')
|
||||
->group(function (): void {
|
||||
Route::get('/', 'edit')->name('profile.edit');
|
||||
Route::patch('/', 'update')->name('profile.update');
|
||||
});
|
||||
});
|
||||
|
||||
Route::middleware(['auth', 'verified'])
|
||||
->prefix('settings')
|
||||
->group(function (): void {
|
||||
Route::delete('profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
|
||||
|
||||
Route::controller(SecurityController::class)->group(function (): void {
|
||||
Route::get('security', 'edit')->name('security.edit');
|
||||
|
||||
Route::put('password', 'update')
|
||||
->middleware('throttle:6,1')
|
||||
->name('user-password.update');
|
||||
});
|
||||
|
||||
Route::prefix('git-connections')
|
||||
->name('git-connections.')
|
||||
->controller(GitConnectionController::class)
|
||||
->group(function (): void {
|
||||
Route::get('/', 'edit')->name('edit');
|
||||
Route::post('/', 'store')->name('store');
|
||||
Route::patch('{gitConnection}', 'update')->name('update');
|
||||
Route::delete('{gitConnection}', 'destroy')->name('destroy');
|
||||
});
|
||||
|
||||
Route::inertia('appearance', 'settings/Appearance')->name('appearance.edit');
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\TeamController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::prefix('teams')->name('teams.')->group(function (): void {
|
||||
|
||||
Route::controller(TeamController::class)->group(function () {
|
||||
Route::get('/', 'index')->middleware('can:view-teams')->name('index');
|
||||
Route::post('/', 'store')->middleware('can:create-team')->name('store');
|
||||
Route::patch('{team}/members', 'updateMembers')->name('members.update');
|
||||
Route::patch('{team}/permissions/users/{user}', 'updateUserPermissions')->name('permissions.users.update');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user