TSTier SlateAll templates

Social & feeds

Stories - posts that delete themselves in 24 hours

Why expiry is a read-time filter plus a background sweep, and why the viewer list is the expensive part.

  • System design
  • core
  • 8 step walkthrough
  • 5 tables

Share

  • Facebook
  • X

What this board gets wrong on purpose

The tension

The viewer list takes one write per view - about 15 billion a day, 520,000 a second at peak - which is 25 times the write rate of the stories themselves, and a celebrity story concentrates millions of those writes on one story id. Expiry is only exact on paths that apply the read-time filter: the CDN keeps serving a cached rendition until its own TTL runs out, a client that downloaded the video still has it, and the sweep that actually deletes bytes runs minutes to hours behind, so "gone after 24 hours" is true for the product and not yet true for the disk. And the tray multigets up to 400 story-head keys per open, so its p99 is the p99 of the slowest cache shard it touched.

Practise this as an interview

Take Stories - posts that delete themselves in 24 hours as a timed system design interview on a blank board - on your own, with the requirements to check yourself against, or with a candidate you invite.

Practise this as an interview

Start here

Why this design

Stories - Instagram, Snapchat, WhatsApp Status, LinkedIn and many others shipped them - look like a feed with a timer. The timer is the interesting part. "Disappears after 24 hours" sounds like a TTL on a row, but no database deletes on time, and a story visible at 24 hours and 4 minutes is a broken promise that users notice and screenshot. The design answer is that expiry is two separate mechanisms with two separate guarantees: a filter that makes expired stories invisible exactly on time, and a sweep that makes them gone some time later. Then there is the part nobody expects to be expensive: the list of who watched each story.

What you will learn

  • Why visibility at 24 hours is enforced by WHERE expires_at > now() on every read, and deletion by a background sweep that may lag.
  • Why the tray ("who has a story for me") is assembled at read time from a story-heads cache rather than pushed into every follower's inbox.
  • Why the viewer list is 25 times the write volume of the stories, and how idempotent inserts and hourly partitions keep it bounded.
  • How signed CDN URLs that expire with the story stop new fetches, and why they do not recall bytes already cached.
  • Why highlights keep a story past 24 hours by reference, and what that does to the sweep.

How to read this board

  1. Press Play and follow one story from POST through STORE, then a viewer opening the tray in WATCH.
  2. Then VIEWER LIST, which is where the writes go, and THE SWEEP at the bottom.
  3. 1 · Requirements, 2 · Capacity, 3 · Storage - the views and the media are the two big numbers.
  4. 4 · Availability - what a late sweep or a slow cache shard costs.
  5. 5 · How it works, 6 · Deployment plan, then the DATA MODEL.

1 · Requirements

Ask these before drawing anything

  • Exactly 24 hours, or "about a day"? The answer decides whether a TTL alone is acceptable. It almost never is.
  • Who sees a story - followers, close friends, a custom list? Audience is checked at read time, so changing a list after posting changes who can see it.
  • Does the author see who viewed, and for how long after expiry? Instagram keeps the list visible for 48 hours.
  • Can a story be kept (archive, highlights)? If yes, "deleted at 24 hours" becomes "removed from the public tray at 24 hours", and the legal wording matters.
  • What does delete mean for compliance - must bytes be gone from backups and caches, and by when?

Functional

  • Post a photo or a video of up to 15 seconds; it is visible to its audience for exactly 24 hours.
  • Open a tray of accounts with live stories, unseen ones first.
  • Record each view once per viewer per story and show the author a viewer list with a count.
  • Optionally pin a story to a highlight, which keeps it beyond 24 hours on the author's profile.

Non-functional

  • Expired stories never returned by any API after expires_at, to the millisecond.
  • Tray open at p99 under 200 ms; first frame of a story under 400 ms.
  • Media bytes of an expired, unpinned story deleted from origin within 6 hours, and CDN copies unreachable within 1 hour.
  • A lost view beacon is acceptable; a doubled view is not (counts are shown to authors).

The rest of this board

Board preview

Available on Tier Slate

This page publishes the question. The answer — 5 more written pages, an 8-step narrated walkthrough and a 5-table schema — is the board itself, and it opens in Tierslate.

  • 5written pages
  • 8walkthrough steps
  • 5tables24 columns

5 pages behind this one

  • Capacity estimation
  • Storage estimation
  • Availability
  • How it works
  • Deployment plan
Open this board in TierslateBrowse every board

More boards

Timelines, follows, fan-out - the read-heavy classics.

  • Social news feed - fan-out on write or on read
  • Media feed - the feed serves URLs, the edge serves bytes
  • The professional graph - degrees, and why it is not a join
  • Comment trees - one range scan, and four writes per vote
  • The social graph - one edge, written twice
  • Home timeline - materialise it, then keep it honest
  • Blog platform - write once, cache everywhere
  • Link previews - fetching a stranger's page safely
  • Reviews and ratings - the average that must not be gamed
  • Content moderation - deciding before everyone sees it
All 100 templatesOpen Tierslate
Tierslate

tierslate.com

HomeTemplatesPrivacyTerms