Activity feed / timeline database schema
An activity-stream schema (actor + verb + object + target) with a fan-out-on-write timeline table. Designed for follow-based feeds at scale.
Database schema previewActivity feed / timeline database schema
Recreate this in Raltey
Copy this prompt
Paste this into Raltey's AI agent to generate the same diagram, then tweak it on the canvas.
Prompt
Design a PostgreSQL database schema for: Activity feed / timeline database schema. An activity-stream schema (actor + verb + object + target) with a fan-out-on-write timeline table. Designed for follow-based feeds at scale. Include these tables: activity, timeline_entry, follow. Use proper primary keys, foreign keys, and indexes. Export SQL DDL for PostgreSQL.
Context
- - Activity model: actor performs a verb on an object (optionally targeting another object).
- - Timeline rows are denormalized per recipient to keep reads cheap.
- - Celebrity accounts skip fan-out-on-write and compute at read time.
Patterns
- - Activity Stream 2.0-style schema (actor, verb, object, target).
- - Fan-out-on-write for normal accounts.
- - Hybrid: skip fan-out for celebrities, merge at read time.
Tables
The schema, table by table
activity
Canonical activity record - the source of truth.
DBML - activity
Table activity {
id uuid pk
actor_id uuid [ref: > user_account.id, not null]
verb text not null // followed, liked, commented
object_type text not null
object_id uuid not null
target_type text
target_id uuid
created_at timestamptz default `now()`
}timeline_entry
One row per recipient per activity (fan-out on write).
DBML - timeline_entry
Table timeline_entry {
user_id uuid [ref: > user_account.id]
activity_id uuid [ref: > activity.id]
created_at timestamptz not null
pk (user_id, created_at, activity_id)
}follow
DBML - follow
Table follow {
follower_id uuid [ref: > user_account.id]
followee_id uuid [ref: > user_account.id]
pk (follower_id, followee_id)
}Relationships
| From | To | Type |
|---|---|---|
| user_account | activity | 1:N |
| activity | timeline_entry | 1:N |
| user_account | timeline_entry | 1:N |
| user_account | follow | 1:N |
Notes from the field
- Cap fan-out to followers active in the last 30 days.
- For >5k follower threshold, skip timeline_entry insertion and read on demand.
- Partition timeline_entry by month if growth exceeds 1B rows.
Frequently asked
Is fan-out-on-write always the right call?
No. It is great for the long tail but breaks for celebrity accounts where one write fans out to millions of timelines. Hybrid models pull celebrity activities at read time instead.
Why duplicate created_at on timeline_entry?
Pagination orders by it. Including it in the composite PK makes the index optimal and keeps the join-free read path fast.
More templates
FlowchartSaaS onboarding email flowFlowchartCustomer support runbook flowFlowchartPayment webhook retry and error flowFlowchartGitHub PR review and merge flowFlowchartLogin with magic link flowArchitectureThree-tier SaaS architecture on AWSArchitectureMicroservices architecture on KubernetesArchitectureReal-time data pipeline on GCP
Open this template in Raltey
Edit it on the canvas, ask the AI agent to extend it, then share or export.
Start for free