DataTalksClub / DataTalksClub/website
Decide the shared masked member identifier for private management surfaces
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
Parent epics: #54 and #108. Split from the shared management-mask gap recorded in #245 and #250.
PM status — owner decision required
FAIL CLOSED. Do not engineer while decision and needs grooming remain.
Choose one default non-PII member label for every authorized private Studio/admin API course-registration, Enrollment, MemberProfile, operation, audit-safe presentation, and export surface. #245 and #250 must consume the same choice; neither may invent a separate email/name mask or reuse the event-provider helper.
This issue is only a product-presentation decision. It does not authorize a route, data read, export, mutation, schema change, production/provider access, or PII disclosure.
Normative authority and fixed invariants
_docs/specs/06-studio-and-admin-api.mdrequires deny-by-default function/object/field authorization, UUID management resources, masked support views, a separate full-PII capability, authorized-queryset-before-lookup behavior, private/no-store responses, and redacted audit evidence._docs/specs/07-security-privacy-operations.mdmakesMemberProfileprivate, requires non-enumerating safe failures, excludes profile values from analytics/observability, and keeps MemberProfile distinct from publiccontent.Person._docs/specs/open-decisions.mdresolves one private account-owned MemberProfile after verified ownership, independent ofcontent.Person.- #247 specifies an immutable
MemberProfileUUID: existing rows receive deterministic UUIDv5 values, later rows UUIDv4 values, and a stored UUID never changes. #247 is groomed but not yet accepted/integrated, so consumers remain dependency-blocked. - #245 and #250 require this shared presentation before their own final grooming.
Every option below retains these invariants:
- The only input is an already-authorized
MemberProfileUUID. Email, normalized email, name, certificate/display alias, organization, profile values,content.Person, provider identifiers, and operator input are never inputs. - Parse the UUID, then canonicalize it as exactly 32 lowercase hexadecimal characters with hyphens removed. Invalid, absent, quarantined, colliding-identity, broken/cyclic/absorbed, inactive, deleted, unauthorized, and nonexistent subjects expose no label and preserve the consuming service's generic non-enumerating result.
- The label is presentation only. The canonical full profile UUID remains the resource identity. A label is never accepted as a route identifier, lookup/search/filter key, idempotency key, authorization input, correlation key, or uniqueness proof.
- A truncated-label collision never reveals PII, extends only one subject's label, changes the grammar dynamically, or changes denial behavior. Colliding labels remain identical; resource UUIDs and authorized object scope distinguish resources.
- Labels are private, zero-TTL, no-store, noindex, absent from public pages/search/sitemaps/analytics. They do not grant PII access and do not widen the authorized queryset.
- Ordinary application logs, metrics, traces, errors, job context, and provider payloads do not record the label. Append-only management audit may store the selected label only as its already-authorized redacted target-label snapshot beside target type/opaque UUID; denied/unknown targets receive no label. If the final audit registry is stricter, it stores the opaque UUID only—never a fallback email/name/digest.
- HTML renders the exact literal text rather than CSS-only truncation. Its accessible name is
Member identifier, starts <spaced prefix>, ends <spaced suffix>for truncated options, so the ellipsis and hexadecimal characters are not the sole spoken distinction. Labels remain text at zoom/reflow, are not color-only, and copy/links/actions keep a distinct accessible name. API and CSV serialize the exact visible string ornull, never a different mask.
Exact candidate formats
Only the following existing-UUID formats are in this decision. They need no new identity input, persistent alias, or masking secret.
Option A — compact UUID edge label (recommended)
Member <first 4 hex>…<last 4 hex>
Use the literal prefix Member and one Unicode horizontal ellipsis … (U+2026), with no surrounding spaces. Example UUID 2f910000-0000-4000-8000-0000a1b2c3d4 renders:
Member 2f91…c3d4
Accessible name:
Member identifier, starts 2 f 9 1, ends c 3 d 4
Consequences:
- exposes 32 bits of the already-authorized opaque UUID; stable for the lifetime of that profile and unaffected by email, name, profile-field, account-state, or course changes;
- compact at mobile/reflow sizes and relatively short for screen-reader repetition;
- truncated labels can collide. The UI/API/CSV must tolerate identical labels and retain the full authorized resource UUID separately; no adaptive suffix or PII fallback is allowed;
- remains linkable across authorized private surfaces, so it is excluded from public output and ordinary observability despite containing no email/name characters.
Option B — extended UUID edge label
Member <first 6 hex>…<last 6 hex>
The same example renders:
Member 2f9100…b2c3d4
Accessible name:
Member identifier, starts 2 f 9 1 0 0, ends b 2 c 3 d 4
Consequences:
- exposes 48 bits of the opaque UUID and is stable under the same conditions as Option A;
- lowers accidental label-collision risk relative to Option A but still is not a uniqueness proof and retains exactly the same collision behavior;
- is longer and more repetitive in dense tables, exports, zoom/reflow, and spoken output;
- has greater cross-surface linkability than Option A and therefore retains the same private/no-store/logging restrictions.
Option C — full opaque UUID label
Member <canonical hyphenated lowercase UUID>
The same example renders:
Member 2f910000-0000-4000-8000-0000a1b2c3d4
Accessible name spells the UUID in its five canonical groups after Member identifier.
Consequences:
- has no truncation collision beyond the authoritative resource identity and requires no second identifier beside the label;
- exposes the complete stable opaque resource identifier and maximizes cross-surface linkability;
- is cumbersome in tables, mobile layouts, CSV review, copying, and repeated screen-reader output;
- is not recommended for the requested masked presentation, although it remains non-PII under current authority. It retains all private/no-store/logging restrictions.
Recommended safe default
Recommend Option A. It uses only the immutable authorized profile UUID, introduces no email/name disclosure, normalization policy, persistent alias, new secret, rotation lifecycle, or model field, and is the smallest consistent presentation across #245 and #250. Its collision tradeoff is acceptable only because the label is explicitly non-unique and never the resource or lookup key.
This is a recommendation, not approval.
Explicitly excluded formats
The following are not candidate defaults and require a new owner-reviewed decision if requested:
- partial or hashed email, domain, name, certificate/display alias, profile text, or combinations of them;
- the existing
protected:<12 hex>helper, which is scoped to an external event-provider identifier and is not member-identity authority; - unkeyed hashes, reversible/encrypted values, stable recipient digests, or provider identifiers;
- keyed/HMAC aliases, which would add secret ownership, rotation, versioning, historical audit/export behavior, and outage semantics not authorized here;
- random stored aliases, which would add schema, uniqueness, migration, lifecycle, restoration, and deletion behavior not authorized here;
- per-page ordinals or unstable masks, which cannot safely correlate list/detail/export/operation results;
- any fallback from a missing/invalid/unauthorized profile UUID to PII or another identifier.
Downstream contract after owner approval
After an authorized owner selects an option and PM records it:
- #245 uses one nullable
member_labelwith the exact shared grammar for masked CourseRegistration and Enrollment Studio rows/details, admin API representations, operation summaries, and CSV columns. Its current defaultmasked account identifier/masked normalized-email snapshotwording must be replaced rather than implemented alongside the shared label. Full account UUID/email remain separately capability-gated PII fields. Missing/unavailable labels serialize asnullin API/CSV and displayHiddenin Studio only where the consuming issue already distinguishes masked from genuinely absent data. - #250 uses the same nullable
member_labelfor Members list/detail and safe correction/resend review/result presentation. The full authorized profile UUID remains the route/API resource ID. Full PII remains separately gated byaccounts.member_profile.view_pii. - Shared operations and permitted audit target-label snapshots use the same grammar; adapters and exports may not fork it.
- Both issues add collision fixtures, null/unavailable/non-enumerating fixtures, exact API/CSV/HTML parity assertions, redaction canaries, and desktop/mobile keyboard/screen-reader/zoom/reflow evidence. Approval of this label does not satisfy either issue's other dependency or lifecycle gates.
Until that reconciliation is complete, #245 and #250 remain decision / needs grooming; #246 may not finalize management result presentation before accepted #245.
Owner response required
An authorized product/security owner should reply with exactly one of:
APPROVE #288 OPTION A — COMPACT UUID EDGE LABEL
APPROVE #288 OPTION B — EXTENDED UUID EDGE LABEL
APPROVE #288 OPTION C — FULL OPAQUE UUID LABEL
or provide an exact replacement covering input, canonicalization, literal grammar, examples, collision behavior, missing/unavailable identities, stability/rotation, privacy/linkability, accessibility, logging/audit, and downstream API/CSV/HTML fields.
Decision acceptance and non-goals
- An authorized owner response selects one exact format or supplies an equally complete replacement.
- PM records the selected immutable grammar and consequences without weakening any invariant above.
- PM reconciles #245 and #250 to one
member_labelcontract, leaves their unrelated dependency gates intact, removes this issue's decision/grooming labels, and closes this decision issue only after that record is complete.
Non-goals: implementing accounts/profile services; changing #247 identity/schema; permissions or PII capability work; course/member reads or exports; operation/audit infrastructure; support correction; Slack resend; privacy-rights workflows; routes/UI/API/OpenAPI; tests; migrations; deployment; production/provider/secret/data access; or changing public content.Person behavior.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read _docs/specs/06-studio-and-admin-api.md, _docs/specs/07-security-privacy-operations.md, and _docs/specs/open-decisions.md, then review dependencies #247, #245, and #250. This issue is blocked until an authorized product/security owner selects an exact option; done means PM records that choice and reconciles the shared member_label contract across #245 and #250.
Written by the indexing model from the issue text.
Assessment
- Domain
- authorization, backend-api-design, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 25/100