Generics, Builders, and Storage Boundaries
Client history uses a Database trait object because callers can swap or wrap
local implementations at runtime. Server handlers instead use
AppState<DB> with DB: atuin_server_database::Database, monomorphizing one
chosen Postgres or SQLite backend through Axum state.
The V2 record model is generic over payload state:
Record<DecryptedData> can be transformed into Record<EncryptedData>. The
type prevents upload code from accidentally accepting plaintext and makes the
cryptographic boundary visible without a runtime flag.
Builders for Record and history capture encode required fields in construction
APIs. Newtypes keep host, record, session, and history IDs distinct. RecordTag
is an extensible product discriminator that lets one sync engine carry several
domain projections.
Atuin uses trait objects where local runtime substitution matters, generics where one server backend should remain statically checked, and payload-state types where an invalid security transition must be hard to express.