DataTalksClub / DataTalksClub/website
Move all course operations into Studio and the admin API
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
Normative authority:
- 04 — Course-platform adoption and Course → Cohort model
- 05 — Events, registration, and Relay-owned email
- 06 — Studio and admin API
- 07 — Security, privacy, accessibility, and operations
- 09 — Migration and rollout roadmap
- 10 — Verification strategy
Scope
Build and enforce the final Course-management completeness matrix. Its inventory universe is the union of:
- #30's adopted CMP source at exact pin
98a235283904b4ef9ad29e196298540756cf1bcc, including its copied-file manifest, original migration identity, generated behavior inventory, and integration-patch ledger; - every copied
cadminroute/action, relevant Django-admin action, compatibility/operational API behavior, and management command at that source identity; - every accepted target-native management service/action introduced by #53, #55–#58, #245, and #246;
- the accepted Course/Cohort authorization, role, object/field, principal, audit, operation, and OpenAPI interfaces from #32/#33/#52; and
- 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; ortemporary_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
cadminproduct 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_nativerow 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_approvedrow has explicit authority, safe replacement/denial, and no reachable ordinary entry point; everytemporary_compatibilityrow 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
cadmindependency. - 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
CourseManagementParityContracthandoff is published for #60, and focused plus graph-selected full verification and independent browser/screenshots receive tester PASS and PM acceptance.
Test scenarios
- Machine-compare source action inventory with capability registry, Studio routes, admin OpenAPI, permission tests, and audit actions; any gap fails CI.
- Execute every capability happy path and denied/stale/replayed/partial/crash path using fixtures.
- 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:
- #32 and #33 — final Studio/admin-API human and service identity, function/object/field policy, audit, reauthentication/API-proof, credential, operation, and OpenAPI mechanisms;
- #52 — final Course/Cohort staff assignments, role/capability/object scope, Person-link, legacy-token, and support-view-as boundary;
- #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;
- #245 and #246 — accepted target-native Registration/Enrollment reads, masked details, exports, conversion, correction, archive/restore, and bulk-operation interfaces; and
- #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
- 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 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