Skip to content

JM: Track event registrations with PaperTrail - #2245

Draft
maebeale wants to merge 10 commits into
mainfrom
maebeale/papertrail-event-registrations
Draft

JM: Track event registrations with PaperTrail#2245
maebeale wants to merge 10 commits into
mainfrom
maebeale/papertrail-event-registrations

Conversation

@maebeale

@maebeale maebeale commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

🤖 suggested review level: 5 Inspect 🔬 versioning + person-scoping across ~22 models incl. a User secret skip-list, polymorphic subject resolvers, and a new indexed versions column a person/record timeline depends on

Goal

Make PaperTrail the source for record-change activity (person-level and per-record), working toward a timeline that interleaves PaperTrail (mutations) + Notifications (communications) + Ahoy (visits/views). This PR lays the tracking + person-scoping foundation; the timeline query/UI is the follow-up. Ahoy stays.

Records now versioned (create / update / destroy)

  • Event-registration cluster: EventRegistration, EventAttendanceTimeEntry, EventRegistrationChecklistCompletion, EventRegistrationOrganization.
  • Associated: Scholarship, FormSubmission, FormAnswer, Comment, User (account changes).
  • Money/membership (were already versioned, now person-scoped): Payment, Allocation, Refund, Discount, ContinuingEducationRegistration, Membership, MembershipInvoice, ProfessionalLicense.
  • Person cluster (for timeline parity): Person, Affiliation, Address, ContactMethod, Asset, Organization.
  • Event-side config: Event, EventForm, RegistrationTicketCallout, EventStaff.

Associations related to coordinating a person's event registration

The full graph around EventRegistration. = versioned; subject = how a version reaches a person's timeline (a column, a resolver method, or unscoped where a record relates to many people); new = added in this branch's latest work.

Core

  • EventRegistration ✅ — registrantPerson, belongs_to :event. subject: registrant_id

Financial — all flow through the polymorphic Allocation ledger

  • Allocation ✅ (resolver) · Payment ✅ (person_id) · Scholarship ✅ (recipient_id) · Refund ✅ (resolver) · Discountunscoped (fans out to many people)

Continuing education / attendance

  • ContinuingEducationRegistration ✅ (resolver) · EventAttendanceTimeEntry ✅ (resolver → registrant_id) · ProfessionalLicense ✅ (person_id)

Roster / onboarding

  • EventRegistrationChecklistCompletion ✅ · EventRegistrationOrganization ✅ · Affiliation ✅ (person_id, auto-minted facilitator link) · EventStaffnew (person_id)

Communication / notes

  • Comment ✅ (resolver) · Notificationnot versioned — stays its own timeline source (communications, read directly)

Form intake (linked via registrant + event, not a direct FK)

  • FormSubmission ✅ (person_id) · FormAnswer ✅ (resolver)

Event-side config — subjectless global trail (shared config, fans out to every registrant)

  • Eventnew · EventFormnew · RegistrationTicketCalloutnew

Parents

  • Person ✅ (id) · Eventnew (subjectless)

subject_person_id on versions (new, indexed)

  • One denormalized column so a person's timeline is a single indexed sweep (PaperTrail::Version.where(subject_person_id:)), not a reify-and-walk per row.
  • Populated uniformly via has_paper_trail meta: — direct column where the person is local, a resolver method where it's on a parent or polymorphic (Comment, Allocation, Refund, Address/ContactMethod by type, Asset by owner, CE, membership invoice).
  • Unscoped by design: Discount, Organization, and the event-side config (Event, EventForm, RegistrationTicketCallout) — each relates to many people (or no single one), so no single owner; the money/roster ones surface to a person via their Allocation / Affiliation versions.
  • Verified: create/update/destroy persist subject_person_id; all resolvers checked.

User — secrets & IPs excluded, activity kept

has_paper_trail skip: drops the secrets (encrypted_password + reset/confirm/unlock/welcome tokens) and the two sign-in IPs (PII in an append-only log fights retention/erasure; the live IP still sits on the record). Sign-in timestamps and counts stay versioned — the login-activity signal. Semantic auth-event labels + the 3 events that skipped columns swallow are a follow-up: #2249.

Architecture (agreed)

Final timeline = PaperTrail (record changes) + Notifications (communications, read directly) + Ahoy (visits/views). PaperTrail is mutation-only and won't absorb page views — those stay in Ahoy. Notifications stay their own source (not versioned). So "remove Ahoy" narrows to removing the redundant Ahoy lifecycle/mutation tracking once PaperTrail covers it; Ahoy's visit/view tracking lives on.

Notes / follow-ups

  • create and destroy recorded by default → full lifecycle incl. deleted records. The Change Log partial's versions.size > 1 guard is display-only.
  • Timeline query/UI not built yet (person: by subject_person_id; record: by item + children; deleted-record viewer).
  • Residual attachment gap: Person avatar / Organization logo are direct has_one_attached (not columns), so their attachment changes aren't versioned — revisit with the attachment question.
  • User semantic auth events: Restore semantic User auth events on the PaperTrail timeline #2249.

Copilot AI lite review requested due to automatic review settings August 17, 2026 12:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 17, 2026 13:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 17, 2026 13:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 17, 2026 13:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 17, 2026 13:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

maebeale and others added 6 commits August 18, 2026 06:21
Give EventRegistration a versioned audit trail (status, payment flags,
attendance, certificate, scholarship changes) and surface it as the
existing Change Log dropdown on the registration edit page. Ahoy stays on
these records; PaperTrail adds a per-record, reify-able history alongside
it. Start with the parent record only and expand to child records as we
see what the log reads like.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extend the registration audit trail to its child records so a full
timeline can reconstruct what changed and by whom, including after a
record is deleted (destroy versions persist in the versions table).

- EventAttendanceTimeEntry: sign-in/out corrections
- EventRegistrationChecklistCompletion: onboarding step completions
- EventRegistrationOrganization: org link add/remove
- Comment: comment history (app-wide, polymorphic — not registration-only)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A scholarship's award amount, agreement signature, and task completion
are part of a registration's story via the allocation that links them.
Track the scholarship so the timeline captures award/acceptance changes;
its comments and joining allocation are already versioned.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Track the submission envelope (event linkage, metadata, create/delete) so
the timeline and audit trail can see when a registrant submitted or a
submission was removed. The answer rows live in form_answers (untracked
here — see PR note).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Foundation for making PaperTrail the single activity-timeline source
(retiring Ahoy) with both person and per-record timelines.

- FormAnswer: version the actual submitted answers (envelope was already
  tracked on FormSubmission).
- User: version account changes, skipping only secrets (password + reset/
  confirm/unlock/welcome tokens). Sign-in timestamps, counts, and IPs are
  kept as the login-activity signal (parity with Ahoy).
- Add versions.subject_person_id (indexed) so a person's timeline is one
  indexed sweep instead of reifying and walking associations. Every
  timeline-tracked model populates it uniformly via has_paper_trail meta;
  Comment resolves its polymorphic commentable to the subject person.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add subject_person_id meta to the already-versioned money/membership models
so their versions land on a person's activity timeline:

- Payment, Membership, ProfessionalLicense: direct person_id
- MembershipInvoice (member), ContinuingEducationRegistration (registrant):
  delegated resolvers
- Allocation, Refund: polymorphic resolvers walking allocatable/refundable
  (and Refund's own person recipient) to the subject person
- Discount stays unscoped by design (fans out to many people; scoped via its
  Allocation versions)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@maebeale
maebeale force-pushed the maebeale/papertrail-event-registrations branch from 3b08b6d to 72872ce Compare August 18, 2026 10:25
Copilot AI review requested due to automatic review settings August 18, 2026 10:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An IP is PII and the versions table is append-only, so versioning it fights
data-retention/erasure. Skip the two sign-in IP columns; the live IP stays on
the user record. Sign-in timestamps and counts remain versioned as the
login-activity signal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 18, 2026 10:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Drop the six self-evident subject_person_id delegator comments; condense the
polymorphic resolver, User skip-list, Discount, and migration comments to the
gotcha they actually carry, per the comment policy.
Copilot AI review requested due to automatic review settings August 18, 2026 10:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Extend PaperTrail + subject_person_id to the records a person's timeline needs
beyond registrations: Person (self), Affiliation (person), Address/ContactMethod
(polymorphic — person-owned only), Asset (owner's person). Organization is
tracked but unscoped — it has many affiliates, so it surfaces to a person via
their affiliation, not a single subject_person_id.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 18, 2026 10:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Completes the event-registration coordination graph. EventStaff is
person-scoped (a staffing role belongs on that person's timeline); Event,
EventForm, and RegistrationTicketCallout have no single person, so they get a
subjectless global trail like Discount.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 18, 2026 11:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@maebeale
maebeale requested a review from jmilljr24 August 18, 2026 11:35
@maebeale

Copy link
Copy Markdown
Collaborator Author

@jmilljr24 looks like this is what would be needed to properly track registration lifecycles (with an eye to person timelines and addition of subject_person_id)

@jmilljr24

Copy link
Copy Markdown
Collaborator

@maebeale check my slack message

@maebeale maebeale changed the title Track event registrations with PaperTrail JM: Track event registrations with PaperTrail Aug 18, 2026
@maebeale
maebeale marked this pull request as ready for review August 18, 2026 14:48
@maebeale
maebeale marked this pull request as draft August 18, 2026 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants