Skip to main content

Command Palette

Search for a command to run...

Design Netflix | System Design Question

Updated
27 min readView as Markdown

You open Netflix, scroll a wall of thumbnails, hit play, and video fills the screen in about a second and keeps playing without a stutter - on your phone on a train, on a smart TV on fibre, for hundreds of millions of people at the same time, all over the world. That last sentence is the whole interview. In this post we design it end to end the way you would at a whiteboard, on a 60-minute budget, reasoning each piece into existence instead of drawing a finished picture cold.

This is a "design X" walkthrough, so it follows the same 4-step interview shape every one of these should: scope it (about 10 minutes), sketch the high-level design (about 15), go deep on the hard parts (about 25), and wrap up (about 5 to 10). If you have not seen that framework before, it is spelled out in the 60-minute system design interview framework; here we just run it.

Step 1 - Scope it before you build anything

"Design Netflix" is enormous. Netflix has profiles, a recommendation engine, downloads for offline, subtitles in dozens of languages, ratings, billing, ads on the cheaper tier, games. You cannot build all of that in an hour, and the interviewer does not want you to try. The first move is always to shrink the problem out loud until it fits, and to make the interviewer agree to the smaller version.

That happens as a conversation. Here is roughly how it goes - and notice it is not one clean answer after another, because real interviewers do not behave that way:

You: What are the core features we need? Browsing the catalog and streaming a video, or the whole product?

Interviewer: Focus on the two that matter: a user finds something and watches it. Streaming has to start fast and not buffer.

You: Which clients - mobile, web, TV?

Interviewer: All three. Assume most watch time is on TVs and phones.

You: How many users should I design for? Give me a daily-active number so I can size things.

Interviewer: You tell me. What is reasonable for a service like this?

You: Fair. Netflix is in the couple-hundred-million subscriber range, so I will assume 200 million daily active users, each watching about 2 hours a day. I will write that down as an assumption and size everything off it - shout if it is way off.

Interviewer: That works.

You: Do we need to handle live events - live sports, a live comedy special?

Interviewer: Yes, actually, let's say we also do live.

You: Live is a genuinely different beast - the video is being produced and encoded in real time, so there is no pre-computed catalog and latency budgets are tighter. It is worth its own design. Can I build the on-demand (pre-recorded) service properly first and treat live as a follow-up? I will note where it would branch off.

Interviewer: Good, park live. Do on-demand.

Three things happened there, and they map to a rule worth stating explicitly:

  • The interviewer gave a clear answer (features, clients). Use it.
  • The interviewer punted ("you tell me" on user count). When that happens, do not freeze. Propose a concrete number, say your reasoning out loud, and write it down as a stated assumption. A number you picked and justified is worth far more than waiting for permission.
  • The interviewer bolted on scope (live). A weak candidate silently tries to cram it in. Name its one-line cost ("live means encoding in real time, no pre-built catalog, tighter latency") and defer it. Scoping down is a senior move, not a dodge.

The requirements, as precise bullets

Now pin it down. Two lists, one point per bullet - never a mushy paragraph.

Functional requirements (what the system does):

  • A user can browse and search a catalog of titles and see each title's metadata (name, description, cast, artwork).
  • A user can press play and stream a title.
  • Playback starts quickly and adapts quality to the network so it does not buffer.
  • The same title plays on mobile, web, and smart TV.
  • Content owners (Netflix, studios) can ingest a new title into the catalog.

Non-functional requirements (how well it does it):

  • Highly available. People notice instantly when Netflix is down. Target "always on" for streaming.
  • Global and low latency. Video starts fast wherever the user is.
  • Massive read/stream scale. Reads (browsing) and streaming vastly outnumber writes (new titles).
  • Reliable. A title, once uploaded and encoded, is never lost.
  • Cost-aware. Serving this much video is the single biggest expense; the design has to fight bandwidth cost directly.

That last non-functional point is unusual. In most designs cost is an afterthought. Here it drives a whole section of the architecture, and we will see exactly why in the estimate.

Back-of-the-envelope: the numbers that shape everything

You do not need precise figures, you need the order of magnitude that forces a decision. (If rough estimation feels shaky, here is a fuller walkthrough of the technique.) Say the assumptions out loud as you go.

Streaming egress - the number that dominates the whole design.

  • 200M daily users * 2 hours watched = 400 million watch-hours per day.
  • Average streaming bitrate across a mix of phones (low), 1080p, and 4K: call it 4 megabits per second (Mbps). "Bitrate" is just how many bits of video you push per second; higher bitrate means a sharper picture and a bigger file.
  • Data per watch-hour = 4 Mbps * 3600 s = 14,400 megabits = 1.8 gigabytes (GB).
  • Daily egress = 400M hours * 1.8 GB = 720 petabytes (PB) per day. (1 PB is a million GB.)
  • Spread evenly that is 720 PB / 86,400 s = about 8.3 terabytes per second (TB/s), or roughly 66 terabits per second (Tbps). But traffic is not even - it peaks in the evening. At a conservative 3x the average, peak egress is on the order of 200 Tbps.

Sit with that for a second, because it is the crux of the entire problem. Two hundred terabits per second, sustained, delivered to screens on every continent. If you tried to serve that out of a cloud region's internet egress, the bandwidth bill alone would be measured in millions of dollars per day, and no single region has the network capacity anyway. The design does not have a video-delivery component bolted on the side. Video delivery is the design, and it is a network problem before it is a software problem.

Storage - surprisingly modest by comparison.

  • Suppose the catalog is about 50,000 hours of unique content.
  • Each source hour gets encoded into many versions (several resolutions, a few codecs, multiple audio and subtitle tracks - we will see why shortly). Call the encoded footprint ~100 GB per source hour.
  • Catalog storage = 50,000 * 100 GB = 5 PB. Stored once, durably, in the cloud.

So the master catalog is single-digit petabytes - big, but a bounded, one-time storage cost. The egress is what is unbounded and terrifying. Storage is cheap; moving bits to eyeballs is not.

Control-plane request rate - the browsing side.

  • Every session fires many small API calls: home rows, search, artwork, "is this user allowed to play this", progress updates. Say 200M users * a handful of sessions * ~20 calls = on the order of 20 billion API calls/day, roughly 230k requests/second average, peaking past 1 million/second.
  • These are almost all reads, and the same popular titles are requested over and over.

Two numbers, two different worlds. ~200 Tbps of video is one problem. ~1M req/s of small, cache-friendly, read-heavy metadata calls is a completely different problem. Recognising that they are different is the key architectural insight, and it gives us the shape of the whole system.

Step 2 - The high-level design

Here is the one idea to anchor on: split the system into two planes.

  • The control plane answers "what should I show and am I allowed to play it" - browsing, search, recommendations, login, billing, playback authorization. Small requests, read-heavy, runs in the cloud.
  • The data plane does exactly one thing: push video bytes to screens. Enormous, bandwidth-bound, and pushed as close to users as physically possible.

They scale independently, fail independently, and cost money for completely different reasons. Keep them separate in your head and the design almost writes itself.

Before components, one definition, because it is the reason streaming is not just "download the file": downloading copies the whole video to your device before you watch; streaming delivers it in small pieces continuously, so the player buffers a few seconds ahead and you start watching in about a second while the rest arrives as you go. Netflix never downloads the whole title to play it - it streams chunks.

Now let's reason each component into existence from the numbers.

  • ~200 Tbps of egress, globally -> we need a content delivery network (CDN): a fleet of servers spread across the world that cache the video near users, so bytes travel a short distance instead of crossing oceans. (The general mechanism of edge caching is covered in scaling frontends with a CDN; we lean on it here rather than re-deriving it.) A generic third-party CDN (CloudFront, Akamai, Fastly) would work, but at Netflix's volume it is both ruinously expensive and not optimized for video. This is where Netflix does something most companies never would: it builds its own CDN. Hold that thought for the deep dive - for now, "CDN" is the data plane.
  • A 5 PB catalog of large binary files -> we need blob storage: a store built for large "binary large objects" (video files), not rows in a database. Think Amazon S3. We actually need two blob stores: one for the pristine original masters and one for the encoded output.
  • Devices and networks are wildly different (a 4K TV on fibre vs a phone on 3G) and raw studio masters are huge and in formats browsers cannot play -> we need a transcoding pipeline that converts each master into many playable versions at different qualities. This is a whole subsystem; we defer its internals to the deep dive.
  • Title metadata, read constantly -> a metadata database, and because reads dwarf writes and the same titles are hot, a cache in front of it. The database is sharded and replicated for scale and availability (the how is in scaling databases).
  • ~1M req/s of control traffic -> a tier of stateless microservices behind an API gateway / load balancer. Stateless means any server can handle any request (no session stuck to one box), so we scale by adding boxes and a dead box just sheds its traffic to the others.

Put the control-plane skeleton together and you get this:

High-level Netflix architecture: clients talk to a control plane of API microservices with a metadata DB and cache, and stream video separately from the Open Connect CDN edge

Notice the split visually: control requests go left to the API tier; the actual video comes from the CDN edge on a totally separate path. The API server's job at play time is tiny - check you are allowed, then hand back a URL and tell your player which edge server to pull from. It never touches a video byte. That is the whole point.

Now the two flows the interviewer will care about: how a title gets in, and how you watch it.

Flow 1 - Ingesting a title

Unlike YouTube, where random users upload 300 MB phone clips all day, Netflix's content is professionally produced and delivered as a small number of very high quality master files. So ingestion is a controlled, batch pipeline, not a firehose of user uploads:

Netflix ingestion pipeline: studio master goes to original blob storage, then the transcoding pipeline encodes a bitrate ladder into encoded storage, a completion queue drives handler workers that update the metadata DB and cache, and encoded output is proactively filled to Open Connect appliances

Walking it through: the master lands in original storage (the upload itself uses a pre-signed URL - a short-lived, permission-scoped URL that lets the uploader write straight to blob storage without the bytes passing through our API servers; we will not re-explain the mechanism here, it is covered in full). The transcoding pipeline picks it up and produces the many encoded versions into encoded storage. When a version finishes, an event goes onto a completion queue - a message queue that decouples "encoding finished" from "record that fact", so a slow database write never stalls an encoder. Completion handler workers drain the queue and update the metadata DB and cache. Finally the encoded files are proactively filled out to the CDN edge, typically overnight, so the video is already sitting near users before anyone presses play. This pre-positioning is a Netflix superpower and we will come back to it.

Flow 2 - Watching a title

This is the request most of the design exists to serve. It is a sequence, so a sequence diagram is the honest way to show it:

Playback sequence: client asks the Playback API to play a title, the API checks auth and DRM then asks a steering service which edge server to use, returns a manifest plus OCA URLs, and the client loops fetching segments at a chosen quality directly from the Open Connect appliance

The player asks the Playback API to start a title. The API checks you are logged in, subscribed, and licensed to watch it, asks a steering service which edge servers are best for this user right now, and hands back a manifest plus URLs. From then on the API is out of the loop: the player talks directly to the edge server, pulling a few seconds of video at a time and adjusting quality on the fly. Everything interesting in that loop - the manifest, the quality switching, the steering, the edge server itself - is what we go deep on next.

Step 3 - The deep dive

We have a working skeleton. Now the hard parts, each posed as a question, weighed, and decided.

3a. Transcoding: why one video becomes fifty

The question: a studio hands us one pristine master. Why not just store it and stream it?

Because that single file is useless for actual delivery. It is enormous (an hour of high-quality source can be hundreds of GB), it is in a professional format no browser or TV can play, and it assumes one fixed quality - hopeless for a phone dipping in and out of signal. Transcoding (also called encoding) fixes all three: it converts the master into many smaller, playable files at a range of qualities. Two terms you will use:

  • Container - the wrapper file that holds the video, audio, and metadata together. You know it by its extension: .mp4, .mov, .mkv.
  • Codec - the compression algorithm inside the container that shrinks the video while keeping it watchable. Common ones are H.264 (universal), VP9, and AV1 (newer, much more efficient). A newer codec at the same quality is a smaller file, which at Netflix scale is a direct bandwidth-cost saving - which is why Netflix invests heavily in them.

Transcoding one title is a big, parallelizable job with per-title quirks (a watermark here, a supplied thumbnail there). Facebook's video pipeline models this as a directed acyclic graph (DAG) - a set of tasks with dependencies and no cycles, so independent tasks (encode the 1080p rung, encode the audio, make the thumbnail) run in parallel while dependent ones wait. We adopt the same model. Zooming into the transcoding box:

Transcoding architecture: original video enters a preprocessor that splits it into GOP chunks and builds a DAG, a DAG scheduler splits it into stages, a resource manager with task/worker/running queues dispatches to task workers for video encode, audio encode, thumbnail, and watermark, which write to temporary storage and produce the encoded output

The preprocessor splits the video into short independent chunks aligned on a GOP (group of pictures) - a few seconds of frames that can be decoded on their own. Independent chunks are the whole trick to parallelism: you can hand different chunks to different machines and encode them all at once, and if one fails you retry just that chunk. The DAG scheduler breaks the job into stages, the resource manager (task queue + worker queue + running queue) matches work to free workers, the task workers do the actual encode/audio/thumbnail/watermark, and the pieces are reassembled into the final encoded files.

One design note the interviewer will fish for: use a message queue between pipeline stages. Without it, "encode" must wait for "download" to finish for that item, and everything runs in lockstep. With a queue, each stage just pulls the next available job, so hundreds of chunks flow through independently and one slow step never blocks the rest. Loose coupling through queues is what makes the pipeline scale.

3b. The bitrate ladder and adaptive streaming

The question: transcoding produced many versions. How does the player pick one, and how does it avoid buffering when the network wobbles?

The set of versions is a bitrate ladder - the same title at ascending quality/bitrate rungs. A simple ladder:

Rung Resolution Approx bitrate
1 240p 0.3 Mbps
2 360p 0.7 Mbps
3 480p 1.5 Mbps
4 720p 3 Mbps
5 1080p 5 Mbps
6 4K 15 Mbps

Every rung is chopped into the same short segments (a few seconds each), and a manifest file lists the rungs and the segment URLs. In HLS the manifest is an .m3u8 file with .ts segments; in MPEG-DASH it is an .mpd with .m4s segments. Both do the same job: hand the player a menu.

Now the actual magic, adaptive bitrate streaming (ABR). The player does not commit to one quality. Every few seconds, before fetching the next segment, it measures how fast the last segments arrived and how much buffer it has, and picks the highest rung it can sustain. Signal drops - it steps down to keep playing; signal recovers - it steps back up. You see this as a moment of softness after a network hiccup instead of the spinner of death. Because every segment is a separate HTTP file, switching quality is just "fetch the next segment from a different rung" - no reconnect. The decision lives entirely in the client:

type Rendition = {
  height: number;      // 240, 360, 480, 720, 1080, 2160
  bitrateKbps: number; // encoded average bitrate of this rung
  codec: "h264" | "vp9" | "av1";
};

// Throughput-based ABR: pick the highest rung we can sustain, with a
// safety margin, but never leap to the top right after a stall - climb
// one rung at a time when the buffer is healthy, and drop fast when it
// is not. This is what keeps playback smooth on a flaky connection.
function chooseRendition(
  ladder: Rendition[],           // sorted low to high bitrate
  estimatedThroughputKbps: number,
  bufferSeconds: number,
  current: Rendition,
): Rendition {
  const SAFETY = 0.8;   // only trust 80% of measured bandwidth
  const MIN_BUFFER = 10; // seconds of buffer before we allow an upshift

  const affordable = ladder.filter(
    (r) => r.bitrateKbps <= estimatedThroughputKbps * SAFETY,
  );

  // Nothing affordable: drop to the lowest rung to keep playing at all.
  if (affordable.length === 0) return ladder[0];

  const best = affordable[affordable.length - 1];

  // Guard against flip-flopping: only climb when the buffer is deep.
  if (best.bitrateKbps > current.bitrateKbps && bufferSeconds < MIN_BUFFER) {
    return current;
  }
  return best;
}

Here is where Netflix goes beyond the textbook. A one-size ladder is wasteful: a still, dialogue-heavy drama needs far fewer bits to look perfect than a fast, grainy action scene, yet a fixed ladder spends the same bitrate on both. So Netflix pioneered per-title encoding - each title gets a ladder tailored to its own visual complexity, described in their per-title encode optimization work. They then pushed further to per-shot (optimized shot-based) encoding, tuning the bitrate shot by shot within a title, which their engineers reported can hit the same quality at less than half the bits of the older approach. Fewer bits at the same quality means smaller files, smaller egress, and a smaller bill - at 200 Tbps a few percent is real money, and this is why the "cost-aware" non-functional requirement earned its place up top.

3c. Open Connect - Netflix builds its own CDN

The question: back to the scary number. ~200 Tbps of peak egress, worldwide. How do we deliver that without going bankrupt or melting the internet?

A normal answer is "use a CDN." Netflix's answer is "be the CDN, and put it inside the internet providers themselves." Their CDN is called Open Connect, and the box that does the work is an Open Connect Appliance (OCA) - a purpose-built storage-and-streaming server (up to hundreds of TB of flash and disk) that Netflix ships, free of charge, to internet service providers (ISPs) and internet exchange points. The ISP racks it in their own data centre. Now when you press play, the video comes from a box that is often inside your own ISP's network - sometimes one hop away - instead of crossing the continent from a cloud region.

Reason past why this is so much better than renting a generic CDN:

  • Bandwidth cost collapses. Traffic served from an OCA inside the ISP never traverses expensive long-haul or peering links. The ISP wins too (less transit to pay for), which is exactly why over a thousand ISPs have installed them - it is a rare deal where both sides save money.
  • Latency and smoothness improve. Bytes travel a short distance, so startup is faster and there is more headroom to hold a high rung.
  • Netflix controls the whole stack - the hardware, the software, the routing - and tunes it purely for video, which a general-purpose CDN cannot.

The catch: an OCA holds hundreds of TB, but the catalog is petabytes. It cannot hold everything. Two ideas resolve this, and both lean on a fact about viewing:

Viewing follows a long-tail (Zipf-like) distribution - a small set of titles accounts for a huge share of watch time, while a long tail is watched rarely. So:

  1. Proactive fill, not reactive caching. Because on-demand content is known in advance, Netflix does not wait for a cache miss. Each night, during off-peak hours, it predicts what will be popular in each region and pre-loads those titles onto the local OCAs. By prime time the popular catalogue is already sitting next to users. (A generic CDN caches reactively - first viewer pays a slow origin fetch; Netflix mostly avoids that.)
  2. Tiered appliances. The hottest titles live on faster flash OCAs; a larger, cheaper storage tier holds more of the catalogue on disk; and regional popularity means a title big in one country need not ship to another. The rare cold title is fetched from a bigger regional cache or origin.

The steering service from the playback flow is what ties a client to the right OCA - ranking appliances by whether they hold the title, health, network proximity, and current load:

type Oca = {
  id: string;
  hasTitle: boolean;   // did tonight's fill place this title here?
  healthy: boolean;
  rttMs: number;       // round-trip time from this client to the OCA
  loadPercent: number; // current utilisation
};

// Steering ranks appliances for one client and one title. Prefer an OCA
// that already holds the title, is healthy, is close, and is not maxed
// out. The player is handed this ranked list and fails over down it.
function rankOcas(candidates: Oca[]): Oca[] {
  return candidates
    .filter((o) => o.healthy && o.hasTitle && o.loadPercent < 90)
    .sort((a, b) => a.rttMs - b.rttMs);
}

Handing the client a ranked list rather than a single server matters: if the top OCA hiccups mid-stream, the player just moves to the next one and playback continues. Resilience is built into the handoff.

3d. Remembering where you paused - the hidden write load

The question: the control plane is read-heavy, but there is one sneaky high-volume write. What is it, and how do we store it?

It is playback progress. To power "Continue Watching" and to resume on another device, the player reports its position periodically while you watch - say every 30 seconds. With tens of millions of concurrent streams, that is on the order of a million writes per second of tiny "user X is at 00:42:15 in title 42" records. A normal relational primary would fall over.

This is a textbook fit for a write-optimized, horizontally scalable store - a wide-column database like Cassandra, which is built to absorb huge write volumes across many nodes and is happy with eventual consistency (if your resume point is a few seconds stale, nobody dies). The lesson worth voicing: "read-heavy overall" does not mean "no serious writes." Find the one write path that scales differently and give it its own store instead of forcing it into the metadata DB.

3e. Keeping the content safe

The question: studios will not license premium content unless we can stop it being copied. How do we protect it?

Three layers, used together:

  • DRM (Digital Rights Management) - the video is encrypted, and the player must obtain a licence with a decryption key from a licence server to play it. The big systems are Apple FairPlay, Google Widevine, and Microsoft PlayReady, and a client uses whichever its platform supports (this is the "DRM licence" check in the playback sequence).
  • AES encryption - the segments themselves are encrypted at rest and in transit, so an intercepted segment is gibberish without the key.
  • Forensic / visual watermarking - identifying marks embedded in the stream so a leaked copy can be traced.

And on ingestion, the pre-signed URL from earlier means only an authorized uploader can write a master to the right storage location - authorization is enforced before a byte is written.

The whole thing, on one diagram

Assemble every decision - two planes, the encoding pipeline in the middle - and this is Netflix at a high level:

Combined Netflix architecture: clients issue control requests to a control plane on AWS (API gateway, microservices, sharded metadata DB, cache); an ingestion-and-encoding pipeline turns studio masters into encoded storage via a transcoding pipeline, completion queue, and handler; encoded output proactively fills Open Connect appliances in the data plane; and clients stream video segments directly from those appliances

Read it as two loops meeting a pipeline. Clients hit the control plane on AWS for everything except video; a separate ingestion pipeline turns masters into encoded files and proactively fills the data plane; and clients pull the actual video straight from an Open Connect appliance near them. The control plane runs on general cloud infrastructure; the data plane is Netflix's own hardware in the internet's plumbing. That separation is the design.

The follow-up questions

The core design is done. This is where the interview really lives - the interviewer probes for holes. Rapid, reasoned answers:

"What happens on a huge launch - a hit show drops and everyone plays it at 8pm?" This is a thundering herd on one title. Netflix's model is unusually well-suited to it: because ingestion is known in advance, the show is proactively pre-filled to OCAs everywhere before release, so launch night is served from local flash appliances, not a scramble to origin. The control-plane spike (millions of "play" authorizations) is absorbed by stateless microservices that autoscale and by caching the title's metadata, which is red-hot and served almost entirely from cache.

"An OCA dies mid-stream. What does the user see?" Ideally nothing. The player was handed a ranked list of appliances, so it fails over to the next one and keeps playing. The dead OCA is health-checked out of steering so new sessions avoid it, and its titles are already replicated across other appliances and the regional cache.

"How do you keep the metadata cache and DB consistent?" Title metadata changes rarely and can tolerate being a little stale, so cache-aside with a TTL is plenty - a reader that misses loads from the DB and populates the cache, and updates invalidate or refresh the entry. (The trade-offs between cache-aside, write-through, and the rest are laid out in caching strategies.) We deliberately do not demand strong consistency here, because the cost is not worth it for artwork and descriptions.

"Scale to 10x - a billion users." The data plane scales by deploying more OCAs into more ISPs; it was designed to grow linearly with the internet's own footprint, which is the point of embedding in ISPs. The control plane scales by adding stateless instances and sharding the metadata and progress stores further. The encoding pipeline is embarrassingly parallel (chunked jobs), so it scales with more workers. Nothing in the design has a hard central ceiling - the honest bottleneck is cost and the physical build-out of appliances, not architecture.

"Where is the single point of failure?" We avoid obvious ones: microservices are stateless and replicated, the metadata DB is sharded and replicated, the queue and workers are replaceable, and steering hands out fallback lists. The subtle risk is a shared dependency (a global auth or licence service, or a bad config rollout) taking down many services at once - which is why real Netflix leans hard on regional isolation, so one region's failure can be routed around by shifting users to another.

"Live streaming - how would this change?" As flagged in scoping: there is no pre-built catalogue and no overnight fill, because the video is being produced right now. You would add a real-time ingest and encoding path that segments the live feed on the fly and pushes segments to the edge with the lowest latency you can manage, trading some of the offline pipeline's per-shot optimization for speed. Same two-plane skeleton, a very different content pipeline.

Wrapping up

Stepping back, the design turns on one idea worth carrying into any streaming question: separate the tiny read-heavy control plane from the enormous bandwidth-bound data plane, and optimize each for what it actually costs. The control plane is a fairly ordinary cloud microservices system - gateway, stateless services, a cached and sharded metadata store, plus one write-heavy store for playback progress. The data plane is where the real engineering is: a purpose-built CDN pushed inside the ISPs, fed by proactive fills that exploit the long tail of viewing, serving video that was encoded shot-by-shot to shave every avoidable bit off a 200-terabit-per-second bill.

The parts that separate a strong answer from a memorized one are the whys: why the egress number, not the storage number, drives everything; why Netflix builds its own CDN when almost no one should; why an unglamorous progress-tracking write needs its own database; and why "cost" earned a spot in the non-functional requirements. Say those out loud, and you are not reciting a diagram - you are designing.