Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Course-launch batch schedule: one confirmed cohort launch-and-schedule enqueues eligible announcements

Đang mở
#468 6 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
35/100
Loại issue
Tính năng
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
django, python

Hướng nghiên cứu

Start with courses/services/launch_batch.py and its focused test courses/tests/test_course_launch_batch_schedule.py, then inspect templates/studio/course_launch.html and the OpenAPI/CLI entry points. Run the focused Django and CLI tests first. Done means preview makes no changes, confirmed execution enqueues each eligible revision once, and Studio/API/CLI expose identical skip reasons; the issue is already marked implemented and QA-accepted.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

admin courses data-migration email enhancement integration operations P1

Course-launch batch schedule (dependent follow-up to #467)

Raw reporter intent preserved: user requires cohort launch to GENERATE AND SCHEDULE automatically (linked to module/project STARTs); sending stays explicit/scheduled. Core #467 generate() creates only unarmed draft proposed times (armed: 0, no dispatch) requiring per-row approve+schedule. This issue adds the missing one-action batch scheduling without changing core semantics.

Groomed spec (PM, 2026-10-17)

Normative links
  • #467 (prerequisite core increment): templates/publications, Course defaults, cohort overrides, native starts, unarmed generation, per-row approve/schedule/send, Relay courses simulation, Telegram quarantine, dual manage+send authority, CLI auth/parity.
  • Specs 04/05/06 + open-decisions §10/§11 (Relay), §19 pattern (no secret retention); playbooks 02-course-launch-social-system.md (module/project announcements), 01-course-platform-setup.md (Monday 23:00 UTC, copy-previous outline).
  • Ownership: website canonical scheduling (C-LAUNCH-1); no CMP change; no new scheduler (reuse community_base.jobs leased dispatch_after_commit).
Scope (website repo only, additive)
  1. One explicit confirmed privileged batch action (launch_and_schedule or equivalent name): Studio + Admin API + CLI parity, same send capability (dual manage+send authority), confirmed: true required, Idempotency-Key required.
  2. Two-step UX: preview/dry-run first (eligible count + per-row skip reasons, no mutations), then confirmed execute. Studio shows batch section separately from per-row approve/schedule; CLI offers --dry-run (default preview) + --confirmed execute.
  3. Eligibility: only generated rows with immutable template version, known future anchor (starts_at present, proposed anchor+offset > now), status draft/approved (not settled/dispatching/submitted/ambiguous, not cancelled), live cohort + current curriculum. Everything else skipped with explicit reason (missing_start, past_due, settled, cancelled, blocked_destination, stale_revision).
  4. Effect per eligible row: approve current copy (set approved_revision = revision after preview render passes) + enqueue one durable scheduled job at proposed time via the exact single-schedule dispatch path (same idempotency key scheme announcement:<id>:<revision>, same revision fencing). Returns per-row enqueued/skipped{reason} + batch summary counts. Rejected naive/missing/past never enqueued; no catch-up.
  5. Safety preserved: simulation default (non-prod or flag-off → simulated, never live); Relay sender courses only; Telegram uncertain-ack quarantine (no auto-retry); no secret/destination persistence beyond setting key; audit redacted; preference enforcement unchanged (enrolled + email_course_updates).
  6. Idempotency/revision: same-key replay returns prior batch result without duplicate jobs; per-row stale revision → skip with reason (never overwrite another operator's edit); assignment/template change mid-batch fences via existing reconcile (disarm) path.
  7. Docs/tests: runbook section (batch vs per-row, eligibility table, dry-run example), OpenAPI + registry entries, focused Django tests, CLI tests, desktop+mobile screenshots of batch preview + result (reason codes visible).
Non-goals
  • No change to #467 core semantics: generate() stays preview-only/unarmed; per-row approve/schedule/send/cancel/reschedule unchanged; no renaming drafts as auto-scheduled.
  • No batch immediate-send (send now stays per-row explicit only); no past-due catch-up; no resurrecting cancelled/settled rows via batch.
  • No new scheduler infra, worker, or cron; no production sender config/deploy; no live/real-user sends; no CMP/import changes; no RBAC redesign (existing dual-authority + global scope).
  • No mass-assignment or existence leaks; support role still excluded from bodies/recipients.
Dependencies
  • Depends on #467 (must land first or coordinator sequences branches; this work must not mutate the frozen v5/v6 core diff). Blocked while #467 gates (broad run + Argon final + PM accept) are pending.
Acceptance criteria
  • Batch preview (dry-run) lists eligible + skipped-with-reason per cohort with zero mutations and zero jobs; confirmed execute with Idempotency-Key enqueues exactly the eligible future rows once each (job per row, proposed time = anchor+offset).
  • Missing/past/settled/cancelled/blocked rows are skipped with explicit reasons; past rows never dispatched; cancelled rows stay cancelled (explicit per-row recovery only).
  • Same-key replay returns identical batch result with no duplicate jobs; stale-revision rows skip (409-style reason) without overwriting.
  • Permission: dual manage+send (or site_admin) can execute; course-only or email-only principals get 401/403 denial with no existence leak and no partial enqueue (atomic per-row, reported).
  • Simulation: dev/flag-off run enqueues simulated jobs only (no live Relay/Telegram IO); live path unchanged and still requires authorized release/config (human step).
  • Studio/API/CLI parity: Studio batch section + API action + CLI command produce identical results; --dry-run default, --confirmed required to execute; --json/help/exit codes consistent with existing CLI.
  • Screenshots: desktop+mobile batch preview + post-execute states showing enqueued/skipped reasons, no error/debug/broken layout.
  • No .env/tokens/DB/screenshots committed; scratch under .tmp/; migration-drift clean (no schema change expected; if any, nullable additive + null-preserving backfill rule from #467 applies).
Django/integration scenarios
  • Live cohort, all starts future → preview N eligible/0 skipped → confirm → N jobs, each row approved+scheduled, single idempotency keys, replay → same result, zero duplicates.
  • Mixed cohort (one missing start, one past start, one cancelled, one dispatched) → preview 1 eligible + 4 skipped with reasons → confirm → 1 job only.
  • Dual-role principal succeeds; single-role principals denied with zero side effects.
Browser scenarios (desktop + mobile)
  • Studio batch preview → confirm → result list (enqueued + skipped reasons); denied principal sees safe denial; empty cohort (no versions/starts) shows guidance, not silent no-op.
Repository/operations scenarios
  • Focused Django + CLI tests for batch contract; Playwright smoke/core as selector demands; versioned verification plan with base/head + digests; no live sends, secrets, or cloud mutations.
Roles
  • Engineer: launch-web (after #467 lands / coordinator sequences). Tester: independent (Argon or next). PM acceptance: after tester passes; overall #467+#468 goal closes only when both shipped.

QA Review (Argon QA launch-qa2, 2026-10-17 — ACCEPT)

Verdict
  • Status: ACCEPT (QA2-468-FINAL-ACCEPT)
  • Reviewer: Independent Final QA (launch-qa2, session b51faf34-e16a-4107-bf14-38f70c545c4c, engine Argon)
  • Frozen Source Bundle: /home/alexey/git/dtc-website-wt-course-launch-integrated/.tmp/launch-integrated19/ (19 changed paths over HEAD 054f233d7e8192f832064603c109fdd3f8b02a15)
    • source-manifest.json SHA-256: 8aff8b24354cbd18f2d82a3465605b5fa3548724faa745404bd415de49b1fb6e
    • tracked.patch SHA-256: 216a9d516e1d26e6e36db6e2de2024e9cc2c2c163bd765a32a5caff229c73e23
    • courses/services/launch_batch.py SHA-256: 172cd9afa30a4a7e827367b43a2d671026becc7b72c8a2505ead358278e60c64
    • courses/tests/test_course_launch_batch_schedule.py SHA-256: fca3a933192bb27b15dddd3905cf9afac64400ab99c0081c50ba2c634ab4295c
    • templates/studio/course_launch.html SHA-256: 3126690b23c9e4ac6039a3d001c9d1488e23c88828e581b33b0f5c942bbe2743
Verification Plan & 7-Component Full Report Validation
  • Author verification-plan.json Digests:
    • Raw file sha256sum: 8b87b6e264aca497c09de15181197c0630aea856062727b9a00ace8df500604d
    • Canonical sha256_json(plan) (report.plan_sha256 at ci/verification.py:879): 88b49abb90bf640c0cd64eccb120103ffe7ccc02ce5154c14da16d0a49a09b60
  • Tester verification-plan.json Digests:
    • Raw file sha256sum: 564f363a407ee9584ba038c435b9aaea35f27aa8561805a8c8699224f72515b0
    • Canonical sha256_json(plan): bae325f0b5587984b60713df03a5a4e27369d091fb3656b86f9fabe51a6114df
  • Shared Plan Digests (Identical Across Author & Tester Plans):
    • source_tree.manifest_sha256: 21ff298bb27c21e141ceed93b28d1ac4eb596c1deb01ce83add00a91a126c621
    • render.sha256: 7af0b74118152b92e9234ad0631e2e47062f1d3b8650ca909a2b623a574c6d6b
    • graph_sha256: bb924cbe4e46a273f1cea46f5e85f1b9b0711e7ff8b1100b0162bc306de1186b
    • verification_state_sha256: 897e2b7b5ef6ff645bec50901772143e103e6a839cc34ab1e67253bb247a34fb
  • Completed Report (/home/alexey/git/dtc-website-wt-course-launch-integrated/.tmp/verification-468-final19b/):
    • verification-report.json SHA-256: 1c753cde5e9e05c6c25761f94ebacb35315d162bf2d31c6fda7610edc28d994d (Verdict: success; validate-report + validate-evidence-directory + all 7 validate-evidence checks PASS)
    • verification-report.md SHA-256: f731e453913b8443d60a9e21c4673a43a9c3726dfe331767a3e71acc06d604a3
    • Explanation of invalid_evidence: [{"component": "screenshots", "reason": "render_inputs_changed"}]: In ci/verification.py:899-905, report["invalid_evidence"] is a mandatory historical plan-selection diagnostic derived from [component for component, item in plan["components"].items() if item["disposition"] == "rerun" and item["reason"] in INVALID_EVIDENCE_REASONS]. Because screenshots is always planned with disposition: "rerun" and reason: "render_inputs_changed" when render inputs change (and "render_inputs_changed" in INVALID_EVIDENCE_REASONS), validate_report strictly enforces that invalid_evidence contains screenshots:render_inputs_changed even after the fresh screenshots rerun (evidence_id: f7af1e6b7496964f395cf82ff34a0b62741f8c0b1f2fb01ed8259df297682582, result: "success") passes in buckets.rerun.
    • Container Ambient Environment Verification: container-environment.json (0a099d7b17b7c90044c908e065e8e20e1fddbfcc77e3a9b3330502c2071da55d) matches component_environment_fingerprint("container") (environment.sha256 = e0764a1d065452d57f9347633766dfe0464f35a8193cb9e365e1d928bb77f9f5) and plan.components.container.environment.sha256 from the normal runner (scripts/ci.py) without any forced fingerprint override (13 container assertions passed, status: "pass").
  • 7 Component Evidence Envelopes (all result=success, failed=0):
    • selector-evidence.json: f149d6c3afc297247495ccf375651479d54bb0dfda02c791d57dea47e4876624 (changed_paths=19, direct_nodes=9, downstream_nodes=10)
    • quality-evidence.json: 90e19ca53dce7d4943c664c9b31b0e85cc66cccbaedf37d4c8ffae2c6792ca45 (tests=765, passed=760, skipped=5, failed=0)
    • django-evidence.json: 805ce02a97c90ba00f6646c9a9b5fa38b792d2b0a065d4962a7dafac51432cc6 (tests=4358, passed=4352, skipped=6, failed=0)
    • playwright-evidence.json: 5cf56448ef09f1b1beb88074cf2c0bfadec39fba97c273881dfeeeeaf2434334 (attempted=352, passed=352, failed=0, rerun=0, quarantined=0)
    • container-evidence.json: 9690c151db030bf7d681a6f84406136322836e923333935adf49a2d117bc8255 (assertions=13, failed=0)
    • screenshots-evidence.json (producer_role=tester): 0c0a06b4edda64c9e046fea489aa817b796ca710a81b3df4719ab2e6308d89c4 (captures=8, assertions=8, failed=0, screenshots.json 3166e1ab17c4b5c9937d088b8c9f1c4aee5b9b906394bdd57f26ed04ba8b5290)
    • evidence_validation-evidence.json: bdefae542ad4777406921b6a3083b17566bb9104d642558cbd57b3bff31d665d (tests=765, passed=760, skipped=5, failed=0)
Independent Functional, Security & Adversarial Verification
  1. Two-Step Preview & Confirmed Batch Execution:
    • preview_cohort_launch_schedule is strictly read-only (0 CourseLaunchAnnouncement, 0 JobIntent, 0 ManagementIdempotencyRecord, and 0 ManagementAuditLog writes) and returns a Django-signed preview_token binding cohort_id, template_state_sha256, and each eligible row's key, revision, anchor_starts_at, and proposed_scheduled_for.
    • confirm_cohort_launch_schedule requires dual courses.manage_course_launch + courses.send_course_launch_announcement authority (checked before idempotency reservation or row mutation), confirmed=True, a valid signed preview_token, and an Idempotency-Key. Legacy client-supplied preview maps (expected_revisions / preview_revisions / eligible_keys) are rejected with 400.
  2. Lock Ordering, Template State Fencing & Prospective Null-Revision Guard:
    • Confirmed execution acquires locks in canonical order Course -> existing CourseLaunchTemplateAssignment -> Cohort -> existing CohortAnnouncementPlan -> CourseLaunchAnnouncement (by PK), raising 409 Conflict cleanly inside the atomic transaction when parent rows disappear or template_state_sha256 (effective assignment, published template version, channel config, destination key, or resolved destination) drifts between preview and confirm.
    • Prospective rows (revision is None in preview_token) require current revision == 1, approved_revision is None, raw subject_template / body_template matching the published template version, context_overrides == {}, and cohort.announcement_context == default_cohort_announcement_context(cohort); any post-preview edit skips the row as stale_revision.
  3. Eligibility, Durable JobIntent Scheduling & Idempotent Replay:
    • Only future-anchored (anchor + offset > now) draft/approved rows on active non-self-paced cohorts with valid destinations are approved and enqueued via _enqueue_scheduled_dispatch (idempotency_key = announcement:<id>:<revision>, scheduled_for = recomputed anchor + offset).
    • Rows with missing/past starts, manual edits, cancelled/settled/already-scheduled states, or blocked destinations are safely skipped with explicit reasons (missing_start, past_due, stale_revision, cancelled, settled, already_scheduled, blocked_destination, not_in_preview) without re-arming or catch-up.
    • Same-key idempotent replay returns the stored response (replayed: True) without creating duplicate JobIntent rows. Non-production / flag-off runs remain strictly simulated (simulated_only).
  4. Studio / Admin API / CLI Parity:
    • Verified across 78 Django course-launch tests (32 in test_course_launch_batch_schedule.py + 46 existing course-launch regressions) and 2 live-server HTTP CLI Playwright tests (playwright_tests/test_course_launch_cli.py), exercising both --dry-run preview and --confirmed --preview-token <TOKEN> --idempotency-key <KEY> execution.
Visual & Screenshot Evidence (Inspected via Image Viewer)
  • 8 Graph-Required Screenshots (/home/alexey/git/dtc-website-wt-course-launch-qa2/.tmp/verification/evidence/screenshots/):
    • courses-courses-desktop-1440x900.png: 5f5a9a3e4429b4fb40ede2c4f439b4ae3cdcc8e53d8fc0a6445116b2f12dd470
    • courses-courses-mobile-390x844.png: 19822e0448354cf6d7c53e1e9f4730cce88fb6670a63307ee1fa0b13c7c0042c
    • home-home-desktop-1440x900.png: 1bd927557c21aa4428854564341d32f18cea1bcc119608aa6bb380da7e0878d3
    • home-home-mobile-390x844.png: 8f64b0818a23a3593ea3510c52100ccbbf634fdb17fb630df79e92c3686a5f59
    • studio-studio-sign-in-desktop-1440x900.png: 84253046e0b9865295302aec4670292e631c0ee0af8edc671233ef9f513f4b27
    • studio-studio-sign-in-mobile-390x844.png: 1a10b294003b658f444baa72fe327d0cd3127e291bbfad3fe00f69e2a5677440
    • verification-missing-not-found-desktop-1440x900.png: d22f14f0225528d6abe09ab2d20e6159d3aa93013752c6d8858170093ad06314
    • verification-missing-not-found-mobile-390x844.png: 9a22572bab68bf58f92bd06a025090ad70a0cc2ab0f5901f72db46439e4048ca
  • 4 Studio Batch Preview & Post-Confirm Screenshots (/home/alexey/git/dtc-website-wt-course-launch-qa2/.tmp/screenshots/issue-468/, manifest.json 86d41e9990b7d8fe8b26fc2877966e29998d64b787be66661e5d91d6f48b1503):
    • batch-preview-desktop-1440x900.png: 3e5739975166c6ec5e44b6d8c8a600504b50c8ba7b17e99d8ea205d96b7a7e66
    • batch-preview-mobile-390x844.png: 06c81c9fc65b5094f0925d4e27c24d1a101f64d0a2282041f26f2579d3421c0b
    • batch-confirmed-desktop-1440x900.png: 666414f273591fe7d0e63709ce943cb5232a818c71c1bd4f5240577131996a56
    • batch-confirmed-mobile-390x844.png: 8850c331ea99d23b0ab8854029eb064bcdab627bd926610d92a00ec8cf563828
Rollout Boundary
  • Code and verification evidence are complete and accepted on the frozen 19-file bundle over 054f233d7e8192f832064603c109fdd3f8b02a15. No live announcements or cloud deployments were triggered during QA; production deployment, live sender credentials, and COURSE_ANNOUNCEMENTS_ENABLED activation (website/settings/announcements.py:12) remain explicit human-operated release steps.
Ngôn ngữ chính
Python
Star
0
Fork
0
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Chuẩn bị môi trường

  • Có Dockerfile hoặc tệp Docker Compose
  • Không có mẫu pull request
  • Không có hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của DataTalksClub/website

Tất cả issue của DataTalksClub/website

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.