Social Network
Create social graphs and feeds while controlling fan-out, abuse, and privacy.
Product overview
Support profiles, follows, posts, media, home feeds, interactions, notifications, and moderation while respecting privacy and high-degree graph behavior.
Main actors
Member, Moderator, Advertiser, Support.
Assumptions
- Follow graph can be directed
- Accounts may be private
- Feed ordering starts chronological with policy filters
- Counters are projections
Non-goals
- Advertising auction
- Opaque engagement ranking
- End-to-end encrypted messaging
- Replicating any named network
Requirements
Must-have
- Profiles and follow lifecycle
- Text/media posts
- Home feed
- Likes/comments
- Block/report/moderation
Should-have
- Private accounts
- Mentions
- Notifications
- Post edit history
Future scope
- Groups
- Federation
- Recommendations
- Direct messages
Non-functional decisions
| Concern | Decision |
|---|---|
| Availability | Post writes survive feed-worker outages; feeds may be delayed with freshness shown internally. |
| Consistency | Privacy/block/follow acceptance is authoritative; feeds and counters converge. |
| Scalability | Hybrid fan-out prevents one high-degree author from overwhelming write fan-out. |
| Safety | Moderation, reports, rate limits, and appeals are first-class workflows. |
| Privacy | Audience is checked again when hydrating feed candidates. |
User roles
| Role | Access boundary |
|---|---|
| Member | Own profile/posts; authorized social content |
| Moderator | Queued reports/content with audited decisions |
| Support | Account recovery metadata, not unrestricted content |
| Safety admin | Policy configuration and restricted appeals |
Core workflows
Domain model
| Entities | Relationship |
|---|---|
Account → FollowEdge | Directed requested/accepted relationship |
Account → Post → Media | Author owns post; media publish follows scan |
Post → Reaction / Comment | Interactions have uniqueness/audience checks |
Account → FeedItem | Materialized candidate with source post |
Report → ModerationDecision | Evidence and reversible policy action |
Database design
PostgreSQL remains the transactional source of truth. Add specialized stores only for the workloads called out below.
follows — Directed social graph
posts — Authoritative post
feed_items — Per-user feed candidates
moderation_actions — Audited policy decisions
Transaction and retention boundaries
- Post and outbox commit atomically
- Accept private follow conditionally changes requested edge
- Block transaction deletes/conflicts follow edges and increments privacy epoch
- Hard delete media only after tombstone propagation/retention; moderation actions remain audited
API design
| Endpoint | Purpose and permission | Idempotency / status |
|---|---|---|
POST /v1/posts | Publish post with finalized media ids Member | Client mutation id 201, 422, 429 |
GET /v1/feed?cursor=… | Stable keyset feed Member | Not required 200 |
POST /v1/accounts/:id/follows | Follow or request follow Member; block rules | Unique edge 200, 403, 409 |
POST /v1/posts/:id/reactions | Set reaction Authorized viewer | Upsert by user/post/type 200, 403 |
POST /v1/reports | Report content/account Member with rate limit | Client report id 201, 429 |
DELETE /v1/posts/:id | Tombstone own post Author or policy-authorized moderator | Idempotent 204, 403 |
List endpoints use opaque keyset cursors unless a small bounded collection is explicit. Unknown objects return 404 where 403 would leak existence.
Architecture
System context
Main application architecture
Critical workflow sequence
Event model
| Event | Producer → consumers | Delivery |
|---|---|---|
PostPublished | Post API → Feed fan-out, search, mention notification | Outbox; feed unique(user,post) |
PrivacyChanged | Graph API → Feed repair, cache invalidation | Epoch/version; hydration remains final guard |
ContentRemoved | Moderation → Feed/search/media purge | High priority, replayable tombstone |
Failure modes
Fan-out lag
Failure
Post exists but followers do not see it yet.
Mitigation
Durable outbox/queue, lag metric, and author-profile read remains authoritative.
Celebrity explosion
Failure
Millions of follower writes per post.
Mitigation
Classify high-fanout authors and merge their posts at read time.
Privacy race
Failure
User becomes private/blocks after item entered feed.
Mitigation
Hydration rechecks current audience/block epoch before returning content.
Duplicate like
Failure
Client retries reaction.
Mitigation
Unique user/post/type upsert; counters consume change events idempotently.
Deleted post remains
Failure
Stale cache/feed references tombstoned post.
Mitigation
Hydration omits tombstones; removal event and short negative cache accelerate cleanup.
Moderation retry
Failure
Same action is applied twice.
Mitigation
Decision idempotency id and state-aware reversible actions.
Consistency and concurrency
Strong consistency / transactions
- Account/block/privacy state
- Post ownership
- follow edge
- moderation decision
Eventual convergence
- Home feed
- reaction/follower counts
- search
- notifications
Concurrency controls
- Unique graph/reaction constraints absorb retries
- Privacy epoch invalidates cached audience decisions
- Post version protects edits
- Feed insertion is idempotent; no per-user distributed lock
Caching and background work
Safe to cache
- Public profile/post with audience epoch
- Media via CDN
- Feed page briefly per user/version
Never a cache authority
- Block decision without epoch
- Unreviewed uploads
- Moderator evidence in shared caches
Cache public immutable media aggressively. Audience-sensitive objects include policy epoch and are reauthorized on hydration.
Background jobs
- Feed fan-out/repair
- Media scan/transcode
- Counter aggregation
- Search indexing/removal
- Notifications
- Abuse classification and retention purge
Security boundaries
Security claims here are design controls, not certification. Threat modeling and jurisdiction-specific review remain required.
- Object-level audience/block checks
- Sanitize text/links and proxy or validate remote previews against SSRF
- Scan and re-encode uploads
- Rate-limit follows, posts, comments, reports by behavioral signals
- Moderator access/actions are least-privilege and audited
- Prevent account enumeration in private/recovery flows
- Deletion and export honor retention/legal constraints explicitly
Observability
Logs
- Post/follow/block/moderation transitions with policy version and safe target ids
- Feed fan-out event, recipient batch, high-fanout classification, and dedupe result
- Audience-filter rejection reason without copying private post bodies
Metrics
- Post-to-feed availability and fan-out queue age by author class
- Feed hydration drop rate from block/privacy/deletion checks
- Reaction/counter projection lag and duplicate-event rate
- Report backlog age, moderation turnaround, and media quarantine failures
Traces
- Trace publish through durable post, fan-out classification, feed insertion, and mention notification
- Trace feed read through candidate merge, authorization filtering, and hydration
Alerts
- Removal events fail to clear feed/search projections
- Report backlog breaches safety response target
- Celebrity fan-out saturates queues used by ordinary authors
Testing strategy
| Layer | What it proves |
|---|---|
| Unit | Audience policy matrix, cursors, post state, fan-out classifier |
| Integration | Graph uniqueness, outbox, tombstone filters, privacy epoch |
| Contract | Versioned feed and moderation events |
| Concurrency | Follow/block races and duplicate reactions |
| Failure | Fan-out outage, stale cache, deletion replay |
| Load | Skewed follower graph and celebrity post bursts |
Do not mock PostgreSQL constraints, transaction isolation, object-store semantics, or provider contract fixtures in the tests intended to prove those boundaries.
Deployment evolution
Scale evolution
These are architecture scenarios, not throughput claims. Each transition should follow measured workload and reliability pressure.
| Scenario | Architecture may evolve toward | Decision rule |
|---|---|---|
| 1K users | One API, PostgreSQL for accounts, follows, and posts, timelines built at read time, a media worker, object storage | Build timelines on read while follower counts are small; privacy and block checks run on every read |
| 100K users | Introduce hybrid fan-out, separate feed store/search/media workers, read replicas for profiles | Fan out on write for ordinary accounts and on read for high-follower accounts once timeline reads dominate |
| 1M+ users | Partition graph/posts by account and feeds by recipient; use explicit routing and accept eventual cross-partition timelines | Accept eventually consistent cross-partition timelines, but never eventually consistent blocks or privacy changes |