safeLoad(); } $appEnv = getenv('APP_ENV') ?: 'production'; if ($appEnv !== 'production') { ini_set('display_errors', '1'); error_reporting(E_ALL); } else { ini_set('display_errors', '0'); } // --------------------------------------------------------------------------- // Migrations — cheap no-op when already current // --------------------------------------------------------------------------- try { $pdo = Connection::pdo(); (new Migrator($pdo))->migrate(); } catch (\Throwable $e) { http_response_code(500); header('Content-Type: text/plain; charset=utf-8'); echo "Database bootstrap failed.\n"; if ($appEnv !== 'production') { echo $e->getMessage() . "\n"; } exit; } // --------------------------------------------------------------------------- // Shared services // --------------------------------------------------------------------------- $view = new View(APP_ROOT . '/views'); $users = new UserRepository($pdo); $audit = new AuditLogger($pdo); $auth = new AuthController($pdo, $users, $audit, $view); // --------------------------------------------------------------------------- // Routing // --------------------------------------------------------------------------- $router = new Router(); $router->get('/', function (Request $req) use ($view, $pdo, $users, $appEnv): Response { $currentUser = SessionGuard::currentUser($users); $schemaVersion = (int) $pdo->query( 'SELECT COALESCE(MAX(version), 0) FROM schema_version' )->fetchColumn(); return Response::html($view->render('home', [ 'title' => 'Sprint Planner', 'currentUser' => $currentUser, 'schemaVersion' => $schemaVersion, 'dbPath' => Connection::path(), 'appEnv' => $appEnv, 'oidcConfigured' => OidcClient::isConfigured(), 'localAdminEnabled' => LocalAdmin::isEnabled(), 'authError' => isset($req->query['auth_error']), 'csrfToken' => SessionGuard::csrfToken(), ])); }); $router->get('/healthz', fn() => Response::text('ok')); $router->get('/auth/login', $auth->login(...)); $router->get('/auth/callback', $auth->callback(...)); $router->post('/auth/logout', $auth->logout(...)); $router->get('/auth/local', $auth->loginLocalForm(...)); $router->post('/auth/local', $auth->loginLocal(...)); // --------------------------------------------------------------------------- // Dispatch // --------------------------------------------------------------------------- $request = Request::fromGlobals(); $response = $router->dispatch($request); $response->send(); // Flush the output buffer opened at the top. if (ob_get_level() > 0) { @ob_end_flush(); }