A full-stack pet adoption web application that connects loving families with pets waiting for their forever homes. Built with React 19, Express.js, and Firebase Firestore.
- Pet Browsing β Browse adoptable pets with filters for species, size, gender, and age category
- Pet Details β View detailed profiles with image galleries, bios, vital stats, and related pets
- Adoption Applications β Multi-section form (personal info, home environment, pet experience) submitted to Firestore
- Favorites β Save and view favorite pets in a bento-grid layout
- Sign In / Profile β Authentication page with Google and Apple social login options
- Responsive Design β Mobile-first layout with Material Design 3 inspired theming and organic/asymmetric card shapes
| Layer | Technology |
|---|---|
| Frontend | React 19, TypeScript, Vite 6 |
| Styling | Tailwind CSS v4, custom MD3 theme tokens |
| Routing | React Router v7 |
| Animations | Motion (Framer Motion) |
| Icons | Material Symbols, Lucide React |
| Backend | Express.js 4 |
| Database | Firebase Firestore (via firebase-admin) |
| Auth | Firebase Authentication (Google provider) |
| Validation | Zod |
| Deployment | Docker, Google Cloud Run, Cloud Build |
βββ src/
β βββ main.tsx # App entry point
β βββ App.tsx # Router configuration
β βββ index.css # Global styles, MD3 theme tokens, custom utilities
β βββ api/
β β βββ pets.ts # Frontend API client (fetchPets, fetchPet, submitApplication)
β βββ components/
β β βββ Navbar.tsx # Fixed top navigation bar
β β βββ Footer.tsx # Site footer with links
β βββ data/
β β βββ pets.ts # Pet type definition and seed data (6 pets)
β βββ layouts/
β β βββ MainLayout.tsx # Navbar + Outlet + Footer wrapper
β βββ pages/
β βββ Home.tsx # Landing page with hero, how-it-works, featured pets, CTA
β βββ PetList.tsx # Browsable pet grid with sidebar filters
β βββ PetDetails.tsx # Individual pet profile with gallery and adoption CTA
β βββ Favorites.tsx # Saved pets in bento-grid layout
β βββ Apply.tsx # Adoption application form
β βββ Profile.tsx # Sign-in / authentication page
βββ server/
β βββ server.ts # Express API server with pet and application routes
β βββ firestore.ts # Firebase Admin SDK initialization
β βββ seed.ts # Database seeder script
βββ Dockerfile # Multi-stage build (Node 20)
βββ cloudbuild.yaml # Google Cloud Build CI/CD pipeline
βββ deploy.sh # One-command Cloud Run deployment script
βββ vite.config.ts # Vite config with proxy to backend
βββ tsconfig.json # Frontend TypeScript config
βββ tsconfig.server.json # Server TypeScript config
- Node.js 20+
- Google Cloud Project with Firestore enabled
- gcloud CLI authenticated (
gcloud auth application-default login)
npm installCopy the example env file and fill in your values:
cp .env.example .env.localGOOGLE_CLOUD_PROJECT=your-gcp-project-id
PORT=3001
# Firebase Web SDK (frontend) β NOT secret, identifies the project
VITE_FIREBASE_API_KEY=your-firebase-web-api-key
VITE_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=your-gcp-project-idSign-in uses Firebase Authentication with the Google provider.
- In the Firebase console, open your project β Authentication β Sign-in method β enable Google.
- Open Project settings β General β "Your apps" β register a Web app and copy the
apiKey,authDomain,projectIdinto.env.localusing theVITE_FIREBASE_*variables above. - To gate admin-only routes (pet CRUD, listing all applications), sign in once to create your user, then grant yourself the
admincustom claim:
tsx server/scripts/grantAdmin.ts <your-uid>The user must sign out and back in for the claim to take effect on the client.
Populate Firestore with sample pet data (6 pets β dogs and cats):
npm run seedStarts both the Vite dev server (port 3000) and Express API server (port 3001) concurrently:
npm run devThe frontend proxies /api requests to the backend automatically.
| Script | Description |
|---|---|
npm run dev |
Start frontend + backend concurrently |
npm run dev:client |
Start Vite dev server only (port 3000) |
npm run dev:server |
Start Express server with hot reload (port 3001) |
npm run build |
Build frontend with Vite |
npm run build:server |
Compile server TypeScript |
npm run build:all |
Build both frontend and server |
npm run start |
Start production server |
npm run seed |
Seed Firestore with sample pet data |
npm run lint |
Type-check with TypeScript |
npm run clean |
Remove build artifacts |
Mutating and admin endpoints require a Firebase ID token in the Authorization: Bearer <token> header. Admin-only routes additionally require the admin: true custom claim (see Firebase Authentication).
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/pets |
β | List all pets (supports species, size, gender, ageCategory query filters) |
GET |
/api/pets/:id |
β | Get a single pet by ID |
POST |
/api/pets |
admin | Create a new pet |
PUT |
/api/pets/:id |
admin | Update a pet |
DELETE |
/api/pets/:id |
admin | Delete a pet |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/api/applications |
user | Submit an adoption application (server stamps userId) |
GET |
/api/applications |
admin | List all applications |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/favorites |
user | List the current user's favorited pet IDs |
PUT |
/api/favorites/:petId |
user | Add a pet to favorites |
DELETE |
/api/favorites/:petId |
user | Remove a pet from favorites |
./deploy.sh <GCP_PROJECT_ID> [REGION] [SERVICE_NAME]
# Example:
./deploy.sh my-gcp-project us-central1 adoptpawsRequired GCP APIs:
- Cloud Run
- Cloud Build
- Artifact Registry
- Firestore
Enable them with:
gcloud services enable run.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
firestore.googleapis.comgcloud builds submit --config cloudbuild.yaml \
--substitutions=_REGION=us-central1,_SERVICE_NAME=adoptpawsdocker build -t adoptpaws .
docker run -p 8080:8080 \
-e NODE_ENV=production \
-e GOOGLE_CLOUD_PROJECT=your-project-id \
adoptpawsThe Dockerfile uses a multi-stage build: stage 1 builds the Vite frontend and compiles the server TypeScript, stage 2 copies only production artifacts and dependencies.
The app uses a custom Material Design 3 inspired theme defined in src/index.css with:
- Fonts: Plus Jakarta Sans (headings), Be Vietnam Pro (body)
- Color tokens: Full MD3 surface/primary/secondary/tertiary/error palette
- Custom utilities:
organic-shape/organic-card/asymmetric-cardfor distinctive rounded corners (3rem top-left/bottom-right, 1rem top-right/bottom-left) - Background: Subtle radial gradient mesh (
bg-mesh)
| Path | Page | Layout |
|---|---|---|
/ |
Home | MainLayout |
/pets |
Pet listing with filters | MainLayout |
/pets/:id |
Pet detail page | MainLayout |
/favorites |
Saved favorites | MainLayout |
/apply/:petId |
Adoption application | MainLayout |
/profile |
Sign in / profile | Full screen (no layout) |
Apache-2.0