UCI Phi Kappa Psi Website

Chapter platform serving recruits, members, and alumni with CMS-driven content and event check-ins

Angular 21TypeScriptFirebaseGraphQLApollo
uciphipsi.kevinnorgaard.com
UCI Phi Kappa Psi Website screenshot

01Problem Statement

The Phi Kappa Psi chapter at UCI had no centralized digital presence — recruitment, alumni outreach, event coordination, and leadership history were all managed manually or scattered across disconnected tools. Officers needed a platform that could serve three distinct audiences (recruits, active members, alumni) and stay relevant year-round without requiring a developer for every content update or seasonal change.

02Architecture

Hygraph serves exec profiles, leadership history, and composite galleries via Apollo GraphQL — zero redeployment for content updates. The root route swaps at build time via an environment flag (normal / rush / philanthropy) to serve different seasonal landing pages from the same codebase. The admin dashboard is gated behind Firebase Auth and reads/writes rushee forms, event check-ins, and alumni records to Firebase Realtime Database.

03Data Model

Firebase Realtime Database

forms:
  "{phone}":
    name:         "LastName, FirstName"
    email:        string
    year:         string
    major:        string
    minor:        string
    cumGpa:       string
    prevGpa:      string
    sports:       string
    achievements: string
    reasons:      string
    referral:     string
    notes:        string  # admin-added
    socialMedia:
      facebook:   string
      instagram:  string
      linkedin:   string

checkins:
  "{phone}":
    "{date}": true  # date format: "YYYY-M-D"

alumni:
  "{name}":
    fullName: string
    email:    string

Hygraph CMS

type Image {
  fileName: String!
  url:      String!
}

type Executive {
  name:     String!
  position: String!
  image:    Image
  url:      String
  order:    Int!
}

type Leader {
  name:  String!
  title: String!
  year:  Int!
}

type MembershipPage {
  compositeImage: Image!
  compositeYear:  Int!
}