rubyforgood / rubyforgood/awbw
[Parked] Restore semantic User auth events on the PaperTrail timeline
Nobody has claimed this yet.
- Dominant language
- Ruby
- Stars
- 15
- Forks
- 26
- Avg merge
- 12h 42m
- Merged PRs (30d)
- 242
Description
🤖 From Claude:
Status (2026-08-23): parked — staying on Ahoy for now. The activity timeline is not moving onto PaperTrail; the Ahoy-based change log (shipped in #2245) is what we're keeping. This issue is therefore decoupled from #2245 and only becomes relevant if a PaperTrail-based timeline is revived later. Left open as a record of what that migration would need.
Background
If the activity timeline were moved onto PaperTrail (not planned right now — see status above), three of Ahoy's semantic auth.* events wouldn't survive the move — they change skipped columns or bypass PaperTrail entirely, so no version is written at all:
| Ahoy event | Trigger | Why no version |
|---|---|---|
auth.password_changed |
encrypted_password change |
encrypted_password is in has_paper_trail skip: (secret) |
auth.password_first_set |
encrypted_password (welcome flow) |
same skip |
auth.account_setup_completed |
welcome_instructions_token cleared |
done via update_columns — bypasses callbacks/PaperTrail |
Separately, the column-backed auth events (login, admin granted/revoked, locked/unlocked, deactivated/reactivated, email changed/confirmed, reset sent, welcome sent, account deleted) do produce versions — but as raw column diffs (super_user: false → true), not the semantic label Ahoy emitted.
Do we have the timestamps we'd need? No.
Present *_at columns cover most events, but two are missing:
password_changed_at— needed forpassword_changed/password_first_setsetup_completed_at(orwelcome_completed_at) — needed foraccount_setup_completed
Proposed plan
- Add non-secret timestamp columns
password_changed_atandsetup_completed_at, stamped whenever those events happen. Stamping them creates a real (non-secret) version, restoring the three lost events. Fix theupdate_columnsbypass so the setup-completion write goes through a normalupdate(or explicitly stamp the timestamp). - Semantic labels for the timeline. Two options — decide in this issue:
- (a) Derive in the timeline presenter from the version's changeset (e.g.
super_usertrue→false ⇒ "Admin revoked"). No schema change; labeling logic lives in one place with the rest of the timeline rendering. - (b)
action_notemeta column onversions, populated at write time viahas_paper_trail meta:(a proc that names the semantic event). Captures intent the diff can't always recover, but duplicates labeling logic and only helps User. - Recommendation: (a) for the column-backed events (the diff already says what happened), plus the new timestamps from step 1 for the three bypass cases. Reserve
action_notefor cases where intent genuinely isn't recoverable from the diff. password_first_setvspassword_changedis still derivable under (a): thepassword_changed_attransition disambiguates them —nil → Tis first-set,T → T'is a change — so this pair doesn't needaction_note.
- (a) Derive in the timeline presenter from the version's changeset (e.g.
- Attribute the actor (
whodunnit) on self-serve Devise flows. The lost/column-backed events fire in controllers that run without a logged-in user —PasswordsControllerandWelcomeControllerbothskip_before_action :authenticate_user!(and confirmation/unlock link flows are the same).set_paper_trail_whodunnitreadscurrent_user, so every version these flows write lands with nil whodunnit and the timeline's "By" column comes up blank — where Ahoy attributed the actor. SetPaperTrail.request.whodunnitto the resource itself (self-serve) in these actions, mirroring the existingupdated_by: current_user || @userpattern already used inwelcome_controller.rb. Without this, restoring the events isn't enough — they'd read as "by (nobody)". - Keep the User
skip:list as-is (secrets stay out of the trail); the new timestamps are the non-secret signal.
Out of scope
- Attachment add/remove (avatar/logo) — separate residual gap, tracked with the broader attachment question.
- Analytics vs. audit: PaperTrail replaces the account change timeline only. Ahoy's page views / prints / downloads / search intent / visits, and its association + rich-text change capture, have no version equivalent and stay on Ahoy. "Retire Ahoy" is scoped to the change-audit timeline, not engagement analytics.
- Not tied to #2245 — that PR ships the Ahoy-based change log we're keeping; this is speculative future work for a PaperTrail timeline.
Contributor guide
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
The issue is explicitly parked while the Ahoy-based timeline remains in use, so no implementation should start unless a PaperTrail migration is revived. If revived, begin with PasswordsController, WelcomeController, and the User PaperTrail skip list; resolve the timestamp, semantic-label, and whodunnit decisions before changing the version timeline. Done would restore the listed auth events with meaningful labels and actor attribution without recording secrets.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ruby
- Domain
- authentication, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100