alumni_lookup

Sub-Phase 9.3: Admin Tooling

Champion Portal Development Sub-Phase 9.3

Status: ✅ Complete
Completed: February 2026
Estimated Effort: 1 week
Prerequisites: Sub-Phase 9.2 Complete

Related Documents:


Completion Summary

What Was Implemented

Controller:

Views (7 files):

Routes:

resources :seeded_questions do
  member do
    get :preview
    patch :activate
    patch :deactivate
  end
end

Tests:

Files Created:

Deferred


Table of Contents

  1. Overview
  2. Admin Location
  3. Feature Requirements
  4. User Interface
  5. Permissions
  6. Implementation Plan
  7. Testing Requirements

1. Overview

Sub-Phase 9.3 provides the administrative interface for managing seeded discussion questions. Staff can create, edit, target, and monitor questions without requiring code deployments.

Scope

In Scope Out of Scope
CRUD for seeded questions Question AI generation
Community type targeting A/B testing framework
Affinity subtype targeting Question scheduling automation
Preview with interpolation Question translation/i18n
Basic engagement metrics Advanced analytics dashboard

2. Admin Location

Route

Namespace: Alumni Lookup Champion Admin (/champions/)
Path: /champions/seeded-questions

Following the pattern of other Champion Admin features:

Controller

File: app/controllers/champions/seeded_questions_controller.rb

module Champions
  class SeededQuestionsController < ApplicationController
    before_action :ensure_portal_admin!
    before_action :set_question, only: [:show, :edit, :update, :destroy, :preview]

    def index
      @questions = Cp::SeededQuestion
        .includes(:exposures)
        .order(created_at: :desc)
        .page(params[:page])
    end

    def show; end
    def new
      @question = Cp::SeededQuestion.new
    end

    def create
      @question = Cp::SeededQuestion.new(question_params)
      if @question.save
        redirect_to champions_seeded_question_path(@question), 
                    notice: "Question created successfully!"
      else
        render :new, status: :unprocessable_entity
      end
    end

    def edit; end

    def update
      if @question.update(question_params)
        redirect_to champions_seeded_question_path(@question), 
                    notice: "Question updated."
      else
        render :edit, status: :unprocessable_entity
      end
    end

    def destroy
      @question.destroy
      redirect_to champions_seeded_questions_path, 
                  notice: "Question deleted."
    end

    # Preview interpolation with sample community
    def preview
      @community = params[:community_id] ? 
                   Cp::Community.find(params[:community_id]) : 
                   sample_community_for_type(@question.target_type)
      @interpolated_title = Cp::QuestionInterpolator.new(@question, @community).interpolate_title
      @interpolated_body = Cp::QuestionInterpolator.new(@question, @community).interpolate_body

      render partial: 'preview'
    end

    private

    def set_question
      @question = Cp::SeededQuestion.find(params[:id])
    end

    def question_params
      params.require(:seeded_question).permit(
        :title, :body, :status, :target_type, :affinity_subtype,
        :priority, :active_from, :active_until
      )
    end

    def sample_community_for_type(type)
      case type
      when 'district'
        Cp::Community.district.active.first
      when 'college'
        Cp::Community.college.active.first
      when 'major'
        Cp::Community.major.active.first
      when 'affinity', 'affinity_subtype'
        Cp::Community.affinity.active.first
      when 'industry'
        Cp::Community.industry.active.first
      else
        Cp::Community.active.first
      end
    end
  end
end

3. Feature Requirements

CRUD Operations

Operation Description Permission
List View all questions with filters portal_admin
Create Add new question with targeting portal_admin
Edit Modify question, targeting, status portal_admin
Delete Remove question (soft delete via archive) portal_admin
Preview See interpolated question with sample community portal_admin

Status Management

Status Description List Filter
draft Question not visible, being edited Draft tab
active Question available for selection Active tab
paused Temporarily disabled Paused tab
archived No longer used, hidden by default Archived tab

Targeting Configuration

Target Type Additional Config
All Communities None
District None (applies to all district communities)
College None (applies to all college communities)
Major None (applies to all major communities)
Affinity None (applies to all affinity communities)
Industry None (applies to all industry communities)
Affinity Subtype Select subtype: greek, athletics, music, service, etc.

Scheduling (Optional)

Field Description
active_from Don’t show before this date
active_until Don’t show after this date
priority Higher priority = more likely selected

4. User Interface

Index Page (List)

┌─────────────────────────────────────────────────────────────────────────────┐
│ Seeded Questions                                            [+ New Question]│
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│ [Active (12)] [Draft (3)] [Paused (2)] [Archived (5)]                      │
│                                                                             │
│ ─────────────────────────────────────────────────────────────────────────── │
│                                                                             │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ "What's your favorite Belmont memory?"                                  │ │
│ │ Target: All Communities · Priority: High · Created Jan 15, 2026         │ │
│ │ 📊 45 exposures · 23 replies · 89 reactions                             │ │
│ │                                                [Preview] [Edit] [Pause] │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                             │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ "What brought you to {community_name}?"                                 │ │
│ │ Target: District · Priority: Medium · Created Jan 14, 2026              │ │
│ │ 📊 12 exposures · 8 replies · 31 reactions                              │ │
│ │                                                [Preview] [Edit] [Pause] │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                             │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ "What's your favorite memory from Greek Week?"                          │ │
│ │ Target: Affinity Subtype (Greek) · Priority: Medium · Created Jan 12    │ │
│ │ 📊 6 exposures · 4 replies · 18 reactions                               │ │
│ │                                                [Preview] [Edit] [Pause] │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                             │
│ [← Previous] [1] [2] [3] [Next →]                                          │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Create/Edit Form

┌─────────────────────────────────────────────────────────────────────────────┐
│ ← Back to Questions                                                         │
│                                                                             │
│ New Seeded Question                                                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│ Question Title *                                                            │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ What brought you to {community_name}?                                   │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ 280 character limit. Use {community_name}, {current_season}, etc.          │
│                                                                             │
│ Body (Optional)                                                             │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ Share what attracted you to this city and how you found                 │ │
│ │ fellow Bruins here!                                                     │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ Additional context or call-to-action.                                       │
│                                                                             │
│ ─────────────────────────────────────────────────────────────────────────── │
│                                                                             │
│ Target                                                                      │
│ ○ All Communities                                                           │
│ ○ District (city communities)                                               │
│ ○ College                                                                   │
│ ○ Major                                                                     │
│ ○ Affinity                                                                  │
│ ● Affinity Subtype: [Greek    ▼]                                           │
│ ○ Industry                                                                  │
│                                                                             │
│ ─────────────────────────────────────────────────────────────────────────── │
│                                                                             │
│ Settings                                                                    │
│                                                                             │
│ Status: [Active ▼]                                                          │
│                                                                             │
│ Priority: [○ Low  ● Medium  ○ High]                                        │
│                                                                             │
│ ☐ Schedule active dates                                                     │
│   Active from: [___________]  Active until: [___________]                   │
│                                                                             │
│ ─────────────────────────────────────────────────────────────────────────── │
│                                                                             │
│                                      [Cancel]  [Save as Draft]  [Publish]   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Preview Panel

Live preview showing interpolation:

┌─────────────────────────────────────────────────────────────────────────────┐
│ Preview                                                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│ Preview in: [Nashville Champions ▼]                                         │
│                                                                             │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 📢 From the Engagement Team                                             │ │
│ │                                                                         │ │
│ │ "What brought you to Nashville Champions?"                              │ │
│ │                                                                         │ │
│ │ Share what attracted you to this city and how you found                 │ │
│ │ fellow Bruins here!                                                     │ │
│ │                                                                         │ │
│ │ 💬 Reply   ❤️ React                                                     │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                             │
│ Variables detected: {community_name}                                        │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Show Page (Question Detail)

┌─────────────────────────────────────────────────────────────────────────────┐
│ ← Back to Questions                                          [Edit] [Pause]│
│                                                                             │
│ "What brought you to {community_name}?"                                     │
│                                                                             │
│ Target: District · Priority: Medium · Status: Active                        │
│ Created Jan 14, 2026 · Last edited Jan 15, 2026                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│ Body:                                                                       │
│ "Share what attracted you to this city and how you found fellow Bruins!"   │
│                                                                             │
│ ─────────────────────────────────────────────────────────────────────────── │
│                                                                             │
│ Performance                                                                 │
│                                                                             │
│ ┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐           │
│ │    12            │  │    8             │  │    31            │           │
│ │  Exposures       │  │  Replies         │  │  Reactions       │           │
│ └──────────────────┘  └──────────────────┘  └──────────────────┘           │
│                                                                             │
│ ─────────────────────────────────────────────────────────────────────────── │
│                                                                             │
│ Exposed In (12 communities)                                                 │
│                                                                             │
│ Community                    Posted       Replies  Reactions                │
│ ─────────────────────────────────────────────────────────────────────────── │
│ Nashville Champions          Jan 15       3        12        [View Post]   │
│ Atlanta Champions            Jan 16       2        8         [View Post]   │
│ Dallas Champions             Jan 16       1        5         [View Post]   │
│ Denver Champions             Jan 17       2        6         [View Post]   │
│ ...                                                                         │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

5. Permissions

Role Requirements

Action Required Role Notes
View list portal_admin Staff cannot view
Create question portal_admin  
Edit question portal_admin  
Delete/Archive portal_admin  
Preview portal_admin  
View metrics portal_admin  

Authorization

# In controller
before_action :ensure_portal_admin!

6. Implementation Plan

Day 1: Routes & Controller

Files to create:

Files to modify:

# config/routes.rb
namespace :champions do
  # ... existing routes ...
  resources :seeded_questions do
    member do
      get :preview
    end
  end
end

Day 2: Index & List Views

Files to create:

Day 3: Create/Edit Forms

Files to create:

Day 4: Show & Preview

Files to create:

JS/Stimulus:

Day 5: Testing & Polish


7. Testing Requirements

Controller Tests

File: test/controllers/champions/seeded_questions_controller_test.rb

class Champions::SeededQuestionsControllerTest < ActionDispatch::IntegrationTest
  setup do
    @admin = users(:admin)
    @staff = users(:staff)
    @question = cp_seeded_questions(:district_question)
  end

  test "portal_admin can access index" do
    sign_in @admin
    get champions_seeded_questions_url
    assert_response :success
  end

  test "staff cannot access index" do
    sign_in @staff
    get champions_seeded_questions_url
    assert_response :forbidden
  end

  test "create question with valid params" do
    sign_in @admin
    assert_difference 'Cp::SeededQuestion.count', 1 do
      post champions_seeded_questions_url, params: {
        seeded_question: {
          title: "Test question for {community_name}",
          target_type: 'district',
          status: 'active'
        }
      }
    end
    assert_redirected_to champions_seeded_question_url(Cp::SeededQuestion.last)
  end

  test "preview renders interpolated content" do
    sign_in @admin
    community = cp_communities(:nashville_district)
    
    get preview_champions_seeded_question_url(@question, community_id: community.id)
    
    assert_response :success
    assert_match /Nashville Champions/, response.body
  end
end

System Tests

File: test/system/champions/seeded_questions_test.rb

class Champions::SeededQuestionsTest < ApplicationSystemTestCase
  setup do
    sign_in users(:admin)
  end

  test "admin creates new seeded question" do
    visit champions_seeded_questions_url
    click_link "New Question"
    
    fill_in "Question Title", with: "What brought you to {community_name}?"
    fill_in "Body", with: "Share your story!"
    choose "District"
    
    click_button "Publish"
    
    assert_text "Question created successfully"
    assert_text "What brought you to {community_name}?"
  end

  test "admin previews question with different communities" do
    question = cp_seeded_questions(:district_question)
    visit champions_seeded_question_url(question)
    
    select "Nashville Champions", from: "Preview in"
    
    within ".preview-panel" do
      assert_text "Nashville Champions"
    end
  end
end

Add link to Champion Admin sidebar:

<%# app/views/layouts/_champion_admin_sidebar.html.erb %>
<nav>
  <!-- Existing links -->
  <%= link_to champions_signups_path, class: nav_link_class('signups') do %>
    Champion Signups
  <% end %>
  
  <%= link_to champions_verification_index_path, class: nav_link_class('verification') do %>
    Verification Queue
  <% end %>
  
  <%= link_to champions_communities_path, class: nav_link_class('communities') do %>
    Communities
  <% end %>
  
  <!-- NEW -->
  <%= link_to champions_seeded_questions_path, class: nav_link_class('seeded_questions') do %>
    Seeded Questions
  <% end %>
</nav>

What Was Implemented

To be updated after implementation


Deferred Items

Item Reason Future Phase
Bulk import from CSV Complexity Post-MVP
Question templates library Nice-to-have Post-MVP
A/B testing framework Out of scope Post-MVP
Question cloning Nice-to-have Post-MVP

Document created: January 2026