Skip to content

How it works

When a user posts an activity, it is written once to their own feed and fanned out along the follow edges to each follower’s feed. Fan-out happens on write, not on read, so reads stay cheap: a feed read is exactly three statements, constant in page size, no matter how many activities exist. Pagination is keyset-based on (activity_time DESC, activity_id DESC) — there is no OFFSET anywhere on the read path. Fan-out workers are idempotent and safe to replay.

Deletes follow the same “write path does the work” idea in reverse: activities are soft-deleted, but the fan-out rows pointing to them are hard-deleted, so the read path never has to filter out a deleted_at. Reaction counts are denormalized on the activity and bumped only when a reaction write actually changes a row, so counting a reaction never means a real-time COUNT(*).

Each tenant gets its own database. A shared platform database holds the tenant registry — the mapping from a tenant to its own database — and the migration runner applies migrations to every tenant database individually. Because tenants live in physically separate databases, not separate rows in a shared one, reads and writes for one tenant can never cross into another’s data.

  • Gateway — holds all authentication, in exactly one place. It verifies the tenant’s HS256 user JWT, resolves the tenant, and never opens a tenant database.
  • Feed service — owns the domain (activities, feeds, follows, reactions) and the BullMQ fan-out worker. It never sees a user JWT; it trusts the tenant and user identity the gateway forwards, authenticated by an internal shared secret between the two services.

Your own backend is the identity provider: it mints HS256 user tokens offline, signed with its private api_secret, with no network call to dropin. dropin issues no tokens of its own and stores no user credentials — there is no session store and no refresh chain, because the tenant can always mint a fresh token for free.

See the guides for how these pieces show up in the SDKs, or the API reference for the underlying HTTP contract.