DataTalksClub / DataTalksClub/website
Consolidate the adopted course account as the single website identity
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
Parent epics: #5, #7, #10
Related implementation owners: #52, #54, #60, #61, and #97
Owner decision and outcome
The account adopted with the Course Management Platform is the single durable website account for learners and human staff. Evolve accounts.CustomUser and its existing relations in place; do not introduce a parallel website user, login, profile, session, or social-account identity.
A returning course learner or staff member must retain the same durable account and be able to authenticate through the preserved login methods after consolidation. The migration retains existing account primary keys where records are not duplicates and retains an explicit old-ID-to-survivor mapping for every reconciled duplicate. Existing enrollments, submissions, reviews, scores, certificates, account profile fields, preferences, social connections, staff links, and audit references continue to resolve to that account.
This decision does not make a GitHub-owned public Person profile an authentication record. Person remains the canonical public editorial identity from #3; an account may be explicitly linked to a Person without granting permissions or duplicating either record.
Product and architecture authority
- 01 — Platform architecture: one
accountsapp and custom user model - 03 — Person identity
- 04 — Adopted learner behavior and high-risk migration checks
- 06 — Studio roles and human authentication
- 07 — Identity and authorization
- 09 — Migration, rollback, and data controls
- 10 — Verification strategy
- Closed adoption baseline #30 at source revision
98a235283904b4ef9ad29e196298540756cf1bcc.
Preserved identity contract
The consolidation starts from the adopted account schema and behavior, including:
accounts.CustomUserasAUTH_USER_MODEL, preserving the existing app/model/table and migration identity;- existing primary key, username/login identifier, normalized email evidence, password hash where supported,
last_login,date_joined, active/staff/superuser state, and current account role fields; - certificate name, country/region, registration role, About me, GitHub/LinkedIn/personal website URLs, dark mode, preferred timezone, email preferences, and course-specific public-display preferences;
- Django Allauth
EmailAddressandSocialAccount/provider links and the currently supported learner login behavior; - Django session ownership and security semantics, protected-route
nextbehavior, logout, and account settings; - account foreign keys from enrollments, submissions, reviews, votes, complaints, scores, certificates, tokens/principals, staff assignments, audit records, and other adopted course data.
The consolidated application must have one authoritative user lookup and one authenticated request.user. New public, learner, course, and Studio surfaces consume that identity and the same session rather than copying account fields into another website profile.
Scope
In-place account consolidation
- Inventory the adopted user model, authentication backends/providers, Allauth email/social records, session backend/cookie behavior, login/logout/settings routes, user foreign keys, compatibility APIs, and account navigation before changing them.
- Evolve the adopted model through expand-and-contract migrations. Do not replace it with a greenfield user table or renumber clean source accounts.
- Make verified normalized email the learner account identity without losing legacy username/login compatibility during the migration window.
- Preserve existing login provider connections and callback behavior. A provider callback for an existing person must resolve the existing account, never create a second website account merely because the visitor arrived from a new site surface.
- Keep current authenticated sessions valid through an ordinary in-place release. Consolidation must not perform a blanket session flush. Legacy-host compatibility sessions remain valid while those routes are served.
- Produce and test a secure cross-host continuity plan for the eventual
courses.datatalks.club→datatalks.clubtransition. It may not broaden cookie scope without security approval or expose handoff credentials in URLs, logs, analytics, screenshots, or referrers. Replay, expiry, CSRF/fixation, logout, revocation, andnexthandling must be explicit. If browser cookie boundaries require visible reauthentication, it must be a reviewed migration exception: the login returns to the intended route and resolves the same account ID, never a new account.
Duplicate and conflict reconciliation
- A snapshot-pinned, idempotent dry run groups candidate duplicates using normalized email, Allauth verified-email evidence, provider plus provider UID, username/login identifiers, and account relations. It reports exact source IDs and counts without logging raw provider payloads, tokens, or unrelated PII.
- Generate a reviewed source-account → survivor mapping. Existing distinct accounts are never merged solely because a social provider supplied an unverified email or because one record has the newest
last_login. - Ambiguous ownership, conflicting provider UIDs, or irreconcilable identifiers fail closed into a quarantine/review report. They do not create an account, attach a provider, or select the “most recent” user automatically.
- Preserve the selected survivor's primary key. Every absorbed source ID remains recorded in a durable alias/migration map so imports, audit evidence, compatibility APIs, and rollback can resolve it.
- Reparent all account-owned relationships exactly once and reconcile totals before an absorbed record can be disabled. Course work from multiple legitimate source records is retained and cannot cross-link to another person's account.
- Privilege is never gained by union:
is_staff, superuser status, groups, course/cohort capabilities, API credentials, and public Person links require their existing authoritative evidence or separate reviewed grant. Duplicate reconciliation cannot turn a learner into staff. - Consent is never inferred or widened. Profile/preference conflicts use documented per-field rules, choose the privacy-preserving state where applicable, and surface unexplained differences instead of silently overwriting them.
- Social connections move only with verified ownership evidence. Password hashes and recovery/email-change state retain safe Django semantics; affected tokens/sessions are invalidated only when required by a documented security condition.
Shared website account navigation
- The adopted Course Management Platform shell is the single authentication-aware shell for new website pages, including the bounded #97 review surfaces.
- Signed-out navigation exposes one same-host login destination. Signed-in navigation exposes the signed-in account, account settings, learner/course destinations, and one logout action. Staff-only destinations are shown through the shared capability policy, not by introducing another staff login or public-Person inference.
- Login, logout, settings, social-connection, callback, and protected-route links preserve safe
nextbehavior and never bounce to a second account system or legacy login page. - Desktop and mobile navigation are keyboard complete, expose state accessibly, avoid horizontal overflow, and do not publicly cache authenticated content.
Anonymized review/test content
- Content-only local imports and the #97 representative release create no real
CustomUser,EmailAddress,SocialAccount, session, provider credential, enrollment, or staff record. - Deterministic local/browser fixtures use synthetic non-routable identities and contain no production email, account ID, social UID, access token, registration data, or profile PII.
- GitHub
Personprojections used by content review remain public content records and do not silently create/link authenticated accounts.
Compatibility, API, and observability
- Existing course HTML and authenticated API behavior keeps using the adopted account through the compatibility window. New learner and management APIs reference the same durable account identity; no endpoint gets a website-only user table.
- Existing tokens/principals are inventoried and mapped to their owner without exposing plaintext. Their hardening/rotation remains coordinated with #33/#52.
- Authentication, linking, duplicate review, merge, disablement, session handoff, and rollback outcomes emit redacted audit events. Raw OAuth/social payloads, email addresses, password material, session keys, cookies, tokens, and handoff credentials never enter logs or issue/test artifacts.
- Metrics distinguish successful returning login, explicit reauthentication, account-link conflict, unexpected new-account creation, session/auth failure, and rollback without using PII labels.
Non-goals
- No second website account/profile/login service, separate learner and staff user tables, public
Personas authentication identity, or account copy generated from content records. - No owner selection of the production staff OIDC provider, claim mapping, MFA evidence, or break-glass custody; #20/#61 own those decisions and integration. Their chosen staff login must attach to this same adopted account.
- No redesign of enrollment, homework, projects, peer review, scoring, leaderboard, certificate, course/cadmin, or Studio capability behavior owned by #52 and #54–#59.
- No full production data cutover in this issue. #60 owns the production-like full rehearsal, final delta/write freeze, and whole-platform reconciliation using this issue's identity mapping and checks.
- No generic automatic merge by newest login, unverified email, fuzzy name, or social display name.
- No destructive deletion of duplicate rows, removal of compatibility identifiers, blanket logout, cookie-security weakening, production PII in local fixtures, or secret/provider payload logging.
- No retirement of the old course hostname or authenticated APIs before #60's compatibility/consumer gate.
Migration and rollback contract
- Pin the source snapshot and run a no-write inventory covering every account, email/social/login relation, session/auth contract, dependent table, and duplicate/conflict cluster.
- Add nullable mapping/alias/reconciliation state and any normalized identity constraints without dropping old columns, identifiers, or rows.
- Dry-run the reviewed mapping repeatedly; report source/target counts, unchanged IDs, duplicate groups, ambiguous groups, per-table relationship totals/checksums, field decisions, and rejected rows.
- Apply survivor mappings and dependent-row changes idempotently with outbound email and provider side effects disabled. Keep absorbed account rows and compatibility identifiers available but unable to authenticate twice after verified consolidation.
- Validate login, provider linking, sessions, account settings, staff capability lookup, course workflows, APIs, and audit references on a production-like copy before enabling the new resolver/navigation in production.
- Cut over behind an observable feature/configuration boundary, run returning-account and duplicate canaries, and retain the old resolver plus non-destructive mapping data for the rollback window.
- Contract old identifiers/rows only after #60's final rehearsal, production verification, backup/restore evidence, and rollback window. Deletion/anonymization follows the privacy process, not ordinary migration cleanup.
Rollback uses an immutable application revision that can still read the expanded schema. It never reverses successful relationship moves destructively, re-enables two independently authenticating accounts for one person, discards post-cutover writes, or clears all sessions. Workers/provider callbacks are paused or pinned as needed, alias mappings remain available, and any authentication-failure threshold is a release rollback trigger under spec 09.
Acceptance criteria
-
accounts.CustomUserremains the oneAUTH_USER_MODEL; all site, course, learner, Studio, compatibility, and API authentication resolves one durable account with no parallel website user/profile/session model. - The account inventory classifies every identity field, login/provider route, session behavior, dependent foreign key, compatibility identifier, and current account navigation action before migration.
- Clean source accounts retain their primary IDs and preserved fields/relations; every reconciled source ID has a durable reviewed survivor mapping and no account-owned educational or audit record is lost or attached to the wrong person.
- Verified normalized-email identity and legacy login compatibility are introduced through forward/backward-tested expand-and-contract migrations without renumbering or recreating the adopted user table.
- Duplicate email, case variant, username/email overlap, multiple
EmailAddress, conflicting social UID, staff/learner collision, and incomplete-profile cases produce deterministic reviewed results; ambiguous cases fail closed and newest-last_loginis not an automatic authority. - Existing supported learner login methods, provider connections, callback outcomes, account settings/profile/social links/preferences, logout, safe
next, and recovery/change behavior remain characterized and pass for returning accounts. - An ordinary consolidation release preserves valid existing sessions and does not globally log users out. Legacy-host and eventual cross-host continuity/explicit-reauth behavior passes the approved fixation, replay, expiry, revocation, logout, cache, and credential-leak tests while always returning the same account ID.
- Duplicate reconciliation cannot grant staff/superuser/group/course capability, infer consent, expose another user's data, or create a new social link without verified ownership.
- Every new website surface renders the one shared signed-out login or signed-in account navigation at desktop/mobile; protected actions use the same session and account, and staff links use capability policy rather than a second login.
- #97 content-only projections and all local review fixtures remain anonymized and create no account/social/session/registration rows or production identifiers.
- Existing course learner and authenticated API characterization suites pass against the consolidated account; compatibility and new APIs agree on account identity and denial behavior.
- The migration is snapshot-pinned, dry-runnable, idempotent, redacted, count/checksum reconciled, and safe to rerun; outbound email/provider side effects remain disabled during rehearsal/import.
- Production-like rehearsal and rollback prove account/login/session continuity, alias resolution, no unexplained relationship-count difference, no lost post-cutover write, no double-authenticating duplicate, and no destructive reversal.
- Logs, metrics, audit events, migration reports, screenshots, and issue comments contain no raw OAuth payload, production email/profile PII, password/session/token/cookie/handoff secret, or provider credential.
Django and integration scenarios
- Single identity: authenticate through each currently supported login path, visit public content, account settings, course dashboard, and an authorized Studio route, and assert one
request.user.pk, session owner, and account record throughout. - Returning learner: import a source learner with profile/preferences, social connection, enrollment, submission, review, score, and certificate; log in after consolidation and verify the same account ID and all records/fields.
- Returning staff: retain the source staff account ID and safe session behavior; prove capabilities are resolved separately, a public Person link grants nothing, and future #61 OIDC attaches to the same account.
- Duplicate matrix: exercise case/whitespace email variants, username-email overlap, one/multiple verified emails, conflicting provider UID, two active learners with course history, learner/staff collision, and missing email. Verify reviewed survivor/alias or fail-closed quarantine with no privilege/consent union.
- Social linking: returning Google/GitHub/Slack fixtures connect only after verified ownership, replay idempotently, and reject unverified/conflicting claims without selecting the most recent user or logging provider payloads.
- Session lifecycle: preserve a valid pre-release session through the in-place migration; test fixation, idle/absolute expiry, logout, staff disablement, password/email/security changes, legacy-host compatibility, and cross-host handoff or explicit reauthentication without account duplication.
- Migration: run dry-run twice, apply twice, and reconcile account IDs, aliases, every dependent table, totals/checksums, ambiguity report, disabled duplicate behavior, and no outbound side effects. Run forward/backward migration-window tests against a production-like database copy.
- Rollback: create account-owned writes after cutover, roll the application back without reversing data, and prove both old/new identifiers resolve safely, sessions follow policy, new writes remain, and only one account authenticates.
- API parity: exercise representative session-authenticated and compatibility token/principal requests before/after migration; assert same account, schema/status/authorization behavior, safe 401/403, and no cross-account lookup leak.
- Anonymized review: load #97 content fixtures and assert zero new user, email/social, session, enrollment, registration, token, and staff rows plus a PII/secret artifact scan.
Browser scenarios
Run at desktop and mobile widths with deterministic synthetic accounts:
- Start signed out on
/, use the shared Login control, authenticate as an existing learner, return vianext, and navigate articles/events/courses/account settings without another login or account ID change. - From the same signed-in shell, traverse course dashboard/homework/project/profile surfaces; verify account navigation, profile/social-link values, theme/timezone preferences, logout, browser-back privacy, and no legacy/second login dead end.
- Exercise a deterministic social-provider callback for an existing account and a duplicate/conflict denial. The successful path lands on the same account; the conflict gives safe recovery guidance without exposing whether another account exists.
- Use a staff account through the shared shell; authorized Studio navigation is present, learner navigation still uses the same account, and a learner/disabled staff receives the expected denial without a second staff identity.
- Exercise the approved legacy-host-to-canonical continuity or explicit-reauth flow, including intended destination, back/refresh/replay/logout, and verify no token appears in URL/history/screenshot.
- Load the #97 content-only review dataset signed out and signed in; shared navigation changes appropriately while database counts prove the content import itself created no identity or PII.
Capture and inspect representative desktop/mobile login, account-menu/settings, returning learner, staff allowed/denied, duplicate-conflict, and continuity/reauth states under .tmp/, with synthetic identifiers only.
Dependencies and coordination
- Depends on closed #30 for the adopted account schema, migrations, login behavior, and characterization baseline.
- #54 consumes this single-account contract for learner registration, linking, enrollment, profile, dashboard, and calendar behavior; it must not create a separate account implementation.
- #60 consumes this issue's reviewed identity mapping and owns the full production-like course-data rehearsal, delta/write freeze, final compatibility proof, and cutover reconciliation.
- #52/#33 own scoped course/admin API credentials and capabilities; they must retain this account as the human owner without treating legacy plaintext tokens as human identity.
- #20/#61 still own the production staff OIDC provider, MFA claims, offboarding, and break-glass details. Their eventual provider identity must link to this same account and cannot create a staff-only user model.
- #97 is independent for content rendering but must use the shared account-aware shell and must keep its content projections anonymized. It does not need account migration or real identity data to complete its read-only review slice.
Delivery convention
Follow _docs/PROCESS.md. Engineering implements and tests without committing; an independent tester verifies migration/browser evidence and synthetic screenshots; product acceptance follows. No pull request is created.
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
Start with accounts.CustomUser and AUTH_USER_MODEL, then inventory Django Allauth records, authentication backends, sessions, login routes, and account foreign keys as required by the issue. Read specs 01, 07, 09, and 10 before defining the migration and verification work. Done means a reviewed, idempotent mapping preserves account IDs, relationships, login behavior, security boundaries, and rollback evidence without introducing a second identity.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- django, python
- Domain
- authentication, backend, databases, security
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100