Persistence
Persistence modules own file layout and durability. Handlers should never directly write database files.
JSON indexes
Section titled “JSON indexes”Small mutable collections use JSON. Loaders parse an expected top-level type and fail startup loudly for missing or invalid required files. Updates write a temporary file, rename it into place, and remove the temporary file on failure. In-memory changes retain enough previous state to roll back.
Message shards
Section titled “Message shards”Messages are JSON objects stored one per line. Each channel or thread storage root uses zero-padded numbered shards. When the active shard reaches 1,000 lines, append creates the next shard. Queries walk these files for tail pagination, IDs, replies, search, pins, and around-message windows.
Edits and deletion locate the containing shard and rewrite it. New messages generate UUIDs and Unix-second timestamps. The server stores internal user IDs, reply targets, signature metadata, attachment records, embeds, reaction ID arrays, and interaction data.
Public boundary
Section titled “Public boundary”dbMessageToPublic is the message serialization boundary. It:
- calculates mentions/pings;
- replaces internal author and reaction user IDs with usernames;
- limits reply previews;
- converts interaction user IDs to usernames while retaining signature fields;
- hydrates poll embeds for the requesting viewer;
- sets
type: "message".
Use existing public serializers for users, roles, threads, polls, assets, and attachments. Never return a raw storage object when it contains internal identities or credentials.
Mutation ordering
Section titled “Mutation ordering”Validate → authorize → normalize → mutate/persist → audit/refresh → return event. A broadcast is a claim that the mutation is durable, so it must come last.
