Persona is an AI-powered campus clubs discovery platform for TAMU that builds a "Persona DNA" for every student across 5 domains: academic, professional, social, sports, and volunteering. It uses local transformer embeddings (all-MiniLM-L6-v2, 384-dim) to match students to clubs, recommend clubs, and discover club events - all with explainable "why" reasoning.
- Frontend: React + TypeScript + Vite + Tailwind CSS + shadcn/ui
- Backend: Node.js + Express
- Database: PostgreSQL with Drizzle ORM + pgvector extension
- AI/ML: Local all-MiniLM-L6-v2 via @xenova/transformers (384-dim vectors), pgvector indexes, no external API dependencies
- Auth: Replit Auth (OpenID Connect)
- Routing: wouter (frontend), Express (backend)
- Bottom navigation bar (mobile-style) with 5 tabs: My DNA, Clubs, Explore, Events, Friends
- No sidebar - uses
BottomNavcomponent fixed at bottom of screen
/- Landing page (unauthenticated) / Profile page (authenticated, own profile)/profile/:userId- View another user's profile (class/year badges, Main Club, Event History, Mutuals)/recommendations- Club recommendations across 5 campus domains/explore- Full-screen topographical map (Leaflet + CartoDB dark tiles) centered on TAMU MSC (30.6187, -96.3365). Shows events within 48h as category-coded markers with heat map overlay, clubs as domain-coded markers (toggled via button), popups with details + friend avatars + Google Maps links, and a color-coded legend./events- Event discovery with persona+social+urgency scoring/social- Social matching with compatibility scores + "View Profile" links to /profile/:userId/about- About / How It Works page (TIDAL summary, interdisciplinary design, AI/ML explanation with code snippets). Opened by clicking the Persona logo in the header.
academic- Academic clubs (IEEE, Coding Club, AI/ML, Research, etc.)professional- Professional development (Consulting, Entrepreneurship, Finance, etc.)social- Social/cultural clubs (Film, Gaming, Korean SA, Dance, etc.)sports- Club sports (Soccer, Climbing, Basketball, Pickleball, etc.)volunteering- Service organizations (Habitat, Big Event, Camp Kesem, etc.)
- Full-screen themed background (Oceanic, Aurora, Ember, or custom image)
- Cover banner uses theme image with gradient overlay
- Avatar + name + class standing badge + grad year badge + cluster badges
- Users table: gradYear, classStanding, mainClubItemId fields
- Own Profile (
/): Settings menu (gear icon), theme switcher, layout editor - Other Profile (
/profile/:userId): Back button, Common/All event toggle, Mutuals section - Glassy see-through sections with backdrop-blur-xl:
- Top 3 Traits: highest scoring personality traits
- Main Club: user's primary club with hybrid ML match score + judge tooltips
- Event History: attended events list with ML match scores (Common/All toggle for other profiles)
- Persona DNA Radar: full radar chart + bar breakdown
- Gallery (Hobby Tags): combined hobby images + vertical reel cards with tags
- Mutual Connections: shared high-match users between viewer and target (other profiles only)
- Theme images stored in
client/src/assets/images/theme-*.png
GET /api/auth/user- Current authenticated userGET /api/taste-profile- User's taste profilePOST /api/onboarding- Complete onboarding with favorites + trait quizPOST /api/onboarding/reset- Reset onboarding (sets onboardingComplete to false)GET /api/recommendations/:domain- Get club recommendations for a domain (academic/professional/social/sports/volunteering)POST /api/interactions- Record user interaction (like/love/skip/save/view)GET /api/interactions/collection- Get user's saved/liked items collectionGET /api/social/matches- Get matched users with scoresGET /api/friends- Get current user's friends with shared clubs/eventsGET /api/friends/suggestions- Get friend suggestions with match scoresPOST /api/friends/:friendId- Add a friendDELETE /api/friends/:friendId- Remove a friendGET /api/events- Get all events (optionally filtered by category)POST /api/events/:id/rsvp- Toggle RSVP for an eventGET /api/events/:id/matches- Get match info for a specific eventGET /api/events/:id/attendee-matches- Get attendee match details for an eventGET /api/events/for-you- Personalized events: finalScore = 0.45personaScore + 0.30socialScore + 0.25*urgencyScoreGET /api/explore/hobbies- Get hobby recommendationsGET /api/explore/map-data- Map data: events (48h window) + clubs with locations, friend overlays, RSVP counts, persona scoresGET /api/profile/:userId- Get user profile data (traits, clusters, class/year)GET /api/profile/:userId/main-club- Get user's main club with hybrid ML match score for viewerGET /api/profile/:userId/event-history?mode=all|common- Event history with ML scores (common = shared events with viewer)GET /api/profile/:userId/mutuals- Mutual connections (users matching both viewer and target at >60%)POST /api/demo/bootstrap- Auto-create demo profile for authenticated userPOST /api/demo/reset- Reset demo state (dev-only auth bypass)GET /api/demo/story- Demo script with talking pointsGET /api/debug/ai-status- AI readiness checkGET /api/debug/embedding-health- Dashboard: embedding coverage, scoring mode statusGET /api/debug/embedding-similarity-sanity- Per-domain cosine similarity proofGET /api/debug/match-proof/:otherUserId- Cold-start matching proofPOST /api/admin/backfill-embeddings- Generate missing embeddings + recompute user profiles
- Embeddings-First Architecture: ML drives ranking; traits only explain. Fallback to traits only if embeddings missing.
- Vector Similarity (55%): Local neural embeddings via @xenova/transformers all-MiniLM-L6-v2 (384-dim, 100% reliable, no external API), cosine similarity scoring
- Collaborative Filtering (25%): Embedding-based neighbor discovery (top 20 users by tasteEmbedding cosine similarity), weighted action aggregation (love 2.0, save 1.5, like 1.0, view 0.3, skip -0.5), communityPicks with explanations
- Trait Explainability (20%): 8-axis trait algebra for human-readable "why" explanations only
- Scoring Methods:
embedding(vector-only),hybrid(vector+CF+traits),trait_fallback(no embeddings) - fallbackReason:
missing_user_embedding,missing_item_embedding,missing_both_embeddings,invalid_embedding_dim - Geolocation-aware event scoring with Haversine distance + privacy radius (TAMU coords: 30.6187, -96.3365)
- User taste embeddings recomputed synchronously on every interaction and onboarding (deterministic, not fire-and-forget)
- Startup warning logged if any items/events/hobbies missing embeddings
- Events include urgencyScore (0-100), urgencyLabel, and deadline fields
- Computed from signupDeadline, duesDeadline, and dateTime
- Labels: "last chance" (24h), "closing soon" (48h), "this week" (72h), "upcoming" (7d), "next week" (14d), "plenty of time"
- finalScore = 0.45 * personaScore + 0.30 * socialScore + 0.25 * urgencyScore
- personaScore: Embedding cosine similarity between user taste profile and event embedding
- socialScore: (avgSimilarity * 0.5 + friendBonus + attendeeBonus), capped at 100, min 15
- urgencyScore: Time-based urgency (100 for <24h, descending)
- Events include mutualFriendsGoingCount, mutualFriendsPreview (top 3), attendeePreview, whyRecommended
- "Mutuals" are attendees with >65% embedding match to the current user
- whyRecommended combines friends going + persona alignment + urgency + deal status
parties- Nightlife, bars, social gatherings (pink badges)deals- Food deals, student discounts, BOGO offers (emerald badges)campus- Campus events, tailgates, watch parties, pop-ups (blue badges)study- Study groups, exam prep, academic meetups (amber badges)shows- Concerts, open mics, vinyl markets, live music (purple badges)misc- Farmers markets, festivals, charity runs, art walks (teal badges)
dealExpiresAt(timestamp) - When a deal/promo expirespriceInfo(text) - Human-readable price/deal detailsisDeal(boolean) - Whether event has a deal/promotionorganizerName(text) - Event organizer name (separate from clubName)
- Trait-based similarity scoring across 8 axes: novelty, intensity, cozy, strategy, social, creativity, nostalgia, adventure
- Tag-to-trait mapping for building user profiles from preferences
- Distance-based RMS scoring for realistic match distribution (green 75+, yellow 50-74, red <50)
- Explainable matching with "why you match" insights
- Cluster generation (Engineering Leader, Creative Builder, Service Leader, etc.)
RadarChart- SVG radar visualization of taste traitsMatchPill- Color-coded match score badge (green/yellow/red)BottomNav- Fixed bottom navigation with 5 tabshobby-images.ts- Mapping of hobby names to stock imagesclub-images.ts- Mapping of club imageUrl keys to imported imagesevent-images.ts- Mapping of event imageUrl keys to imported imagesitem-images.ts- Mapping of item imageUrl keys to imported images
- 16 hobby images stored in
client/src/assets/images/ - Profile cover image at
client/src/assets/images/profile-cover.jpg - Theme images at
client/src/assets/images/theme-*.png - Imported via
@/assets/images/alias - Used in explore page hobby cards, profile personal images, and reels sections
users- Auth users (managed by Replit Auth) + locationLat/locationLng/privacyRadiusKm + gradYear/classStanding/mainClubItemId/instagramUrl/phoneNumbersessions- Session storage (managed by Replit Auth)taste_profiles- User taste DNA with 8 trait axes + clusters + embedding vector(384) + onboardingComplete flagitems- Campus clubs across 5 domains with trait values + embedding vector(384) + meeting details + signup/instagram URLs + dues info + location coordsinteractions- User interactions with items (like/love/skip/save/view) with weight valuesmatches- Cached match computationshobbies- Campus hobby entries with trait values + embedding vector(384)events- Lifestyle events with trait values + embedding vector(384) + locationLat/locationLng + dealExpiresAt/priceInfo/isDeal/organizerName + categories: parties/deals/campus/study/shows/miscevent_rsvps- RSVP records linking users to eventsfriendships- Bidirectional friend relationships between users
server/hybrid-engine.ts- Embeddings-first scoring: vector sim + CF + traits (explainability only)server/collaborative-filtering.ts- Embedding-based neighbor CF with weighted action aggregationserver/embeddings.ts- Local @xenova/transformers embeddings (all-MiniLM-L6-v2, 384-dim), recomputeTasteEmbedding (synchronous), checkEmbeddingHealthserver/taste-engine.ts- 8-axis trait algebra (explainability layer only)server/seed.ts- 50 TAMU campus clubs + 24 events + 16 hobbies + 10 seed users with embedding pipelineserver/routes.ts- Express API routes (30+ endpoints) including debug/health, demo/reset, friends, profile, and admin/backfill endpointsserver/storage.ts- DatabaseStorage class implementing IStorage interface for all CRUD operationsserver/db.ts- PostgreSQL pool and Drizzle ORM instanceserver/index.ts- Express app setup, middleware, server startup
client/src/App.tsx- Root app with auth flow, header with Persona dropdown menu (About, Retake Quiz, Log Out), theme toggleclient/src/pages/onboarding.tsx- Two-phase onboarding: intro/instructions screen then 6 Best-Worst Block questionsclient/src/pages/profile.tsx- Full-screen themed profile (own + other user) with glassy sectionsclient/src/pages/recommendations.tsx- Club recommendations across 5 domains with urgency scoringclient/src/pages/explore.tsx- Leaflet map with heat map overlay, marker spreading, event/club popupsclient/src/pages/events.tsx- Event discovery with persona+social+urgency scoringclient/src/pages/social.tsx- Friends list + Discover tab with swipeable friend suggestionsclient/src/pages/landing.tsx- Landing page for unauthenticated usersclient/src/pages/about.tsx- About/How It Works page
- 50 campus clubs: 10 per domain (academic, professional, social, sports, volunteering)
- 24 lifestyle events (parties, deals, study groups, concerts, campus events, misc) within 48h rolling window
- 16 campus-specific hobbies (intramural sports, hackathon building, tailgating, etc.)
- 10 seed users with diverse profiles, interactions, and RSVPs: Colin, Andy, Devon, Maya, Sophia, Marcus, Jake, Ravi, Emma, Lily
- Demo user profile: Tech Innovator / Hackathon Builder / Research Explorer
- Dark mode by default
- Green accent color scheme (primary: hsl(142, 76%, 36%))
- Mobile-first bottom navigation design
- Modular/customizable profile layout
- Fixed nested
<a>tag bug in social.tsx FriendListCard (caused React DOM warnings about<a>inside<a>). Changed outer<Link>todivwith onClick navigation. - Also fixed Instagram URL to use actual friend.instagramUrl instead of hardcoded URL.