ServerlessIRCd Docs

Docs home

ADR-004: AWS DynamoDB schema

Date: 2025-02-15 (Phase 4) Status: Accepted Supersedes: — Superseded by: —

Context

The AWS adapter runs IRC state on DynamoDB (single table family, not single-table design). Unlike Cloudflare Durable Objects, DynamoDB does not serialize access to a record by default — concurrent writes can interleave. Nick uniqueness, channel membership atomicity, and gone-connection cleanup all require explicit concurrency control.

The schema must support: connection records, channel metadata, channel membership (roster), nick registry, and SASL account credentials. It must also handle the Lambda invocation model: each $default invocation is a fresh process that reads state, runs a reducer, and writes back — there is no in-memory state between invocations.

Decision

Five tables, each with a clear partition-key boundary:

Table Partition Key Sort Key TTL Purpose
Connections connectionId — idleSince Per-connection state: nick, user, host, caps, joined channels, away
ChannelMeta channelName — — Topic, modes, key, limit
ChannelMembers channelName connectionId — Roster: membership + prefix flags (op/voice)
Nicks nickLower — — Nick → connectionId registry
Accounts account — — SASL credentials (scrypt-hashed, never plaintext)

Concurrency invariants:

SASL credentials (Accounts): stored as scrypt HashedAccountCredential rows ({ account, algorithm, salt, hash }, base64-encoded). The Lambda pre-loads all rows at cold start into an in-memory DynamoAccountStore; the reducer's AccountStore.verify() stays synchronous (reducers are pure — no async). Seed tooling (tools/seed-aws-accounts.ts) writes hashed rows; never plaintext.

Consequences

Positive:

Negative:

References