# Consent & Privacy Service

**Solution Architecture v1.0 · Amazon Web Services · Security & Identity Architecture · 2026-10 · 22 views · 15 architecture decision records**

Everyone has used this system without being told its name. The cookie banner. The "manage your ad preferences" screen three taps into an app. The email footer that says unsubscribe and sometimes means it. The "download your data" button that mails a zip the next day. The "delete my account" flow that warns you it is permanent, and then — somewhere behind the screen — has to make it permanent across forty internal systems and sixty vendors that were each sent a copy of you years ago. The screens are easy. What is hard is that each of them is a claim about the behaviour of an entire estate, made to a person who has no way to check it, enforced by a company whose incentive is to use the data, and audited by a regulator who will ask what was permitted on a specific Tuesday eighteen months ago. This package is the internal consent and privacy plane for an assumed consumer SaaS: 180 million registered subjects, 40 internal processing systems, 60 external recipients, 9 regional deployments across 3 jurisdictional boundaries, 120,000 permission decisions a second at steady state and 25,000 rights requests a day — on DynamoDB for the append-only consent ledger and its projection, Aurora Global for the no-personal-data purpose registry, EventBridge for withdrawal fan-out, Step Functions for rights-case orchestration, KMS per-subject keys for crypto-shredding, and S3 Object Lock for tamper-evident evidence.

The product is not the ability to record a preference. It is **the ability to make a screen's promise true across systems nobody here controls, and to prove afterwards that it was true** — which means the honest deliverable is not a guarantee of completeness but an evidenced completeness whose residual gap is measured and published.

The design rests on one rule: **this platform is the system of record for permission and never for personal data — it holds what each person allowed, and the data stays with its owner, which must ask.**

The decisions that carry the design:

- **Permission is the system of record; data stays federated.** A compromise here yields what people refused, not who they are. It is also why erasure is an orchestrated protocol, why purpose limitation lives on the read path, and why the purpose-to-system map is a correctness dependency rather than a catalogue (ADR-01).
- **The identifier graph is centralised, and is the most dangerous store in the design.** Proving an erasure reached every alias requires knowing every alias. That risk is accepted deliberately, constrained hard, and named rather than implied (ADR-02).
- **The consent ledger is the truth; current state is a projection.** Append-only, RPO 0, every answer naming the ledger version it came from — which is what turns point-in-time evidence into a query instead of a reconstruction (ADR-03).
- **Lawful basis is per purpose version per jurisdiction, and widening re-asks.** The same processing is consent in one place and legitimate interest in another, and adding a recipient is not an edit (ADR-04).
- **There is no default purpose, and an unregistered one is rejected rather than denied.** DENY would let a typo look like a lawful refusal and hide the only interesting fact — that something is processing under a name nobody declared (ADR-05).
- **Purpose limitation is enforced at the point of use.** Collection-time filtering is irreversible and cannot honour a later grant; an irreversible mechanism cannot implement a reversible policy (ADR-06).
- **Consent state is pushed, with a published staleness ceiling.** The decision is an in-process lookup, the ledger stays authoritative, and lag is measured per enforcement point because an average hides the one cache that stopped consuming (ADR-07).
- **Fail closed, with fail-open as a declared per-purpose posture.** The dangerous choice sits in one registry field behind counsel approval and two-person sign-off, and reliance on it is counted (ADR-08).
- **UNKNOWN is a verdict, and never readable as ALLOW.** Collapsing "no grant" with "could not read the grant" makes a failing projection indistinguishable from mass opt-out (ADR-09).
- **Erasure is a four-state verified protocol per target.** Instructed, acknowledged, attested, verified — never a boolean, because a boolean manufactures completed erasures out of accepted messages (ADR-10).
- **The erasure technique is declared per store, in advance.** Hard delete, crypto-shredding, anonymisation or tombstone-plus-suppression; immutable logs and model weights rule some of them out, and discovering that inside a thirty-day clock is too late (ADR-11).
- **Silence from a target is failure, not pending.** A false completion is an unlawful state the organisation believes is lawful; a false block is visible work (ADR-12).
- **The suppression list is mandatory on every ingestion and restore path.** You cannot enumerate every way data gets back in, so the control goes where everything enters (ADR-13).
- **Residency is enforced in the data path, and consent metadata is personal data.** Regional stacks, per-region keys, no replica and no failover: a boundary enforced by correctness of configuration is a boundary you cross by accident (ADR-14).
- **Evidence that an erasure happened survives the erasure.** The platform keeps the minimum needed to prove it, under a basis the subject cannot withdraw, and says so plainly rather than engineering the tension away (ADR-15).

The architecture one-pager (including why the design should still hold up in ten years, what a four-week prototype should prove, and the six risks that would change it) 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) (~14 min) and [docs/decision-record.md](docs/decision-record.md) (~56 min).

---

## What is here

| Path | Contents |
|---|---|
| `diagrams/index.html` | The landing page: 22 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 15 decision records, the capability-to-technology table and the package glossary as markdown |
| `specs/part-a..c.json` | Diagram specifications, the source of truth for every view |
| `specs/manifest-a..c.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-two views

| # | View | What it answers |
|---|---|---|
| 01 | System Context | Eleven things outside the boundary, three of which want to be told no, and the deliberate omission at the centre |
| 02 | High-Level Architecture | Five stages, and the seam between Decide and Act that the rest of the set exists to explain |
| 03 | Actors and Their Journeys | Eight actors, including the one who must be able to refuse before anyone knows who they are |
| 04 | Journey — Withdraw a Consent | The toggle takes 200 ms, the consequence up to fifteen minutes, and the gap is the whole experience |
| 05 | Journey — Delete My Account | Every phase after the second belongs to somebody else's system behaving |
| 06 | Journey — Answer a Regulator | The trough is reconstruction, removed for free by storing the notice version at capture |
| 07 | Layered Architecture | Eight layers, six repeated per jurisdiction, exactly one allowed to be global |
| 08 | Platform Components | Two planes as two boxes, because they fail independently and only one may be global |
| 09 | Interface Catalogue | Three contracts each way, and the registration rule that a system which cannot be told will not be told |
| 10 | Data Flow — Toggle to Denied Read | One subject action followed to the read refused because of it, through the measurement that makes it checkable |
| 11 | State Classes | Three classes ordered by what loss costs; only one row has an RPO worth arguing about |
| 12 | Data Model | Twelve entities, and what is absent from the view is the argument of the package |
| 13 | Critical Flow — Withdrawal | Fourteen messages, and the one self-call that decides whether the architecture is honest |
| 14 | Erasure Fan-Out | Six target classes, four states each, and two cells left empty on purpose |
| 15 | Purpose Limitation Path | Three verdicts and one rejection, and why the rejection is not a denial |
| 16 | Deployment Architecture | Three jurisdictional boundaries of the same shape, and the deliberate absence of any arrow between them |
| 17 | Observability | Six signal families across six stages, reduced to four alarms that wake a human |
| 18 | Consent Lifecycle | Seven states, and the closing arrow most implementations never draw |
| 19 | Purpose Change — Release Path | Two gates that refuse at design time what would otherwise be found at audit |
| 20 | Trust Zones | Five zones, and the separation the whole security argument rests on |
| 21 | Identity & Authorisation Flow | An agent acting for a caller, and the message that keeps the identifier graph out of their hands |
| 22 | Failure Classes | Ten classes, what bounds each, and the two the design chooses rather than suffers |

## Rebuilding

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

Node 20+ and nothing else. No draw.io Desktop, no browser, no network. The build assembles
`specs/views.json` and `specs/manifest.json` from the authoring parts, generates the draw.io
sources, fails on any geometry or routing defect, renders the editable and plain SVGs, writes the
HTML pages and the index, injects the one-pager and the decision record, and proves every relative
link in `diagrams/` resolves.

At v1.0 the geometry gate reports 0 errors and 0 warnings across 22 files, the routing gate 0 errors
and 0 warnings across 165 edges, all 331 nodes resolve to an icon with no weak matches, and the link
check passes on 174 relative links. Getting to zero routing warnings cost three editorial cuts rather
than three geometry tweaks: the interface catalogue went from four surfaces a side to three, with the
two displaced contracts drawn where they are decided instead; two long-range gutter edges on the data
flow dropped labels the stage titles already carried; and the trust-zone view reorders its data zone so
the two labelled zone crossings are not neighbours. Each of those was a sign that the view was
carrying something it did not need.

## A note on the numbers

Every rate, latency, volume, retention and cost figure in this package is a **stated assumption**,
chosen to be defensible and arguable rather than measured. They are stated precisely so that a
reviewer can disagree with one and follow it to the decision that depends on it. `ask.md` marks them
as assumptions section by section; the decision record's evidence note restates the operating context
in one paragraph.
