Performance-first portfolio with:
- Public landing page
- Projects page (category tabs, all published projects)
- Certificates page (image preview, issuer, year, verification link)
- Admin dashboard (
/admin) with Firebase Auth login - Image uploads stored in Supabase Storage public buckets
- Secure admin API in
server/server.jsusing Firebase Admin SDK + Firestore
- Frontend: Vue 3 + Vite + Vue Router
- Data: Cloud Firestore
- Auth: Firebase Authentication
- Admin API: Express + Firebase Admin SDK
- Image storage: Supabase Storage
/landing page/projectsproject list with category tabs/projects/:idproject detail page by ID/certificatescertificate gallery
/adminlogin and content management
Admin write operations call API endpoints and require Firebase ID token with admin: true custom claim.
Create .env in project root:
VITE_FIREBASE_API_KEY=...
VITE_FIREBASE_AUTH_DOMAIN=...
VITE_FIREBASE_PROJECT_ID=...
VITE_FIREBASE_STORAGE_BUCKET=...
VITE_FIREBASE_MESSAGING_SENDER_ID=...
VITE_FIREBASE_APP_ID=...
VITE_SUPABASE_URL=...
VITE_SUPABASE_ANON_KEY=...
VITE_SUPABASE_STORAGE_BUCKET=...
VITE_API_BASE_URL=http://localhost:3001Important: do not hardcode Firebase values in source files. Keep them only in environment variables so they are not embedded as fallback literals in deployed JS.
Set this variable for server/server.js:
FIREBASE_SERVICE_ACCOUNT={"type":"service_account",...}
PORT=3001FIREBASE_SERVICE_ACCOUNT must be a valid JSON string of your service account key.
projects/{id}title,summary,category,imageUrl,projectUrl,repoUrl,techStack[],featured,status
certificates/{id}title,issuer,year,imageUrl,verifyUrl,status
Use status: "published" to show items on public pages.
- Admin image file uploads now go to Supabase Storage.
- Set
VITE_SUPABASE_URL,VITE_SUPABASE_ANON_KEY, andVITE_SUPABASE_STORAGE_BUCKETin.env. - Uploaded public image URL is saved into Firestore
imageUrl. - Use a public Supabase bucket for the fastest browser delivery.
- Public
GET /api/public/projectsGET /api/public/certificates
- Admin (requires bearer ID token with admin claim)
POST /api/admin/projectsPUT /api/admin/projects/:idDELETE /api/admin/projects/:idPOST /api/admin/certificatesPUT /api/admin/certificates/:idDELETE /api/admin/certificates/:id
Frontend:
npm install
npm run devServer:
cd server
npm install
npm run dev- Rules:
firestore.rules - Indexes:
firestore.indexes.json - Storage rules:
storage.rules
Deploy after setup:
firebase deploy --only firestore:rules,firestore:indexes,storage