Private Firebase-powered member portal for planning a family reunion with approval-based access, attendee registration, events, hotels, files, bulletin posts, direct messages, and a single privileged Cloud Function API.
- React 19 + Vite + TypeScript
- Firebase Auth with Google sign-in
- Firestore for app data
- Firebase Storage for images and PDFs
- Vercel for the SPA
- One HTTPS Cloud Function for privileged admin work
- The client uses Firebase web config, which is public by design.
- No service account keys or Admin SDK credentials are stored in the client.
- Firestore Rules and Storage Rules enforce access control.
- Member approval and role changes route through
functions/src/index.ts. - Uploads are limited to images and PDFs in Storage Rules.
-
Install app dependencies:
npm install
-
Install function dependencies:
npm --prefix functions install
-
Copy
.env.exampleto.env.localand fill in your Firebase web app config and function URL. -
Start the app:
npm run dev
If the Storage page shows “Due to recent security improvements…” and Attach permissions errors, Storage is misconfigured at the project level until this is fixed. CORS alone will not help.
-
Blaze billing — Cloud Storage for Firebase now requires the pay-as-you-go (Blaze) plan. Upgrade in Firebase → Upgrade if you’re still on Spark.
-
Manual IAM (when the console repair fails)
- Open Google Cloud IAM for the project (must be Owner or Project IAM Admin).
- Project settings in Firebase → copy Project number (numeric).
- Grant access → New principals:
service-<PROJECT_NUMBER>@gcp-sa-firebasestorage.iam.gserviceaccount.com
Example: if project number is123456789, useservice-123456789@gcp-sa-firebasestorage.iam.gserviceaccount.com. - Role: Storage Admin (
roles/storage.admin) or try Firebase Admin SDK Administrator Service Agent if listed. Save. - Wait a minute, reload Firebase → Storage, then try Fix issue / Attach permissions again.
-
If it still fails: Firebase support or an org admin (organization policies sometimes block automatic role grants).
-
Bucket name — Your console shows
gs://gtfast-7bf85.appspot.com. Your web app’sstorageBucketmust match that bucket (not a different bucket). If the SDK points atgtfast-7bf85.firebasestorage.appbut the only bucket isappspot.com, align.envwith the bucket Firebase shows.
CORS is per bucket. If VITE_FIREBASE_STORAGE_BUCKET is gtfast-7bf85.firebasestorage.app but you only ran gsutil on …appspot.com, production uploads still fail.
From the repo root (applies CORS to both default bucket names if they exist):
gcloud auth login
npm run storage:corsOr manually:
gsutil cors set storage-cors.json gs://gtfast-7bf85.firebasestorage.app
gsutil cors set storage-cors.json gs://gtfast-7bf85.appspot.comEdit storage-cors.json to add origins (for example your Vercel production domain and preview domain), then run the command again for the same bucket your app uses. VITE_FIREBASE_STORAGE_BUCKET must match the bucket name in Firebase Console → Storage (rebuild after changing secrets).
- Build the app:
npm run build - Build functions:
npm run build:functions - Deploy the frontend with Vercel
- Deploy Firebase backend resources after authenticating and enabling Firestore, Storage, and Functions on project
gtfast-7bf85 - In Vercel, set
VITE_FUNCTIONS_URLto your deployed HTTPS Function URL because the old Firebase Hosting/apirewrite is gone
The app shows Demo mode when Firebase config is missing or incomplete. Then it uses fake data so you can still click around. Config comes from env vars (VITE_FIREBASE_*).
- Local: Add a
.env.local(copy from.env.example) and fill in your real Firebase web app config from Firebase Console → Project settings → Your apps. Restartnpm run devafter changing env. - Deployed site: The Vercel build must have those env vars at build time. If they are not set, the deployed app has no config and stays in demo mode.
Pushes to main (and manual runs) deploy Firebase backend resources via .github/workflows/deploy-firebase.yml.
- FIREBASE_TOKEN (for deploy): run
firebase login:ciand add the token as a repo secret. - Configure your frontend environment variables in Vercel instead of GitHub Actions.
The workflow uses the project in .firebaserc (default: gtfast-7bf85).
users: approval state, role, profiledirectory: approved member directory for messagingregistrations: one attendee record per approved userevents: reunion schedulehotels: room-block info and booking linksbulletinPostsandbulletinCommentsthreads/{threadId}/messagesassetsinvites
- Email invite sending is intentionally left as a backend extension point. The current function API creates opaque invite links and returns a clear error for email sending until a mail provider is configured securely.
- If Firebase is unavailable, the UI falls back to demo-mode sample data so the portal can still be previewed.