# URL Shortener & Link Management Service

**Solution Architecture v1.0 · Microsoft Azure · Platform Architecture · 2026-09 · 23 views · 16 architecture decision records**

The service behind every short link anybody has ever tapped without thinking about it: `bit.ly/…`, `lnkd.in/…`, the tracked link in a marketing email, the QR code on a conference badge. A customer submits a destination and receives a short code on a domain they control; every click on that code is resolved and redirected in single-digit milliseconds, anywhere in the world, and every click is counted. It handles 150,000 redirects per second at steady state and 600,000 at peak across twelve read regions, built from Azure Front Door for anycast termination and a 30-second response cache, Cosmos DB for the globally replicated link table with native TTL, Azure Cache for Redis for the per-region hot set, Container Apps for the resolver and management planes, Event Hubs for the click stream and Azure Data Explorer for click analytics.

The product is not the abbreviation — any hash function abbreviates. It is **the permanence of the code, the speed of the redirect, the attribution of the click, and the ability to change or kill the destination after the code has already been printed on ten thousand tote bags.**

The design rests on one rule: **the redirect plane and the management plane are separate systems joined only by one-way propagation, and the redirect plane never writes.** Everything the platform wants from a click happens after the redirect has already been sent.

The decisions that carry the design:

- **The redirect path reads a projection and holds no write credential.** At a 500:1 read-to-write ratio, a click that writes anything makes the write store carry the read rate and the redirect's availability the availability of the click pipeline. A four-hour management-plane outage costs zero redirects (ADR-01).
- **Revocation travels on its own channel.** Killing a link has a 60-second deadline; editing one has five minutes. Sizing a single channel for the tighter deadline pays urgency tax on all 1.2 million daily creations, so stop instructions get a compact delta and their own bound (ADR-02).
- **A code is identity; a destination is state.** Seven unguessable base62 characters, claimed by conditional create, never reassigned and never reissued after retirement — because the platform cannot reach the poster it was printed on (ADR-03, ADR-04).
- **Exactly one thing is strongly consistent, and it is alias uniqueness.** Two clients claiming `/spring` in the same millisecond produce one winner and one named conflict, never a silently substituted code. Everything else on the read path is eventually consistent, with its staleness published as a number (ADR-05, ADR-15).
- **A 302 with a 30-second cache lifetime, never a permanent redirect.** Slower and more expensive than a 301, and the only choice that keeps a printed link both countable and killable. That 30 seconds is simultaneously the hot-key absorber, the dominant cost lever and the outer bound on the revocation promise (ADR-08).
- **Clicks are counted from the edge access log, not from application code.** This is what lets the redirect be cached without losing the click, and it is why the redirect path needs no write credential at all (ADR-10).
- **Bots are classified and served, never blocked or silently counted.** An assumed 18% of traffic is unfurlers and scanners; they are tagged, excluded from customer counts and quotas, and kept in the raw data so a reclassification can be replayed over history (ADR-12).
- **Screening is continuous and blocking is loud.** A destination that was clean in March can be phishing in June, so links are re-screened while live and a block returns a platform interstitial naming the reason — never a silent 404 (ADR-13, ADR-14).
- **Twelve thousand branded domains are the platform's problem.** Whoever serves the host owns its availability: verification, certificate issuance and renewal alerting all belong to the platform, not to the customer who will not track 12,000 expiry dates (ADR-16).

The architecture one-pager (including why the design should still hold up in ten years) and the full decision record appear on the landing page of the diagram set, directly below the index of views. The same content is published as [docs/architecture-one-pager.md](docs/architecture-one-pager.md) (~13 min) and [docs/decision-record.md](docs/decision-record.md) (~60 min).

---

## What is here

| Path | Contents |
|---|---|
| `diagrams/index.html` | The landing page: 23 views in seven acts with every format linked, then the **architecture one-pager** and the **decision record** |
| `diagrams/*.html` | One self-contained page per view: the inlined diagram plus the reasoning cards, with copy / PNG / PDF export |
| `diagrams/svg/*.svg` | The same views as SVG with the diagram XML embedded; they re-open fully editable in diagrams.net |
| `diagrams/drawio/*.drawio` | draw.io source |
| `docs/architecture-one-pager.md` | The one-pager as markdown |
| `docs/decision-record.md` | The 16 decision records, the capability-to-technology table and the package glossary as markdown |
| `specs/part-a..d.json` | Diagram specifications, the source of truth for every view |
| `specs/manifest-a..b.json` | Acts, page titles, subtitles and reasoning cards |
| `specs/adr-onepager.json`, `specs/adr-records-a..b.json` | The one-pager, the decision records, the capability-to-technology table and the glossary |
| `scripts/build.sh` | Rebuilds every deliverable from the specs (Node only, no network) |
| `ask.md` | The requirement |

## The twenty-three views

| # | View | What it answers |
|---|---|---|
| 01 | System Context | Who touches the platform, and the actor who arrives 150,000 times a second with no identity |
| 02 | High-Level Architecture | Seven stages from a claimed code to an accounted-for click |
| 03 | Actors and Journeys | Nine actors, two of them machines that must be counted separately |
| 04 | Journey — Click a Short Link | The only journey at full scale, and its two troughs: a cold code and a dead one |
| 05 | Journey — Launch a Printed Link | Why a code is identity and a destination is only state |
| 06 | Journey — Kill a Live Link | The minute the whole revocation design exists to serve |
| 07 | Layered Architecture | Seven layers, and the single downward path between the planes |
| 08 | Container View | The C4 level-2 view, drawn so the plane boundary is the most visible thing on it |
| 09 | Inside a Resolution | Every component one click touches, and the three guards that run before any lookup |
| 10 | Integration Surface | Every interface the platform owns, and the two that can never change |
| 11 | Storage Zones | Authoritative, derived, evidential — and the recovery plan each implies |
| 12 | Data Model | Eleven entities, including the one that exists only so a code can be retired |
| 13 | Two Propagation Paths | One write, two channels, two published bounds |
| 14 | Critical Flow — One Click | Eighteen messages, of which the first four are what 97% of clicks experience |
| 15 | Critical Flow — Claiming a Code | The only strongly consistent operation in the architecture |
| 16 | Critical Flow — Stopping a Link | How the 60 seconds is spent, and what the cache TTL bounds |
| 17 | Click Analytics Pipeline | From an edge log row to a number somebody bills on |
| 18 | Deployment Architecture | Twelve stateless read regions, two write regions, and why that asymmetry is the point |
| 19 | Release Pipeline | The three gates that test the promises rather than the code |
| 20 | Observability | Five signal classes, including two probes that test what the platform sells |
| 21 | Link Lifecycle | Six states, and the one transition that never reverses |
| 22 | Security Trust Zones | Five zones, and a redirect plane with no writable credential |
| 23 | Identity and Access | Who proves what, and the path where nobody has to |

## Rebuilding

```bash
bash scripts/build.sh
```

Node 20+ and nothing else: no draw.io Desktop, no browser, no network. The build assembles the specs, checks that every node resolves to an icon, generates the draw.io sources, runs the geometry and routing gates, renders both SVG forms, writes the HTML pages and the index, checks every relative link, and then renders the one-pager and the decision record into the landing page and into `docs/`.

Current state: **23 views, 0 validator errors, 0 validator warnings, 237 edges routed with 0 routing errors and 0 routing warnings, 376 icons embedded, all relative links resolving.**
