53 — Contact ID — the identity layer (release-era spec)
Release headline feature. Governed by
00-ROADMAP.md— defer to it on any conflict. Created 2026-07-03 (owner-raised, stakeholder-confirmed: Contact ID is one of the two headline features for the Release, alongside Discovery/Events —52-DISCOVERY-EVENTS.md). Supersedes the framing of16-MENU-CONTACTID-DESIGN.md(web-first / Capacitor era): doc-16 stays as the card-design archive (three visual concepts); its web implementation notes (React/Tailwind components,qrcode.react, menu placement, effort estimates) are superseded by iOS-native (22-IOS-DESIGN-SYSTEM.md). Builds on:47-PRODUCT-NORTH-STAR.md§10.3 (account = own corner; "Contact ID" was the named-later identity phase — now elevated) ·51-INVITES-UX-REFERENCE.md(patterns, citedINV-xx) ·26-IDENTITY-SHARING-NAVIGATION.md·38-ANALYTICS-INSIGHTS.md(privacy posture) ·21-DATA-ARCHITECTURE-AND-IDENTITY.md.
1. Vision — identity & belonging
"Contact ID is great to have a sense of identification, and a sense of belonging to a club." — owner
Contact ID is the professional identity layer of Sonnance:
- Identification — every person on the platform has one living, verified card: who you are, what you do, what you've actually worked on. The industry handshake — "the first thing you share when you meet someone" (doc-16's original insight, still true).
- Belonging — "the club" — carrying a Sonnance Contact ID means you're part of the working music world on the platform: your card shows real collaborations and credits, not vanity numbers. Belonging is demonstrated by the graph (
INV-18), never bought. - Semi-private by design — the card has an inside and an outside. To your contacts it's rich; to an outsider it shows exactly what you configured — possibly nothing (§3).
- The reference is Linktree — a Contact ID carries a capped, composable set of tiles (
INV-16): links, releases, a highlight track — your corner of the internet, but verified by real platform activity instead of self-assertion. - It travels — QR-forward, and in Apple Wallet as a
.pkpass: pull out your phone, show the code, be added (§4.5).
Why it's a Release headline: the loop (doc-25) serves teams that already know each other; Contact ID is how new professional relationships enter the platform — and it's the identity substrate Discovery needs (lineups, hosts, guests are all Contact IDs — doc-52 §7).
2. What carries over from doc-16 (and what doesn't)
Restated here so this doc is self-sufficient; visuals and history in doc-16.
Still valid — carried into this spec:
| Decision | Notes |
|---|---|
| Linktree as the reference model | Now concretized as tiles (INV-16) |
| Dynamic QR → profile | QR is a peer of the link, not an extra (INV-11) |
Share link sonnance.com/@username | Handle scheme to reconcile with doc-21 identity (§6 Q1) |
| Card preview: avatar · name · role · key stats | Stats become opt-in + graph-derived (§4.4) |
| Download card as image | Cheap, keeps working in every chat app |
Apple Wallet .pkpass | Backend pass generation (e.g. passkit-generator) still the right shape |
| NFC | Still later (v2+), unchanged |
| "Vinyl Card" visual direction | The recommended concept of doc-16's three; re-cut in Liquid Glass (doc-22) |
Superseded: web-first placement (profile dropdown / account tab), React/Tailwind component plan, qrcode.react, and doc-16's effort table — the Release build is iOS-native SwiftUI first (doc-22, doc-49 components), web parity later per roadmap Phase 2.
Updated by doc-54 (2026-07-04) — placement resolved: Contact ID lives in the new Contact tab (5th tab, extreme right; naming open — owner to pick) together with account/user config and the Discovery entry (top-right of the view, doc-52). It absorbs the
AppMenuDrawerduties and realizes doc-47 §10.3's "own corner" as a literal tab. Same day: name locked "Contact", tab icon = the user's avatar in a circle (fallback symbol); the shell shipped (identity seed card + account + Discovery corner) — this doc's card (QR · Wallet · tiles · lenses) grows into that seed.
3. The identity privacy philosophy (the gap this doc fills)
The platform already has a privacy philosophy for data: aggregate-by-default, identified is opt-in (doc-38 §privacy) and owner-private by default, opt-in visibility, "one graph, many lenses" (doc-26's shipped StripPrivateTagsInterceptor, doc-33). Contact ID extends the same posture to people:
- Owner-private by default. A new Contact ID exposes nothing beyond name + role until its owner opts fields in. Private is the zero-state, not a setting you find later.
- Opt-in visibility per field. Each card element (avatar, links/tiles, stats, credits, contact channels, "who I've worked with") carries its own audience: me · my contacts · everyone.
- The outsider view is a configured lens. What a non-contact sees is a first-class preview the owner can inspect ("view as outsider" — same move as Invites' preview-before-publish,
INV-03). Apple's "names match your Contacts unless you edit them" and per-reply identity (INV-15) are the model: identity presented is contextual, owner-controlled. - Asymmetry is stated in prose where it applies (
INV-12): "only you can see who has your card" — written on the surface, changeable inline, never buried. - Graph-minimal consent (
INV-14): building your contacts never demands the address book; adding people works one-by-one, via QR, via event (doc-52 afterglow), or via out-of-graph link — the iOS limited-contacts ethic applied to our own graph. - Transparency in reach (
INV-20): "see how your data is managed" one tap from the card's settings; posture backed by doc-09.
Messaging, stats, and the contacts graph (§4) are all derived capabilities gated by this philosophy — each one asks "which lens is this visible through?" before it ships.
4. Capabilities
4.1 The card
Identity zone (name · role · avatar · verified-activity hint) + tiles (INV-16: up to N links with title/description and domain-transparency chips INV-17, a highlight release/track, key credits) + share row (QR · link · Wallet · download). Anatomically a doc-49 Portal Identity+Content pair worn as a card — same grammar, personal altitude.
4.2 Messaging enablement
Contact ID is the handle that unlocks messaging: having someone's card (mutual or accepted) is what allows a DM thread — no open inbox, no cold spam. Scope v1 is deliberately thin — request → accept → thread — and rides the existing websocket/notification modules; a fuller messaging pass is its own doc later (doc-17 sketched a Message entity). The gate, not the chat, is the Contact ID feature.
Updated by doc-54 §8.3 (2026-07-04) — placement: the threads list lives as a Messages zone on the Contact tab (rendered when non-empty, principle 7); conversations also open from any contact card and from notifications. The contact list = the tab's Contacts zone → full-list drill-in.
4.3 The contacts graph — "the club"
- My contacts — cards I hold (people I've connected with: scanned, matched at an event, collaborated with).
- Who has me — visible only to me (
INV-12asymmetry), with the option to prune. - Mutuals & provenance — how we're related: "met at ⟨event⟩" (doc-52 afterglow), "worked on ⟨project⟩" — relations derived from the real graph (
INV-18), which is what makes belonging feel earned.
Updated by doc-54 (2026-07-04): contact cards also carry event relations — attending (upcoming) · registered (RSVP'd) · attended (past) — derived from doc-52's RSVP/lineup/guest records; the same records give events their people refs (host · lineup · guests), all under the §3 visibility lenses.
4.4 Statistics
Card stats are graph-derived and opt-in per stat: collaborations count, releases shipped, credits by role, active-since — sourced from the doc-38 pipeline (aggregate-by-default; a stat that would leak a private collaboration simply can't be enabled). No follower counts (§5).
4.5 Apple Wallet pass
The card as a QR-forward .pkpass: front = name/role/QR; the show-at-the-door moment at events (doc-52 Live stage check-in shares the same QR rail, INV-11). Pass updates on card edits (cadence — §6 Q4).
5. Trade-offs / non-goals (v1)
- Not a public social profile. No follower/following counts, no public feed, no engagement mechanics — a card, not a channel (doc-47 §7 calm).
- No cold messaging. Messaging strictly gated by the graph (§4.2) — spam-resistance is a feature.
- No NFC v1 (unchanged from doc-16); QR + Wallet cover the physical moment.
- Verification depth deferred: v1 "verified" = real platform activity (credits/collabs exist); formal credit verification is doc-31 fair-credit territory, later.
- Trade-off owned: per-field audiences (§3.2) cost UI and model complexity vs a single public/private switch — we pay it, because the philosophy (semi-private, lens-based) is the feature the owner asked for; what we don't pay for v1 is per-contact custom lenses (me/contacts/everyone only).
6. Open questions for the stakeholder
- Handle scheme:
sonnance.com/@username(doc-16) vs the doc-21 identity/slug system — one namespace for users, artists, workspaces? Collision policy?Resolved (owner, 2026-07-04, via doc-54):
sonnance.com/@usernameapproved as proposed — pending the doc-21 namespace reconciliation (users vs artists vs workspaces collision policy still to be cut; schedule that pass). - Messaging v1 cut: request→accept→thread only, or is read-receipt/presence in scope? (Each addition drags the doc-35 real-time pass forward.)
- Which stats are public-eligible even as opt-in — is "collaborations count" safe territory, are credits-by-role too revealing for some roles?
- Wallet pass update cadence — regenerate on every card edit, or explicit "update my pass"?
- Outsider zero-state — should a non-contact hitting
sonnance.com/@yousee name+role (directory utility) or nothing-until-configured (maximal privacy)? Philosophy §3.1 says the latter; directory value says the former.