Facebook-like Social Network — System Design

[!NOTE] Demo document for MDView: headings, TOC, GFM, callouts, tasks, wide tables, code, math, and Mermaid diagrams.

Contents


Goal

Design a simplified Facebook-style social platform with:


How it works

At a high level:

  1. User creates a post.
  2. Post is stored in the Post Service.
  3. Fanout workers distribute the post to follower feeds.
  4. Feed Service reads precomputed timelines.
  5. Notification Service alerts interested users.
[Diagram]

GFM support

Core entities

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

Example rules

Autolink example: https://example.com/privacy-policy


Admonitions and Callouts

[!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.


Task list


Wide table

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

Code

Post creation API

POST /v1/posts
Authorization: Bearer <token>
Content-Type: application/json

{
  "text": "Hello world",
  "visibility": "friends",
  "media_ids": ["m_123"]
}

Example event

{
  "event_type": "PostCreated",
  "event_id": "evt_9f31",
  "post_id": "post_123",
  "author_id": "user_42",
  "visibility": "friends",
  "created_at": "2026-04-30T18:00:00Z"
}

Fanout worker pseudocode

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
        )

Math

Fanout cost

If a user has (F) friends and creates (P) posts per day:

[Formula]

For a celebrity account:

[Formula]
[Formula]

That is why pure fanout-on-write is dangerous.

Feed ranking score

A simplified score:

[Formula]

Where freshness may decay as:

[Formula]

Diagram

[Diagram]

Feed read path

[Diagram]

Storage model

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)
);

Final architecture rule

[!IMPORTANT] The feed is an optimization, not the source of truth. The source of truth is always: posts + graph + privacy settings.