Generated: November 26, 2025
Purpose: Comprehensive documentation of the alumni_lookup codebase for developers and AI systems.
| Layer | Technology |
|---|---|
| Framework | Ruby on Rails 7.1.5.1 |
| Language | Ruby 3.2.3+ |
| Database | PostgreSQL |
| Frontend | Tailwind CSS + TailwindUI, Turbo/Hotwire |
| JavaScript | Import Maps (no bundler) |
| Authentication | Devise |
| Search | PgSearch (PostgreSQL full-text) |
| Pagination | Kaminari |
| Background Jobs | Solid Queue |
Alumni Lookup is a university alumni engagement tracking and management system that:
alumni_lookup/
├── app/
│ ├── controllers/ # 18 controllers (RESTful + custom)
│ ├── models/ # 15 ActiveRecord models
│ ├── views/ # ERB templates with Turbo support
│ ├── services/ # 9 service objects (business logic)
│ ├── helpers/ # View helpers and utilities
│ ├── javascript/ # Stimulus controllers
│ └── assets/ # CSS (Tailwind)
├── config/
│ ├── routes.rb # Route definitions
│ ├── database.yml # Database configuration
│ └── initializers/ # App initialization
├── db/
│ ├── migrate/ # 34 migrations
│ ├── schema.rb # Current schema
│ └── seeds.rb # Seed data
├── docs/ # Documentation
│ ├── development/ # Developer guides
│ └── features/ # Feature documentation
├── lib/
│ └── tasks/ # Custom Rake tasks
├── spec/ # RSpec test suite
└── test/ # Minitest (appears unused)
| Controller | Purpose | Key Actions |
|---|---|---|
AlumniController |
Alumni CRUD & search | index, show, search |
EngagementActivitiesController |
Activity management | index, new, create, destroy |
EngagementStatsController |
Dashboard & analytics | index (with tabs) |
DegreesController |
Degree management | index, import workflows |
DegreeImportsController |
Bulk degree imports | new, preview, create |
ListsController |
Alumni list management | CRUD + member management |
ListMembersController |
List membership | add/remove members |
CollegesController |
College reference data | index, show |
MajorsController |
Major reference data | index, show |
EngagementTypesController |
Activity type config | CRUD |
EventAttendeesController |
Event tracking | index, import, export |
CsvImportsController |
Generic CSV imports | upload, preview, commit |
ReportsController |
Report generation | various reports |
PagesController |
Static pages | home, about |
SearchController |
Global search | search action |
AdminController |
Admin functions | dashboard |
UsersController |
User management | CRUD |
Devise::* |
Authentication | login, logout, etc. |
| Model | Table | Purpose |
|---|---|---|
Alumni |
alumnis |
Core alumni records |
Degree |
degrees |
Academic degrees |
Major |
majors |
Academic majors |
College |
colleges |
Academic colleges |
EngagementActivity |
engagement_activities |
Individual activities |
EngagementType |
engagement_types |
Activity type definitions |
EngagementScore |
engagement_scores |
Calculated scores (cached) |
List |
lists |
Custom alumni lists |
ListMember |
list_members |
List membership join |
EventAttendee |
event_attendees |
Event attendance |
CsvImport |
csv_imports |
Import job tracking |
User |
users |
Application users (Devise) |
TopEngagedCache |
top_engaged_caches |
Performance cache |
ApplicationRecord |
- | Base class |
Current |
- | Current context (thread-safe) |
| Service | Purpose |
|---|---|
EngagementScoreCalculator |
Core scoring algorithm with activity caps |
TopEngagedAlumniService |
Ranking with time period filtering |
DegreeImportService |
Bulk degree import processing |
EngagementImportService |
Engagement activity imports |
ListImportService |
Alumni list imports |
AlumniSearchService |
Full-text search logic |
CsvExportService |
CSV generation for exports |
EngagementStatsService |
Statistics calculations |
FlagshipEventService |
Flagship event analysis |
Core Concept: Alumni engagement is tracked through activities, each assigned a level (0-4) that maps to points.
Level Mapping:
Level 0 → 0 points (Inactive/administrative)
Level 1 → 1 point (Low engagement: email opens, website visits)
Level 2 → 3 points (Medium: event RSVPs, email clicks)
Level 3 → 7 points (High: event attendance, donations)
Level 4 → 10 points (Highest: major gifts, volunteer leadership)
Scoring Formula:
distance = √((score × 1.5)² + (capped_activity_count × 1.0)²)
Activity Caps (prevents gaming):
email_click: max 5 per periodevent_rsvp: max 2 per periodTime Period Filtering:
CSV Upload → Header Mapping → Preview → Validation → Commit
↓
Creates missing Alumni
Maps major codes/descriptions
Key Features:
pg_searchCreate List → Add Members (manual or CSV) → Export → Share
Tabs:
Full Details: See development/MODEL_RELATIONSHIPS.md for complete association documentation.
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ College │────<│ Major │────<│ Degree │>────│ Alumni │
│ college_code│ │ major_code │ │ degree_code │ │ buid │
└─────────────┘ └─────────────┘ │ major_code │ └─────────────┘
│ buid │ │
└─────────────┘ │
│
┌─────────────────────┐ │
│ EngagementActivity │───────────────────────────────────────────┘
│ buid │
└─────────────────────┘
┌─────────────┐ ┌───────────────┐
│ ChampionSignup│────>│ Alumni │
│ buid │ │ buid │
└─────────────┘ └───────────────┘
# ✅ CORRECT - College filtering requires nested joins through major
EngagementActivity.joins(alumni: { degrees: { major: :college } })
# ❌ WRONG - Degrees don't directly associate with colleges
EngagementActivity.joins(alumni: { degrees: :college })
# ✅ CORRECT - Association name is :alumni
EngagementActivity.joins(:alumni)
# ❌ WRONG - No :alumnus association exists
EngagementActivity.joins(:alumnus)
| Gem | Version | Purpose |
|---|---|---|
rails |
7.1.5.1 | Web framework |
pg |
~> 1.1 | PostgreSQL adapter |
puma |
>= 5.0 | Web server |
devise |
~> 4.9 | Authentication |
kaminari |
- | Pagination |
pg_search |
- | Full-text search |
tailwindcss-rails |
- | CSS framework |
turbo-rails |
- | Hotwire Turbo |
stimulus-rails |
- | Hotwire Stimulus |
importmap-rails |
- | JavaScript imports |
solid_queue |
- | Background jobs |
propshaft |
- | Asset pipeline |
| Gem | Purpose |
|---|---|
rspec-rails |
Testing framework |
factory_bot_rails |
Test factories |
faker |
Test data generation |
shoulda-matchers |
RSpec matchers |
rubocop-rails |
Code linting |
debug |
Debugging |
web-console |
Browser debugging |
// config/importmap.rb
pin "application"
pin "@hotwired/turbo-rails"
pin "@hotwired/stimulus"
pin_all_from "app/javascript/controllers"
spec/ directory)test/)spec/
├── controllers/ # Controller specs (MINIMAL)
├── factories/ # Factory definitions (3 files)
│ ├── alumnis.rb
│ ├── degrees.rb
│ └── majors.rb
├── features/ # Feature/integration specs (EMPTY)
├── models/ # Model specs (MINIMAL)
│ ├── alumni_spec.rb
│ └── degree_spec.rb
├── requests/ # Request specs (EMPTY)
├── routing/ # Routing specs (EMPTY)
├── services/ # Service specs (LIMITED)
│ └── engagement_score_calculator_spec.rb
├── support/ # Test support files
├── rails_helper.rb
└── spec_helper.rb
| Area | Status | Gap Level |
|---|---|---|
| Models | 2 specs (Alumni, Degree) | 🔴 HIGH - 13 models untested |
| Controllers | Minimal | 🔴 HIGH - 18 controllers untested |
| Services | 1 spec (EngagementScoreCalculator) | 🔴 HIGH - 8 services untested |
| Features/Integration | None | 🔴 HIGH - No E2E tests |
| Requests | None | 🔴 HIGH - No API tests |
| Factories | 3 defined | 🟡 MEDIUM - Need more factories |
| System Tests | None | 🔴 HIGH - No browser tests |
TopEngagedAlumniService (complex ranking logic)DegreeImportService (critical import workflow)EngagementActivityEngagementTypeCollegeList/ListMemberUser| Pattern | Example | Usage |
|---|---|---|
*_id |
list_id, user_id |
Foreign keys (standard) |
*_code |
major_code, activity_code |
Lookup/classification keys |
buid |
B12345678 |
Alumni unique identifier (Belmont University ID) |
pref_* |
pref_email, pref_phone |
Preferred contact fields |
*_date |
degree_date, engagement_date |
Date columns |
contact_id |
C-000000000 |
CRM-compatible identifier |
# Standard RESTful actions with Turbo support
class ResourceController < ApplicationController
before_action :set_resource, only: [:show, :edit, :update, :destroy]
def index
@resources = Resource.page(params[:page])
end
def show
respond_to do |format|
format.html
format.turbo_stream
end
end
private
def set_resource
@resource = Resource.find(params[:id])
end
end
# Services encapsulate business logic
class SomeService
def initialize(params)
@params = params
end
def call
# Business logic here
end
private
# Helper methods
end
_ (e.g., _form.html.erb)app/views/shared/# CSV imports follow: Upload → Preview → Commit
class ImportController
def new # Upload form
def preview # Show preview with validation
def create # Commit import
end
docs/ and AGENTS.md# Model: Alumni (singular)
# Table: alumnis (incorrect pluralization - should be 'alumni')
# This is acceptable but worth noting
# Most models use integer `id`
# Alumni relationships use `buid` as primary key for joins
# This hybrid approach works but requires careful documentation
Some services return different structures:
Some controllers have grown large:
EngagementStatsController handles multiple tab viewsapp/views/
├── shared/ # Some shared partials
├── components/ # NOT PRESENT - could be added
└── layouts/ # Standard Rails layouts
Consider adding a components/ directory for reusable UI elements.
Should verify indexes exist on:
engagement_activities.buidengagement_activities.activity_codedegrees.buiddegrees.major_codeSolid Queue is configured but no job tests exist.
| Item | Priority | Notes |
|---|---|---|
| Add comprehensive tests | HIGH | Blocks safe refactoring |
| Standardize service returns | MEDIUM | Improve consistency |
| Add request specs for API | MEDIUM | Document API behavior |
| Extract large controllers | LOW | Improve maintainability |
| Add component directory | LOW | Better view organization |
# Start development server
bin/dev
# Run tests
bundle exec rspec
# Rails console
rails console
# Database operations
rails db:migrate
rails db:seed
rails db:reset
# Generate migration
rails generate migration AddFieldToTable field:type
# Tailwind build (watch)
rails tailwindcss:watch
config/routes.rb - All application routesapp/models/alumni.rb - Core data modelapp/services/engagement_score_calculator.rb - Scoring logicdocs/development/MODEL_RELATIONSHIPS.md - Association details.github/copilot-instructions.md - AI coding guidelinesCheck .env.example or config/credentials.yml.enc for required configuration.
This document should be updated as the codebase evolves.