# System Design: [Video platform name]

> Reference design for video upload and adaptive bitrate streaming: resumable
> upload, a transcoding pipeline that produces a renditions ladder, CMAF
> packaging for HLS and DASH, CDN delivery, a DRM note, view counting, storage
> tiers and cost. It follows the structure of the System Design Document
> template and is pre-filled with a worked design to adapt. Values marked
> *Example* are assumptions: replace them and recompute; egress and storage
> numbers move by orders of magnitude with your audience.

<!--
Guidance: How to use this template
- Start with 3.1: uploads per day, average duration, views per day and
  average watch time. Egress (3.4) is almost always the largest cost.
- Choose the renditions ladder (7.2) from your audience's devices and
  networks, not from a generic table, and revisit it once you have data.
- Decide DRM early. It changes packaging, players and licensing, and is a
  contract matter with content owners.
- Keep the failure-mode and trade-off tables filled; reviewers check them first.
-->

## Document control

<!-- Guidance: A design is a proposal until it is approved; record who decided and when. -->

| Field | Value |
|---|---|
| Document ID | [SDD-VID-001] |
| System / feature | [Video upload and streaming] |
| Version | [0.1] |
| Status | [Draft / In review / Approved / Implemented / Superseded] |
| Author(s) | [@author] |
| Reviewers | [@reviewer-1], [@reviewer-2] |
| Last updated | YYYY-MM-DD |
| Related | [PRD], [CDN contract], [Content licensing requirements], [ADR: codec strategy] |

### Approvals

| Role | Name | Decision | Date |
|---|---|---|---|
| Tech lead | [@name] | [Approved / Changes requested] | YYYY-MM-DD |
| Staff / principal engineer | [@name] | [Decision] | YYYY-MM-DD |
| SRE / operations | [@name] | [Decision] | YYYY-MM-DD |
| Media / video engineering lead | [@name] | [Decision] | YYYY-MM-DD |
| Finance (CDN and storage cost) | [@name] | [Decision] | YYYY-MM-DD |

## Revision history

<!-- Guidance: Note what changed in the design, not the wording. -->

| Version | Date | Author | Change summary |
|---|---|---|---|
| 0.1 | YYYY-MM-DD | [@name] | First draft for design review |
| 0.2 | YYYY-MM-DD | [@name] | *Example:* CMAF packaging to serve HLS and DASH from one set of segments |
| 0.3 | YYYY-MM-DD | [@name] | *Example:* AV1 renditions only for videos above 1 000 views |
| 1.0 | YYYY-MM-DD | [@name] | *Example:* Approved |

## Contents

<!-- Guidance: Keep aligned with the headings. -->

1. [Overview](#1-overview)
2. [Requirements](#2-requirements)
3. [Capacity estimation](#3-capacity-estimation)
4. [API design](#4-api-design)
5. [Data model](#5-data-model)
6. [High-level design](#6-high-level-design)
7. [Detailed design](#7-detailed-design)
8. [Scalability and performance](#8-scalability-and-performance)
9. [Reliability, security and operations](#9-reliability-security-and-operations)
10. [Trade-offs and alternatives](#10-trade-offs-and-alternatives)
11. [Delivery plan and risks](#11-delivery-plan-and-risks)
12. [Appendices](#12-appendices)

## 1. Overview

<!-- Guidance: One page that a busy reviewer can read alone: problem, proposed solution in a paragraph, and the decisions that need their attention. -->

### 1.1 Problem statement

[*Example:* Creators upload MP4 files that we serve as progressive downloads
from a single bucket. Mobile viewers on weak networks stall every 20 seconds,
a 4 GB upload fails if the connection drops, and our cloud egress bill grew
4x in a year.]

### 1.2 Proposed solution

[*Example:* Clients upload directly to object storage with resumable,
chunked uploads. An upload event starts a transcoding workflow that splits
the source into chunks, encodes them in parallel into a ladder of renditions,
and packages fragmented MP4 segments (CMAF) with HLS and DASH manifests.
Players choose the rendition per segment based on measured throughput (adaptive
bitrate). A CDN serves segments from the edge with an origin shield in front
of storage. View events stream into an aggregation pipeline for counts and
analytics. Older and rarely watched renditions move to cheaper storage tiers.]

### 1.3 Decisions requested from reviewers

| ID | Question | Recommended option | Section |
|---|---|---|---|
| Q-01 | *Example:* Codecs at launch? | H.264 for all; AV1 added for popular videos | 7.2, 10 |
| Q-02 | *Example:* Segment duration? | 4 s segments, 2 s GOP | 7.3 |
| Q-03 | *Example:* DRM in v1? | Only for licensed catalogue; user uploads use signed URLs | 7.5 |
| Q-04 | *Example:* Keep source files? | Yes, in archive tier after 30 days | 7.7 |
| [Q-nn] | [Question] | [Option] | [Section] |

## 2. Requirements

<!-- Guidance: Functional requirements describe behaviour; non-functional requirements describe qualities with numbers. Mark what is out of scope so nobody designs for it. -->

### 2.1 Functional requirements

| ID | Requirement | Priority |
|---|---|---|
| FR-01 | *Example:* Upload files up to 20 GB and 4 h, resumable after network loss | Must |
| FR-02 | *Example:* Transcode to an adaptive ladder from 240p to 1080p (4K for eligible creators) | Must |
| FR-03 | *Example:* Play on web, iOS, Android and TV apps with adaptive bitrate | Must |
| FR-04 | *Example:* Thumbnails and preview sprites | Must |
| FR-05 | *Example:* Captions (WebVTT) uploaded or generated | Should |
| FR-06 | *Example:* View counts visible within 5 minutes | Should |
| FR-07 | *Example:* DRM for licensed content | Must for licensed catalogue |
| [FR-nn] | [Requirement] | [Must / Should / Could] |

### 2.2 Non-functional requirements

| ID | Quality | Target | Measured as |
|---|---|---|---|
| NFR-01 | Startup time | *Example:* Video start p90 at or below 1.5 s | Player telemetry |
| NFR-02 | Rebuffering | *Example:* Rebuffer ratio below 0.5% of watch time | Player telemetry |
| NFR-03 | Processing time | *Example:* 10-minute 1080p video playable within 5 min of upload | Workflow metrics |
| NFR-04 | Availability | *Example:* 99.95% playback availability | Synthetic playback probes per region |
| NFR-05 | Durability | *Example:* Sources and renditions 11 nines (object storage class) | Provider SLA, checksums |
| [NFR-nn] | [Quality] | [Target] | [Measurement] |

### 2.3 Out of scope

- [*Example:* live streaming (separate design: ingest, low-latency packaging)]
- [*Example:* recommendations and search]
- [*Example:* in-browser video editing]
- [Item deferred, with the release that will take it]

## 3. Capacity estimation

<!-- Guidance: Back-of-the-envelope numbers decide the shape of the design. Show inputs, formulas and results; round generously and say which way you rounded. -->

### 3.1 Assumptions

| Input | Symbol | Value | Source |
|---|---|---|---|
| Uploads per day | $U$ | *Example:* 100 000 | Growth plan |
| Average duration | $d$ | *Example:* 10 min | Current uploads |
| Average source bitrate | $b_s$ | *Example:* 8 Mbit/s | Current uploads |
| Ladder bitrate sum (H.264) | $b_l$ | *Example:* 10.7 Mbit/s | 7.2 |
| Views per day | $V$ | *Example:* 100 million | Analytics forecast |
| Average watch time per view | $w$ | *Example:* 5 min | Analytics |
| Average delivered bitrate | $b_d$ | *Example:* 3 Mbit/s | Player telemetry |
| Encoding cost | $e$ | *Example:* 6 vCPU-min per minute of video (full ladder) | Benchmark |
| Peak to average factor | $k$ | *Example:* 2 (evening) | Traffic history |

### 3.2 Storage

Source per video: $600 \ \text{s} \times 8 \ \text{Mbit/s} = 4\,800 \ \text{Mbit} = 600 \ \text{MB}$.
Renditions per video: $600 \times 10.7 = 6\,420 \ \text{Mbit} \approx 800 \ \text{MB}$.

$$
S_{day} = U \times (600 + 800) \ \text{MB} = 10^{5} \times 1.4 \ \text{GB} = 140 \ \text{TB/day}
$$

$$
S_{year} \approx 140 \ \text{TB} \times 365 \approx 51 \ \text{PB/year}
$$

Storage tiering (7.7) is therefore part of the design, not an afterthought.

### 3.3 Transcoding compute

$$
C = U \times d \times e = 10^{5} \times 10 \times 6 = 6 \times 10^{6} \ \text{vCPU-min/day} = 10^{5} \ \text{vCPU-hours/day}
$$

$$
\text{average concurrency} = \frac{10^{5}}{24} \approx 4\,200 \ \text{vCPU}, \qquad \text{peak} \approx 8\,400 \ \text{vCPU}
$$

Spot or preemptible capacity suits this load because chunks are short and
retryable.

### 3.4 Egress

$$
E_{day} = V \times w \times b_d = 10^{8} \times 300 \ \text{s} \times 3 \ \text{Mbit/s} = 9 \times 10^{10} \ \text{Mbit} = 11.25 \ \text{PB/day}
$$

$$
\bar{B} = \frac{9 \times 10^{10} \ \text{Mbit}}{86\,400 \ \text{s}} \approx 1.04 \ \text{Tbit/s}, \qquad B_{peak} \approx 2.1 \ \text{Tbit/s}
$$

### 3.5 Summary

| Quantity | Estimate | Design consequence |
|---|---|---|
| New storage | ~140 TB/day, ~51 PB/year | Tiering, source archive, delete unused renditions |
| Transcoding | ~4 200 vCPU average, ~8 400 peak | Chunked parallel encoding on spot capacity |
| Egress | ~11 PB/day, ~2 Tbit/s peak | Multi-CDN with origin shield; cache hit ratio is the key cost lever |
| View events | ~1 160/s average (plus heartbeats) | Stream aggregation, not database counters |

## 4. API design

<!-- Guidance: Define the contract first: resources, methods, request and response shapes, errors, idempotency, pagination, rate limits and versioning. Use RFC 9457 problem details for errors. -->

### 4.1 Endpoints

| Method | Path | Purpose | Auth | Idempotent |
|---|---|---|---|---|
| POST | `/v1/videos` | Create video record, get resumable upload session | Creator token | With `Idempotency-Key` |
| PUT | upload session URL (object storage) | Upload chunks with byte ranges | Signed session | Yes per chunk |
| POST | `/v1/videos/{id}/complete` | Finish upload, start processing | Creator token | Yes |
| GET | `/v1/videos/{id}` | Metadata and processing state | Token or public | Yes |
| GET | `/v1/videos/{id}/playback` | Manifest URLs, signed CDN token, DRM licence URL | Viewer token or public | Yes |
| POST | `/v1/views` | View start and heartbeat events | Viewer session | Dedup by `viewId` + sequence |

### 4.2 Request and response examples

The playback endpoint returns short-lived signed URLs for both manifest types:

```http
GET /v1/videos/v_9QK2/playback HTTP/1.1
Authorization: Bearer [viewer token]
```

```json
{"videoId": "v_9QK2", "hls": "https://cdn.example.net/v/v_9QK2/master.m3u8?token=eyJ...", "dash": "https://cdn.example.net/v/v_9QK2/manifest.mpd?token=eyJ...", "expiresAt": "2026-03-14T20:00:00Z", "drm": null, "captions": [{"lang": "en", "url": "https://cdn.example.net/v/v_9QK2/en.vtt"}]}
```

### 4.3 Errors and limits

| Status | Problem type | When |
|---|---|---|
| 403 | `geo-restricted` | Viewer region not licensed |
| 409 | `not-ready` | Processing not finished |
| 413 | `upload-too-large` | Source over limit |
| 422 | `unsupported-media` | Source cannot be decoded |
| 429 | `upload-quota-exceeded` | Creator daily upload quota reached |

## 5. Data model

<!-- Guidance: Choose storage by access pattern, not by habit. Show entities, keys, partitioning and the queries each store must answer. -->

### 5.1 Entities

Video metadata lives in a database; media objects live in object storage and
are referenced by key.

```mermaid
erDiagram
  VIDEO {
    string video_id PK
    string owner_id
    string title
    string state
    int duration_s
    string source_key
    datetime created_at
  }
  RENDITION {
    string video_id PK
    string rendition_id PK
    string codec
    int height
    int bitrate_kbps
    string storage_tier
  }
  PROCESSING_JOB {
    string job_id PK
    string video_id FK
    string step
    string state
    int attempts
  }
  CAPTION_TRACK {
    string video_id PK
    string lang PK
    string source
    string object_key
  }
  VIEW_COUNT {
    string video_id PK
    date day PK
    bigint views
    bigint watch_seconds
  }
  VIDEO ||--o{ RENDITION : "encoded as"
  VIDEO ||--o{ PROCESSING_JOB : "processed by"
  VIDEO ||--o{ CAPTION_TRACK : has
  VIDEO ||--o{ VIEW_COUNT : "counted in"
```

### 5.2 Storage choices

| Data | Store | Key | Main queries | Why |
|---|---|---|---|---|
| Video metadata | Relational database (sharded by `video_id`) | `video_id` | Get by ID; list by owner | Transactions on state changes |
| Sources | Object storage, standard then archive tier | `src/{video_id}` | Read for re-encode | Large, rarely read after processing |
| Segments and manifests | Object storage, standard then infrequent-access tier | `v/{video_id}/{rendition}/{n}.m4s` | Read by CDN origin | Immutable, cacheable forever |
| Workflow state | Durable workflow engine | `job_id` | Resume and retry steps | Long-running, failure-prone |
| View counts | Stream aggregates into wide-column store | `video_id`, `day` | Totals and daily series | High write rate |

## 6. High-level design

<!-- Guidance: One diagram that shows every component on the request paths and where state lives. Name components by responsibility. -->

Uploads and playback never pass through application servers; the API only
issues signed URLs and tracks state.

```mermaid
flowchart LR
  creator([Creator app]) --> api[Video API]
  creator -->|resumable chunks| upl[(Upload bucket)]
  upl --> ev[[Upload complete event]]
  ev --> wf[Workflow orchestrator]
  wf --> split[Probe and split]
  split --> enc[Encoder pool, spot]
  enc --> pkg[CMAF packager]
  pkg --> media[(Media bucket)]
  wf --> meta[(Video metadata DB)]
  viewer([Player]) --> api
  viewer --> cdn[Multi-CDN edge]
  cdn --> shield[Origin shield]
  shield --> media
  viewer -->|view events| ingest[Event ingestion]
  ingest --> agg[Stream aggregation]
  agg --> counts[(View counts)]
  lic[DRM licence service] --- viewer
```

| Component | Responsibility | Scales by |
|---|---|---|
| Video API | Create videos, issue upload sessions and playback tokens | Stateless replicas |
| Workflow orchestrator | Run processing steps with retries and timeouts | Workflow workers |
| Encoder pool | Encode chunks per rendition | vCPU or GPU instances, spot |
| CMAF packager | Produce segments, HLS and DASH manifests, encryption when DRM is on | Stateless workers |
| CDN and origin shield | Serve segments; collapse origin requests | Provider capacity |
| Stream aggregation | Deduplicate and count views | Stream partitions |
| [Component] | [Responsibility] | [Scaling unit] |

## 7. Detailed design

<!-- Guidance: Go deep on the parts that are new, risky or contested. Show the sequence of calls and the failure behaviour of each step. -->

### 7.1 Upload and processing workflow

Processing state is a small state machine stored on the video record; the
workflow engine drives transitions and retries each step independently.

```mermaid
stateDiagram-v2
  [*] --> uploading
  uploading --> uploaded: complete call, checksum ok
  uploading --> abandoned: session expired after 7 days
  uploaded --> processing: workflow started
  processing --> ready: minimum renditions packaged
  processing --> failed: source undecodable or retries exhausted
  ready --> ready: extra renditions added
  ready --> removed: owner delete or policy takedown
  failed --> processing: manual retry
  removed --> [*]
  abandoned --> [*]
```

A video becomes `ready` as soon as the 360p and 720p renditions exist, so
viewers can start watching while higher renditions finish.

### 7.2 Renditions ladder

| Rendition | Resolution | Video bitrate (H.264) | Audio | Typical use |
|---|---|---|---|---|
| *Example:* 1080p | 1920x1080 | 5 000 kbit/s | 128 kbit/s AAC | Wi-Fi, TV |
| 720p | 1280x720 | 3 000 kbit/s | 128 kbit/s | Good mobile, laptop |
| 480p | 854x480 | 1 500 kbit/s | 96 kbit/s | Average mobile |
| 360p | 640x360 | 800 kbit/s | 96 kbit/s | Weak mobile, fast start |
| 240p | 426x240 | 400 kbit/s | 64 kbit/s | Very weak networks |

The video bitrates sum to 10.7 Mbit/s (the $b_l$ input in 3.1; audio is
shared across renditions and adds little). Per-title encoding can lower these
bitrates substantially for simple content such as slides or animation; adopt
it once quality metrics (for example VMAF) are in place. AV1 renditions save
roughly 30% or more bandwidth at equal quality on supporting devices but cost
several times more compute, so they are produced only for videos above
*Example:* 1 000 views, where egress savings exceed encoding cost.

### 7.3 Chunked encoding and packaging

- The source is probed, then split at keyframes into chunks of about 30 s.
- Each chunk is encoded per rendition with a fixed GOP of 2 s and
  closed GOPs so segments align across renditions; players can switch at any
  segment boundary.
- The packager writes CMAF fragmented MP4 segments of 4 s, one HLS master
  playlist with media playlists, and one DASH MPD, all referencing the same
  segment files.
- Failed chunks are retried individually (up to 3 attempts, then on
  on-demand capacity), so a spot interruption costs at most one chunk.

### 7.4 Playback path (critical path)

The player fetches a manifest, then segments, choosing a rendition per segment
from throughput and buffer level.

```mermaid
sequenceDiagram
  participant P as Player
  participant A as Video API
  participant C as CDN edge
  participant S as Origin shield
  participant M as Media bucket
  participant E as Event ingestion
  P->>A: GET /videos/v_9QK2/playback
  A-->>P: manifest URLs with signed token
  P->>C: GET master.m3u8
  C-->>P: master playlist (cached)
  P->>C: GET 360p segment 1 (fast start)
  alt edge hit
    C-->>P: segment
  else edge miss
    C->>S: GET segment
    S->>M: GET object (on shield miss)
    M-->>S: segment
    S-->>C: segment
    C-->>P: segment
  end
  P->>P: measure throughput, switch up to 720p
  P--)E: view start, heartbeats every 30 s
```

Manifests for on-demand videos are immutable after `ready`, except when
renditions are added; they are cached for minutes, segments for a year.

### 7.5 DRM note

For licensed content, segments are encrypted with Common Encryption (CENC)
using the `cbcs` scheme, which lets one set of CMAF segments work with
FairPlay (Apple devices), Widevine (Chrome, Android) and PlayReady (Windows,
many TVs). The licence service checks entitlement and issues keys with
policies (rental expiry, output protection). DRM requires licensing agreements
with each DRM vendor, adds a licence round trip to startup and complicates
offline playback; user uploads without licensing obligations use signed URLs
and token-authenticated CDN access instead.

### 7.6 View counting and consistency model

- Players send a view-start event with a random `viewId`, then heartbeats.
  A view counts once watch time passes *Example:* 30 s, which filters
  autoplay noise.
- The stream job deduplicates by `viewId`, drops bot traffic by rules and
  reputation, and updates per-minute aggregates; public counts are refreshed
  every 5 minutes. Counts are eventually consistent and can be corrected
  downward after fraud review.
- Video metadata and state changes are strongly consistent in the database.
  Segments are immutable objects, so CDN caches can never serve a mixed
  version of a segment; deletions propagate by CDN purge within minutes.

### 7.7 Storage tiers

| Object | Day 0-30 | Day 31-365 | After 365 days |
|---|---|---|---|
| Source | Standard | Archive tier (hours to restore) | Archive tier |
| Popular renditions (views in last 30 days) | Standard | Standard | Standard |
| Unpopular renditions | Standard | Infrequent access | Infrequent access; delete 1080p if no views for a year and re-encode on demand from source |
| Thumbnails, manifests | Standard | Standard | Standard |

## 8. Scalability and performance

<!-- Guidance: Show how the design meets the numbers in section 3 and where it will break first. -->

| Concern | Approach | Limit before redesign |
|---|---|---|
| Egress | Multi-CDN, origin shield, long cache lifetimes | CDN commit levels; consider own edge caches above ~10 Tbit/s |
| Viral video | Shield collapses requests; first segments pre-warmed for trending videos | Edge capacity per region |
| Encoding backlog | Spot pool autoscaling on queue depth; priority for short videos | Regional spot availability |
| Metadata reads | Cache playback responses for 60 s | [Limit] |
| Origin requests | Target CDN hit ratio of 95% or more | Shield capacity |

Startup budget for a video start (target p90 1.5 s):

| Step | Budget |
|---|---|
| Playback API | 150 ms |
| Master and media playlists | 200 ms |
| First segment at 360p (4 s x 0.9 Mbit/s, about 450 KB) | 600 ms |
| Decoder start | 150 ms |
| Headroom | 400 ms |

## 9. Reliability, security and operations

<!-- Guidance: Name the failure modes, the threats and the signals operators watch. Each mitigation should be testable. -->

### 9.1 Failure modes

| Failure | Impact | Detection | Mitigation |
|---|---|---|---|
| CDN provider degraded in a region | Rebuffering, failed starts | Player error and rebuffer rates per CDN | Multi-CDN switching by player or DNS steering |
| Spot capacity reclaimed | Slower processing | Workflow queue age | Chunk retries; fallback to on-demand for jobs older than 15 min |
| Corrupt rendition | Playback errors at a point | Player decode errors by rendition | Automated validation after packaging; re-encode |
| Metadata DB unavailable | New playback sessions fail | API error rate | Cached playback responses; read replicas |
| Upload interrupted | Creator frustration | Session abandonment rate | Resumable sessions valid 7 days |
| [Failure] | [Impact] | [Signal] | [Mitigation] |

### 9.2 Security and abuse

| Threat | Control |
|---|---|
| Hotlinking and unauthorised redistribution | Signed CDN tokens bound to path and expiry; DRM for licensed content |
| Malicious media files exploiting decoders | Decode in sandboxed, unprivileged workers with resource limits; patch media libraries promptly |
| Illegal or harmful content | Upload scanning against hash lists, classifiers, reporting and takedown workflow |
| View count fraud | Dedup by `viewId`, bot detection, retroactive correction |
| [Threat] | [Control] |

### 9.3 Observability

| Signal | Metric or log | Alert threshold |
|---|---|---|
| Startup time | Player p90 | Above 1.5 s for 15 min in a region |
| Rebuffer ratio | Rebuffer time / watch time | Above 0.5% |
| Playback errors | Fatal errors per 1 000 starts | Above 2 |
| Processing time | Upload complete to `ready` p95 | Above 5 min for 10-min videos |
| CDN hit ratio | Edge hits / requests | Below 95% |

### 9.4 Cost estimate

| Item | Unit cost | Quantity | Monthly cost |
|---|---|---|---|
| CDN egress | *Example:* $0.005/GB at committed volume | *Example:* ~337 PB | *Example:* ~$1.7 million |
| Object storage (standard, IA, archive) | [$/TB-month per tier] | *Example:* +4.2 PB/month | [$] |
| Transcoding compute (spot) | [$/vCPU-hour] | *Example:* 3 million vCPU-hours | [$] |
| DRM licences | [$/licence or flat] | [n] | [$] |
| **Total** | | | **[$]** |

## 10. Trade-offs and alternatives

<!-- Guidance: For each major decision list the options, what each costs and why you chose one. Reviewers will propose the alternatives anyway; answer them here. -->

| Decision | Options | Chosen | Why | What we give up |
|---|---|---|---|---|
| Delivery | Progressive MP4; HLS only; DASH only; CMAF for both | CMAF for HLS and DASH | One set of segments for all devices | Older devices without fMP4 support need a TS fallback or are unsupported |
| Codecs | H.264 only; H.264 + HEVC; H.264 + AV1 | H.264 + AV1 for popular videos | Universal compatibility plus bandwidth savings where it pays | Two encoder pipelines |
| Encoding | Whole file per worker; chunked parallel | Chunked parallel | Fast turnaround, cheap retries on spot | Chunk boundary handling and stitching complexity |
| Transcoding service | Managed cloud service; own pipeline | [Own / Managed] | [Reason: cost at scale, control of ladder] | [Cost] |
| CDN | Single CDN; multi-CDN | Multi-CDN | Resilience and price leverage | Steering logic and per-CDN tokens |
| Storage of unpopular renditions | Keep all; delete and re-encode on demand | Delete 1080p after a year without views | Large storage savings | First viewer waits or gets 720p |
| [Decision] | [Options] | [Chosen] | [Why] | [Cost] |

## 11. Delivery plan and risks

<!-- Guidance: How the design reaches production safely, and what could stop it. -->

### 11.1 Milestones

| Milestone | Scope | Exit criterion | Target date |
|---|---|---|---|
| M1 | Resumable upload, H.264 ladder, HLS via one CDN | Rebuffer ratio below 1% in beta | YYYY-MM-DD |
| M2 | CMAF HLS + DASH, origin shield, view counting | CDN hit ratio 95%; counts within 5 min | YYYY-MM-DD |
| M3 | Multi-CDN and storage tiering | Egress cost per GB down 20% | YYYY-MM-DD |
| M4 | DRM for licensed catalogue; AV1 for popular videos | Licence partner certification | YYYY-MM-DD |

### 11.2 Rollout and rollback

[*Example:* Re-encode the existing catalogue in the background, most viewed
first. The player chooses adaptive streaming when a `ready` ladder exists and
falls back to the old MP4 otherwise; rollback sets a flag that forces the MP4
path.]

### 11.3 Risks

| ID | Risk | Likelihood | Impact | Mitigation | Owner |
|---|---|---|---|---|---|
| R-01 | *Example:* Egress cost exceeds forecast | Medium | High | Per-title encoding, AV1, committed-use CDN contracts | [@name] |
| R-02 | *Example:* Spot shortage delays processing | Medium | Medium | On-demand fallback; multiple instance types and regions | [@name] |
| R-03 | *Example:* DRM integration delays licensed launch | Medium | High | Start certification early; use a packaging vendor | [@name] |
| [R-nn] | [Risk] | [L / M / H] | [L / M / H] | [Mitigation] | [@name] |

## 12. Appendices

<!-- Guidance: Supporting detail, glossary and open questions. -->

### 12.1 Open questions

| ID | Question | Owner | Due |
|---|---|---|---|
| OQ-01 | *Example:* Do we offer 4K for all creators or only partners? | [@name] | YYYY-MM-DD |
| OQ-02 | *Example:* Automatic captions: in-house model or vendor? | [@name] | YYYY-MM-DD |
| [OQ-nn] | [Question] | [@name] | YYYY-MM-DD |

### 12.2 Glossary

| Term | Meaning |
|---|---|
| ABR | Adaptive bitrate: player switches renditions based on network conditions |
| Rendition | One encoded version of a video at a resolution and bitrate |
| Ladder | Set of renditions offered for a video |
| CMAF | Common Media Application Format: fragmented MP4 segments shared by HLS and DASH |
| GOP | Group of pictures: frames between keyframes |
| Origin shield | Cache layer between CDN edges and storage that reduces origin load |
| [Term] | [Meaning] |

### 12.3 References

| Reference | Use |
|---|---|
| RFC 8216 HTTP Live Streaming | HLS playlists |
| ISO/IEC 23009-1 (MPEG-DASH) | DASH manifests |
| ISO/IEC 23000-19 (CMAF) | Segment format |
| ISO/IEC 23001-7 (Common Encryption) | DRM encryption schemes |
| W3C WebVTT | Captions |

## Standard and licence note

Based on common industry practice for video-on-demand platforms and on the
specifications cited in 12.3; no text from ISO/IEC standards is reproduced.
This is a reference design to adapt, with illustrative numbers and prices.
Original text written for this collection. Template licence: MIT.
