Updated: November 26, 2025
Purpose: Document the two-domain architecture, routing structure, and component organization for the alumni_lookup application.
The alumni_lookup application serves two distinct audiences through a subdomain-based architecture:
| Domain | Audience | Purpose | Authentication |
|---|---|---|---|
lookup.bualum.co |
Internal staff | Alumni research, engagement tracking, data management | Required (Devise) |
champions.bualum.co |
External alumni | Champion signup flow, future champion portal | Currently public |
┌─────────────────────────────────────────────────────────────────────┐
│ alumni_lookup Application │
├─────────────────────────────────┬───────────────────────────────────┤
│ lookup.bualum.co │ champions.bualum.co │
│ (Internal) │ (External) │
├─────────────────────────────────┼───────────────────────────────────┤
│ • Alumni Search │ • Champion Signup Flow │
│ • Engagement Stats │ • (Future) Champion Portal │
│ • Champion Management │ • (Future) City Leader Tools │
│ • Data Import/Export │ │
│ • Settings/Admin │ │
├─────────────────────────────────┴───────────────────────────────────┤
│ Shared Components │
│ • Models (Alumni, ChampionSignup, Degree, etc.) │
│ • Services (EngagementScoreCalculator, etc.) │
│ • Database (PostgreSQL) │
└─────────────────────────────────────────────────────────────────────┘
The internal site provides staff-facing tools for alumni relationship management:
Core Features:
Access Control:
ensure_admin or authorize_admin! callbacksThe external site provides public-facing features for alumni engagement:
Current Features:
Planned Features (Future Phases):
Access Control:
The application uses Rails subdomain constraints to route requests:
# config/routes.rb
# Champions subdomain - external site
constraints subdomain: 'champions' do
scope module: 'champions' do
resources :signups, controller: 'champion_signups', only: [:new, :create, :show]
root to: "champion_signups#new"
end
end
# Default (no subdomain constraint) - internal site
# All other routes handle lookup.bualum.co
| Route | Controller | Purpose |
|——-|————|———|
| GET / (champions) | Champions::ChampionSignupsController#new | Signup wizard start |
| POST /signups (champions) | Champions::ChampionSignupsController#create | Process signup steps |
| GET /signups/:id (champions) | Champions::ChampionSignupsController#show | Signup confirmation |
| Route | Controller | Purpose |
|——-|————|———|
| GET /alumni_search | AlumniController#search | Main search interface |
| GET /alumni/:id | AlumniController#show | Alumni profile view |
| GET /engagement_stats | EngagementStatsController#index | Analytics dashboard |
| GET /champion_signups | ChampionSignupsController#index | Manage signups |
| GET /batch_search | BatchSearchController#new | Bulk lookup |
| Route | Controller | Guard |
|——-|————|——-|
| /settings/* | Settings::* | ensure_admin |
| /users | UsersController | authorize_admin! |
| /people | PeopleController | ensure_admin |
| Route | Controller | Purpose |
|——-|————|———|
| GET /api/affinities | Api::AffinitiesController | Affinity dropdown data |
| GET /api/alumni | Api::AlumniController | Alumni typeahead search |
| GET /api/majors | Api::MajorsController | Major dropdown data |
| GET /api/activity_descriptions | Api::ActivityDescriptionsController | Activity filter data |
See API.md for detailed API documentation.
app/controllers/
├── application_controller.rb # Base controller, auth helpers
├── public_controller.rb # Base for public (unauthenticated) controllers
├── alumni_controller.rb # Alumni search, show, update
├── alumni_affinities_controller.rb # Alumni-affinity management
├── batch_search_controller.rb # Bulk name/email lookup
├── champion_signups_controller.rb # Internal champion management
├── engagement_activities_controller.rb # Activity listing
├── engagement_stats_controller.rb # Analytics dashboard
├── people_controller.rb # Alumni data import
├── statistics_controller.rb # Degree statistics
├── users_controller.rb # User management
│
├── api/ # Internal JSON API
│ ├── activity_descriptions_controller.rb
│ ├── affinities_controller.rb
│ ├── alumni_controller.rb
│ └── majors_controller.rb
│
├── champions/ # External site (subdomain)
│ └── champion_signups_controller.rb # Inherits from PublicController
│
└── settings/ # Admin configuration
├── settings_controller.rb
├── affinities_controller.rb
├── alumni_controller.rb
├── colleges_controller.rb
├── engagement_activities_controller.rb
└── majors_controller.rb
| Namespace | Base Class | Purpose |
|---|---|---|
| (root) | ApplicationController |
Core internal features |
Api:: |
ApplicationController |
JSON endpoints for JavaScript |
Champions:: |
PublicController |
External public-facing features |
Settings:: |
ApplicationController |
Admin-only configuration |
All models are shared between internal and external sites:
| Model | Internal Use | External Use |
|---|---|---|
Alumni |
Search, display, management | Signup matching |
ChampionSignup |
Review, merge, manage | Create, update |
Degree |
Display, import | (read-only context) |
EngagementActivity |
Stats, scoring | (none currently) |
Affinity |
Assignment, filtering | (none currently) |
Full association details: See MODEL_RELATIONSHIPS.md
| Service | Purpose | Used By |
|———|———|———|
| EngagementScoreCalculator | Calculate engagement scores | Internal stats |
| TopEngagedAlumniService | Generate leaderboards | Internal stats |
| ChampionSignupMerger | Merge duplicate signups | Internal management |
| AlumniMatcher | Match names to alumni records | Both sites |
| AlumniFilterService | Filter alumni by various criteria | Internal stats |
| EngagementStats::BaseService | Base class for stats services | Stats services |
| EngagementStats::OverviewService | Overview tab calculations | Engagement stats |
| EngagementStats::AnalyticsService | Analytics tab calculations | Engagement stats |
| EngagementStats::BreakdownService | Breakdown tab calculations | Engagement stats |
| EngagementStats::DemographicsService | Demographics tab calculations | Engagement stats |
| EngagementStats::MatrixService | Matrix quadrant calculations | Engagement stats |
| EngagementStats::ActivityPairsService | Activity pairs calculations | Engagement stats |
| Helper | Scope |
|——–|——-|
| ApplicationHelper | Global utilities |
| ChampionSignupsHelper | Signup flow questions/logic |
| EngagementStatsHelper | Stats formatting |
| AffinitiesHelper | Affinity name lookups |
Settings:: controllersEngagementStatsControllerBatchSearchControllerPeopleControllerapplication (with navigation)Champions::ChampionSignupsControllerpublic (minimal, branded)| Layout | File | Used By |
|---|---|---|
application |
app/views/layouts/application.html.erb |
All internal pages |
public |
app/views/layouts/public.html.erb |
Champions subdomain |
devise |
(inherited) | Login/password pages |
# Internal controllers use application layout by default
# Champions controllers explicitly use public layout
class Champions::ChampionSignupsController < ApplicationController
layout "public"
end
Champion model or role to existing User modelCityLeader role with geographic scopeChampions::Dashboard controllerChampions::Profile controllerChampions::BaseController for shared logicThis section defines the rules for placing controllers and features in the correct namespace, ensuring clean separation between internal and external functionality.
| Controller Type | Base Class | Layout | Auth Required |
|---|---|---|---|
| Internal features | ApplicationController |
application |
Yes |
| Settings/Admin | ApplicationController + ensure_admin |
application |
Yes + Admin |
| Public features | PublicController |
public |
No |
| Champion portal (future) | PublicController + auth |
public |
Yes (Champion role) |
app/controllers/ (Root)For: Core internal features used by staff
Includes:
AlumniController - Alumni search, view, updateEngagementStatsController - Analytics dashboardChampionSignupsController - Managing external signupsBatchSearchController - Bulk lookupsStatisticsController - Degree statisticsUsersController - Staff user managementDo NOT place here:
app/controllers/api/For: JSON API endpoints for JavaScript components
Includes:
Rules:
authenticate_user! to secure endpointsapp/controllers/champions/For: External site features (champions.bualum.co)
Currently Includes:
ChampionSignupsController - Public signup flowFuture additions should include:
Champions::DashboardController - Authenticated champion homeChampions::ProfileController - Champion profile managementChampions::EventsController - Event RSVP (champion-facing)Rules:
PublicController for public featurespublic layoutPublicControllerapp/controllers/settings/For: Admin-only configuration and data management
Currently Includes:
SettingsController - Main settings pageMajorsController - Major CRUD/importCollegesController - College CRUD/importAffinitiesController - Affinity CRUD/importAlumniController - Alumni/degree importEngagementActivitiesController - Activity importRules:
ensure_admin or equivalentApplicationControllerWhen implementing role-based access, follow these placement rules:
Internal Site (lookup.bualum.co) - Admin and Staff roles:
| Feature | Namespace | Base Class | Notes |
|---|---|---|---|
| Staff Features | Root | ApplicationController |
Internal site |
| Admin-only Settings | Settings:: |
ApplicationController |
Internal site |
| Admin User Management | Root (UsersController) |
ApplicationController |
Internal site |
External Site (champions.bualum.co) - CLC and Champion roles:
| Feature | Namespace | Base Class | Notes |
|---|---|---|---|
| Champion Dashboard | Champions:: |
PublicController + champion auth |
External site |
| Champion Profile CRUD | Champions:: |
PublicController + champion auth |
External site |
| CLC Regional Dashboard | Champions::Regional |
PublicController + CLC auth |
External site |
| CLC Champion Management | Champions::Regional |
PublicController + CLC auth |
External site |
Note: CLC (City Leadership Council) is an external/Champion Portal role, not an internal role. CLC is to Champion as Admin is to Staff—the “regional admin” version.
The EngagementStats::* service objects were created to support future role-based features:
# Example: CLC regional dashboard using champion-facing services with regional filtering
class Champions::RegionalDashboardController < PublicController
before_action :require_city_leader!
def index
# Future: Pass regional filter to services
@regional_champions = ChampionSignup.where(region: current_champion.region)
@regional_stats = Champions::RegionalStatsService.new(region: current_champion.region).calculate
end
end
Service Design Principles:
Last updated: November 2025