alumni_lookup

Event Check-in Integration: Phased Plan

This roadmap outlines incremental phases to integrate alum-events functionality into Alumni Lookup. Each phase is testable and deployable independently.


Data Model Summary

Contact

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

Event

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

Registrant

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

Model Relationships

# 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

Phase 0: Decision & Framing

Duration: 1 week

Goals

Scope

Dependencies

Champion Portal Impact

Testing / Docs


Phase 1: Data & Architecture Foundations

Duration: 2-3 weeks

Goals

Scope

Migrations:

Models:

Authorization (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.

Service:

Dependencies

Champion Portal Impact

Testing / Docs

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

Phase 2: Import & Export Integration

Duration: 2-3 weeks

Goals

Scope

Service: GiveCampusCsvImporter

Controller: Events::ImportsController

Service: EventExporter

Controller: Events::ExportsController

UI:

Dependencies

Champion Portal Impact

Testing / Docs

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

Phase 3: Internal Check-in UI (MVP)

Duration: 3-4 weeks

Goals

Scope

Routes: Namespaced under /events/

Controllers:

Session-based event:

Search & Navigation:

Action Bar (per registrant):

Print List:

Real-Time Stats View:

Mobile Optimization:

**Walk-in Flow:

Service updates:

Dependencies

Champion Portal Impact

Testing / Docs

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

Phase 4: Badge Printing & Extended Features

Duration: 3-4 weeks

Goals

Scope

Badge templates:

Print List Bulk Actions:

Group check-in:

Regrets:

Photos:

Dependencies

Champion Portal Impact

Testing / Docs

Type Expectation
System tests Bulk check-in, print flow
View tests Badge template rendering
Documentation Create docs/features/EVENT_BADGE_PRINTING.md

Phase 5: Champion Portal Alignment

Duration: 2-3 weeks (after Portal v1)

Goals

Scope

Champion-facing views:

API endpoint (if needed):

Future planning:

Dependencies

Champion Portal Impact

Testing / Docs

Type Expectation
API tests Events endpoint for champions
Documentation Update Champion Portal planning docs with integration notes

Summary Timeline

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.


Deferred / Out of Scope for v1

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

Reference: alum-events Source Documentation

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 |