galena
Architecture

Overview

Three paths that fail independently, and the apps and packages that make them.

Galena is built around one promise: the status page must stay up when the things it reports on are down, including Galena itself. So it is split into three paths that share as little as possible.

Galena's three paths Probes in three regions feed a queue and an evaluator that keeps state in DynamoDB; only state changes reach the trigger.dev workers, which share Aurora with the API and publish the status page to S3 and CloudFront, the only part visitors load. Hot path: every minute Cold path: on change Read path: what visitors load state changes only dispatch publish Probes Lambda, 3 regions Queue SQS FIFO Evaluator Lambda Telemetry DynamoDB Dashboard Next.js on S3 API Lambda, Hono Aurora Postgres Workers trigger.dev Status page S3 + CloudFront Own regions, replicated. Serves while the rest is down. AWS compute Data store Outside AWS Event path
PathRuns onJobTouches
Hot pathProbe Lambdas in three regions, SQS FIFO, an evaluator Lambda, DynamoDBCheck every monitor every minute and work out its stateNever the database
Cold pathThe API on Lambda, Aurora Serverless v2, trigger.dev tasksIncidents, maintenance, notifications, publishingWoken only by people and by state changes
Read pathS3 and CloudFront in two regions of their ownServe the status page and its data filesOnly files

A visitor's request only ever reaches the read path. If the API, the database and trigger.dev are all down at once, the last published page still serves. The page's subscribe form is the one exception, and it fails gracefully.

Regions

A deployment uses a home region for the API, the database, detection and the workers' AWS access, at least three probe regions, and a primary and replica region for the page. The config refuses a page region that is also the home region. The defaults are all in Europe:

RoleRegion
Homeeu-central-1 (Frankfurt)
Probeseu-west-1 (Ireland), eu-west-3 (Paris), eu-north-1 (Stockholm)
Pageeu-west-1 primary, eu-north-1 replica
CloudFront certificatesus-east-1

Pick a home region where the services you watch don't run. If the home region fails with them, detection stops, but the page keeps serving its last snapshot from its own regions.

Repository

apps/
  web/          Next.js static export: landing, docs, dashboard
  status/       Astro: the status page, built to static files
  api/          Hono on Lambda (a Node server locally)
  probe/        Lambda: runs checks in each probe region
  evaluator/    Lambda: reads check results, runs detection
  workers/      trigger.dev tasks
packages/
  contracts/    Zod schemas, enums and events shared by everything
  core/         Pure domain logic: detection, lifecycles, status, uptime
  db/           Drizzle schema, migrations and repositories
  integrations/ The SSRF guard, the HTTP check, Slack and webhook senders, sealing keys
  publisher/    snapshot files, feeds, badge and favicons
  emails/       React Email templates
  ui/           Design tokens
infra/          The CDK app

Dependency rules are enforced by pnpm check:deps:

Packages and what they may import Apps import adapters, adapters import the pure domain core, and core imports only the shared contracts; probe and evaluator never import the database package. Apps web status api workers probe evaluator Adapters db integrations publisher emails Domain core Shared contracts ui tokens Each layer imports only layers below it. probe and evaluator never import db.
PackageMay importMay not import
contractszodany other workspace package
corecontractsdb, integrations, the AWS SDK, any I/O
probe, evaluatorcontracts, core, the network and config parts of integrationsdb, publisher, emails
statuscontracts, publisher types, ui tokensthe API client, db, workers
any appany packageanother app

packages/core is pure: no I/O, no clock, no environment. Time and storage come in through ports, so the same rules run in Lambda, in trigger.dev, in tests and in the replay harness.

Stacks

StackRegionHolds
galena-<stage>-ci-accessHomeGitHub's OIDC provider and the deploy role
galena-<stage>-foundationHomeKMS key, VPC with isolated subnets only, Aurora, DynamoDB, the SQS FIFO queue and its dead-letter queue, the config bucket, SSM parameters
galena-<stage>-probe-<region>Each probe regionThe probe Lambda and its every-minute schedule
galena-<stage>-detectionHomeThe evaluator
galena-<stage>-apiHomeThe API Lambda, HTTP API, the migration Lambda, the origin secret
galena-<stage>-web, -web-certificateHome, us-east-1The dashboard's bucket, CloudFront distribution and, with a domain, its certificate
galena-<stage>-worker-accessHomeThe IAM user trigger.dev acts as
galena-<stage>-emailHomeSES identity, configuration set and bounce handling
galena-<stage>-page, -page-replica, -page-certificatePage regions, us-east-1Page buckets, CloudFront, certificate

Every stack passes cdk-nag's AWS Solutions rules; each exception carries its reason in code.

No NAT, no Lambda in a VPC

Aurora lives in isolated subnets with no route to the internet. Nothing reaches it over the network: the API, the migrations, the bounce handler and the workers all use the RDS Data API, an HTTPS endpoint authorised by IAM. No Lambda runs in the VPC, and there's no NAT gateway, which would cost more than the rest of an idle deployment together.

On this page