get('/api/health', [HealthController::class, 'index']); $router->get('/api/categories', [CategoriesController::class, 'index']); $router->get('/api/categories/:slug', [CategoriesController::class, 'show']); $router->get('/api/members', [MembersController::class, 'index']); $router->get('/api/members/:slug', [MembersController::class, 'show']); $router->get('/api/projects', [ProjectsController::class, 'index']); $router->get('/api/projects/:slug', [ProjectsController::class, 'show']); $router->get('/api/projects/:slug/roadmap', [RoadmapController::class, 'index']); $router->get('/api/projects/:slug/members', [ProjectMembersController::class, 'index']); $router->get('/api/projects/:slug/discussions', [DiscussionsController::class, 'index']); $router->get('/api/projects/:slug/resources', [ResourcesController::class, 'index']); $router->get('/api/projects/:slug/images', [ImagesController::class, 'index']); $router->get('/api/activity', [ActivityController::class, 'index']); $router->get('/api/stats', [StatsController::class, 'index']); // ---------------------------------------------------------------------------- // Écritures (POST/PATCH/DELETE) — protégées automatiquement par Bearer token // (le Router marque ces méthodes comme `auth: true`). // ---------------------------------------------------------------------------- $router->post ('/api/categories', [CategoriesController::class, 'store']); $router->patch ('/api/categories/:slug', [CategoriesController::class, 'update']); $router->delete('/api/categories/:slug', [CategoriesController::class, 'destroy']); $router->post ('/api/members', [MembersController::class, 'store']); $router->patch ('/api/members/:slug', [MembersController::class, 'update']); $router->delete('/api/members/:slug', [MembersController::class, 'destroy']); $router->post ('/api/projects', [ProjectsController::class, 'store']); $router->patch ('/api/projects/:slug', [ProjectsController::class, 'update']); $router->delete('/api/projects/:slug', [ProjectsController::class, 'destroy']); $router->post ('/api/projects/:slug/members', [ProjectMembersController::class, 'store']); $router->delete('/api/projects/:slug/members/:member_slug', [ProjectMembersController::class, 'destroy']); $router->post ('/api/projects/:slug/roadmap', [RoadmapController::class, 'store']); $router->patch ('/api/projects/:slug/roadmap/:id', [RoadmapController::class, 'update']); $router->delete('/api/projects/:slug/roadmap/:id', [RoadmapController::class, 'destroy']); $router->post ('/api/projects/:slug/discussions', [DiscussionsController::class, 'store']); $router->patch ('/api/projects/:slug/discussions/:id', [DiscussionsController::class, 'update']); $router->delete('/api/projects/:slug/discussions/:id', [DiscussionsController::class, 'destroy']); $router->post ('/api/projects/:slug/resources', [ResourcesController::class, 'store']); $router->patch ('/api/projects/:slug/resources/:id', [ResourcesController::class, 'update']); $router->delete('/api/projects/:slug/resources/:id', [ResourcesController::class, 'destroy']); $router->post ('/api/projects/:slug/images', [ImagesController::class, 'store']); $router->patch ('/api/projects/:slug/images/:id', [ImagesController::class, 'update']); $router->delete('/api/projects/:slug/images/:id', [ImagesController::class, 'destroy']); // ---------------------------------------------------------------------------- // Dispatch + handler global d'exceptions. // ---------------------------------------------------------------------------- try { $request = new Request(); [$route, $params] = $router->dispatch($request->method(), $request->path()); if ($route['auth']) { Auth::requireAdmin($request); } [$class, $action] = $route['handler']; $controller = new $class(); $controller->$action($request, $params); } catch (ApiException $e) { Response::emit($e->statusCode, $e->payload); } catch (\Throwable $e) { // Toujours loggé vers stderr (visible dans Dozzle côté serveur). error_log(sprintf( '[unhandled] %s in %s:%d — %s', $e::class, $e->getFile(), $e->getLine(), $e->getMessage() )); $debug = (getenv('APP_DEBUG') ?: 'false') === 'true'; if ($debug) { Response::emit(500, [ 'error' => 'internal_server_error', 'message' => $e->getMessage(), 'class' => $e::class, 'file' => $e->getFile(), 'line' => $e->getLine(), ]); } else { Response::emit(500, ['error' => 'internal_server_error']); } }