Skip to content
This repository was archived by the owner on Jul 26, 2026. It is now read-only.
This repository was archived by the owner on Jul 26, 2026. It is now read-only.

[Architecture] Decompose the server entrypoint into feature adapters and an explicit runtime lifecycle #41

Description

@mhbdev

Summary

apps/server/src/index.ts is a roughly 2,400-line host module that currently owns all of the following:

  • process-level logger and database-migration startup;
  • authentication middleware, CORS, request scopes, and tRPC mounting;
  • SSH, Docker-container, and Docker-host terminal session routes and WebSockets;
  • archive uploads to applications, containers, and volumes;
  • deployment webhooks and GitHub/GitLab/Gitea webhook handling;
  • Git-provider OAuth callbacks and token exchange;
  • SCIM protocol handling and global user/session mutations;
  • UpGal/AI chat routes and API-key handling;
  • worker/scheduler construction, readiness checks, Caddy initialization, monitoring, auto-update, cleanup timers, and graceful shutdown.

The host should assemble independently testable adapters and lifecycle components. Instead, route behavior, infrastructure orchestration, startup side effects, and shutdown are interleaved in one module.

Reviewed against master at 7f9e26400a474aa5a706d261f24fa2bf3d98ce8c.

Architectural impact

  • Changes in unrelated features create frequent merge conflicts in the entrypoint.
  • Route-level tests require importing a module that performs migrations and starts runtime services.
  • Startup ordering is implicit in top-level execution and import side effects.
  • Partial startup failure and cleanup ownership are difficult to reason about.
  • Feature adapters cannot be mounted independently for testing or alternate hosts.
  • Security middleware and request-scope conventions can diverge between manually declared routes.
  • The Bun listener configuration, application construction, and process lifecycle cannot be tested separately.

Proposed direction

  1. Introduce a pure createServerApp(dependencies) function that builds and returns the Hono app without starting workers, migrations, or listeners.
  2. Split route adapters into feature modules, for example:
    • routes/auth;
    • routes/terminals;
    • routes/uploads;
    • routes/deployment-webhooks;
    • routes/git-provider-oauth;
    • routes/scim;
    • routes/upgal;
    • routes/health.
  3. Give each module typed dependencies and mount it through a common adapter interface.
  4. Introduce a ServerRuntime/lifecycle coordinator whose components implement start, ready, stop, and optional diagnostics.
  5. Move database migration, Caddy initialization, deployment workers, backup/notification workers, schedulers, monitoring, auto-update, and Docker cleanup into explicit lifecycle components.
  6. Start components in dependency order and stop them in reverse order, with rollback when startup fails halfway.
  7. Keep signal handling and process.exit in a minimal executable entrypoint.
  8. Add route registration tests that detect duplicate paths and verify standard middleware coverage.

Acceptance criteria

  • Importing the app factory does not run migrations, start timers, open Redis/Docker/SSH connections, or register process signals.
  • Each major HTTP/protocol feature is mounted from its own module.
  • Runtime components expose consistent start/readiness/stop semantics.
  • Partial startup failure stops already-started components cleanly.
  • Health readiness is derived from the lifecycle registry rather than manually enumerated booleans.
  • Route modules can be integration-tested with focused fake dependencies.
  • The executable index.ts is reduced to composition, startup, listener export, and signal handling.
  • Existing tRPC, auth, terminal WebSocket, webhook, SCIM, upload, and AI behavior remains covered.

Suggested migration order

  1. Extract pure app factory and health routes.
  2. Extract terminal and upload route modules.
  3. Extract Git-provider callbacks/webhooks and SCIM.
  4. Extract AI/API-key routes.
  5. Introduce the lifecycle registry and move current runtimes one by one.
  6. Reduce the final entrypoint after behavior-equivalence tests pass.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions