Internal admin portal for the Texas A&M SHPE chapter. Officers use this Next.js app to manage the same Firebase backend (tamushpemobileapp) as the chapter mobile app — events, membership verification, points, committees, and operational tools.
Access is restricted to @tamu.edu Google accounts with Firebase custom claims (admin, officer, or developer).
| Route | Purpose |
|---|---|
/dashboard |
Post-login landing (stub) |
/events |
Event calendar and pending attendance approvals |
/points |
School-year points ledger with edit, export, and recalculation |
/membership |
SHPE membership verification (approve/deny requests) |
/committees |
Read-only committee directory |
/tools |
Resume zip generation and shirt pickup tracker |
For a full architecture breakdown, data model, and feature documentation, see docs/PURPOSE_AND_FUNCTIONALITY.md.
Local development runs entirely against the Firebase Emulator Suite — no real Firebase credentials are needed (or present) until go-live cutover.
One command boots the emulators, seeds fixture data, and starts the Next.js app:
docker compose up| Service | URL / port |
|---|---|
| App | http://localhost:3001 |
| Emulator UI | http://localhost:4000 |
| Firestore | localhost:8080 |
| Auth | localhost:9099 |
| Storage | localhost:9199 |
On first boot the web service runs bun install, waits for the emulators, runs bun run seed, then bun run dev. The repo is bind-mounted, so edits on the host hot-reload inside the container.
Emulator sign-in (seeded officer account):
- Email:
shpe-officer@tamu.edu - Password:
testpassword
Use the email/password form on the login page (not Google OAuth) while on the emulators.
Stop with Ctrl+C, or run detached with docker compose up -d / docker compose down.
If you already have the emulators running and want to run the app on the host:
bun install
bun run seed # seed emulator fixtures (idempotent)
bun run dev # http://localhost:3000
bun run build
bun run start
bun run lintHost runs expect the emulator host env vars from .env.development (FIRESTORE_EMULATOR_HOST=localhost:8080, etc.).
Point a host bun run dev at the real tamushpemobileapp project via gitignored .env.local. See .env.example for the full template.
- Copy the Production-local block from
.env.exampleinto.env.local(already scaffolded with placeholders if present). - Fill secrets from Firebase Console → project
tamushpemobileapp:NEXT_PUBLIC_GOOGLE_API_KEY— Project settings → Your apps → Web API keyFIREBASE_SERVICE_ACCOUNT_KEY— Project settings → Service accounts → Generate new private key → stringify to one line (keep\nescapes insideprivate_key)
- Keep emulator overrides explicit in
.env.local(required — omitting them leaves.env.developmentvalues in effect):NEXT_PUBLIC_USE_FIREBASE_EMULATORS=falseFIRESTORE_EMULATOR_HOST=/FIREBASE_AUTH_EMULATOR_HOST=/FIREBASE_STORAGE_EMULATOR_HOST=(empty)
- Stop
docker compose(do not use Docker for this mode). - On the host:
bun install && bun run dev→ http://localhost:3000 - Sign in with Google
@tamu.edu(the emulator email/password form does not apply). Your account needs a recognized custom claim (admin/officer/developer).
Warning: every write hits real chapter data.
next build gotcha: without emulator hosts set, FIREBASE_SERVICE_ACCOUNT_KEY must be a valid service-account JSON — Admin SDK initializes at import time for /api/[[...route]].
Convention tracking: there is no need to pre-create a convention-tracking collection in the console. The first successful track (POST /api/conventions/track) creates convention-tracking/{uid} via the Admin SDK. An empty roster UI is expected until officers import/track members. Production Firestore read rules must allow officers to read convention-tracking/{document=**} (same claim gate as other admin reads); without that, the tracker UI fails even though track/untrack writes succeed.
- Next.js 14 (App Router) + React 18 + TypeScript
- Tailwind CSS for styling
- Firebase (Auth, Firestore, Storage, Cloud Functions)
- ExcelJS for client-side points export
app/
├── page.tsx # Login
├── (main)/ # Authenticated pages (events, points, membership, …)
├── api/firebaseUtils.ts # Client-side Firestore helpers (not HTTP routes)
├── config/ # Firebase initialization
├── helpers/ # Auth and utilities
└── types/ # Domain models (kept in sync with mobile app)
- Mobile app — shares Firestore collections and type definitions
- Firebase Cloud Functions —
updateAllUserPoints,sendNotificationMemberSHPE,zipResume(not in this repo)
Hosted on Vercel. See cors.json for allowed origins.