Data Flow & RoPA¶
Derived from registers/ropa.md (UK GDPR Art 30),
technical/data-architecture.md, and
registers/retention-schedule.md.
Lawful bases are provisional [counsel required]. There is no real user
data yet; pre-launch seed data is fictional and tagged users.is_seed = true.
What personal data enters, and where it goes¶
flowchart LR
%% source: registers/ropa.md, technical/data-architecture.md (2026-06-14)
subgraph inputs["Personal data entering"]
li["LinkedIn OIDC<br/>sub, email, name, picture"]
bp["Boarding pass<br/>decoded ON DEVICE — raw payload,<br/>PNR, name, seat never leave transient memory"]
authored["User-authored content<br/>headline, summary, intent tags,<br/>request notes, messages, reports"]
grants["Consent choices<br/>analytics / ml_training / marketing"]
end
subgraph sor["System of record — Cloud SQL (private)"]
ident["users · external_identities · traveler_profiles<br/>(PII — life of account)"]
pres["flight_presences<br/>(derived personal: airport, window,<br/>verification level — 7d after expiry)"]
matches["match_candidates · connection_requests<br/>· match_rationales"]
msgs["conversations · conversation_messages<br/>(90d after last activity)"]
safety["user_blocks · user_reports"]
consents["user_consents (notice-version evidence)"]
events["app_events — pseudonymized, consent-tiered,<br/>no content/secrets/identity (ML-04/05)"]
end
ml[("ml_training_snapshots<br/>anonymous k-anonymous aggregates —<br/>survive erasure (ML-07)")]
claude["Anthropic Claude (key-gated)<br/>receives ONLY minimized fields:<br/>display name, headline, intent tags"]
li --> ident
bp -->|"derived fields only"| pres
authored --> matches
authored --> msgs
authored --> safety
grants --> consents
pres --> matches
ident -->|"minimized prompt"| claude
claude -->|"cached rationale sentence"| matches
consents -.->|"gates T1/T2 emission"| events
events -->|"whitelisted T2 only,<br/>low-k suppressed"| ml
Re-identification rule (load-bearing): airport + gate + departure time +
time-of-day is a small anonymity set, so presence and match data are treated
as personal data even with no name attached. Redis holds only self-expiring
security state (OAuth state ~10 min, handoff codes 120 s, hashed rate-limit
counters) — no durable personal data.
Processing activities (RoPA summary)¶
The authoritative record is registers/ropa.md; this
table summarizes it. Bases marked † are [counsel required].
| # | Activity | Key data | Lawful basis (provisional) | Retention target |
|---|---|---|---|---|
| 1 | Account & authentication | LinkedIn sub, email, name, picture | Contract | Life of account + grace |
| 2 | Session management | Hashed token, timestamps | Contract | 30d after expiry/revoke |
| 3 | Flight presence intake | Derived airport/window/verification only | Consent (proximity) | 7d after expiry |
| 4 | Matching & connect requests | Pair, place/time context, note, state | Legitimate interest / contract | 30d after terminal status |
| 5 | Messaging | Body, sender, timestamps | Contract | 90d after last activity (TBD) |
| 6 | Trust & safety | Block pairs; report reason/details | Legitimate interest (safety) | Block: life of account; report: 180d after resolve (TBD) |
| 7 | Analytics / ML (planned) | Tiered events | Consent (T1/T2) | TBD |
| 8 | Persistent connections | Accepted pair, minimized profile fields | Contract / LI † | Beyond trip window; erased with account |
| 9 | Profile enrichment (deferred) | PDL/ZoomInfo attributes — none today | Legitimate interest (provisional) | Deferred |
| 10 | Profile management | LinkedIn display + self-authored fields | Contract / LI † | Life of account |
| 11 | AI rationale & interview (key-gated) | Minimized fields only; interview stateless | LI / contract † | Cache expires with input TTL |
| 12 | Pre-launch seed testing | Fictional mock data only | Not personal data if fictional † | Purge before GA |
| 13 | Trip-history persistence (STUB — not built) | Movement profile: past flights beyond the trip window | OPEN † (C29 — required before user-facing) | OPEN — no retention class yet |
Erasure path¶
Account deletion (DELETE /account) soft-deletes, revokes all sessions, then a
worker hard-purges after the grace window; FK cascades remove the personal
graph. Erasure propagates to the pseudonymized event store but not to
anonymous ML snapshots — the anonymization boundary is the gating control
(ML-07). Full lifecycle: Retention Lifecycle.