# Architecture One-Pager

*URL Shortener & Link Management Service · Solution Architecture v1.0 · Microsoft Azure · Platform Architecture · 2026-09 · 23 views · 16 architecture decision records*

**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.**

A short link is the most disposable-looking artefact in software and one of the least changeable. It goes into an email, onto a poster, into a QR code on a badge, and from that moment the platform cannot reach it. What it can change is where the code points — and that is the product. So the system has to do three things that pull against each other: answer 150,000 lookups a second from everywhere on earth in single-digit milliseconds; let an owner repoint or kill a code that is already printed on ten thousand cards, and have that take effect globally in under a minute; and count every click accurately enough to bill on, without ever putting a write in front of a read that outnumbers writes 500 to 1. The obvious architecture — one service, one database, look up the code, increment the counter, redirect — satisfies all three on a whiteboard and none of them in production.

Codes are claimed once, by a conditional create against a strongly consistent reservation index, and are then immutable for the life of the platform: never reassigned, never reissued, never reclaimed. The link record is written only by the management plane, in one write region, and is the single authority for what a code means. Resolution reads a projection of it, never the record itself on the hot path: Front Door terminates TLS at the nearest of 190+ PoPs for both the shared and the 12,000 branded domains, caches the redirect for 30 seconds, and forwards a miss to the nearest of twelve stateless read regions, where a resolver checks the deny-set first, coalesces concurrent misses, then walks an in-process LRU, a regional Redis hot set and an in-region Cosmos replica. Two propagation channels cross from management into resolution, with two published bounds: a compact revocation delta that reaches every region within 60 seconds, and a full projection off the change feed within five minutes. Clicks are counted from the edge access log rather than from application code, which is what lets a redirect be cached without losing the click, and which keeps every write off the read path. Destinations are screened before a code is issued and re-screened afterwards, because a destination that was clean in March can be phishing in June.

## What it is, and what it is not

- **A read-only redirect plane fed by one-way propagation** — not one service that reads and writes the link table on the click path, which is correct in every steady-state diagram and makes the write store carry the read rate.
- **Clicks counted from the edge access log** — not a counter incremented by the resolver, which forces every click to reach application code and makes caching and analytics mutually exclusive.
- **Revocation on its own fast channel with a published 60-second bound** — not one propagation path sized for the tightest deadline, which pays the urgent cost on every routine edit.
- **A code that is identity, and a destination that is state** — not a reusable code, which eventually resolves a 2024 QR code to a stranger's site.
- **Exactly one strongly consistent operation, and it is alias uniqueness** — not strong consistency on the read path, which would make a global redirect a coordination problem.
- **A 302 with a 30-second cache lifetime** — not a permanent redirect, which is faster, cheaper, and makes both revocation and counting impossible for as long as a browser chooses to remember it.
- **Four distinct terminal states the clicker can act on** — not a generic 404 for unknown, expired, deactivated and blocked alike, which turns every dead link into a support ticket.
- **Screening as a product requirement** — not an abuse process bolted on after the first phishing campaign, by which time the domain's reputation is already the problem.

## The decisions that are the architecture

1. **Two planes, one-way propagation** (ADR-01) — The management plane is the only writer; the redirect plane reads a projection and a deny-set and holds no write credential. A four-hour management outage costs zero redirects.
2. **Revocation has its own channel** (ADR-02) — Stop instructions travel as a compact delta with a 60-second bound, independent of the five-minute projection. Urgency is bought where it is needed and nowhere else.
3. **Codes are random, then immutable** (ADR-03) — Seven unguessable base62 characters, claimed by conditional create, never reassigned and never reissued after retirement. (ADR-04 carries the rest.)
4. **One strongly consistent operation** (ADR-05) — Alias uniqueness. Everything else on the read path is eventually consistent, with its staleness published as a number rather than implied as instant. (ADR-15 carries the rest.)
5. **302 with a 30-second cache** (ADR-08) — Slower and more expensive than a permanent redirect, and the only choice that keeps a printed link both countable and killable.
6. **The redirect path never writes** (ADR-10) — Click events come from the edge access log after the response has left, durably buffered, with a 0.05% loss budget and daily reconciliation. (ADR-11 carries the rest.)
7. **Bots are classified, not blocked** (ADR-12) — An assumed 18% of traffic is unfurlers and scanners. They are served, tagged, excluded from customer counts and from tenant quotas, and kept in the raw data.
8. **Screening is continuous, and blocking is loud** (ADR-13) — Destinations are checked before a code is issued and re-checked afterwards; a blocked link gets a platform interstitial that names the reason, never a silent 404. (ADR-14 carries the rest.)
9. **Branded domains are the platform's problem** (ADR-16) — Twelve thousand customer domains mean certificate renewal is an availability risk the platform owns and alarms on before expiry, not a customer responsibility.

## Why this should still be right in ten years

A link platform outlives everything around it, because its output is printed, embedded and forwarded by people who will never contact it again. These are the properties that should survive a change of scale, of cloud, and of the team.

- **Code immutability is the promise that ages best.** Every other decision here can be revisited. This one cannot, because the evidence of its violation arrives years later as a QR code on a poster resolving to a stranger's site. It depends on no technology and costs almost nothing to keep — which is exactly why a future team, looking at a table of desirable retired aliases, will be tempted to break it.
- **The plane boundary survives the cloud.** ADR-01 says the redirect path reads a projection and never writes. That holds if Front Door is replaced by a programmable edge, if Cosmos DB is replaced by anything with a point read, and if the whole thing moves to another provider. What would break it is one feature request — real-time click counts on the redirect response — which is why the boundary is drawn in views 08 and 14 rather than left as a convention.
- **Published staleness is a contract, not a caveat.** The 60-second revocation bound and the five-minute edit bound will both be argued about, and both may tighten as technology improves. What must not change is that the platform states a number instead of implying immediacy, because support answers, customer expectations and abuse response all derive from that number being sayable in one sentence.
- **Counting from the edge log is a structural choice.** It is the reason caching and analytics are not in conflict, and it will still be the reason on any edge platform that produces a request log. The fragile version of this decision is counting in application code, which looks identical on a dashboard and quietly couples the cache hit rate to the accuracy of the numbers customers are billed on.
- **Resolution placement is the decision most likely to be redone.** ADR-07 puts the lookup in twelve regional resolvers because Azure offers no general-purpose replicated key-value store at the PoP. That is a statement about 2026, not about architecture. When a programmable edge with a replicated store is available and affordable, the lookup should move — and nothing above needs to change when it does, which is the test of whether the boundary was drawn in the right place.

## Non-functional targets

Every number here is a stated assumption from the requirement, chosen to be argued with. The right-hand column names the view where the mechanism that meets it is drawn.

| Quality | Target | How it is met | View |
|---|---|---|---|
| Redirect availability | ≥ 99.99% monthly per region | Anycast edge with a 30 s response cache, twelve stateless read regions, and no synchronous dependency on the management plane or the click pipeline. | 18 |
| Redirect latency | p50 ≤ 8 ms, p99 ≤ 40 ms; ≤ 120 ms p99 on a cold read | Edge cache, then an in-process LRU, a regional Redis hot set and an in-region Cosmos replica, with concurrent misses coalesced per code. | 14 |
| Correctness | Zero codes resolving to a destination they were not assigned | Conditional create against a strongly consistent reservation index, permanent code retirement, and a continuous synthetic wrong-destination probe. | 15 |
| Revocation | Effective globally ≤ 30 s p95, ≤ 60 s p99 | A compact revocation delta on its own channel, pulled every 5 s, matched before any cache layer; the 30 s edge TTL bounds the worst case. | 16 |
| Edit propagation | ≤ 5 min p99 globally; ≤ 1 s p99 in the creating region | Cosmos change feed to a projection worker in each read region, pre-warming the hot set at creation. | 13 |
| Throughput | 150,000 redirects/s steady, 600,000/s peak for 5 min | 97% served at the edge; resolver fleets scaled on requests per second with 4× headroom for the assumed burst. | 18 |
| Hot key | A single code at 80,000/s without degrading others | In-process LRU ahead of the shared cache, request coalescing, and a hot-set distribution that does not concentrate on one cache shard. | 09 |
| Creation | p99 ≤ 250 ms; 10,000-link import ≤ 60 s p99 | Single-region conditional create plus a durable write, with bulk import as an asynchronous job on separate capacity. | 15 |
| Analytics freshness | Click visible ≤ 60 s p95, ≤ 5 min p99 | Edge access log to Event Hubs to Azure Data Explorer, with rollups as materialised views. | 17 |
| Analytics accuracy | Loss ≤ 0.05%; counts within ±0.5%; uniques ±2%, labelled | Durable buffering at the point of collection and daily reconciliation against the edge counters. | 17 |
| Durability | Link table RPO 0, read RTO ≤ 60 s, write RTO ≤ 5 min | Cosmos DB multi-region replication with a single write region and a named failover target. | 18 |
| Rebuildability | All derived state rebuilt ≤ 30 min, no operator input | Hot set, negative cache and deny-set are all projections of the link table, rebuilt from the change feed; drilled monthly. | 19 |
| Cost | ≤ $0.05 per million redirects; alarm above $0.08 | Edge hit rate ≥ 97% as the primary lever, raw click retention capped at 90 days, bot traffic metered separately. | 20 |

## Scope

**In scope**

- Code allocation, custom aliases, reserved-name refusal and permanent code retirement.
- The redirect path: edge termination for shared and branded domains, resolution, routing rules, parameter merge and the four terminal states.
- Link lifecycle: destination editing, scheduled expiry, deactivation, reactivation and the audit trail behind each.
- Revocation and its published 60-second bound, including abuse blocking and the interstitial.
- Branded domain verification, certificate provisioning and renewal alerting.
- Click collection, bot classification, rollups, the export stream and the billing meter feed.
- Destination screening at creation and periodically thereafter, the review queue and the appeal path.

**Explicitly out of scope**

- Campaign management, email or SMS sending, and CRM integration. The platform publishes click data and stops there.
- The destination page. The platform never fetches, renders, proxies or rewrites it — it names a location.
- Link-in-bio pages, QR design and creative tooling. QR generation appears only as a Phase 3 item over the same code.
- Customer-side attribution modelling. The platform reports clicks, not conversions.
- Consent management, because the click record deliberately holds no identifier that would require it.

## What a four-week prototype should prove

Four of this architecture's claims are cheap to test and expensive to be wrong about. A prototype that proves these can be built on; one that skips them is a demonstration of HTTP redirection, which is the easy half.

1. The revocation promise end to end: kill a link and measure, from outside, when the last PoP stops serving it — across all regions, with the edge cache warm, repeated a thousand times and reported at p99 rather than as an average.
2. Uniqueness under a real race: thousands of concurrent claims for the same alias across regions, asserting exactly one winner and a named conflict for everyone else, including claims against retired codes.
3. Hot key absorption: one code taken from zero to 80,000 requests per second in thirty seconds with a cold cache, measuring both its own latency and the p99 of every other code in the same region throughout.
4. Counting from the edge log at the full cache hit rate: 97% of clicks never reaching application code, reconciled against the edge counters to within ±0.5%, because this is the claim that makes ADR-08 and ADR-10 compatible.

- Fail the write region mid-import and confirm creation is refused with a retryable error and the bulk job resumes without issuing a second code for any row.
- Flush every regional hot set and deny-set at once and confirm the deny-set is restored first, so a killed link never resolves during the rebuild window.
- Flip a reputation feed's verdict on a link with live traffic and confirm it stops resolving within 60 seconds at every PoP, with the evidence recorded and the owner able to see the reason.
- Let a link's TTL expire while its 302 is cached at a PoP and confirm the clicker gets a 410 rather than a redirect within the published bound, and that the expiry is not discoverable early by an enumerating client.

## Open risks, carried rather than hidden

| Risk | If it lands | Response |
|---|---|---|
| The edge cache hit rate does not reach 97% | Cost per million redirects rises towards the origin-read price, the resolver fleet must grow several times over, and the 40 ms p99 becomes a cold-path p99 instead. | Measure the real code popularity distribution early. The designed levers are a longer TTL (which weakens the revocation bound and must be traded explicitly), a larger hot set, and pre-warming on creation. |
| Revocation is promised at 60 seconds and delivered at five minutes | The platform's safety claim fails silently: dashboards stay green because the mechanism is healthy while the end-to-end result misses the bound. | The synthetic revocation probe in view 20 is the control, alarmed on the promise rather than on component health. The 30 s edge TTL is a design parameter and any proposal to raise it must state the new bound. |
| A single write region constrains creation availability | Regional failover makes link creation unavailable for up to five minutes, which a large customer's bulk import will eventually hit. | Accepted deliberately: refusing creation is preferable to two winners for one alias. Bulk imports are jobs with resumable semantics, so a failover delays rather than fails them. |
| Bot classification is wrong in the direction customers notice | Either campaigns are judged on preview traffic, or genuine clicks are discarded as bots — and the second is far worse because it is invisible. | Classification tags and never blocks; the raw class is retained so a reclassification can be replayed over history rather than requiring the data to be re-collected. |
| The platform becomes phishing infrastructure | The shared domain's reputation is destroyed by browser and mail-provider blocklists, which takes every legitimate tenant's links down with it. | Screening before issuance, periodic re-screening, challenges on bulk creation from unverified accounts, and a revocation path fast enough that response time is measured in seconds. |

The reasoning behind every component and technology choice is in the [Architecture Decision Record](decision-record): 16 records across 5 areas, each with the alternatives that lost and what the choice costs.
