# Relaystation Architecture

Relaystation is a webhook and event relay service. Upstream producers POST
signed events to the relay; the relay validates the signature, persists the
event, and dispatches it to the correct downstream service.

## Components

- **relay** (`src/relay.js`) — HTTP ingest endpoint, in-memory dispatch queue,
  and the delivery loop. Owns the main HTTP server on `PORT` (default 8080)
  and exposes a health check on port 9090.
- **router** (`src/router.js`) — loads service definitions from `services/*.json`
  and matches inbound events to a target service by topic prefix.
- **retry** (`src/retry.js`) — a timer-driven backoff queue for events whose
  first delivery attempt failed. Retries use exponential backoff up to a
  fixed maximum attempt count.
- **auth** (`src/auth.js`) — verifies the HMAC signature on every inbound
  event and rejects requests carrying an expired issuance token.
- **metrics** (`src/metrics.js`) — process-local counters for ingest,
  delivery, drop, and retry events. No external metrics backend is wired up
  yet; counters are logged periodically to stdout.
- **store** (`src/store.js`) — an in-memory event list backed by an
  append-only file under `RELAY_DATA_DIR`, used to replay events after a
  restart.

## Data flow

1. A producer POSTs an event to the relay's ingest endpoint.
2. `auth.verify` checks the signature and token freshness.
3. The event is appended to the store and pushed onto the in-process
   dispatch queue.
4. `router.resolve` matches the event to a service definition in
   `services/`.
5. The relay attempts delivery directly; on failure, the event is handed to
   `retry` for backoff-scheduled redelivery.

## Configuration

The relay reads its upstream broker location from `RELAY_QUEUE_URL` and
falls back to a default internal broker hostname if unset. Service-specific
delivery targets, timeouts, and ownership metadata live in `services/*.json`
— one file per downstream integration. Every service currently declares a
`timeout_ms` of 5000; there is no per-service retry policy configured today,
so all retry behavior is governed centrally by `src/retry.js`.

## Health checks

Operators should poll the relay's health endpoint on port 9090 to confirm
the process is accepting connections before routing production traffic to
an instance. The health endpoint does not currently report queue depth or
retry backlog — see `docs/runbook.md` for how to inspect those out of band.

## Known limitations

- The dispatch queue and retry queue are both in-memory and unbounded;
  sustained downstream unavailability can grow them without limit.
- Service definitions are read from disk lazily and cached until an
  explicit reload, so config changes require a process restart or manual
  reload call.
