[!NOTE] Demo document for MDView: headings, TOC, GFM, callouts, tasks, wide tables, code, math, and Mermaid diagrams.
Design a simplified Facebook-style social platform with:
At a high level:
| Entity | Description |
|---|---|
| User | Account, profile, privacy settings |
| Post | Text, media, author, visibility |
| Edge | Friendship or follow relationship |
| Reaction | Like, love, angry, etc. |
| Comment | Threaded discussion under a post |
visibility = friends must be checked on every read path.Autolink example: https://example.com/privacy-policy
[!IMPORTANT] Authorization must happen on both write path and read path. Feed precomputation is not a substitute for privacy checks.
[!WARNING] Celebrity accounts can have millions of followers, so naive fanout-on-write can overload workers.
[!TIP] Use hybrid fanout: push posts from normal users, pull posts from huge accounts at read time.
[!CAUTION] Deleted posts must be removed from feeds, search index, notification previews, and caches.
| Subsystem | Main responsibility | Storage | Cache | Queue/Event | Scaling strategy | Consistency model | Failure concern | Notes |
|---|---|---|---|---|---|---|---|---|
| API Gateway | Auth, routing, rate limits | None | Edge cache | None | Horizontal replicas | Stateless | Bad deploy blocks all traffic | Keep thin |
| User Service | Profiles and settings | Postgres / MySQL | Redis | UserUpdated | Shard by user_id | Strong for profile writes | Hot users | Privacy settings critical |
| Graph Service | Friends/follows | Graph DB / MySQL adjacency lists | Redis sets | EdgeCreated | Shard by user_id | Eventual for feed fanout | Large adjacency lists | Needs fast mutual lookup |
| Post Service | Create/read posts | Cassandra / DynamoDB | Redis | PostCreated | Shard by author_id | Strong write, eventual fanout | Hot partitions | Immutable post body preferred |
| Feed Service | Home timeline | Cassandra / RocksDB | Redis | FeedUpdated | Shard by viewer_id | Eventual | Stale feed items | Hybrid fanout |
| Media Service | Photos/videos | Object storage | CDN | MediaProcessed | CDN + async workers | Eventual | Large uploads | Store metadata separately |
| Notification Service | Push/email/in-app alerts | Cassandra | Redis | NotificationCreated | Shard by recipient_id | Eventual | Spam storms | Deduplicate aggressively |
| Search Service | User/post search | Search index | Query cache | IndexPost | Async indexing | Eventual | Stale results | Respect privacy filters |
| Ranking Service | Feed scoring | Feature store | Redis | FeatureUpdated | Model serving replicas | Best effort | Bad model rollout | Use fallback ranking |
POST /v1/posts
Authorization: Bearer <token>
Content-Type: application/json
{
"text": "Hello world",
"visibility": "friends",
"media_ids": ["m_123"]
}
{
"event_type": "PostCreated",
"event_id": "evt_9f31",
"post_id": "post_123",
"author_id": "user_42",
"visibility": "friends",
"created_at": "2026-04-30T18:00:00Z"
}
def handle_post_created(event):
post = posts.get(event["post_id"])
followers = graph.get_visible_recipients(
author_id=post.author_id,
visibility=post.visibility
)
for user_id in followers:
feed.insert(
viewer_id=user_id,
post_id=post.id,
score=rank_initial(post),
created_at=post.created_at
)
If a user has (F) friends and creates (P) posts per day:
For a celebrity account:
That is why pure fanout-on-write is dangerous.
A simplified score:
Where freshness may decay as:
CREATE TABLE posts (
post_id BIGINT PRIMARY KEY,
author_id BIGINT NOT NULL,
visibility TEXT NOT NULL,
text TEXT,
media_ids JSONB,
created_at TIMESTAMP NOT NULL,
deleted_at TIMESTAMP
);
CREATE TABLE feed_items (
viewer_id BIGINT NOT NULL,
created_at TIMESTAMP NOT NULL,
post_id BIGINT NOT NULL,
score DOUBLE PRECISION,
PRIMARY KEY (viewer_id, created_at, post_id)
);
[!IMPORTANT] The feed is an optimization, not the source of truth. The source of truth is always: posts + graph + privacy settings.