Skip to content

Architecture ​

Finluth is a modular monolith.

  • apps/web is the React dashboard.
  • apps/server is the Fastify API, health loop, and deployment runner. In production it also serves the built dashboard.
  • packages/db is the Drizzle schema and SQL migrations.
  • packages/shared is validation and organization roles.

Modules inside the server:

  • Identity: sessions, invites, roles
  • Catalog: projects, environments, services, secrets
  • Delivery: manual records and an SSH provider behind an allowlisted command
  • Observe: HTTP health checks, a host heartbeat for CPU, memory, and disk, and one chat webhook for down, still down, recovery, and a failed deploy

The first organization is created at boot. The first project is inserted from deploy/seed.json. Application code does not special-case any project.

Request path ​

finluth.com shows the public page. finluth.com/status shows production health, with no deploy detail. app.finluth.com is the signed-in dashboard and /api. Both hostnames hit the same process. Caddy terminates TLS.

Deployments ​

A service has a deployment target. manual stores a record. ssh connects with an encrypted key, runs an allowlisted command in an allowlisted directory, then checks the health URL. Production SSH deploys require the actor to have TOTP enabled. A GitHub push deploys production only when that project’s webhook option is on; the webhook secret is the credential. An owner can schedule that same kind of command hourly, daily, or weekly. The first run waits for one full interval, and a production schedule requires two-factor on the account that saved it.

apps/cli is the finluth command. It calls this API with a bearer token from Settings. finluth status prints each service. finluth deploy <project> <service> queues that service’s SSH target. finluth logs <project> <service> pulls the last lines. It uses app.finluth.com. Production deploys still require two-factor on the account that owns the token.

Data ​

Tenant rows carry organization_id. Secrets and SSH keys are AES-256-GCM ciphertext. The master key lives in APP_MASTER_KEY, not in the database. Audit rows are append-only from the application. There is no API that updates or deletes them.

Later ​

A second project is another row. A second deploy provider is another class behind the same deployment table. If deploys need to leave the request process, run the delivery module as a second entrypoint that reads status = queued. Do not add a queue broker before that is necessary.

Private operations documentation for the Finluth workspace.