Summary
Refactor the web app lifecycle so module loading and route collection building happen once during adapter boot, not on every request. Keep start() focused on per-request execution only.
Problem
WebAppAdapter::start() currently performs module loading (loadModules()) per request. In long-lived app instances (including feature tests with multiple requests), this causes repeated DI route registration behavior and lifecycle coupling between boot and request phases.
Goals
- Enforce lifecycle separation:
- Boot phase: one-time app setup, including module/route loading.
- Request phase: resolve route, run middleware/dispatch, send response, clean request-scoped state.
- Prevent repeated route collection registration across requests.
- Preserve backward-compatible request behavior (including downstream expectations around
response() access after send).
Scope Requirements
- Add/restore
LoadModulesStage under src/App/Stages/:
- Register/get
ModuleLoader.
- Build
RouteCollection via RouteBuilder from module route closures/config.
- Store collection in DI.
- Wire
LoadModulesStage into WebAppAdapter constructor boot pipeline.
- Remove per-request module-loading call from
WebAppAdapter::start().
- Keep
start() request-only flow:
OPTIONS handling
- route resolution
- dispatch/middleware flow
- response send + request cleanup
- Keep request cleanup after send, but do not flush response payload in cleanup (compatibility requirement).
Non-Goals
- No redesign of DI container semantics.
- No reintroduction of
handle() API unless separately scoped.
- No dynamic hot-reload of modules/routes in normal runtime path.
Acceptance Criteria
- Core unit tests pass, including
tests/Unit/App/Adapters/WebAppAdapterTest.php.
- Multiple requests against one app instance do not trigger route collection re-registration failures.
- Downstream feature suite passes without requiring app recreation per request.
- Request context is cleaned after send; response payload remains readable for compatibility.
Validation Plan
- Run core:
vendor/bin/phpunit
composer phpstan
composer cs:check
- Run downstream project full feature tests against path-linked core.
- Smoke test CLI/web startup manually.
Risks / Notes
- Runtime changes to module config/routes during the same app instance will no longer auto-apply per request.
- If dynamic refresh is needed later, add an explicit "reload routing/modules" mechanism as a separate ticket.
Deliverables
- Stage implementation file.
- Adapter pipeline update.
- Request-flow cleanup adjustments/tests.
- Changelog entry describing lifecycle contract.
Summary
Refactor the web app lifecycle so module loading and route collection building happen once during adapter boot, not on every request. Keep
start()focused on per-request execution only.Problem
WebAppAdapter::start()currently performs module loading (loadModules()) per request. In long-lived app instances (including feature tests with multiple requests), this causes repeated DI route registration behavior and lifecycle coupling between boot and request phases.Goals
response()access after send).Scope Requirements
LoadModulesStageundersrc/App/Stages/:ModuleLoader.RouteCollectionviaRouteBuilderfrom module route closures/config.LoadModulesStageintoWebAppAdapterconstructor boot pipeline.WebAppAdapter::start().start()request-only flow:OPTIONShandlingNon-Goals
handle()API unless separately scoped.Acceptance Criteria
tests/Unit/App/Adapters/WebAppAdapterTest.php.Validation Plan
vendor/bin/phpunitcomposer phpstancomposer cs:checkRisks / Notes
Deliverables