alumni_lookup

Sub-Phase 3.9: Public Landing Pages

Champion Portal Development Sub-Phase 3.9

Status: ✅ Complete (January 2026)
Estimated Effort: 2-3 days
Focus: Public preview pages for events, discussions, and communities to support rich link sharing

Prerequisites: Phase 3.5 Complete (Discussion Boards)

Related Documents:


Completion Summary (January 2026)

What Was Implemented:

Controllers

Views

Helpers & Models

Key Files Created/Modified

| File | Change | |——|——–| | app/views/cp/shared/_public_cta_box.html.erb | NEW - Reusable CTA component | | app/helpers/meta_tags_helper.rb | NEW - Rich preview meta tags | | app/controllers/cp/base_controller.rb | Return path storage | | app/controllers/cp/events_controller.rb | Public access for global/public events | | app/controllers/cp/boards_controller.rb | Public access for public community posts | | app/controllers/cp/communities_controller.rb | Public stats and landing page sections | | app/models/cp/champion.rb | public_display_name method |

Tests

Design Decisions


Table of Contents

  1. Overview
  2. Why This Sub-Phase Exists
  3. Scope
  4. Technical Design
  5. UI Specifications
  6. Implementation Checklist
  7. Tests to Create

1. Overview

When Champions share links to events, discussions, or communities via iMessage/SMS, the recipient sees a rich preview (via Open Graph meta tags implemented in the meta_tags_helper). However, clicking through currently requires authentication before seeing any content.

This phase creates public “landing pages” that:

Goal: Convert link clicks into signups by showing value before asking for commitment.


2. Why This Sub-Phase Exists

The Problem

  1. Champion shares an event link via iMessage
  2. Recipient sees rich preview: “Spring Brunch May 15, 2025 Nashville”
  3. Recipient clicks → hits login wall → bounces

The Solution

  1. Champion shares an event link via iMessage
  2. Recipient sees rich preview with enticing description
  3. Recipient clicks → sees event details + warm CTA to join
  4. Recipient signs up → lands directly on the event page

JTBD Alignment

From JOBS-TO-BE-DONE.md:

Job C9: Feel Like I Belong “When I’m far from Nashville or years past graduation, I want to feel part of something bigger.”

Public landing pages extend the sense of belonging to potential Champions, showing them the vibrant community they could join.


3. Scope

In Scope

Feature Description
Public Event Pages View event details without auth (for global or public community events)
Public Discussion Posts View post content without auth (for public community posts)
Enhanced Public Community Pages Show activity metrics (member count, post count, event count)
Reusable CTA Component Warm, encouraging “Join” box with Belmont language
Return Path Storage Store intended URL, redirect after signup/login

Out of Scope

Feature Reason
Public access to private communities Privacy by design
Comments visible on public posts Encourage joining to see conversation
RSVP functionality on public events Incentive to join
Member list details on public communities Privacy protection

Visibility Rules

Content Type When Public
Events Global events (show_globally: true) OR events in public communities
Discussion Posts Posts in public communities only
Communities Communities with visibility: :public OR accessed with ref param

4. Technical Design

4.1 Controller Changes

Events Controller

Modify Cp::EventsController to allow public access to show action for qualifying events:

# app/controllers/cp/events_controller.rb

before_action :authenticate_cp_champion!, except: [:show]
before_action :require_authentication_or_public, only: [:show]

private

def require_authentication_or_public
  return if public_event_view?
  authenticate_cp_champion!
end

def public_event_view?
  return false unless @event
  
  # Global events are always public
  return true if @event.show_globally?
  
  # Events in public communities are public
  @event.communities.any?(&:visibility_public?)
end

Boards Controller

Modify Cp::BoardsController to allow public access to show action for qualifying posts:

# app/controllers/cp/boards_controller.rb

before_action :authenticate_cp_champion!, except: [:show]
before_action :require_authentication_or_public, only: [:show]

private

def require_authentication_or_public
  return if public_post_view?
  authenticate_cp_champion!
end

def public_post_view?
  return false unless @community
  @community.visibility_public?
end

Communities Controller

Already supports public access. Enhance to load activity metrics for public view:

# In show action, add for public view:
if !@is_logged_in
  @public_stats = {
    member_count: @community.champions.verified.count,
    post_count: @community.board_posts.active.count,
    event_count: @community.events.published.upcoming.count
  }
end

4.2 Return Path Storage

Add to ApplicationController or Cp::BaseController:

# Store the intended destination before redirecting to login
def store_return_path
  session[:return_to] = request.original_url if request.get?
end

# Retrieve and clear the stored path
def stored_return_path
  session.delete(:return_to)
end

Modify authentication redirect in Devise configuration or controller:

# After successful sign in
def after_sign_in_path_for(resource)
  stored_return_path || super
end

4.3 View Conditionals

Views will check cp_champion_signed_in? to show/hide content:

<% if cp_champion_signed_in? %>
  <!-- Full interactive content -->
<% else %>
  <!-- Public preview + CTA -->
  <%= render "cp/shared/public_cta_box", content_type: :event, community: @event.communities.first %>
<% end %>

4.4 Open Graph & Twitter Card Meta Tags

File: app/helpers/meta_tags_helper.rb

Rich link previews (iMessage, SMS, Slack, Facebook, LinkedIn) require Open Graph and Twitter Card meta tags. The MetaTagsHelper provides a centralized system for dynamic meta tag generation.

Default Values

Tag Default Value
Title “Belmont Alumni Champions”
Description “Once a Bruin, Always Connected.”
Image https://alumnichampions.com/meta-image-champions.png
Type “website”

Core Methods

# Generic meta tag setter - use in any view
set_meta_tags(
  title: "My Page Title",
  description: "Page description for previews",
  image: url_for(@image),
  url: request.original_url,
  type: "website"
)

# Render in layout <head>
<%= render_meta_tags %>

Convenience Methods

Method Content Type Description
set_community_meta_tags(community, inviter) Community Uses hero/thumbnail image, member count
set_event_meta_tags(event) Event Date, location, cover image, type=”event”
set_board_post_meta_tags(post, community) Discussion Post preview, community context
set_invite_meta_tags(inviter, community) Invite Link Personalized invite from Champion
set_news_post_meta_tags(post) News Article preview, type=”article”
set_roadmap_meta_tags Roadmap Development roadmap page

Generated HTML Output

<!-- Open Graph tags -->
<meta property="og:title" content="Spring Brunch | Belmont Alumni Champions">
<meta property="og:description" content="May 15, 2025 • Café Lula, Nashville • Join us for a casual brunch...">
<meta property="og:image" content="https://alumnichampions.com/rails/active_storage/blobs/.../event-cover.jpg">
<meta property="og:url" content="https://alumnichampions.com/events/spring-brunch-2025">
<meta property="og:type" content="event">

<!-- Twitter Card tags -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Spring Brunch | Belmont Alumni Champions">
<meta name="twitter:description" content="May 15, 2025 • Café Lula, Nashville • Join us for a casual brunch...">
<meta name="twitter:image" content="https://alumnichampions.com/rails/active_storage/blobs/.../event-cover.jpg">

Content-Specific Formatting

Events:

Communities:

Discussion Posts:

Invite Links:

Layout Integration

Both Champion Portal layouts include meta tags:

<!-- app/views/layouts/champions.html.erb -->
<head>
  <%= render_meta_tags %>
  ...
</head>

<!-- app/views/layouts/public.html.erb -->
<head>
  <%= render_meta_tags %>
  ...
</head>

Usage in Views

<%# Event show page %>
<% set_event_meta_tags(@event) %>

<%# Community page %>
<% set_community_meta_tags(@community) %>

<%# Discussion post %>
<% set_board_post_meta_tags(@post, @community) %>

<%# Signup page with invite context %>
<% set_invite_meta_tags(@inviter, @community) %>

Image Handling


5. UI Specifications

5.1 Public Event Page

Visible:

Hidden:

Layout:

┌─────────────────────────────────────────────────────────────────────┐
│ [Cover Image - full width]                                          │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  Spring Brunch with Nashville Champions                             │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━                            │
│                                                                     │
│  📅 Saturday, May 15, 2025 • 10:00 AM CT                            │
│  📍 Café Lula, Nashville, TN                                        │
│  👥 Hosted by Nashville Champions                                   │
│                                                                     │
│  Join us for a casual brunch to connect with fellow Bruins in       │
│  Nashville! We'll meet at Café Lula on 12 South for good food       │
│  and great conversation...                                          │
│                                                                     │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ╭─────────────────────────────────────────────────────────────╮    │
│  │  🎓 Want to RSVP?                                           │    │
│  │                                                             │    │
│  │  Join the Belmont Alumni Champions community to RSVP for    │    │
│  │  this event and connect with fellow Bruins.                 │    │
│  │                                                             │    │
│  │  [Join Alumni Champions]  [Already a member? Sign in]       │    │
│  ╰─────────────────────────────────────────────────────────────╯    │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

5.2 Public Discussion Post Page

Visible:

Hidden:

Layout:

┌─────────────────────────────────────────────────────────────────────┐
│  ← Back to Nashville Champions                                      │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  Best coffee shops for working remotely?                            │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━                            │
│                                                                     │
│  Posted by Sarah C. • January 15, 2026                              │
│                                                                     │
│  Hey Nashville Bruins! I'm looking for recommendations for          │
│  coffee shops with good wifi and space to work. I usually           │
│  work from home but want to mix it up sometimes...                  │
│                                                                     │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ╭─────────────────────────────────────────────────────────────╮    │
│  │  💬 Join the conversation!                                  │    │
│  │                                                             │    │
│  │  This discussion has 12 replies from fellow Champions.      │    │
│  │  Join to see comments and share your thoughts.              │    │
│  │                                                             │    │
│  │  [Join Alumni Champions]  [Already a member? Sign in]       │    │
│  ╰─────────────────────────────────────────────────────────────╯    │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

5.3 Enhanced Public Community Page

Visible:

Hidden:

Layout:

┌─────────────────────────────────────────────────────────────────────┐
│ [Hero Image - Nashville skyline]                                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  Nashville Champions                                                │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━                            │
│                                                                     │
│  Connect with fellow Bruins in Nashville! Join us for local         │
│  events, discussions, and community building.                       │
│                                                                     │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐                    │
│  │   👥 45     │ │   💬 23     │ │   📅 3      │                    │
│  │  Champions  │ │ Discussions │ │   Events    │                    │
│  └─────────────┘ └─────────────┘ └─────────────┘                    │
│                                                                     │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ╭─────────────────────────────────────────────────────────────╮    │
│  │  🏠 Find your Belmont home in Nashville                     │    │
│  │                                                             │    │
│  │  Join 45 fellow Bruins who are staying connected,           │    │
│  │  attending events, and building community together.         │    │
│  │                                                             │    │
│  │  [Join Nashville Champions]  [Already a member? Sign in]    │    │
│  ╰─────────────────────────────────────────────────────────────╯    │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

5.4 Reusable CTA Component

File: app/views/cp/shared/_public_cta_box.html.erb

Props:

Copy by Content Type:

Type Headline Body
Event “🎓 Want to RSVP?” “Join the Belmont Alumni Champions community to RSVP for this event and connect with fellow Bruins.”
Discussion “💬 Join the conversation!” “This discussion has {N} replies from fellow Champions. Join to see comments and share your thoughts.”
Community “🏠 Find your Belmont home in {City}” “Join {N} fellow Bruins who are staying connected, attending events, and building community together.”

Buttons:

Styling:


6. Implementation Checklist

Controllers

Views

Helpers


7. Tests to Create

Controller Tests

# test/controllers/cp/events_controller_test.rb

test "show allows public access for global event" do
  # No sign in
  get cp_event_url(@global_event)
  assert_response :success
end

test "show allows public access for event in public community" do
  get cp_event_url(@public_community_event)
  assert_response :success
end

test "show requires auth for event in private community" do
  get cp_event_url(@private_community_event)
  assert_redirected_to new_cp_champion_session_path
end

test "show stores return path for non-auth users" do
  get cp_event_url(@global_event)
  assert_equal cp_event_url(@global_event), session[:return_to]
end
# test/controllers/cp/boards_controller_test.rb

test "show allows public access for post in public community" do
  get cp_board_post_url(@public_community, @post)
  assert_response :success
end

test "show requires auth for post in private community" do
  get cp_board_post_url(@private_community, @post)
  assert_redirected_to new_cp_champion_session_path
end

test "show hides comments for non-auth users" do
  get cp_board_post_url(@public_community, @post)
  assert_select ".comments-section", count: 0
end

Helper Tests

# test/helpers/champion_helper_test.rb

test "public_display_name returns first name and last initial" do
  champion = cp_champions(:sarah_champion)
  champion.update!(first_name: "Sarah", last_name: "Champion")
  assert_equal "Sarah C.", champion.public_display_name
end

Integration Tests

# test/integration/public_landing_pages_test.rb

test "non-auth user can view public event and sign up" do
  # View event without auth
  get cp_event_url(@global_event)
  assert_response :success
  assert_select ".public-cta-box"
  
  # Click "Join" should preserve return path
  # (Full flow would be tested in system test)
end

8. Questions Resolved

Question Decision
Event visibility Global events OR events in public communities
Discussion visibility Posts in public communities only
Author display First name + last initial (e.g., “Sarah C.”)
CTA destination Use existing flow: /signup?community=slug with session-based return path

9. Files to Create/Modify

New Files

File Purpose
app/views/cp/shared/_public_cta_box.html.erb Reusable CTA component
test/integration/public_landing_pages_test.rb Integration tests

Modified Files

File Changes
app/controllers/cp/events_controller.rb Add public access logic
app/controllers/cp/boards_controller.rb Add public access logic
app/controllers/cp/communities_controller.rb Add public stats loading
app/controllers/cp/base_controller.rb Add return path methods
app/views/cp/events/show.html.erb Add public view conditional
app/views/cp/boards/show.html.erb Add public view conditional
app/views/cp/communities/show.html.erb Add activity metrics
app/models/cp/champion.rb Add public_display_name method
test/controllers/cp/events_controller_test.rb Add public access tests
test/controllers/cp/boards_controller_test.rb Add public access tests

10. Definition of Done