Monolog\Level::Debug, 'NOTICE' => Monolog\Level::Notice, 'WARNING' => Monolog\Level::Warning, 'ERROR' => Monolog\Level::Error, 'CRITICAL' => Monolog\Level::Critical, default => Monolog\Level::Info, }; $logger = new Logger('ui'); $handler = new StreamHandler('php://stdout', $logLevel); $handler->setFormatter(new JsonFormatter()); $logger->pushHandler($handler); $app = AppFactory::create(); $twig = Twig::create(__DIR__ . '/../resources/views', [ 'cache' => false, 'auto_reload' => $appEnv === 'development', ]); $app->add(TwigMiddleware::create($app, $twig)); $app->addRoutingMiddleware(); $app->addBodyParsingMiddleware(); $app->addErrorMiddleware($appEnv === 'development', true, true, $logger); $app->get('/', function (Request $request, Response $response) use ($twig): Response { return $twig->render($response, 'pages/hello.twig'); }); $app->get('/healthz', function (Request $request, Response $response): Response { // Stub healthcheck. Later milestones extend with real api reachability checks. $payload = [ 'status' => 'ok', 'api_reachable' => null, 'last_api_check_at' => null, ]; $response->getBody()->write((string) json_encode($payload)); return $response->withHeader('Content-Type', 'application/json'); }); $app->map( ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], '/{routes:.+}', function (Request $request, Response $response): Response { $response->getBody()->write((string) json_encode(['error' => 'not_found'])); return $response ->withHeader('Content-Type', 'application/json') ->withStatus(404); } ); $app->run();