A complete, production-ready railway ticket booking application built with React + Spring Boot
- Project Overview
- Architecture
- Repository Layout
- Feature List
- Tech Stack Summary
- Quick Start
- Full Booking Flow
- Seeded Data
- Environment Setup Checklist
- API Overview
- Known Limitations
- Bug Fixes History
- Future Roadmap
RailBook is a full-stack railway ticket booking system modelled after Indian Railways. Users can search trains across 20 city pairs, select seats visually, fill passenger details, and complete payment through Razorpay β all within a polished, responsive UI that supports both dark and light themes.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Browser β
β React 18 + Vite Β· Tailwind CSS Β· React Router β
β http://localhost:5173 β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β REST API (JSON)
β Axios + JWT Bearer token
β
ββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββ
β Spring Boot 3.2 β
β JWT Auth Β· Spring Security Β· Spring Data JPA β
β http://localhost:8080 β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β JDBC / Hibernate ORM
β
ββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββ
β MySQL 8 (railbook_db) β
β 10 tables Β· Auto-created Β· Auto-seeded β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββ΄βββββββββββ
β β
βββββββΌβββββββ ββββββββΌβββββββ
β Razorpay β β Gmail SMTP β
β Payments β β Emails β
ββββββββββββββ βββββββββββββββ
railbook/
βββ README.md β This file (full project overview)
β
βββ railbook-frontend/ β React Frontend
β βββ README.md β Frontend-specific README
β βββ public/train-icon.svg β Custom train SVG favicon
β βββ .env β API URL + Razorpay Key ID
β βββ src/
β βββ api/ β Axios wrappers (7 files)
β βββ components/ β Reusable UI (7 components)
β βββ context/ β Auth + Booking + Theme state
β βββ hooks/ β useAuth, useTheme
β βββ pages/ β 19 pages / routes
β βββ utils/ β helpers.js
β
βββ railbook-backend/ β Spring Boot Backend
βββ README.md β Backend-specific README
βββ pom.xml
βββ src/main/
βββ resources/
β βββ application.yml β All credentials & config
βββ java/com/railbook/
βββ config/ β Security, CORS, DataSeeder
βββ controller/ β 6 REST controllers
βββ dto/ β 9 request + 11 response DTOs
βββ entity/ β 10 JPA entities
βββ enums/ β 5 enums
βββ exception/ β 8 exception classes
βββ repository/ β 9 repositories
βββ security/ β JWT filter + entry point
βββ service/ β 6 interfaces + 7 implementations
βββ util/ β 4 mappers + PnrGenerator
- Register with name, email, password, phone
- Login with JWT access token (24h) + refresh token (7 days)
- Auto token refresh on expiry
- User profile dropdown with sign out
- Search trains by From / To / Date / Passengers / Class
- Smart search β matches on city name OR station name (e.g. "Kolkata" finds "Kolkata Howrah")
- Browse all trains with live text search + type filter + class filter + sort
- 48 pre-seeded trains across 20 bidirectional Indian city pairs
- Search β enter route + date
- Select Train β filter by class, sort by price/rating/departure
- Select Seats β choose 1β6 passengers, pick seats on visual coach map
- Passenger Details β name, age, gender, berth pref, ID proof per passenger
- Payment β Razorpay checkout (Card / UPI / Netbanking / Wallet)
- Confirmation β E-ticket with PNR, passenger table, fare breakdown, print/share
- My Bookings β full history with status badges
- PNR Status β live lookup by PNR number
- Cancel Ticket β lookup by PNR with confirmation prompt
- Email confirmation on booking (Gmail SMTP)
- Dark / Light theme toggle β persists to localStorage, respects system preference
- Fully responsive β mobile, tablet, desktop
- 6-step booking progress stepper
- Sticky booking summary sidebar with live fare calculation
- Debounced station autocomplete (300ms)
- Loading spinners on all async operations
- Form validation with per-field error messages
Home Β· All Trains Β· Trains (search results) Β· Seats Β· Passengers Β· Payment Β· Confirmation Β· Login Β· Register Β· My Bookings Β· PNR Status Β· Help (FAQ) Β· Cancel Ticket Β· Contact Β· Refund Policy Β· Terms Β· Privacy Β· 404
| Framework | React 18.2 + Vite 5.1 |
| Styling | Tailwind CSS 3.4 (dark mode: class) |
| Routing | React Router DOM 6.22 |
| HTTP | Axios 1.6 with JWT interceptor |
| Icons | Lucide React 0.383 |
| State | React Context API (Auth + Booking + Theme) |
| Payment | Razorpay JS checkout widget |
| Framework | Spring Boot 3.2.3 |
| Language | Java 21 |
| Security | Spring Security 6.2 + JJWT 0.12.5 |
| Database | MySQL 8 via Spring Data JPA + Hibernate 6.4 |
| Payment | Razorpay Java SDK 1.4.5 |
| Spring Mail (Gmail SMTP) | |
| Build | Maven 3.9 |
# 1. Set your credentials in application.yml
# - spring.datasource.password
# - app.razorpay.key-id + key-secret
# - spring.mail.username + password
cd railbook-backend
mvn clean install
mvn spring-boot:run
# β http://localhost:8080
# β DB auto-created, 48 trains auto-seeded# 1. Set .env
# VITE_API_BASE_URL=http://localhost:8080/api
# VITE_RAZORPAY_KEY_ID=rzp_test_XXXXXXXXXXXXXXXX
cd railbook-frontend
npm install
npm run dev
# β http://localhost:5173Navigate to http://localhost:5173, register an account, and book a train.
[Home] Search: Delhi β Kolkata, 2 passengers
β
[Train List] Pick Rajdhani Express, 3A class β click Book
β
[Seats] Set passengers = 2, pick 2 seats from coach map
β
[Passengers] Fill details for Passenger 1 & 2 + contact info
β POST /api/bookings β creates PENDING booking, returns PNR
β
[Payment] Select UPI β click Pay βΉ4,XXX
β POST /api/payments/create-order β Razorpay order created
β Razorpay checkout opens
β POST /api/payments/verify β HMAC verified β CONFIRMED
β Confirmation email sent
β
[Confirmation] E-ticket shown with PNR, passenger list, fare breakdown
New Delhi (NDLS), Kolkata Howrah (HWH), Mumbai Central (MMCT), Chennai Central (MAS), Bangalore City (SBC), Hyderabad (HYB), Pune (PUNE), Chandigarh (CDG), Bhopal (BPL), Jaipur (JP), Prayagraj (ALD), Lucknow (LKO), Patna (PNBE), Bhubaneswar (BBS), Amritsar (ASR)
| Code | Name |
|---|---|
| SL | Sleeper |
| 3A | AC 3-Tier |
| 2A | AC 2-Tier |
| 1A | First Class AC |
| CC | Chair Car |
| EC | Executive Chair Car |
-
spring.datasource.passwordβ your MySQL password -
app.jwt.secretβ change to a secure 64-char secret in production -
app.razorpay.key-idβ from Razorpay Dashboard β Settings β API Keys -
app.razorpay.key-secretβ same location (never expose this) -
spring.mail.usernameβ your Gmail address -
spring.mail.passwordβ Gmail App Password (not your login password)
-
VITE_API_BASE_URL=http://localhost:8080/api -
VITE_RAZORPAY_KEY_ID=rzp_test_XXXXXXβ Key ID only (not secret)
- dashboard.razorpay.com β Sign up
- Switch to Test Mode (top right toggle)
- Settings β API Keys β Generate Test Key
- Copy Key ID β frontend
.envAND backendapplication.yml - Copy Key Secret β backend
application.ymlONLY
- Google Account β Security β 2-Step Verification (enable)
- Security β App Passwords β Generate
- Use the 16-char password in
spring.mail.password
Base URL: http://localhost:8080
All protected endpoints require: Authorization: Bearer <accessToken>
| Domain | Public Endpoints | Protected Endpoints |
|---|---|---|
| Auth | POST /register, /login, /refresh | POST /logout |
| Users | β | GET/PUT /users/me |
| Trains | POST /trains/search, GET /trains/all, /trains/{id}, /trains/{id}/seats | β |
| Stations | GET /stations, /stations/search | β |
| Bookings | GET /bookings/pnr/{pnr} | POST /bookings, GET /bookings, PATCH /{pnr}/cancel |
| Payments | β | POST /payments/create-order, /payments/verify |
| Item | Details |
|---|---|
| Contact form | UI only β no email service integrated yet |
| Seat locking | Seats marked BOOKED on POST /bookings β no real-time lock between concurrent users |
| Payment | Test mode only β use Razorpay test card 4111 1111 1111 1111 |
| Requires Gmail App Password and 2FA enabled | |
| No admin panel | Admin role exists in DB but no admin UI built yet |
| # | Bug | Fix |
|---|---|---|
| 1 | Login fails after 1β2 days with "Duplicate entry for refresh_tokens" | @Modifying @Query deleteByUserId() ensures DELETE flushes before INSERT |
| 2 | All Trains page returns 400 Bad Request | Removed @NotBlank/@NotNull from TrainSearchRequest |
| 3 | No trains found for Kolkata β Delhi search | DataSeeder now seeds 48 bidirectional trains; search also matches city name |
| 4 | Seat page always shows "Choose 1 seat" even for multi-passenger | Added passenger count selector (1β6) directly on SeatsPage |
| 5 | Register page: white text on white input in dark mode | Added text-slate-800 bg-white to all inputs in RegisterPage.jsx |
| 6 | OAuth2 removed | All Google/GitHub OAuth2 code removed from both frontend and backend |
- Contact Us β integrate EmailJS or Spring Boot
/api/contactendpoint - Admin panel β manage trains, view all bookings, update seat counts
- Real-time seat locking β Redis-based seat hold with 10-minute expiry
- Waitlist / RAC support
- Ticket PDF download
- SMS notification via Twilio
- Multi-language support (Hindi)
- PWA β offline mode and home screen install