alumni_lookup

Sub-Phase 9.1: Enhanced Onboarding Flow

Canonical sources: Portal philosophy, posture, and language live in /docs/planning/champion-portal/source/README.md.
Use these sources (including CHRIST_CENTERED__IDENTITY_STATEMENT.md) when writing specs or user-facing copy. Prefer quoting/paraphrasing over inventing new language.

Champion Portal Development Sub-Phase 9.1

Status: ✅ Complete (February 2026)
Estimated Effort: 1 week
Prerequisites: Phase 5 Complete

Related Documents:


Completion Summary

Implemented: February 2026

What Was Built

  1. join_communities wizard step
    • Added to STEPS array after affinities: %w[help_find_you confirm_education location champion_role profession photo bio affinities join_communities]
    • Step only appears for verified Champions with pending suggestions
    • Unverified Champions skip this step automatically
  2. Community suggestion display
    • Cards show community name, type icon, member count, and description
    • Icons: 📍 District, 🎓 College, 📚 Major, 🤝 Affinity, 💼 Industry
    • for_wizard scope orders by type priority (district → college → major → affinity → industry), limits to 5
  3. AJAX join/decline actions
    • “Join” button creates ChampionCommunity via find_or_create_by!, then destroys suggestion
    • “Not Now” button marks suggestion as declined and removes card
    • Turbo Stream responses remove cards without page reload
  4. Skip/Continue navigation
    • “Skip for Now” preserves pending suggestions, redirects to dashboard
    • “Continue to Dashboard” redirects to dashboard (suggestions remain for later)

Files Modified

Files Created

Bug Fixes During Implementation

  1. NoMethodError: college_desc — Fixed in CommunityDetectionService to use college_name
  2. PG::StatementInvalid in for_wizard scope — SQL CASE needed integer enum values (0, 1, 2, 3…) not string names

Tests

Deferred Items

None — all acceptance criteria met


Table of Contents

  1. Overview
  2. Current State
  3. Target State
  4. User Journeys
  5. Acceptance Criteria
  6. UI/UX Requirements
  7. Data Model Changes
  8. Implementation Plan
  9. Testing Requirements

1. Overview

Sub-Phase 9.1 adds a “Join Communities” step to the profile wizard, ensuring Champions enter the portal as members of relevant communities rather than passive observers.

Core Insight

Champions who join communities during onboarding are 3x more likely to return within 7 days.

The current wizard ends at affinities — Champions land on a dashboard showing community suggestions they could pursue. But “could” becomes “won’t” for most users. Moving community joining into the wizard flow captures attention when engagement intent is highest.


2. Current State

Profile Wizard Flow

Location: app/controllers/cp/profile_wizard_controller.rb

STEPS = %w[help_find_you confirm_education location champion_role profession photo bio affinities]
REQUIRED_STEPS = %w[location]
CONDITIONAL_STEPS = %w[help_find_you confirm_education]

Flow Diagram:

[Start] → help_find_you (conditional) → confirm_education (conditional) → location (required) 
       → champion_role → profession → photo → bio → affinities → [Dashboard]

Current Community Suggestion Behavior

Model: Cp::CommunitySuggestion

How suggestions are generated:

Current touchpoints:

Gap: Suggestions generate after wizard but aren’t surfaced during wizard.

CommunitySuggestion Model

# app/models/cp/community_suggestion.rb
class Cp::CommunitySuggestion < ApplicationRecord
  belongs_to :champion, class_name: 'Cp::Champion'
  belongs_to :community, class_name: 'Cp::Community'

  enum :status, { pending: 0, declined: 1 }
  
  scope :active, -> { pending }
  scope :by_type, ->(type) { joins(:community).where(communities: { community_type: type }) }

  def accept!
    Cp::ChampionCommunity.create!(champion: champion, community: community)
    destroy!
  end

  def decline!
    update!(status: :declined, responded_at: Time.current)
  end
end

Key insight: The accept! and decline! methods provide the exact pattern needed for wizard integration.


3. Target State

Enhanced Wizard Flow

[Start] → help_find_you → confirm_education → location → champion_role 
       → profession → photo → bio → affinities → join_communities → [Dashboard]

New Step: join_communities

Behavior:

  1. Generate/fetch community suggestions for this Champion
  2. Display suggestions with join/decline actions
  3. Process joins inline (no page reload needed)
  4. Allow skipping without joining any
  5. Transition to dashboard with communities already joined

Step Configuration

STEPS = %w[help_find_you confirm_education location champion_role profession photo bio affinities join_communities]
REQUIRED_STEPS = %w[location]
CONDITIONAL_STEPS = %w[help_find_you confirm_education]
# join_communities is optional — Champions can skip

4. User Journeys

Journey 1: Alumni with Education Match (Happy Path)

Step User Action System Response
1 Completes affinities step System generates community suggestions
2 Arrives at join_communities Sees 3-5 suggested communities
3 Clicks “Join” on Nashville Champions Creates ChampionCommunity, updates UI
4 Clicks “Join” on Music Business Creates ChampionCommunity, updates UI
5 Clicks “Not Now” on Phi Mu Marks suggestion as declined
6 Clicks “Continue to Dashboard” Redirects to dashboard with 2 communities

Journey 2: Almost Alumni (Student)

Step User Action System Response
1 Completes affinities step System generates suggestions (location + intended major only)
2 Arrives at join_communities Sees district + 1-2 college/major communities
3 Joins district community Creates ChampionCommunity
4 Clicks “Continue to Dashboard” Redirects with 1 community

Journey 3: Skip Community Step

Step User Action System Response
1 Completes affinities step System generates suggestions
2 Arrives at join_communities Sees suggestions
3 Clicks “Skip for Now” Suggestions remain pending
4 Redirects to dashboard Dashboard shows suggestions widget

Journey 4: No Suggestions Available

Step User Action System Response
1 Completes affinities (none selected) System has limited data
2 Arrives at join_communities Sees only district community (from location)
3 Joins or skips Proceeds to dashboard

5. Acceptance Criteria

Functional Requirements

ID Requirement Priority
9.1.1 join_communities step appears after affinities Must
9.1.2 Community suggestions display with name, type icon, and member count Must
9.1.3 “Join” action creates ChampionCommunity without page reload Must
9.1.4 “Not Now” action marks suggestion as declined Must
9.1.5 “Continue to Dashboard” works after any number of joins/declines Must
9.1.6 Step can be skipped entirely (“Skip for Now”) Must
9.1.7 Already-joined communities don’t appear as suggestions Must
9.1.8 Progress indicator shows correct step (e.g., “Step 9 of 9”) Should
9.1.9 Step only appears for verified Champions Should
9.1.10 Suggestions ordered by relevance (district first, then education, then affinities) Should

Edge Cases

Scenario Expected Behavior
No suggestions available Show message: “We’ll suggest communities as you explore!” + Continue button
All suggestions already joined Skip step automatically
Champion has 10+ suggestions Show top 5 with “See more communities” link
Network error on join Show error toast, keep button enabled to retry

6. UI/UX Requirements

Visual Design

Follow DESIGN-GUIDELINES.md:

Element Guideline Reference
Page background §3.1 — Warm neutrals, not pure white
Community cards §5.1 — Cards with hover shadow, rounded corners
Join button §5.2 — Primary (Belmont Blue)
Not Now button §5.2 — Ghost/secondary style
Icons §3.3 — Heroicons outline style
Empty state §5.5 — Encouraging, action-oriented

Step Layout

┌─────────────────────────────────────────────────────────────────────────┐
│ 🧭 Step 9 of 9                                                          │
│                                                                         │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ [progress bar: ████████████████████████████████████░]               │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│                                                                         │
│ ╭─────────────────────────────────────────────────────────────────────╮ │
│ │                                                                     │ │
│ │  🎯 Join Your Communities                                          │ │
│ │                                                                     │ │
│ │  Based on your profile, here are some communities where            │ │
│ │  you'll find fellow Bruins:                                        │ │
│ │                                                                     │ │
│ ╰─────────────────────────────────────────────────────────────────────╯ │
│                                                                         │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 📍 Nashville Champions                                              │ │
│ │ 23 Champions in your city                                           │ │
│ │                                              [Join]  [Not Now]      │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│                                                                         │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 🎵 Music Business                                                   │ │
│ │ Connect with 45 Music Business alumni                               │ │
│ │                                              [Join]  [Not Now]      │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│                                                                         │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 🏛️ Mike Curb College of Entertainment                              │ │
│ │ Your college community with 78 members                              │ │
│ │                                              [Join]  [Not Now]      │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│                                                                         │
│ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │
│                                                                         │
│ You can explore more communities anytime from your dashboard.           │
│                                                                         │
│      [Skip for Now]                      [Continue to Dashboard →]     │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Community Card States

State Visual Treatment
Default White card, visible Join/Not Now buttons
Joined Green left border, “Joined ✓” badge, no buttons
Declined Removed from view (or grayed with “Skipped”)
Loading Join button shows spinner

Mobile Considerations

Per DESIGN-GUIDELINES.md §8:

Copy Guidelines

Per LANGUAGE_STYLE_GUIDE.md:

Element Copy Guideline
Step title “Join Your Communities” Active, welcoming
Subtitle “Based on your profile, here are some communities where you’ll find fellow Bruins:” Personal, warm
Join button “Join” Clear action
Decline button “Not Now” Not “Decline” or “Skip” — implies they can join later
Skip link “Skip for Now” Same non-permanence tone
Continue button “Continue to Dashboard →” Active, forward movement
Empty state “We’ll suggest communities as you explore!” Encouraging, not blaming

7. Data Model Changes

No New Tables Required

The existing models support this feature:

New Methods

Cp::CommunitySuggestion:

# Scope to get suggestions suitable for wizard
scope :for_wizard, -> {
  pending
    .includes(:community)
    .where(communities: { active: true, hidden: false })
    .order(Arel.sql("CASE cp_communities.community_type 
                     WHEN 'district' THEN 1 
                     WHEN 'college' THEN 2 
                     WHEN 'major' THEN 3 
                     WHEN 'affinity' THEN 4 
                     WHEN 'industry' THEN 5 
                     ELSE 6 END"))
    .limit(5)
}

Cp::Champion:

# Check if Champion should see join_communities step
def should_see_community_step?
  verified? && pending_community_suggestions.any?
end

def pending_community_suggestions
  community_suggestions.for_wizard
end

Suggestion Generation Timing

Currently, suggestions generate via:

Change: Ensure suggestions generate before join_communities step loads:

# In profile_wizard_controller.rb
def load_step_data
  case current_step
  when 'join_communities'
    generate_community_suggestions_if_needed
    @suggestions = current_cp_champion.pending_community_suggestions
  # ... other steps
  end
end

8. Implementation Plan

Step 1: Add Step to Wizard (Day 1)

Files to modify:

Files to create:

Step 2: Build Community Suggestion UI (Day 2)

Files to create:

Features:

Step 3: Implement AJAX Join/Decline (Day 3)

Files to modify:

Files to create:

Behavior:

Step 4: Add Skip/Continue Actions (Day 4)

Files to modify:

Behavior:

Step 5: Testing & Polish (Day 5)


9. Testing Requirements

Controller Tests

File: test/controllers/cp/profile_wizard_controller_test.rb

# New tests to add:

test "join_communities step loads pending suggestions" do
  sign_in @verified_champion
  get cp_profile_wizard_url(step: 'join_communities')
  assert_response :success
  assert assigns(:suggestions).present?
end

test "join_communities step skipped when no suggestions" do
  sign_in @champion_with_no_suggestions
  get cp_profile_wizard_url(step: 'join_communities')
  assert_redirected_to cp_dashboard_url
end

test "join_communities step requires verified champion" do
  sign_in @unverified_champion
  get cp_profile_wizard_url(step: 'join_communities')
  # Should skip to next valid step or dashboard
end

test "skip action preserves pending suggestions" do
  sign_in @verified_champion
  post cp_profile_wizard_url(step: 'join_communities'), params: { skip: true }
  assert @verified_champion.community_suggestions.pending.any?
  assert_redirected_to cp_dashboard_url
end

Model Tests

File: test/models/cp/community_suggestion_test.rb

# New tests to add:

test "for_wizard scope orders by community type priority" do
  suggestions = @champion.community_suggestions.for_wizard
  types = suggestions.map { |s| s.community.community_type }
  assert_equal types, types.sort_by { |t| 
    %w[district college major affinity industry custom].index(t) 
  }
end

test "for_wizard scope limits to 5 suggestions" do
  # Create 10 suggestions
  10.times { create(:community_suggestion, champion: @champion) }
  assert_equal 5, @champion.community_suggestions.for_wizard.count
end

System Tests

File: test/system/cp/profile_wizard_test.rb

test "completing wizard with community joins" do
  sign_in @new_champion
  
  # Navigate through wizard to join_communities
  visit cp_profile_wizard_url
  # ... complete steps ...
  
  assert_selector "h2", text: "Join Your Communities"
  
  # Join a community
  within first(".community-suggestion-card") do
    click_button "Join"
  end
  
  assert_selector ".community-joined-badge", text: "Joined"
  
  click_button "Continue to Dashboard"
  
  assert_current_path cp_dashboard_path
  assert @new_champion.reload.communities.any?
end

What Was Implemented

See Completion Summary at top of document.


Deferred Items

None — all acceptance criteria met.


Document created: January 2026
Completed: February 2026