Skip to content
┌─kranthi@dev:~$
All projects
2026·Live

TravelGo

Full-stack travel booking platform with Google OAuth, JWT, seat selection, and a Gemini-powered travel assistant.

Full-stackAI

Problem

Bus booking portals in India are slow, cluttered, and rarely offer contextual travel guidance. TravelGo is a lean alternative: search, pick seats, book, and get AI-assisted travel recommendations in one flow.

Impact

  • 76 automated unit + integration tests
  • 91%+ code coverage
  • Load-tested with k6 under concurrent traffic
  • Role-based access control across users and operators

Architecture

flowchart LR
  U[User] --> W[React SPA]
  W -->|OAuth 2.0 / JWT| A[Auth Middleware]
  A --> API[REST API]
  API --> DB[(PostgreSQL via Supabase)]
  W -->|chat| G[Gemini 1.5 Flash]
  API --> Seats[Seat Locking Service]

Mermaid flowchart source — renders as a diagram when embedded in docs.

Data model

  • users (id, email, role, created_at)
  • operators (id, name, verified)
  • routes (id, origin, destination, distance_km)
  • trips (id, route_id, operator_id, departs_at, price)
  • seats (id, trip_id, code, status)
  • bookings (id, user_id, trip_id, seat_ids[], status, total)
  • payments (id, booking_id, provider, status)

API design

MethodPathPurpose
GET/api/trips?from&to&dateSearch trips
GET/api/trips/:id/seatsSeat map for a trip
POST/api/bookingsCreate a booking (protected)
GET/api/bookings/meCurrent user's bookings
POST/api/assistant/chatContext-aware Gemini chat

Features

  • Google OAuth 2.0 sign-in with JWT session issuance
  • Trip search with origin/destination/date filters
  • Live seat map with optimistic locking on selection
  • Role-based routes for users, operators, and admins
  • AI travel assistant grounded in the user's trip context

Engineering decisions & tradeoffs

Supabase over self-hosted Postgres

Trades vendor lock-in for a faster path to production auth, RLS, and hosted Postgres. Schema is portable, so migrating away later is a database export, not a rewrite.

JWT alongside OAuth

Google handles identity; the API issues its own short-lived JWTs so role claims and revocation are owned by the app, not the identity provider.

Tests as design pressure

Writing 76 tests up front forced small, pure modules — the seat-locking logic and booking state machine ended up isolated and easy to reason about.

Gemini 1.5 Flash over larger models

Flash is fast enough for interactive chat and cheap enough to keep free-tier friendly. Latency and cost mattered more than reasoning depth for travel Q&A.

Challenges & lessons

  • Preventing double-booking of the same seat under concurrent traffic — solved with a short-lived hold + transactional confirm.
  • Keeping the Gemini assistant grounded in the user's live trip context without leaking other users' data.
  • Shaping RLS policies so operators only see their own trips while admins can see everything.

Future improvements

  • Payments integration with idempotent webhooks
  • Push notifications for departures and cancellations
  • Move seat-locking to Redis for lower latency at scale