add(new CorsMiddleware()); // Global OPTIONS route for CORS preflight (must be before other routes) $app->options('/{routes:.+}', function ($request, $response) { return $response->withStatus(204); }); // Root route - redirect to docs $app->get('/', function ($request, $response) { return $response ->withHeader('Location', '/docs') ->withStatus(302); }); // Docs route - serve Swagger UI // NOTE: Saat ini PUBLIC. Jika perlu protect, tambahkan JwtMiddleware atau IpWhitelistMiddleware $app->get('/docs', function ($request, $response) { $docsPath = __DIR__ . '/docs/index.html'; if (!file_exists($docsPath)) { $response->getBody()->write('

Documentation not found

'); return $response ->withStatus(404) ->withHeader('Content-Type', 'text/html'); } $html = file_get_contents($docsPath); $response->getBody()->write($html); return $response->withHeader('Content-Type', 'text/html'); }); // Serve OpenAPI JSON // NOTE: Saat ini PUBLIC. Jika perlu protect, tambahkan middleware $app->get('/docs/openapi.json', function ($request, $response) use ($app) { $openApiPath = __DIR__ . '/docs/openapi.json'; $autoGenerate = AppConfig::get('OPENAPI_AUTO_GENERATE', 'false') === 'true'; // Auto-generate if enabled if ($autoGenerate) { try { $generator = new OpenAPIGenerator($app); $spec = $generator->generate(); $json = json_encode($spec, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); // Optionally save to file file_put_contents($openApiPath, $json); $response->getBody()->write($json); return $response->withHeader('Content-Type', 'application/json'); } catch (\Exception $e) { // Fallback to file if generation fails error_log('OpenAPI generation failed: ' . $e->getMessage()); } } // Load from file (default behavior) if (!file_exists($openApiPath)) { $response->getBody()->write(json_encode(['error' => 'OpenAPI spec not found'])); return $response ->withStatus(404) ->withHeader('Content-Type', 'application/json'); } $json = file_get_contents($openApiPath); $response->getBody()->write($json); return $response->withHeader('Content-Type', 'application/json'); }); // Register module routes HealthRoutes::register($app); AuthRoutes::register($app); RetribusiRoutes::register($app); SummaryRoutes::register($app); DashboardRoutes::register($app); RealtimeRoutes::register($app); // Run application $app->run();