Skip to content
Jevon Christopher Loanda
All projects

PersonalReservation Systems2026

TAYO

One seat, multiple journeys. One safe booking decision.

A bus-booking application with segment-aware seat allocation, PostgreSQL advisory locks, idempotent booking, and temporary seat holds.

TAYO seat map with seat C2 selected and an active five-minute hold before booking

Overview

TAYO is a bus-booking application where passengers search scheduled trips, choose boarding and destination stops, and reserve a seat. An operations UI manages routes, buses, trips, and booking status. The engineering challenge is keeping seat availability correct across both route segments and competing requests.

TAYO boarding selection in Jakarta with destination choices in Bandung, Cirebon, and Semarang
A trip has ordered stops. Passengers reserve a journey between two stops, rather than the entire route. All shown trips and bookings use fictional demo data.

A Seat Belongs to a Segment

A single occupied flag would waste capacity: a passenger getting off in Bandung should not prevent another from using that seat onward to Semarang. TAYO compares ordered stop intervals. Adjacent journeys are valid; intervals that share any stretch of the route conflict. Pending and confirmed bookings both occupy inventory; cancelled bookings do not.

Segment-aware occupancy

Seat A1 can serve two adjacent journeys on the same trip.

JakartaBandungCirebonSemarang
Passenger A · seat A1Valid booking

Jakarta to Bandung

Passenger B · seat A1Valid adjacent reuse

Bandung to Semarang

Another request · seat A1Rejected: overlaps

Jakarta to Cirebon

The same overlap rule applies to active holds. A seat must also belong to the trip's bus, both stops must belong to its route, and the destination must follow the boarding stop. Availability shown in the browser is a snapshot; the write path validates the current database state again.

The Database Makes the Decision

Two passengers can see the same available seat before either submits a request. Checking availability and then inserting separately would leave a race. TAYO's Go/Gin API delegates to services and repositories; the repository makes the occupancy decision inside a PostgreSQL transaction.

Booking correctness boundary

Competing requests for the same trip and seat are serialized before checking occupancy.

01

Two passengers · Go API

Validate the request and derive user identity from the authenticated session.

02

Shared PostgreSQL advisory lock

Every hold or booking claim acquires the transaction-scoped lock for its trip and seat. A competing claim waits.

03

Validate segment + current occupancy

Check route order, bus membership, pending or confirmed bookings, and unexpired holds for overlap.

04

Commit one decision

Create a hold or booking when available; reject an overlapping claim. Hold conversion, booking, and retry mapping commit together.

The lock is deliberately scoped to the physical seat on a trip, even when requests concern different segments. This keeps one occupancy decision understandable at the cost of serializing those requests. It relies on every inventory-changing path using the same locking rule, including admin reconfirmation.

Booking creation also takes a user-scoped idempotency lock before the seat lock. A retry with the same key and payload returns the original booking instead of allocating again; reusing the key for a different payload is rejected. The frontend retains the confirmation key for the current hold while retrying.

A Hold Is Temporary, a Booking Is Durable

Selecting a seat creates a temporary hold for the chosen segment. PostgreSQL assigns its expiry and returns server time; the browser countdown is feedback, not the authority for reservation validity. The default hold lasts five minutes.

TAYO route segment and seat map showing selected seat C2, a five-minute hold countdown, and Confirm booking
The selected seat is protected during confirmation. Other passengers cannot claim an overlapping segment while this hold remains active.

Confirmation checks ownership, status, expiry, and occupancy under the seat lock, then creates a pending booking and marks the hold converted in the same transaction. Confirming a hold does not mean payment or admin approval: admins separately confirm or cancel bookings.

Expired holds stop blocking inventory through database-time filtering, without waiting for a cleanup job. The UI clears the selection, refreshes availability, and asks the passenger to choose again. Released holds also free inventory; stale or competing requests receive explicit recovery messages.

Successful TAYO demo booking for seat C2 from Jakarta to Semarang, showing pending status, departure, arrival, and price
A successful hold conversion creates one durable pending booking. The receipt distinguishes that state from later admin confirmation.

Proof & Current Scope

PostgreSQL integration tests cover adjacent reuse, overlapping races, concurrent requests with the same idempotency key, active and expired holds, confirmation races, and expiry boundaries. The backend suite and vet passed locally against an isolated PostgreSQL database during extraction. GitHub Actions is configured to run backend checks with PostgreSQL 17; no remote CI result is claimed.

Session handling uses HttpOnly cookies, validated JWT access tokens, and rotating refresh tokens stored as SHA-256 digests. Health and database-readiness endpoints, request IDs, and structured request logs support runtime diagnosis. These support the booking flow without replacing its transaction-level correctness checks.

TAYO currently demonstrates the reservation workflow in a local environment. Payment and ticket resale are not implemented. The screenshots use the existing fictional operational seed; they do not represent customers, production traffic, or commercial deployment.