A full-stack appointment booking platform β pick a slot, sign in once, and your reservation is confirmed in real time.
Live Demo Β· API Health Β· Report a Bug
- Overview
- Features
- Architecture
- Project Structure
- Tech Stack
- Getting Started
- Environment Variables
- API Reference
- Deployment
- Security
- Contributing
- License
Bookly is a modern appointment booking system built with a Go backend and a vanilla HTML/CSS/JS frontend. It uses Firebase Authentication for identity management and Cloud Firestore as its database.
Every booking goes through an atomic Firestore transaction β slot capacity is checked and the booking is created in a single operation, preventing double-bookings even under concurrent load. Both the frontend and backend are deployed on Vercel β the frontend as a static site and the backend as a serverless Go function.
| Feature | Description |
|---|---|
| π Firebase Auth | Sign in with Google OAuth or email/password. Firebase ID tokens are verified on every protected API call. |
| π Real-time Slot Availability | Available slots are fetched live from the Go backend on every page load β no stale cache. |
| βοΈ Atomic Bookings | Slot capacity checks and booking creation happen inside a single Firestore transaction, eliminating race conditions. |
| π§Ύ Personal Dashboard | Authenticated users can view all their past and upcoming bookings, each enriched with the related slot details. |
| π Dynamic Auth UI | Navigation and hero buttons automatically reflect the user's sign-in state β "Sign In" becomes "Logout" after authentication. |
| π Booking Confirmation | A confetti animation fires on successful booking for a satisfying user experience. |
| βοΈ Serverless Backend | The Go API runs as a single Vercel serverless function with zero cold-start infrastructure to manage. |
| π± Auto-seeded Slots | Default time slots are seeded automatically on first deployment via an idempotent seed function. |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Browser / Client β
β HTML + CSS + Vanilla JS (Vercel Static) β
β β
β ββββββββββββββββ Firebase SDK ββββββββββββββββββββββββ β
β β Auth Pages β βββββββββββββββ β Firebase Auth β β
β ββββββββββββββββ β (ID Token issuance) β β
β ββββββββββββββββ REST + Bearer ββββββββββββββββββββββββ β
β β Slots / Bookβ ββββββββββββββββββββββββββββββββββββββββββΌββ
β β Dashboard β β β
β ββββββββββββββββ β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β HTTPS
βββββββββββββββββββββββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Vercel Serverless Function (Go 1.22) β
β api/index.go βββΊ chi Router β
β β
β Middleware: Firebase Token Verification, CORS, Logger β
β β
β βββββββββββββββ ββββββββββββββββ βββββββββββββββββββββ β
β β /api/slots β β /api/book β β /api/bookings β β
β β (public) β β (protected) β β (protected) β β
β βββββββββββββββ ββββββββββββββββ βββββββββββββββββββββ β
β β
β Cloud Firestore (Firebase Admin SDK) β
β ββββββββββββββββ βββββββββββββββββ ββββββββββββββββββ β
β β /slots β β /bookings β β /users β β
β ββββββββββββββββ βββββββββββββββββ ββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Bookly/
β
βββ api/
β βββ index.go # Vercel serverless entry point; router setup & middleware
β
βββ cmd/ # Optional CLI tooling
β
βββ pkg/
β βββ config/ # Firebase Admin SDK initialisation (env vars / credentials)
β βββ db/ # Firestore seed functions
β βββ handlers/
β β βββ auth.go # POST /api/auth/verify
β β βββ bookings.go # POST /api/book, GET /api/bookings
β β βββ data.go # Generic CRUD: /api/data
β β βββ slots.go # GET /api/slots
β β βββ users.go # POST /api/users/sync, GET /api/user/:id
β β βββ response.go # Shared JSON/error helpers
β βββ middleware/
β β βββ auth.go # Firebase ID-token verification middleware
β βββ models/ # Booking, Slot, User struct definitions
β
βββ frontend/
β βββ index.html # Landing page
β βββ auth.html # Sign-in / sign-up page
β βββ slots.html # Available slots listing
β βββ booking.html # Booking confirmation page
β βββ dashboard.html # User's bookings dashboard
β βββ favicon.png # App icon
β βββ css/
β β βββ style.css # Global design system & component styles
β βββ js/
β βββ firebase-config.js # Firebase SDK initialisation (client-side)
β βββ nav-auth.js # Dynamic auth button state management
β βββ ... # Page-specific scripts
β
βββ main.go # Local development server entry point
βββ go.mod / go.sum # Go module definition & checksums
βββ vercel.json # Vercel routing & CORS header config
βββ .env.example # Template for required environment variables
βββ .gitignore
| Technology | Purpose | |
|---|---|---|
| πΉ | Go 1.22 | Core API language |
| π | go-chi/chi v5 | HTTP router |
| π₯ | Firebase Admin SDK (Go) | Firestore client & Auth token verification |
| βοΈ | Cloud Firestore | NoSQL database |
| βοΈ | joho/godotenv | .env loading for local development |
| π | Vercel | Serverless deployment |
| Technology | Purpose | |
|---|---|---|
| π | HTML5 / CSS3 | Markup and design system |
| β¨ | Vanilla JavaScript (ESM) | Page logic and API calls |
| π₯ | Firebase JS SDK v10 | Client-side auth (Google, email/password) |
| π | canvas-confetti | Booking confirmation animation |
| ποΈ | Inter (Google Fonts) | Typography |
| π | Vercel | Static frontend hosting |
- Go 1.22+
- A Firebase project with Firestore and Authentication enabled
- A Firebase service account JSON key (download from Project Settings β Service Accounts)
- Node.js and Firebase CLI (for frontend deployment only)
- A local HTTP server such as Live Server for frontend development
- Go to Firebase Console and create a project.
- Enable Authentication β Sign-in methods β Email/Password and Google.
- Enable Firestore Database in production mode.
- Under Project Settings β Service Accounts, click Generate new private key and save the JSON file.
- Register a Web App in Firebase Console and copy the config object β this goes into
frontend/js/firebase-config.js.
1. Clone the repository
git clone https://github.com/Pranav-IIITM/Bookly.git
cd Bookly2. Configure environment variables
cp .env.example .envOpen .env and fill in your values:
PORT=8080
FIREBASE_PROJECT_ID=your-project-id
# Option A β Base64-encoded service account JSON (recommended)
FIREBASE_CREDENTIALS_JSON=<base64-encoded-service-account>
# Option B β Path to local JSON file (local dev only)
# FIREBASE_CREDENTIALS_PATH=pkg/firebase-credentials.jsonTo generate the Base64 value:
# PowerShell
[Convert]::ToBase64String([IO.File]::ReadAllBytes("path\to\service-account.json"))# Linux / macOS
base64 -w0 path/to/service-account.json3. Install Go dependencies
go mod download4. Run the server
go run main.go
# β Bookly backend listening on http://localhost:8080The seed function will automatically populate Firestore with default slots if the slots collection is empty.
- Open
frontend/js/firebase-config.jsand ensure the Firebase config object matches your project. - Set the
API_BASEvariable to point to your local backend:const API_BASE = "http://localhost:8080";
- Serve the
frontend/directory with any static server, e.g. VS Code Live Server on port5500or5501. - Navigate to
http://localhost:5500(or whichever port your server uses).
| Variable | Required | Description |
|---|---|---|
PORT |
No | Port for the local server. Defaults to 8080. |
FIREBASE_PROJECT_ID |
Yes | Your Firebase project ID (e.g. my-project-abc12). |
FIREBASE_CREDENTIALS_JSON |
Yes* | Base64-encoded Firebase service account JSON. Required in production (Vercel). |
FIREBASE_CREDENTIALS_PATH |
Yes* | Path to the service account JSON file. Alternative to FIREBASE_CREDENTIALS_JSON for local dev. |
* One of
FIREBASE_CREDENTIALS_JSONorFIREBASE_CREDENTIALS_PATHmust be provided.
All API responses are JSON. Protected endpoints require a Firebase ID token in the Authorization: Bearer <token> header.
Returns the server status and Firebase configuration info.
{
"status": "ok",
"project_id": "your-project-id",
"cred_length": 1234,
"key_id": "abc123"
}Returns all available (not fully booked) slots, sorted by date and time.
{
"slots": [
{
"id": "slot_001",
"date": "2026-07-01",
"time": "09:00",
"capacity": 5,
"bookedCount": 2
}
]
}Require
Authorization: Bearer <firebase-id-token>header.
Verifies the provided Firebase token and returns the decoded claims.
{
"uid": "firebase_uid",
"email": "user@example.com",
"name": "Jane Doe"
}Creates or updates the Firestore user document for the authenticated user. Call this after sign-in.
Returns the user document for the given Firestore document ID.
Creates a booking for the authenticated user. Atomically validates slot capacity.
Request body:
{ "slotId": "slot_001" }Response (201):
{
"booking": {
"id": "booking_xyz",
"userId": "user_abc",
"slotId": "slot_001",
"status": "confirmed",
"createdAt": "2026-06-23T10:00:00Z",
"slot": { ... }
}
}Error responses:
| Status | Reason |
|---|---|
400 |
Slot is already full |
401 |
Missing or invalid Firebase token |
404 |
Slot or user not found |
Returns all bookings for the authenticated user, newest first, each enriched with the related slot data.
{
"bookings": [ { ... } ]
}| Method | Endpoint | Description |
|---|---|---|
POST |
/api/data |
Create a Firestore document |
GET |
/api/data/{id} |
Read a document by ID |
PUT |
/api/data/{id} |
Update a document |
DELETE |
/api/data/{id} |
Delete a document |
- Push your code to GitHub.
- Import the repository in the Vercel dashboard.
- Set the following Environment Variables in Project Settings β Environment Variables:
FIREBASE_PROJECT_IDFIREBASE_CREDENTIALS_JSON(Base64-encoded service account)
- Vercel will use
vercel.jsonto route all/api/*requests toapi/index.go. - Deploy β the Go function initialises Firebase once per cold start and caches the router.
- Push your code to GitHub (the
frontend/directory is included in the repo root). - In the Vercel dashboard, import the same repository.
- Set the Root Directory to
frontendin the project settings. - Update
API_BASEin your JS files to point to your backend Vercel deployment URL. - Deploy β Vercel will serve the static files automatically on every push to
main.
- Credentials are never committed.
.env, all*firebase-credentials*.jsonfiles, andbase64_credentials.txtare listed in.gitignore. - Firebase ID tokens are verified server-side on every protected endpoint via the Firebase Admin SDK β the client cannot forge a valid token.
- CORS is explicitly whitelisted to only accept requests from the known frontend origins (Firebase Hosting and localhost).
- Use
.env.exampleas the template. Never add real secrets to.env.example.
Contributions are welcome! Please follow these steps:
- Fork the repository and create a feature branch:
git checkout -b feat/your-feature-name
- Make your changes and ensure the backend compiles:
go build ./...
- Commit using Conventional Commits:
feat: add cancellation endpoint fix: handle empty slot collection gracefully - Open a Pull Request against
mainwith a clear description of your changes.
Please open an issue first for significant features or breaking changes.
This project is licensed under the MIT License.