Campus Communities — Full Stack

GryphChat

💭 Ever struggled to find the group chat for your class or people to study with on campus?

Between scattered Discord links, Instagram chats, and last minute invites, it always felt harder than it should be to connect with classmates or organize study sessions. I ran into the same problem, so I built GryphChat, a campus-wide messaging platform where students can discover their class group chats, message peers, run polls, and plan study sessions all in one place.

🔗 gryphchat.com

Currently, this project is built specifically for students in the University of Guelph though if you would like to see an app like this for your university, feel free to connect with me!

From a technical standpoint, GryphChat is a full-stack web application built with production reliability in mind:

  • OAuth 2.0 (Google) + credentials via NextAuth
  • Next.js 16 (App Router) + React 19
  • Prisma + Postgres for users, courses, memberships, messages
  • Supabase Realtime with a polling fallback
  • Cursor-based pagination with infinite scroll

This project pushed me to think beyond features and focus on scalability, user experience, and real world deployment constraints while building something students would actually use.

We are currently testing GryphChat with 50+ active users, and I would love any feedback as we continue to iterate and improve the platform.

#FullStack #NextJS #React #OAuth #SoftwareEngineering #WebDevelopment #StudentBuilders

Active Users 50+ testers
Campus University of Guelph
Delivery Realtime + polling fallback
Screenshot of gryphchat.com landing page
Course-aware chat UI that toggles between realtime Supabase channels and fast polling.

Next.js + React 19

App Router build with server components for data loading and client components for interactivity, keeping chat, dashboards, and onboarding fast and predictable.

Authentication

NextAuth with Prisma adapter + Postgres enables Google OAuth alongside bcrypt-backed credentials. Sessions use the database strategy to keep auth state durable across deployments.

Data Layer

Prisma runs on a pg pool via @prisma/adapter-pg with guards to avoid PgBouncer/poolers; connections must hit port 5432 directly for stability.

Design System

Tailwind CSS v4 lives in app/globals.css with custom CSS variables and a light/dark theme persisted in localStorage (theme init in app/layout.tsx and app/providers.tsx).

Landing + Lobby

Public landing page (app/page.tsx) introduces the product and embeds an AnonymousGlobalChat component for drop-in conversation backed by a dedicated anonymous user and the global course helper.

Auth + Onboarding

app/auth/page.tsx offers Google or credentials tabs; credentials signup hashes passwords, and login accepts email or username. app/onboarding/page.tsx lets newcomers claim a username via server action.

Dashboard + Discovery

app/dashboard/page.tsx fetches memberships server-side to show recent classes. app/classes/page.tsx lists all courses with member counts and search/filter/sort controls so students can join then redirect to chat.

Chat Experience

app/chat/page.tsx gates access on session, auto-enrolls users into the global course, honors ?courseId= for deep links, and renders a ChatExperience client with course filtering, membership pills, infinite scroll, and profile modals.

Realtime & Ordering

When Supabase keys exist, clients subscribe to messages-course-{id} channels for INSERT fan-out; otherwise they poll every 3 seconds. Client-side sortMessages/mergeMessages normalize ordering so pagination and live events co-exist cleanly.

Messaging Surface

The UI announces delivery mode (“Realtime connected” vs. “Live via polling”), exposes “Load older messages” when a cursor exists, and keeps compose + sender profile modals responsive during mode changes.

Global Membership

A seeded global-chat Course and helper auto-enroll new users so everyone can chat immediately, while the anonymous user powers the public lobby.

APIs

/api/messages handles cursor pagination and auto-join on read/send, /api/courses/join supports join by id or code, /api/profile validates majors/years + normalizes interests, and /api/public-global-chat runs the anonymous lobby.

Data Model

Prisma schema defines User (username, majorId, year, interests, optional passwordHash), Account/Session/VerificationToken, Course + ClassMembership join table, and Message indexed by course and creation timestamp.

Tooling & Seeds

scripts/maybe-run-migrations.js runs migrations pre-build if the DB is reachable. scripts/seed-courses.js ingests full_course_offerings.json (~6.5MB) to populate thousands of Course rows with derived major/level data.

Environment Guards

Env keys: DATABASE_URL (direct Postgres 5432), GOOGLE_CLIENT_ID/SECRET, NEXTAUTH_SECRET, NEXTAUTH_URL, optional NEXT_PUBLIC_SUPABASE_URL/NEXT_PUBLIC_SUPABASE_ANON_KEY, SKIP_PRISMA_MIGRATE, DB_CONNECT_TIMEOUT_MS, and PRISMA_INSECURE_TLS.

Profile UX

app/profile/page.tsx + ProfileForm let users edit name/major/year/interests with validation (lib/profile.ts), calling /api/profile. Snapshot cards mirror current selections for quick verification.

Navigation + Layout

AppLayout + TopNav provide active link highlighting, theme toggles, and sign-out flows while maintaining consistent rounded cards, gradients, and accessibility-focused focus states.

Portfolio Wins

Built a dual-auth, course-aware chat product with realtime + graceful polling fallback, infinite scroll, membership auto-enrollment, seeded course catalog, and deployment-friendly migration guards.