Side Project
TravelTrek: Travel & Tour Booking Platform
A full-stack travel and tour platform where customers book flights, hotels, and tours in one itinerary, while agents and admins manage operations and automated workers keep statuses up to date.

Overview
TravelTrek is a production-grade travel booking platform I built end to end, from the PostgreSQL schema to the phone-first UI: tours, hotels and rooms, flights, and payments in one system. It is both a working product and a portfolio piece, with a public demo board that runs the live system against real inventory served by its own API. It is a monorepo: a Next.js (App Router) + React 19 TypeScript frontend and an Express 5 + PostgreSQL TypeScript backend, sharing Zod validation across the wire. It is live at traveltrek.manuru.dev and MIT-licensed.
The Problem
Booking systems that touch money and inventory are deceptively hard to get right. Seats, rooms, and tour slots can be oversold under concurrent bookings; unpaid holds need to expire and return stock; payment webhooks can arrive twice and double-charge or double-notify; and money must never drift through floating-point rounding. On top of that, a real platform needs customer self-service (booking, cancellation, refunds, verified reviews) and staff operations (inventory, on-behalf-of bookings, reports) with proper roles, plus authentication solid enough to be trusted with people's contact details and payments. I wanted to build all of that to a production standard on my own.
The Solution
The backend is a strictly layered Express API (routes to controllers to dependency-injected services to Prisma), so the 350+ integration tests can swap fakes for Paystack, Cloudinary, mail/SMS, and the clock while hitting a real Postgres. Every concurrency-sensitive write (tour slots, flight seats, room inventory, payment settlement) uses guarded atomic updates inside transactions, so double-booking and duplicate-webhook races can't oversell or double-notify. All money is integer pesewas end to end, and each payment uses its Paystack reference as an idempotency key, with a refund-requested to refunded flow for cancellations. Staff and customers are deliberately separate tables with cross-table contact uniqueness, so a public signup can never shadow a staff login, and soft deletes with Restrict foreign keys mean money history can't cascade away. Background automation runs on BullMQ + Redis (in-process or as a dedicated worker): a deadline sweep cancels expired unpaid bookings and restores inventory, flight and tour statuses advance automatically from their dates, and every email/SMS is a durable job with retries and backoff. Auth is short-lived JWTs in httpOnly cookies with refresh-token rotation, replay detection, and session epochs (steal a token and every session dies), plus optional 2FA, passwordless OTP and Google sign-in, verified email and phone changes, account lockout, and enumeration-safe 401s. The Next.js frontend uses Redux Toolkit + RTK Query with a mutex-deduped silent refresh, react-hook-form with the same Zod schemas the server uses, and a phone-first UI, with observability throughout: pino structured logs, request correlation, Sentry, and health probes.