DataTalksClub / DataTalksClub/website
Add event registration operations, attendance, exports, and notification triggers
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
Parent epic: #6
Normative authority:
_docs/specs/05-events-registration-email.md, especially accountless registration, Event changes, durable delivery, and sender/provider boundaries;_docs/specs/06-studio-and-admin-api.md, for Event-operator/support capabilities, bulk-operation resources, parity, audit, and formula-safe export;_docs/specs/07-security-privacy-operations.md, for PII minimization, retention, no-store responses, high-risk controls, and redaction;_docs/specs/09-migration-rollout-roadmap.md, Milestone 6 and historical aggregate rollout;_docs/specs/10-verification-strategy.md, especially Event/email, management, export, and browser evidence; and_docs/PROCESS.md.
Accepted policy/foundation inputs: #23, #28, #31, #86, and #87.
PM disposition
GROOMED / P0 / DEPENDENCY-BLOCKED. Do not dispatch engineering yet.
#47 owns protected Event-registration operations and the deterministic, non-sending domain trigger contract for later Event messages. It does not own Relay routing, template/version selection, EmailDelivery, a sender, or provider activation.
The former blanket dependency on #49–#50 was circular. #50 consumes the accepted #47 trigger contract; it cannot be a prerequisite for producing that contract. #49 supplies the generic delivery service consumed downstream by #50. Neither issue is authority to send.
There is no valid immediate model/parser/fixture child before #45 and #46 are accepted. Lookup, correction, attendance, exports, audience snapshots, ICS sequence, and trigger idempotency all require the accepted Event and native-registration identities, revisions, lifecycle states, and retention rules. Engineering must not duplicate those models or guess their seams.
Outcome
Give authorized Event operators shared application services, exposed with Studio/admin-API parity, to:
- perform bounded, authorized registration lookup and counts with masked PII by default;
- correct allowed fields, cancel/reactivate registrations with a required reason, and preserve revision/audit history;
- import or mark attendance through bounded, replay-safe, partial-failure-aware operations;
- generate formula-neutralized, permission-gated registration exports;
- preview, confirm, start, resume, inspect, and cancel Event reschedule, cancellation, reminder, and follow-up operations; and
- atomically create one immutable non-sending Event-message trigger per intended registration/purpose/Event revision/registration version/calendar sequence.
The trigger is a domain handoff, not an email intent. It contains only stable domain references, purpose, audience/version/idempotency scalars, the deterministic ICS action/sequence where applicable, and minimal secret-free typed context allowed by retention policy. It contains no rendered subject/body, template key/version, resolved sender, credential, provider state/payload, or network behavior.
Exact ownership and dependency DAG
“Accepted” means independently tested, PM-accepted, committed, locally merged/pushed, terminal-green, and identified by the exact merge/interface identity.
accepted #45 Event lifecycle/revision/calendar/change service
+ accepted #46 native EventRegistration identity/lifecycle/version/retention service
+ accepted #28 high-risk policy and #86/#87 management foundations
-> #47 protected operations + immutable non-sending trigger contract
accepted #48 template consumer contract
+ accepted #49 ordinary durable delivery
+ accepted #47 trigger contract
+ accepted #227 recipient preference/eligibility service
-> #50 Event-purpose route/template/sender/context mapping and delivery integration
accepted automated/source #50 + accepted #60 rehearsal + operational safeguards
-> separately authorized development canary -> #50 HUMAN acceptance
-> #73 outbound-disabled aggregate rehearsal
-> separately authorized #74 production activation/cutover
Dependency corrections:
- #45 and #46 are the only hard domain prerequisites for #47 engineering. #46 already owns its own #45/#49/#227 gates; #47 does not weaken or bypass them.
- #28 is closed accepted policy, not an open blocker. Closed #86/#87 provide the capability, operation, audit, and admin-API foundations used by this domain issue.
- #32/#33 later complete production staff identity, credentials, and high-risk acceptance across registered capabilities. They are not prerequisites for deterministic #47 domain source work with synthetic actors, but production use cannot precede their accepted controls.
- #48 is not a direct dependency. #49 and #48 remain downstream delivery infrastructure from #47’s perspective.
- #50 is strictly downstream of the accepted #47 trigger contract. #47 creates no
EmailDeliveryand selects no Relay route/template/sender. #50 must not recreate Event mutations, audience snapshots, calendar sequencing, or registration rules. - #111 may extend accepted #46/#47 private forms and sponsor export under its own exact affirmative-consent contract. It is not a blanket #47 prerequisite.
- #112 remains an independent aggregate-only historical lane. Its exact public
N registeredvalue never supplies native rows, attendance, PII, an audience, or a trigger. - #73 and #74 are rehearsal/activation consumers only. They never block source implementation and never grant sender, provider, protected-data, credential, or production authority.
Valid non-sending source lane
After #45 and #46 are accepted and pinned, #47 itself is a bounded source-only/non-sending lane. It may implement the services, models required solely for operation/audit/attendance/trigger state, Studio/admin adapters, synthetic fixtures, and deterministic tests in this issue. It may be closed with Closes #47 after its independent tester and PM gates because actual routing/delivery is explicitly owned by #50.
This lane must remain inert:
- no
EmailDeliveryor provider queue/job creation; - no Relay, Datamailer, SES, Mailchimp, webhook, credential, sender, or network call;
- no live recipient, protected source, production row, queue, or provider access;
- no template key/version, sender ID, rendered body, or provider-specific payload in the trigger; and
- no claim that a green source candidate enables an Event purpose.
Before #45/#46 acceptance, even this lane is invalid: a speculative operation or trigger schema would freeze unaccepted identity/version/retention semantics.
Protected registration operations
- Authorize the queryset before lookup. Management routes use Event/registration UUIDs; public Event ID/slug and email are never management selectors.
- Separate permissions for masked lookup/count, full PII, correction, cancellation/reactivation, attendance, export, and change/notification operations. Support sees masked values by default.
- Correction is field-bounded, reasoned, revision-guarded, audited, and cannot silently change Event identity, normalized-email uniqueness, ownership, consent/preference, or registration version.
- Cancellation/reactivation use #46’s lifecycle service and version rules; no adapter writes models directly.
- Attendance import/marking is bounded, resumable, idempotent, duplicate/unknown-safe, and returns capped per-row safe errors. It never infers attendance from registration or #112 provider statuses.
- Export is bounded, formula-neutralized, private/no-store/noindex, explicitly confirmed, audited, and contains only fields authorized for that export. There is no generic newsletter/sponsor export.
- Events/registrations with retained history are archived or transitioned according to the owning lifecycle; #47 performs no physical deletion outside accepted privacy services.
Event operations and trigger contract
- Reschedule/cancellation snapshots the accepted #45 Event revision and calendar sequence plus the accepted #46 active-registration audience/version under one transactional boundary.
- The operation advances the calendar sequence exactly once where required and creates exactly one immutable trigger for each intended active registration/purpose/sequence. Rollback creates neither the Event change nor triggers.
- Reminder/follow-up audience cutoffs and purpose/version inputs are explicit and snapshot once. Replay, resume, worker restart, and concurrent starts converge through database constraints and stable idempotency values.
- A trigger records only the domain facts #50 needs to map an accepted purpose. A changed Event/registration/audience/sequence conflicts or creates the next version; it is never hidden under an existing key.
- Bulk work is resumable, cancellable where safe, rate-aware, bounded, and exposes progress, safe counts, capped errors, and a deterministic result. Cancellation stops unclaimed work; it does not rewrite completed facts.
- #47 performs no recipient-preference evaluation or delivery submission. #50 later evaluates #227 eligibility and invokes #49 under its own atomicity/idempotency contract. A suppressed or unavailable route remains downstream and cannot mutate the accepted Event operation.
Public and privacy boundary
No management lookup, count, answer, attendance, export, operation, or trigger becomes public. Public Event pages expose no attendee identity, name, initial, avatar, profile, directory, search, list, or export. #112 alone may expose its separately reconciled, non-identifying exact N registered aggregate.
#111 sponsor export may contain only current affirmative Event+sponsor+statement-version evidence and its minimum approved audit columns. Ordinary answers, registration, attendance, newsletter state, or missing/negative/revoked consent never imply sponsor sharing.
All protected responses are private/no-store/noindex. Logs, audit, operation errors, screenshots, and issue evidence exclude raw email, token, answer, exported row, source locator, complete query, trigger context, or reversible protected identifier.
Acceptance criteria
- Exact accepted #45 Event service and #46 EventRegistration model/service/migration identities are recorded before engineering; no duplicate Event/registration lifecycle or guessed version seam is introduced.
- Authorized lookup/count, masked/full PII, correction, cancellation/reactivation, attendance, export, and change-operation permissions are distinct and authorize the queryset before object lookup.
- Correction and lifecycle commands are reasoned, revision-guarded, idempotent, audited, and preserve uniqueness, ownership, consent/preference, retention, and version invariants.
- Attendance marking/import is bounded, resumable, replay-safe, duplicate/unknown-safe, partial-failure-aware, and never inferred from registration or historical aggregate/provider status.
- CSV exports are bounded, explicit-confirmation gated, formula-neutralized, audited, redacted by capability, private/no-store/noindex, and contain no unapproved newsletter/sponsor/answer data.
- Reschedule/cancellation atomically applies one accepted Event revision/calendar-sequence change and creates exactly one immutable non-sending trigger per intended active registration/purpose/version/sequence; rollback creates neither.
- Reminder/follow-up/change operations snapshot an explicit audience and cutoff, and replay/resume/concurrency/worker crash/cancellation converge with deterministic progress, capped safe errors, and no duplicate trigger.
- Trigger rows/context contain only approved domain references and secret-free typed scalars; no template, rendered body, sender, credential, provider payload/state,
EmailDelivery, outbound job, or network action exists in #47. - Studio and admin API use the same application services and have capability, object, field, revision, idempotency, confirmation, audit, operation-resource, error, and result parity.
- #111 sponsor evidence and #112 aggregate totals remain isolated; no public identity/list/export path exists and no historical aggregate creates native registration, attendance, audience, or trigger state.
- Repository/network-negative tests prove no Relay, Datamailer, SES, Mailchimp, webhook, provider, or direct-send path is reachable; production staff/provider/protected-data activation remains downstream.
- Focused Django, migration, concurrency/security/redaction/export, service/API parity, and graph-selected Playwright/container checks pass through one current verification plan and independent tester gate.
Required service scenarios
- No/one/many registrations; masked/full/denied lookup; cross-Event UUID; stale revision; correction conflict; cancel/reactivate replay; archived/expired/cancelled/attended/no-show states.
- Attendance zero/duplicate/unknown/wrong-Event/malformed/oversized/partial batch, interruption, resume, cancellation, replay, and formula-like values.
- Export no/one/many rows, masked/full scope, malicious spreadsheet cells, stale confirmation, duplicate command, cancellation, capped artifact, audit/redaction, and forbidden sponsor/newsletter/answer columns.
- Reschedule and cancellation rollback, concurrent starts, audience change before/after snapshot, Event/registration version change, repeated ICS update/cancel, crash at each operation boundary, resume, and duplicate-trigger rejection.
- Reminder/follow-up cutoff, empty audience, stale Event revision, registration cancellation/reactivation during work, operation cancel, and deterministic safe result/error counts.
- Assert zero delivery/job/queue/network/provider effect for success, rollback, replay, crash, and denial; assert trigger output is sufficient and deterministic for later #50 mapping without naming a template or sender.
- Sponsor affirmative/missing/negative/revoked/stale evidence and #112 zero/one/many/incomplete aggregate coexistence; prove neither affects ordinary export, attendance, audience, or trigger creation.
Browser and screenshots
Using synthetic data and deterministic local fakes only, the independent tester exercises Studio at approximately 1440x900 and 390x844: masked/full registration views, correction, cancel/reactivate, attendance import/results, export preview/confirmation/result, Event-change preview/count/confirmation, operation progress/resume/cancel/result, stale/denied/unavailable/partial-failure states, keyboard/focus/error summary, JavaScript-off paths selected by the graph, and zoom/reflow. Equivalent admin API positive/negative/parity cases are required.
Every graph-selected screenshot is stored under .tmp/screenshots/, inspected, and contains the intended page with no email, token, answer, exported row, source locator, trigger context, secret, credential, template/body, provider data, or debug output.
Lifecycle
- Keep #47 unassigned until #45 and #46 are accepted/integrated and PM pins their exact merge/model/service/migration identities on a clean current main.
- Dispatch one isolated #47 source-only/non-sending engineer lane. The engineer uses synthetic fixtures/fakes, implements/tests without committing, and posts the versioned verification handoff.
- A separate tester recomputes the plan, validates every criterion, runs focused and graph-selected checks, and captures/inspects required screenshots.
- PM accepts only a complete tester PASS with no required skip or pending evidence.
- The engineer creates a focused
Closes #47commit; the orchestrator locally merges with--no-ff, pushes, and on-call observes terminal-green CI. - #50 consumes the immutable #47 trigger identity and owns purpose routing/delivery integration. Its source acceptance, separately authorized development canary, #73 rehearsal, and #74 production activation remain separate later gates.
Explicit non-goals
- No Event or EventRegistration model/lifecycle duplication; no guessed identity, registration version, audience, preference, or retention semantics.
- No public attendee identity/directory/search/list/export or attendance-derived public copy.
- No capacity/waitlist, marketing campaign, generic newsletter export/question, or sponsor consent inference.
- No Relay route/template/version/sender mapping,
EmailDelivery, callback/reconciliation, provider attempt/event store, direct send, or fallback sender. - No live email/recipient, provider/Relay/Datamailer/SES/Mailchimp access, credential readback, protected source/production data, deployment, canary, freeze/drain, sender activation, or production mutation.
- No inference that #47 source acceptance satisfies #50, authorizes #73, or permits #74 production work.
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 _docs/specs/05-events-registration-email.md, _docs/specs/06-studio-and-admin-api.md, _docs/specs/07-security-privacy-operations.md, and the verification strategy, but wait for accepted #45 and #46 identities before locating implementation seams. Done means the protected operations and non-sending trigger contract meet the listed acceptance criteria, with deterministic tests and no delivery or provider behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend, databases, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100