This roadmap outlines incremental phases to integrate alum-events functionality into Alumni Lookup. Each phase is testable and deployable independently.
Represents any person who may attend events. Matches BruinQuest terminology.
create_table :contacts do |t|
t.string :bqid # C-000000000 format (unique if present)
t.references :alumni, null: true, foreign_key: true
t.string :first_name, null: false
t.string :last_name, null: false
t.string :email
t.string :phone
t.string :contact_type, null: false, default: 'unknown'
# Types: alumni, parent, student, staff, guest, vip, unknown
t.timestamps
t.index :bqid, unique: true, where: "bqid IS NOT NULL"
t.index :alumni_id, unique: true, where: "alumni_id IS NOT NULL"
t.index [:email, :first_name, :last_name]
end
Represents a specific event occurrence.
create_table :events do |t|
t.string :name, null: false
t.date :event_date
t.string :badge_template
t.text :description
t.timestamps
end
Links a Contact to an Event with attendance status.
create_table :registrants do |t|
t.references :event, null: false, foreign_key: true
t.references :contact, null: false, foreign_key: true
t.string :unique_id # Group/registration ID from GiveCampus
t.string :affiliation_raw # Original GiveCampus affiliation value
t.datetime :checked_in_at
t.datetime :printed_at
t.datetime :regrets_at
t.string :status
t.timestamps
t.index [:event_id, :contact_id], unique: true
t.index [:event_id, :unique_id]
end
# Contact
class Contact < ApplicationRecord
belongs_to :alumni, optional: true
has_many :registrants, dependent: :destroy
has_many :events, through: :registrants
validates :first_name, :last_name, presence: true
validates :bqid, uniqueness: true, allow_nil: true
validates :bqid, format: { with: /\AC-\d{9}\z/ }, allow_nil: true
enum contact_type: {
unknown: 'unknown',
alumni: 'alumni',
parent: 'parent',
student: 'student',
staff: 'staff',
guest: 'guest',
vip: 'vip'
}
end
# Event
class Event < ApplicationRecord
has_many :registrants, dependent: :destroy
has_many :contacts, through: :registrants
validates :name, presence: true
end
# Registrant
class Registrant < ApplicationRecord
belongs_to :event
belongs_to :contact
validates :contact_id, uniqueness: { scope: :event_id }
scope :checked_in, -> { where.not(checked_in_at: nil) }
scope :not_checked_in, -> { where(checked_in_at: nil, regrets_at: nil) }
scope :regrets, -> { where.not(regrets_at: nil) }
end
# Alumni (add association)
class Alumni < ApplicationRecord
has_one :contact, dependent: :nullify
# ... existing associations ...
end
Duration: 1 week
docs/README.md with new planning folderCHANGELOG.mdDuration: 2-3 weeks
Alumni recordsEngagementActivity recordsMigrations:
contacts tableevents tableregistrants tableusers table:
can_event_checkin (boolean, default: false)can_event_manage (boolean, default: false)Models:
Contact with belongs_to :alumni (optional)Event with has_many :registrantsRegistrant with belongs_to :event, belongs_to :contacthas_one :contact to AlumniAuthorization (Hybrid Model - Roles + Permission Flags):
Event permissions follow the hybrid authorization model documented in PERMISSIONS_MATRIX.md. Auth & Roles project establishes the infrastructure; this phase adds event-specific flags.
users table (extending existing pattern):
can_event_checkin: boolean, default falsecan_event_manage: boolean, default falseuser.can_event_checkin? → true if flag is set OR user is adminuser.can_event_manage? → true if flag is set OR user is adminEventPolicy — controls access to event CRUDRegistrantPolicy — controls check-in actionsevent_checkin: search, check-in, mark printed, view statsevent_manage: create/edit events, import, export, settingsService:
EventAttendanceService — creates EngagementActivity on check-in
event_attended| Type | Expectation |
|---|---|
| Model tests | Contact, Event, Registrant validations and associations |
| Policy tests | EventPolicy, RegistrantPolicy permission checks |
| Service test | EventAttendanceService creates activity correctly |
| Documentation | Update MODEL_RELATIONSHIPS.md with new associations |
| Documentation | Update PERMISSIONS_MATRIX.md with event permissions |
| Changelog | Add migration notes to CHANGELOG.md |
Duration: 2-3 weeks
Alumni records via BQID/BUID/name+emailService: GiveCampusCsvImporter
contact_type from affiliation fieldController: Events::ImportsController
new — file upload formcreate — process CSV, show resultsService: EventExporter
Controller: Events::ExportsController
show — download CSV for eventUI:
| Type | Expectation |
|---|---|
| Service tests | CSV parsing, 5-step matching logic, edge cases (missing IDs, duplicates) |
| Request tests | Import and export endpoints |
| Fixtures | Sample GiveCampus CSV for testing |
| Documentation | Create docs/features/EVENT_IMPORT_EXPORT.md documenting CSV format and workflow |
Duration: 3-4 weeks
Routes: Namespaced under /events/
Controllers:
EventsController — CRUD for events, set active event in sessionEvents::CheckinsController — search, check-in, walk-in, undo actionsEvents::PrintController — print list, mark as printedEvents::StatsController — real-time attendance statsSession-based event:
session[:active_event_id]Search & Navigation:
Action Bar (per registrant):
Print List:
Real-Time Stats View:
Mobile Optimization:
**Walk-in Flow:
Service updates:
EventAttendanceService called on check-in (creates EngagementActivity for alumni)Registrant#checked_in_at, #printed_at, #regrets_at| Type | Expectation |
|---|---|
| System tests | Full check-in flow with Capybara, print list auto-refresh |
| Controller tests | Search, check-in, walk-in, undo actions, stats endpoint |
| JavaScript tests | Auto-refresh polling, filter toggles |
| Mobile testing | Manual testing on iPhone/Android for check-in and stats views |
| Documentation | Update AGENTS.md with event check-in debugging tips |
| Documentation | Create docs/features/EVENT_CHECKIN_SYSTEM.md |
Duration: 3-4 weeks
Badge templates:
app/views/events/badges/_*.html.erb_default.html.erb, _labels.html.erb, _stickers.html.erb, etc.Event#badge_template) or via sessionPrint List Bulk Actions:
printed_at for all listed registrantsGroup check-in:
unique_id prefix (from GiveCampus Registration ID)Regrets:
Registrant#regrets_at timestampPhotos:
Alumni or Contact via Active Storagephoto_variant(size:)| Type | Expectation |
|---|---|
| System tests | Bulk check-in, print flow |
| View tests | Badge template rendering |
| Documentation | Create docs/features/EVENT_BADGE_PRINTING.md |
Duration: 2-3 weeks (after Portal v1)
Champion-facing views:
API endpoint (if needed):
/api/champions/:buid/events — returns attended eventsFuture planning:
Event model| Type | Expectation |
|---|---|
| API tests | Events endpoint for champions |
| Documentation | Update Champion Portal planning docs with integration notes |
| Phase | Duration | Cumulative | Key Deliverable |
|---|---|---|---|
| Phase 0 | 1 week | 1 week | Decision confirmed |
| Phase 1 | 2-3 weeks | 3-4 weeks | Data model in place |
| Phase 2 | 2-3 weeks | 5-7 weeks | Import/export working |
| Phase 3 | 3-4 weeks | 8-11 weeks | Check-in UI live |
| Phase 4 | 3-4 weeks | 11-15 weeks | Full feature parity |
| Phase 5 | 2-3 weeks | 13-18 weeks | Portal integration |
Total: ~3-4.5 months for full integration.
| Feature | Reason | Revisit When |
|---|---|---|
| Offline mode | Complex, requires service workers and sync logic | If venue connectivity is consistently problematic |
| GiveCampus API integration | CSV upload is sufficient | If import frequency increases significantly |
| Champion-submitted events | Wait for Portal Phase 2 | Phase 5+ |
| Automatic BQID creation | Manual review preferred by Advancement Services | If process changes |
| Search-as-you-type | Nice-to-have UX improvement | Phase 4+ if requested |
| Keyboard shortcuts | Power user feature | After core features stable |
The standalone event check-in app (alum-events) has comprehensive documentation that informed this integration plan:
| Document | Contents |
|---|---|
01-architecture.md |
System overview, external integrations, ID systems (BUID/BQID), active event pattern |
02-data-models.md |
Attendee, AttendeeEvent, Event, Setting models and relationships |
03-functionality.md |
Search, check-in, action bar UI, print list, badge printing, photos, CSV import/export |
04-development.md |
Local setup, deployment, testing, troubleshooting |
05-frontend.md |
CSS (Picnic), JavaScript (Stimulus), badge templates, print styles |
06-routes-api.md |
All routes, path helpers, parameters |
07-future-features.md |
Planned improvements including incremental import, session-based events, print list bulk actions |
These documents remain in the alum-events repository as the authoritative source for the existing standalone application. | Automatic BQID creation | Manual review preferred | If Advancement Services requests |