Skip to content

feat: add database-backed invitation logging and resilient bulk invitations#2546

Open
mroderick wants to merge 6 commits intocodebar:masterfrom
mroderick:fix/workshop-invitation-resilience
Open

feat: add database-backed invitation logging and resilient bulk invitations#2546
mroderick wants to merge 6 commits intocodebar:masterfrom
mroderick:fix/workshop-invitation-resilience

Conversation

@mroderick
Copy link
Copy Markdown
Collaborator

@mroderick mroderick commented Mar 30, 2026

Summary

Fixes #2542 - Adds database-backed logging for workshop invitations and makes bulk invitation creation resilient to individual failures.

This enables administrators to:

  • See who initiated an invitation job and when
  • Track which workshop/chapter invitations were sent for
  • Monitor success/failure/skip counts in real time
  • View failed invitations with detailed error reasons
  • Automatically clean up logs after 180 days

Additionally, bulk invitation creation now continues gracefully if any individual member fails, rather than crashing the entire batch.

Problem

When sending workshop invitations in bulk, two problems existed:

  1. No logging - There was no way to track which invitations were sent, who initiated them, or which ones failed. Debugging invitation issues required manual database queries.

  2. Fragile batch processing - If any single member failed during invitation creation (e.g., due to a database constraint violation), the entire process would crash. The remaining members would never receive invitations.

For example, if sending invites to 700 members and the 300th member's invitation creation failed, the remaining 400 members would never be invited.

Solution

Invitation Logging

Added a polymorphic logging system with two models:

  • InvitationLog - Tracks a batch of invitations (who initiated, when, for what workshop, success/failure counts, status)
  • InvitationLogEntry - Tracks each individual invitation attempt (member, status, failure reason, processed_at)

The InvitationLogger service integrates with InvitationManager to log every workshop/virtual workshop email send. Logs are viewable from the admin workshop page.

Resilient Bulk Invitations

  • Use find_or_create_by to handle duplicate invitations safely
  • Wrap invitation creation in begin/rescue to catch StandardError
  • Log errors with context (workshop_id, member_id) but NO PII
  • Continue processing remaining members after individual failures

Changes

Commit Description
5db15526 Migration, models (InvitationLog, InvitationLogEntry), fabricators, model specs
9312a829 InvitationLogger service with batch tracking, service specs
c3bbc8d9 Integration into InvitationManager, Workshop association, controller params, integration specs
234fca52 Admin UI (controller, policy, views, routes, seeds), controller & policy specs
189a0ba4 Cleanup job (180-day retention), rake task, job specs

Total: 42 tests passing across all commits

How to Verify

Set up an admin user

# In rails console:
bundle exec rails console

# Make yourself admin:
Member.find_by(email: "your@example.com").add_role(:admin)

View invitation logs

  1. Start the server: bundle exec rails server
  2. Navigate to any workshop: /admin/workshops/:id
  3. You should see an "Invitation Logs" section with recent logs
  4. Click "View All Logs" to see the full list
  5. Click any log to see detailed entries (success/failure/skip per member)
image

Seed data

bundle exec rake db:seed

This creates sample invitation logs across past workshops.

Cleanup expired logs

bundle exec rake invitation_logs:cleanup

Run tests

bundle exec rspec spec/models/invitation_log_spec.rb \
  spec/models/invitation_log_entry_spec.rb \
  spec/services/invitation_logger_spec.rb \
  spec/models/invitation_manager_logging_spec.rb \
  spec/controllers/admin/workshop_invitation_logs_controller_spec.rb \
  spec/policies/invitation_log_policy_spec.rb \
  spec/jobs/cleanup_expired_invitation_logs_job_spec.rb

All 42 tests pass.

- Use find_or_create_by instead of create to handle duplicate invitations
- Add exception handling to catch database errors and continue processing
- Log errors at ERROR level with member_id and context IDs (workshop/event/meeting)
- Add tests for exception handling and bulk resilience
- Update existing tests to use find_or_create_by

This fixes issue codebar#2542 where workshop invitations would fail silently if any
individual member's invitation creation raised an exception, causing the
entire bulk invitation process to abort and leaving remaining members without
invitations.
@mroderick mroderick marked this pull request as ready for review March 30, 2026 17:45
@mroderick mroderick requested a review from jonodrew March 30, 2026 17:49
@mroderick mroderick marked this pull request as draft March 30, 2026 19:18
@mroderick
Copy link
Copy Markdown
Collaborator Author

Putting this back to draft, I have more improvements up my sleeve

mroderick and others added 5 commits March 31, 2026 00:08
- Create invitation_logs and invitation_log_entries tables
- Add InvitationLog model with enums, associations, expiration callback
- Add InvitationLogEntry model with status tracking
- Add fabricators for test data
- Add model specs

Co-Authored-By: opencode <noreply@opencode.ai>
- Service for logging invitation batch operations
- Tracks success/failure/skip counts per batch
- Provides convenience methods for starting/finishing/failing batches

Co-Authored-By: opencode <noreply@opencode.ai>
- Add invitation_logs association to Workshop model
- Integrate InvitationLogger into workshop email sending
- Pass current_user.id for audit trail
- Handle WorkshopPresenter via workshop.model in scope

Co-Authored-By: opencode <noreply@opencode.ai>
- Add WorkshopInvitationLogsController with index/show actions
- Add InvitationLogPolicy for authorization
- Add views for listing and detail of invitation logs
- Add route nesting under admin/workshops
- Add seed data for invitation logs
- Add controller and policy specs

Co-Authored-By: opencode <noreply@opencode.ai>
- Add CleanupExpiredInvitationLogsJob for 180-day retention
- Add rake task invitation_logs:cleanup
- Add job specs

Co-Authored-By: opencode <noreply@opencode.ai>
@mroderick mroderick changed the title fix: make bulk invitation creation resilient to individual failures feat: add database-backed invitation logging and resilient bulk invitations Mar 30, 2026
@mroderick mroderick marked this pull request as ready for review March 30, 2026 22:17
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.

Large numbers of members not being invited to workshops

1 participant