Skip to content

Track and visualise member activity: append-only activity log + admin weekly strip #2857

Description

@mroderick

Problem

Admins can't tell which organisers are still active. Outreach to dormant organisers is guesswork — is someone quiet because they've drifted away, or because their chapter simply hasn't run a workshop lately? The same gap hides dying chapters and makes trustee reporting harder.

The app has no sign-in tracking, and most organiser and member actions leave no attributable trace. What history exists is scattered across tables with different shapes (invitations, invitation_logs since March 2026, member notes), and some actions — feedback submissions, waiting-list promotions — have no actor attribution at all.

What we're building

Two things, delivered as one data layer plus one view:

  1. An append-only activity log. Every member, organiser, and admin action that we can attribute lands as one row in the existing activities table (public_activity, already installed and used for sponsor audits): owner = the acting member, key = a dotted action name (member.login, workshop_invitation.rsvp, organiser_role.granted, …), trackable = the affected object, recipient = the affected member for actions on others. A single MemberActivityRecorder funnel with a fixed key vocabulary keeps call sites consistent; recording failures are logged, never raised, so activity tracking can't break a user flow.
  2. A weekly activity strip on the admin member profile (/admin/members/:id, organisers only): 52 ISO-week cells, GitHub-contribution style. Cells have three states — empty, dim (logins/logouts only), solid (any other action) — so an admin can see at a glance whether a member is active, merely present, or gone quiet, with per-week tooltips for detail.

Key decisions

  • Reuse the activities table rather than add a new member_actions table — the gem's schema (owner/key/trackable/recipient) is exactly the event log we need, and one migration covers everything.
  • Log-only history. The log starts at deploy; earlier weeks read as empty and self-heal. No backfill, no union with legacy tables.
  • All member activity counts, not just organiser actions — RSVPs, subscriptions, and check-ins light cells too. Profile edits are included deliberately: that signal helps reveal misuse and account takeovers.
  • Admin entity CRUD is excluded (chapters, sponsors, announcements…): it says more about entity management than member activity. Known gap with a built-in check — if the /admin/organisers overview shows admins drifting to "quiet" while clearly working, we revisit.
  • Feedback submissions and waiting-list auto-promotions stay invisible — no actor attribution exists today.

PR stack

PR Scope
#2850 Recorder + session lifecycle (member.login/logout, provider-unlink site)
#2851 Subscriptions, mailing lists, profile edits, TOC acceptance
#2852 Event/meeting RSVPs, token-based workshop RSVPs, waiting lists, check-ins
#2853 Admin actions: organiser roles, bans, RSVP overrides, verification, notes, admin subscription/meeting-invitation changes
#2854 Workshop creation + created_by_id stamp, invitation batch sends
#2855 Weekly strip on the admin member profile

Merge bottom-up — each PR builds on the previous.

Out of scope

The /admin/organisers overview table, chapter health quantification, per-action-type detail views, anything member-facing, and GDPR erasure of activities.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions