Plan issue: community-base docs/plan/phase-1.md D1.1. Depends on C1.5, R1.1, R1.2 (all done); the D0.1a package pin (v0.3.0) is on main.
Goal
Replace the site's jobs app (DurableJob machinery on django_q) with the community-base jobs app, executed by Relay.
Scope
- Install
community_base.jobs (P2). Re-point every jobs.registry.register_handler and jobs.dispatch call site to the package, keeping handler names.
- Move schedule semantics to the package: the package's
cb-jobs-run-due / cb-jobs-sweep Relay schedules drive due intents; the site's dtc:durable-job-relay django_q bridge dies with django_q.
- Data migration (P6): copy pending
jobs.DurableJob rows into cb_jobs.JobIntent (raw-SQL migration in a surviving app so it runs after the old app is removed); old tables stay for a later cleanup.
- Settings:
COMMUNITY_BASE["SITE_URL"], RELAY_BASE_URL, RELAY_API_KEY, RELAY_WEBHOOK_SECRET read from the environment (deployment secrets provision the values); JOBS_BACKEND="relay" in development/production, "sync" in test/local.
- Add
sync_relay_schedules to the deploy steps after migrate; remove the qcluster container from deploy task definitions.
- Remove
django_q from INSTALLED_APPS (+ Q_CLUSTER), remove the jobs/ app and its tests; mount the package ingress route and allow internal/jobs/run in the core.middleware request boundary (CSRF exempt, no session).
Non-goals
- Handler business logic does not change — only registration and transport.
- Dropping the orphaned
jobs_durablejob / django_q tables (later cleanup once the copy is verified in development).
- Provisioning the Relay client secret in the dev environment (operator step; the code reads
RELAY_API_KEY from env and dispatch failures are retried until it is set).
Acceptance criteria
Plan issue: community-base
docs/plan/phase-1.mdD1.1. Depends on C1.5, R1.1, R1.2 (all done); the D0.1a package pin (v0.3.0) is on main.Goal
Replace the site's
jobsapp (DurableJob machinery on django_q) with the community-base jobs app, executed by Relay.Scope
community_base.jobs(P2). Re-point everyjobs.registry.register_handlerandjobs.dispatchcall site to the package, keeping handler names.cb-jobs-run-due/cb-jobs-sweepRelay schedules drive due intents; the site'sdtc:durable-job-relaydjango_q bridge dies with django_q.jobs.DurableJobrows intocb_jobs.JobIntent(raw-SQL migration in a surviving app so it runs after the old app is removed); old tables stay for a later cleanup.COMMUNITY_BASE["SITE_URL"],RELAY_BASE_URL,RELAY_API_KEY,RELAY_WEBHOOK_SECRETread from the environment (deployment secrets provision the values);JOBS_BACKEND="relay"in development/production,"sync"in test/local.sync_relay_schedulesto the deploy steps after migrate; remove theqclustercontainer from deploy task definitions.django_qfromINSTALLED_APPS(+Q_CLUSTER), remove thejobs/app and its tests; mount the package ingress route and allowinternal/jobs/runin thecore.middlewarerequest boundary (CSRF exempt, no session).Non-goals
jobs_durablejob/ django_q tables (later cleanup once the copy is verified in development).RELAY_API_KEYfrom env and dispatch failures are retried until it is set).Acceptance criteria
uv run pytest -qpasses (full suite)uv run python manage.py makemigrations --check --dry-runreports no changes beyond the intended migrationgrep -rn "django_q\|from jobs" --include=*.py website/ events/ email_app/ content_sync/ api/shows no stale runtime imports outside the historical migrationmanage.py jobs_ingress_selftest-> OK andsync_relay_schedules --dry-run-> no diff (needs the operator-provisioned Relay client secret; recorded here when run)