DataTalksClub / DataTalksClub/website

Move all course operations into Studio and the admin API

Open
#59 8 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

accessibility admin courses data-migration email enhancement frontend integration operations P0 security testing
Dominant language
Python
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

Parent epics: #5, #7

Normative authority:

Scope

Build and enforce the final Course-management completeness matrix. Its inventory universe is the union of:

  1. #30's adopted CMP source at exact pin 98a235283904b4ef9ad29e196298540756cf1bcc, including its copied-file manifest, original migration identity, generated behavior inventory, and integration-patch ledger;
  2. every copied cadmin route/action, relevant Django-admin action, compatibility/operational API behavior, and management command at that source identity;
  3. every accepted target-native management service/action introduced by #53, #55–#58, #245, and #246;
  4. the accepted Course/Cohort authorization, role, object/field, principal, audit, operation, and OpenAPI interfaces from #32/#33/#52; and
  5. the accepted Relay-template and website logical-delivery management interfaces from #48/#49, subject to the strict send-disabled boundary below.

Each source and evolved target action appears exactly once. Each row records stable source identity and checksum, owning issue/contract fingerprint, disposition, shared service/result, Studio route/state, admin-API path/method/OpenAPI operation ID, capability/principal/object/field/PII policy, revision/idempotency/concurrency/high-risk policy, sync or durable-operation behavior, audit/redaction/retention, migration implications, tests, and compatibility removal gate.

Allowed dispositions are exactly:

  • target_native: one accepted owning shared service with Studio/admin-API parity;
  • retired_approved: explicit normative or owner authority, safe replacement/denial, regression test, and no remaining ordinary entry point; or
  • temporary_compatibility: one target service, staff-only adapter, named owner, tested direct destination, and removal gate. It never renders a second product interface.

Unknown, duplicate, multiply owned, stale, or schema-invalid rows fail the repository gate. A renamed route, redirect adapter, or internally self-consistent registry cannot make a source behavior disappear.

#59 does not reimplement accepted domain services. It fills only the remaining service-adapter, Studio, admin-API, registry/OpenAPI, authorization/audit, compatibility, and completeness-test gaps identified by the frozen matrix. Cover course/cohort lifecycle and duplication, campaigns/registrations/enrollment, learner repair/archive, homework/project/review, scoring/statistics/complaints, certificates/Wrapped, communication projections, health/job diagnostics, imports/exports, and scoped view-as.

Non-goals

  • Do not declare parity by route count alone, leave hidden Django-admin-only operational actions at production cutover, bypass shared services from either adapter, or render a second cadmin product UI.
  • No Course/Cohort, registration/Enrollment, curriculum, homework/project/review, score/complaint, certificate/Wrapped, identity, role, template, or delivery behavior redefinition owned by a prerequisite.
  • No source-pin advance, CMP upstream port, public/learner redesign, arbitrary new operation, direct model/serializer mutation, production/protected import, provider/AWS/Relay access, credential handling, canary, redirect/DNS activation, sender/purpose activation, destructive contraction, deployment, or cutover.
  • No inference that source acceptance, a local candidate, a deployment receipt, elapsed observation, #59 acceptance, or #60 rehearsal authorizes #50, #74, #287, provider work, production access, or legacy removal.

Acceptance criteria

  • The frozen inventory is bound to the exact #30 source pin/manifests plus every accepted evolved target action; every source and target action appears exactly once with a schema-valid disposition and owner.
  • Every target_native row maps to one accepted shared service and has exact Studio/admin-API route, OpenAPI operation, capability/principal/object/field policy, revision/idempotency/concurrency, audit/redaction, result, safe-error, and test parity.
  • Every retired_approved row has explicit authority, safe replacement/denial, and no reachable ordinary entry point; every temporary_compatibility row has one target destination, owner, tested access behavior, and removal gate.
  • Machine checks compare the full source/evolved inventory with services, registry, Studio routes, admin OpenAPI, permissions, audit actions, operations/jobs, migrations, and tests; missing, duplicate, stale, or extra rows fail CI.
  • High-risk, bulk, export, scoring/repair, certificate, and reconciliation actions preserve the owning contract's scope/count/impact, reauthentication/API proof, confirmation, bounded async/partial/cancel/recovery semantics, and safe errors.
  • Positive and negative evidence covers every declared human/service role, Course/Cohort and cross-scope object state, sensitive field, stale/replay/concurrency state, and denial without existence or PII leakage.
  • Studio → Courses is the only ordinary human interface; compatibility routes never render a second UI, and production cutover has no ordinary Django-admin or unclassified cadmin dependency.
  • Datamailer remains read-only/send-disabled; no sender, provider, delivery purpose, recipient rule, dispatch/requeue/callback/fallback, production data, or network side effect is introduced or exercised.
  • Exact source, merge, migration, schema, matrix, compatibility, registry, OpenAPI, service, audit, test, and verification digests are recorded and internally consistent.
  • The immutable CourseManagementParityContract handoff is published for #60, and focused plus graph-selected full verification and independent browser/screenshots receive tester PASS and PM acceptance.

Test scenarios

  1. Machine-compare source action inventory with capability registry, Studio routes, admin OpenAPI, permission tests, and audit actions; any gap fails CI.
  2. Execute every capability happy path and denied/stale/replayed/partial/crash path using fixtures.
  3. Validate temporary route banners/access/removal gate and production Django-admin restriction.
Playwright

Role-based walkthrough of every Studio course section and retained compatibility route; capture each changed page, empty/error/progress/confirmation state, and verify no 404/debug/broken layout.

Dependencies and dispatch gate

Accepted baseline inputs are #30's adopted source/characterization, #31's shared service/capability/operation/job primitives, #115/#116's canonical Studio → Courses naming/mount, and the closed #20/#23/#28 identity, privacy, and high-risk decisions. They are inputs, not #59 completion evidence.

Engineering hard-depends on accepted, integrated, and on-call-green current-main handoffs for:

  1. #32 and #33 — final Studio/admin-API human and service identity, function/object/field policy, audit, reauthentication/API-proof, credential, operation, and OpenAPI mechanisms;
  2. #52 — final Course/Cohort staff assignments, role/capability/object scope, Person-link, legacy-token, and support-view-as boundary;
  3. #53 and #55–#58 — accepted lifecycle/duplication, homework, project/review, score/leaderboard/complaint, graduate/certificate/Wrapped services, schemas, migration identities, operations, capabilities, and audit contracts;
  4. #245 and #246 — accepted target-native Registration/Enrollment reads, masked details, exports, conversion, correction, archive/restore, and bulk-operation interfaces; and
  5. #48 and #49 — accepted Relay-owned template-management and website logical-delivery/status/reconciliation management source contracts.

#51 is transitive through #53 and later domain handoffs. #224, #230/#231/#234, #242–#244, #247/#248, #288, #40/#61, external MFA, and Relay #1/#2/#3 are consumed through their accepted direct owners above; an open, decision-blocked, or merely local transitive input cannot be inferred as accepted. Broad parent #54 is coordination only and is not a prerequisite.

No #59 engineer lane starts until all direct inputs are integrated on one green current-main base. PM then freezes the exact inventory and identities below. Any prerequisite, source pin, migration leaf, service/result schema, capability/policy, registry, OpenAPI, masking, route, send boundary, or consumer drift returns #59 to PM.

Strict send-disabled boundary

#59 may expose only the accepted #48/#49 management source interfaces: template catalog/draft/version preview and publication controls, website logical-delivery/redacted-status inspection, and guarded reconciliation/ambiguity/manual-operation states exactly as their owning contracts permit.

It must not create a new Course trigger, recipient-selection rule, purpose, template version, sender route, or provider policy; activate a test or real sender, broad recipient, Relay credential, callback endpoint, or provider configuration; call Relay, Datamailer, SES, or another provider during implementation, migration, verification, or #60 rehearsal; or make copied Datamailer dispatch, immediate-send, requeue, callback, writable-outbox, or rollback-sender behavior reachable.

Copied Datamailer rows and identifiers are read-only, send-disabled migration/history/reconciliation input only. #50 remains downstream: it consumes accepted course-domain trigger contracts, activates separately approved purpose/sender paths, and owns Datamailer freeze/drain/retirement. Neither #59 parity nor #60 rehearsal satisfies #50 or grants canary/cutover authority.

Evidence and migration identity

Before engineering, and again in the frozen engineer handoff, record:

  • exact current base/head full SHAs and every prerequisite merge SHA;
  • #30 merge/source identity, adopted source pin 98a235283904b4ef9ad29e196298540756cf1bcc, copied-file-manifest digest, integration-patch-ledger digest, and behavior-inventory digest;
  • exact Django app labels, original retained migration identity, current migration leaf set, and deterministic schema/migration-plan fingerprint;
  • accepted #53/#55–#58 and #245/#246 service/result/mapping/fixture contract fingerprints;
  • accepted #32/#33/#52 policy/capability/principal/audit fingerprints and #48/#49 template/delivery management contract identities;
  • matrix schema version and row counts by source kind/disposition/owner, canonical no-gap matrix digest, compatibility/removal-manifest digest, registry/OpenAPI/service/action/audit/test-manifest digests; and
  • change-selective graph/plan/report plus all rerun/reused/not-applicable evidence identities required by _docs/PROCESS.md.

Repository verification uses deterministic synthetic fixtures only. It preserves app labels, stable legacy mappings, original migration history, and accepted downstream schema identities. Missing/duplicate mappings, unexpected leaves, unexplained schema/result drift, or any send-capable legacy path fails closed. Protected production-like rows, snapshots, migration execution, and reconciliation remain #60 under separate explicit authority.

Exact handoff to #60

Accepted #59 publishes one immutable, PII-free CourseManagementParityContract identity containing the canonical no-gap matrix digest and row counts; exact prerequisite/source/migration fingerprints; Studio route, admin OpenAPI, capability/policy, service/result, audit, operation/job, and test-manifest digests; every retained compatibility row with owner/removal gate; proof that no ordinary Course operation depends on Django admin or an unclassified cadmin behavior; and the send-disabled Datamailer/Relay boundary plus zero-network verification result.

#60 freezes and validates that exact identity during the full side-effect-disabled production-like rehearsal. It does not fill a #59 matrix gap, reinterpret an owning service, activate a compatibility redirect, access a provider, or enable a sender. #60 is downstream and never a #59 prerequisite.

Readiness and lifecycle

Readiness: GROOMED / DEPENDENCY-BLOCKED. After every hard input is accepted/integrated and green, PM freezes the row-by-row matrix and exact identities. One engineer then implements only the identified gaps in an isolated current-main worktree and leaves the candidate uncommitted with a complete versioned verification report. A separate tester recomputes the plan, verifies every criterion and graph-selected gate, and captures/inspects all required desktop/mobile screenshots. PM accepts only a complete tester PASS with no pending or required skip.

Only after those gates may the engineer create a focused commit containing Closes #59; the orchestrator locally merges with --no-ff, pushes main, and on-call alone observes terminal CI/deployment. No pull request is created. #60 may consume only the accepted, integrated, on-call-green CourseManagementParityContract identity.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the normative course and Studio/admin API specs and _docs/PROCESS.md, then inspect the frozen #30 source pin, accepted prerequisite contracts, and the Course-management completeness matrix. Verify the Studio → Courses routes, admin OpenAPI, capability/audit registries, and Playwright scenarios; done requires gap-free machine checks, focused/full verification, and the immutable CourseManagementParityContract handoff to #60.

Written by the indexing model from the issue text.

Assessment

Tech stack
openapi, playwright, python
Domain
api, backend, frontend, security, testing
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.