Skip to content

Pranav-IIITM/Bookly

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

31 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Bookly Logo

Bookly

A full-stack appointment booking platform β€” pick a slot, sign in once, and your reservation is confirmed in real time.

Go Version Firebase Deployed on Vercel Frontend on Vercel License: MIT

Live Demo Β· API Health Β· Report a Bug


Table of Contents


Overview

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.


Features

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.

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        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       β”‚  β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Project Structure

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

Tech Stack

Backend

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

Frontend

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

Getting Started

Prerequisites

  • 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

Firebase Setup

  1. Go to Firebase Console and create a project.
  2. Enable Authentication β†’ Sign-in methods β†’ Email/Password and Google.
  3. Enable Firestore Database in production mode.
  4. Under Project Settings β†’ Service Accounts, click Generate new private key and save the JSON file.
  5. Register a Web App in Firebase Console and copy the config object β€” this goes into frontend/js/firebase-config.js.

Backend β€” Local Development

1. Clone the repository

git clone https://github.com/Pranav-IIITM/Bookly.git
cd Bookly

2. Configure environment variables

cp .env.example .env

Open .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.json

To generate the Base64 value:

# PowerShell
[Convert]::ToBase64String([IO.File]::ReadAllBytes("path\to\service-account.json"))
# Linux / macOS
base64 -w0 path/to/service-account.json

3. Install Go dependencies

go mod download

4. Run the server

go run main.go
# β†’ Bookly backend listening on http://localhost:8080

The seed function will automatically populate Firestore with default slots if the slots collection is empty.


Frontend β€” Local Development

  1. Open frontend/js/firebase-config.js and ensure the Firebase config object matches your project.
  2. Set the API_BASE variable to point to your local backend:
    const API_BASE = "http://localhost:8080";
  3. Serve the frontend/ directory with any static server, e.g. VS Code Live Server on port 5500 or 5501.
  4. Navigate to http://localhost:5500 (or whichever port your server uses).

Environment Variables

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_JSON or FIREBASE_CREDENTIALS_PATH must be provided.


API Reference

All API responses are JSON. Protected endpoints require a Firebase ID token in the Authorization: Bearer <token> header.

Public Endpoints

GET /api/health

Returns the server status and Firebase configuration info.

{
  "status": "ok",
  "project_id": "your-project-id",
  "cred_length": 1234,
  "key_id": "abc123"
}

GET /api/slots

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
    }
  ]
}

Protected Endpoints

Require Authorization: Bearer <firebase-id-token> header.

POST /api/auth/verify

Verifies the provided Firebase token and returns the decoded claims.

{
  "uid": "firebase_uid",
  "email": "user@example.com",
  "name": "Jane Doe"
}

POST /api/users/sync

Creates or updates the Firestore user document for the authenticated user. Call this after sign-in.

GET /api/user/{id}

Returns the user document for the given Firestore document ID.

POST /api/book

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

GET /api/bookings

Returns all bookings for the authenticated user, newest first, each enriched with the related slot data.

{
  "bookings": [ { ... } ]
}

Generic CRUD β€” /api/data

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

Deployment

Backend β€” Vercel

  1. Push your code to GitHub.
  2. Import the repository in the Vercel dashboard.
  3. Set the following Environment Variables in Project Settings β†’ Environment Variables:
    • FIREBASE_PROJECT_ID
    • FIREBASE_CREDENTIALS_JSON (Base64-encoded service account)
  4. Vercel will use vercel.json to route all /api/* requests to api/index.go.
  5. Deploy β€” the Go function initialises Firebase once per cold start and caches the router.

Frontend β€” Vercel

  1. Push your code to GitHub (the frontend/ directory is included in the repo root).
  2. In the Vercel dashboard, import the same repository.
  3. Set the Root Directory to frontend in the project settings.
  4. Update API_BASE in your JS files to point to your backend Vercel deployment URL.
  5. Deploy β€” Vercel will serve the static files automatically on every push to main.

Security

  • Credentials are never committed. .env, all *firebase-credentials*.json files, and base64_credentials.txt are 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.example as the template. Never add real secrets to .env.example.

Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository and create a feature branch:
    git checkout -b feat/your-feature-name
  2. Make your changes and ensure the backend compiles:
    go build ./...
  3. Commit using Conventional Commits:
    feat: add cancellation endpoint
    fix: handle empty slot collection gracefully
    
  4. Open a Pull Request against main with a clear description of your changes.

Please open an issue first for significant features or breaking changes.


License

This project is licensed under the MIT License.


Built with ❀️ using Go, Firebase, and Vanilla JS.

About

Appointment Booking Platform

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors