- Type: Decentralized travel booking platform on Stellar blockchain
- Stack: Express.js (TypeORM, PostgreSQL), Next.js, Socket.io, Soroban smart contracts
- Key Features: Flight booking, smart contracts, refunds, loyalty programs
- Architecture: Monorepo with backend, client, and contracts packages
- Uses TypeORM with PostgreSQL for production (SQLite for tests)
- Existing WebSocket infrastructure via Socket.io with Redis adapter support
- Validation using Zod schema
- JWT authentication middleware
- Idempotency key pattern already implemented for bookings
- Redis for WebSocket Redis adapter (optional, fallback to in-memory)
- Existing migration system in place at
src/db/migrations/
Improve database query performance through indexing, query optimization, and connection pooling.
Files to create/modify:
packages/backend/src/db/analysis/queryAnalysis.ts(new)packages/backend/src/db/analysis/index-strategy.md(new)
Tasks:
-
Analyze current queries in key repositories:
flightRepository.ts- search, filter by date, airportbookingOrchestrationService.ts- booking queries- Flight-related aggregations
-
Identify N+1 query patterns:
- Bookings with eager-loaded Flight and Passenger
- Refunds with related bookings
- Flight search with price history
-
Create query performance report
Files to create:
packages/backend/src/db/migrations/1750001000000-AddMissingIndexes.ts(new)
Indexes to add:
-- Flight table optimizations
CREATE INDEX idx_flights_departure_time_airport ON flights(departureTime, fromAirport, toAirport);
CREATE INDEX idx_flights_status_updated ON flights(status, updatedAt);
CREATE INDEX idx_flights_sync_status ON flights(syncStatus, lastSyncedAt);
-- Booking table optimizations
CREATE INDEX idx_bookings_passenger_status ON bookings(passenger_id, status);
CREATE INDEX idx_bookings_flight_status ON bookings(flight_id, status);
CREATE INDEX idx_bookings_created_status ON bookings(createdAt, status);
-- Refund table optimizations
CREATE INDEX idx_refunds_booking_status ON refunds(booking_id, status);
CREATE INDEX idx_refunds_updated ON refunds(updatedAt);
-- User & Admin tables
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_admin_audit_created ON admin_audit_logs(createdAt, action);Files to modify:
packages/backend/src/services/bookingOrchestrationService.tspackages/backend/src/services/flightSearchService.tspackages/backend/src/api/routes/bookings.tspackages/backend/src/api/routes/flights.ts
Approach:
- Replace eager loading with explicit
.leftJoinAndSelect()in queries - Use
.relation()for lazy loading when needed - Batch queries for bulk operations
- Add query result caching for expensive operations
Example optimization:
// Before (N+1)
const bookings = await bookingRepo.find({ relations: ['flight', 'passenger'] });
// After (Query builder)
const bookings = await bookingRepo
.createQueryBuilder('booking')
.leftJoinAndSelect('booking.flight', 'flight')
.leftJoinAndSelect('booking.passenger', 'passenger')
.where('booking.status = :status', { status: 'confirmed' })
.select(['booking', 'flight.id', 'flight.flightNumber', 'passenger.email'])
.getMany();Files to modify:
packages/backend/src/db/dataSource.tspackages/backend/src/config/index.ts(add pooling config)
Implementation:
- Update dataSource configuration:
{
type: "postgres",
url: config.databaseUrl,
// Add connection pooling
extra: {
max: 20, // max connections
min: 5, // min connections
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
}
}- Add database health check endpoint for monitoring
- Migration file with indexes
- Updated repositories with optimized queries
- Database configuration updates
- Performance documentation
Real-time notifications for flight status changes (delays, gate changes, cancellations) via WebSocket.
Files to create:
packages/backend/src/services/flight-status.ts(new)packages/backend/src/jobs/flight-status-sync.ts(new)
Flight Status Service:
// Handle status updates: SCHEDULED, DELAYED, BOARDING, LANDED, CANCELLED
// Track: delayMinutes, gate, terminal, cancellationReason
// Broadcast via WebSocket to subscribed clientsImplementation details:
- Add status change detection logic
- Create job to periodically sync flight status from external APIs (Amadeus)
- Emit WebSocket events when changes detected
- Store historical status changes
Files to modify:
packages/backend/src/websockets/server.ts(extend)
New WebSocket events:
// Server → Client
flightStatusChange: (data: {
flightId: string;
previousStatus: string;
newStatus: string;
delayMinutes?: number;
gate?: string;
terminal?: string;
timestamp: Date;
}) => void;
// Client → Server
subscribeFlight: (flightId: string) => void;
unsubscribeFlight: (flightId: string) => void;Tasks:
- Add flight status subscription logic to WebSocket server
- Create room/namespace for each flight:
/flights/{flightId} - Handle subscriptions with idempotency (prevent duplicate subscriptions)
- Implement user-based access control (only show relevant flights)
Files to create:
packages/client/hooks/use-flight-status.ts(new)
Hook implementation:
export function useFlightStatus(flightId: string) {
const { socket, isConnected } = useSocket();
const [status, setStatus] = useState<FlightStatus | null>(null);
const [history, setHistory] = useState<StatusUpdate[]>([]);
const [isSubscribed, setIsSubscribed] = useState(false);
// Subscribe to flight status
// Handle status change events
// Track history
// Notify user of significant changes
return { status, history, isSubscribed };
}Files to modify:
packages/backend/src/services/PushNotificationService.ts(extend)packages/backend/src/services/flight-status.ts(add notifications)
Implementation:
- Send push notifications for:
- Flight delays > 15 minutes
- Gate changes
- Flight cancellations
- Use Firebase Cloud Messaging or similar
- Respect user notification preferences
- Include deep link to flight details
Files to create:
packages/backend/src/db/entities/FlightStatusHistory.ts(new)packages/backend/src/db/migrations/1750002000000-CreateFlightStatusHistory.ts(new)
Entity:
@Entity({ name: 'flight_status_history' })
export class FlightStatusHistory {
flightId: string;
previousStatus: string;
newStatus: string;
delayMinutes?: number;
gate?: string;
terminal?: string;
cancellationReason?: string;
timestamp: Date;
createdAt: Date;
}Files to modify:
packages/client/hooks/use-flight-search.ts(extend)packages/client/app/search/page.tsx(or similar search page)
Changes:
- Add real-time status indicator in flight cards
- Show delay warnings
- Gate/terminal info when available
- Highlight cancelled flights
- Flight status service
- Flight status sync job
- WebSocket event handlers
- Client hook for flight status
- Push notification integration
- Historical tracking with new entity
- Updated search UI
Comprehensive server-side validation, output encoding, and injection prevention.
Files to create:
packages/backend/src/middleware/validation.ts(new, comprehensive version)packages/backend/src/schemas/sanitization.ts(new)
Validation Middleware:
- Extend existing
validationMiddleware.tswith:- String length limits
- Pattern matching (emails, phone numbers, etc.)
- Type coercion & strict checking
- Nested object validation
- Array validation with item limits
Sanitization schemas:
// Passenger sanitization
export const passengerSanitizationSchema = z.object({
email: z.string().email().toLowerCase().trim(),
firstName: z.string().min(1).max(100).regex(/^[a-zA-Z\s'-]*$/),
lastName: z.string().min(1).max(100).regex(/^[a-zA-Z\s'-]*$/),
phone: z.string().regex(/^\+?[1-9]\d{1,14}$/).optional(),
sorobanAddress: z.string().regex(/^G[A-Z0-9]{55}$/),
});
// Booking sanitization
export const bookingSanitizationSchema = z.object({
flightId: z.string().uuid(),
passenger: passengerSanitizationSchema,
});- Create global validation middleware that:
- Validates all request bodies
- Validates query parameters
- Validates path parameters
- Removes unknown fields (whitelist approach)
Files to modify:
packages/backend/src/repositories/flightRepository.tspackages/backend/src/services/flightSearchService.ts- All API route handlers
Implementation:
- Audit all raw SQL queries (if any exist)
- Ensure ALL queries use parameterized queries with TypeORM
- Add query builder type safety
- Create protected method that prevents raw SQL:
// Example: Prevent raw queries
export class SafeQueryBuilder {
static ensureParamQuery(query: string) {
if (!query.includes(':param')) {
throw new Error('Raw SQL detected, use parameterized queries');
}
}
}- Test with SQL injection payloads:
'; DROP TABLE flights; --" OR 1=1 --
Files to modify:
packages/backend/src/services/amadeus/index.ts- Any MongoDB/Mongoose code (check loyalty service)
Implementation:
- Sanitize all input before database queries
- Use schema validation for all NoSQL operations
- No dynamic key evaluation:
db[userInput] - Use explicit query builders
Files to create:
packages/backend/src/utils/outputEncoder.ts(new)
Implementation:
- HTML entity encoding for XSS prevention:
export const encodeHTML = (str: string): string => {
const map: { [key: string]: string } = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
};
return str.replace(/[&<>"']/g, m => map[m]);
};-
Apply encoding in API responses:
- User-generated content
- Flight descriptions
- Cancellation reasons
- Error messages
-
JSON context encoding for API responses
Files to create:
packages/backend/src/api/schemas/full-validation.ts(comprehensive schemas)
Scope:
- Auth endpoints (
/auth/challenge,/auth/verify, etc.) - Booking endpoints (
POST /bookings,GET /bookings, etc.) - Flight endpoints (
GET /flights/search) - Refund endpoints (
POST /refunds/request) - User endpoints (
GET /users/profile, etc.)
Each schema should validate:
- Required fields
- Type correctness
- Length limits
- Format/pattern
- Business logic constraints
Files to modify:
packages/backend/src/middleware/securityMiddleware.tspackages/backend/src/middleware/csp.ts
Headers to ensure:
// CSP for XSS
'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline'"
// CORS strict
cors: {
origin: process.env.ALLOWED_ORIGINS?.split(',') || [],
credentials: true,
}
// X-Frame-Options for clickjacking
'X-Frame-Options': 'DENY'
// X-Content-Type-Options
'X-Content-Type-Options': 'nosniff'Files to modify:
packages/backend/src/middleware/rate-limit.ts
Add specific limits:
- Auth endpoints: 5 requests/hour per IP
- Search endpoints: 30 requests/minute per user
- Booking endpoints: 10 requests/minute per user
- File uploads: 5 requests/hour
Files to create:
packages/backend/src/security/validation-audit.ts(new)
Track:
- Failed validations (log details for analysis)
- Injection attempts
- Suspicious patterns
- Rate limit violations
- Comprehensive validation middleware
- Sanitization schemas
- Output encoding utilities
- SQL/NoSQL injection tests
- Updated security headers
- Rate limiting enhancements
- Security audit logging
Allow users to book multiple flight segments in a single transaction with combined pricing and refunds.
Files to create:
packages/backend/src/db/entities/MultiCityBooking.ts(new)packages/backend/src/db/entities/BookingSegment.ts(new)packages/backend/src/db/migrations/1750003000000-CreateMultiCityBooking.ts(new)
MultiCityBooking Entity:
@Entity({ name: 'multi_city_bookings' })
export class MultiCityBooking {
id: string; // UUID
userId: string;
totalPriceCents: number;
segmentCount: number;
status: BookingStatus;
// Links to individual flight bookings (segments)
segments: BookingSegment[];
// Combined refund handling
linkedRefundId?: string;
createdAt: Date;
updatedAt: Date;
}
@Entity({ name: 'booking_segments' })
export class BookingSegment {
id: string;
multiCityBookingId: string;
bookingId: string; // References individual Booking
sequenceNumber: number; // Order of segments
createdAt: Date;
}Files to create:
packages/backend/src/repositories/multiCityBookingRepository.ts(new)packages/backend/src/services/multi-city-booking.ts(new)
Multi-City Booking Service:
export class MultiCityBookingService {
// Create multi-city booking from flight segments
async createMultiCityBooking(
userId: string,
segments: Array<{ flightId: string; passenger: PassengerInfo }>
): Promise<MultiCityBooking>;
// Calculate total price across all segments
async calculateTotalPrice(segments: Flight[]): Promise<number>;
// Validate segment compatibility (no overlapping times, same passenger, etc.)
async validateSegments(segments: Flight[]): Promise<ValidationResult>;
// Handle combined booking submission to blockchain
async submitMultiCityBooking(bookingId: string, unsignedXdr: string): Promise<string>;
// Process combined refunds
async processMultiCityRefund(bookingId: string): Promise<void>;
}Files to create:
packages/backend/src/services/multiCitySmartContract.ts(new)
Smart Contract Integration:
- Create Soroban contract method for linked bookings
- Handle linked booking submission
- Track segment dependencies for refunds
- Ensure atomic transaction (all segments or none)
Contract considerations:
- Treat as single transaction on-chain
- Implement rollback if any segment fails
- Share refund pool across segments
Files to modify/create:
packages/backend/src/api/routes/bookings.ts(extend)packages/backend/src/api/schemas/multi-city.ts(new)
New endpoints:
POST /api/v1/bookings/multi-city
// Create multi-city booking
{
segments: [
{ flightId: "...", passenger: { ... } },
{ flightId: "...", passenger: { ... } }
]
}
// Returns: multi-city booking with total price and segments
GET /api/v1/bookings/multi-city/{bookingId}
// Get multi-city booking details with all segments
GET /api/v1/bookings/multi-city/{bookingId}/segments
// List all segments of a multi-city booking
DELETE /api/v1/bookings/multi-city/{bookingId}
// Cancel entire multi-city bookingFiles to create:
packages/client/app/book/multi-city/page.tsx(new)packages/client/components/multi-city-booking/SegmentForm.tsx(new)packages/client/components/multi-city-booking/SegmentList.tsx(new)packages/client/components/multi-city-booking/PriceSummary.tsx(new)packages/client/hooks/use-multi-city-booking.ts(new)
Multi-City Booking Page:
- Segment builder (add/remove flights)
- Date and time validation UI
- Passenger info forms (can reuse or simplify for multi-city)
- Combined price calculation
- Review all segments before booking
- Smart contract confirmation
UI Components:
- Add flight segment (date picker, airports, etc.)
- Flight segment card (remove button, details)
- Price breakdown (per segment + total)
- Booking summary
Files to modify:
packages/backend/src/services/refundService.ts(extend)packages/backend/src/api/routes/refunds.ts(extend)
Implementation:
- Create
MultiCityRefundentity or extend Refund - Handle partial refunds (refund single segment or all)
- Combine refund amounts
- Track dependencies between segments
Scenarios:
- Refund entire booking → refund all segments
- Refund single segment → calculate remaining segments
- Partial refund policies per segment
Files to create:
packages/backend/src/validators/multiCityValidator.ts(new)
Validations:
- Segments must have same passenger
- No overlapping flights (connection times)
- Minimum connection time (e.g., 2 hours)
- Maximum booking span (e.g., 30 days)
- Price calculations correct
- All segments on same booking
Files to create:
packages/client/hooks/use-multi-city-booking.ts(comprehensive)
Hook functionality:
export function useMultiCityBooking() {
const [segments, setSegments] = useState<FlightSegment[]>([]);
const [totalPrice, setTotalPrice] = useState(0);
const [isLoading, setIsLoading] = useState(false);
// Add/remove segments
// Validate segments
// Calculate price
// Submit booking
// Track booking status
}Files to create:
packages/backend/__tests__/services/multi-city-booking.test.ts(new)packages/client/tests/hooks/use-multi-city-booking.test.ts(new)
Test cases:
- Create multi-city booking with valid segments
- Validate segment compatibility
- Calculate correct total price
- Handle payment processing for multi-city
- Process multi-city refunds
- Edge cases (empty segments, invalid dates, etc.)
- New entities: MultiCityBooking, BookingSegment
- Multi-city booking service with all operations
- API endpoints for multi-city bookings
- Frontend pages and components
- Client hook for state management
- Smart contract integration
- Combined refund logic
- Comprehensive validation
- Test coverage
| Issue | Type | Priority | Complexity | Files | Timeline |
|---|---|---|---|---|---|
| #223 | Performance | Medium | Medium | 5-8 | 2-3 weeks |
| #209 | Feature | High | High | 10-15 | 3-4 weeks |
| #221 | Security | High | Medium | 8-12 | 2-3 weeks |
| #208 | Feature | High | High | 12-18 | 4-5 weeks |
- #221 (Security) - Foundation for other features
- #223 (Performance) - Optimize before adding heavy features
- #208 (Multi-City) - Core feature enhancement
- #209 (Real-Time) - UI improvement with WebSocket
- #221 → #209 (validation needed for real-time updates)
- #223 → #208 (optimization improves multi-city booking performance)
- #209 can run parallel to others (WebSocket is independent)