# VIP Coordinator - Claude AI Context **Last Updated:** 2026-01-25 **Status:** Active Development - Starting Fresh Build ## Project Overview VIP Coordinator is a full-stack web application for managing VIP transportation logistics and event coordination. It handles VIP profiles, driver assignments, event scheduling with conflict detection, flight tracking, and user management with role-based access control. **⚠️ CURRENT STATUS: FRESH BUILD IN PROGRESS** - Starting from scratch with modern 2026 best practices - No production data - database can be reset at any time - Feel free to make breaking changes without asking - **Focus:** Getting features working correctly > preserving legacy code --- ## Technology Stack (2026 Best Practices) ### Backend - **Framework:** NestJS 10.x (TypeScript) - **Database ORM:** Prisma 5.x - **Database:** PostgreSQL 15+ - **Caching:** Redis 7 (optional, for driver location tracking) - **Authentication:** Auth0 + Passport.js (JWT strategy) - **Validation:** class-validator + class-transformer - **Runtime:** Node.js 20+ ### Frontend - **Framework:** React 18.2.0 (stable) - **Build Tool:** Vite 5.x - **UI Components:** Shadcn UI (modern, lightweight) - **Styling:** Tailwind CSS 3.4+ - **Data Fetching:** TanStack Query v5 (formerly React Query) - **Routing:** React Router 6.x - **Forms:** React Hook Form + Zod - **Auth:** Auth0 React SDK (@auth0/auth0-react) ### Infrastructure - **Development:** Docker + Docker Compose - **Production Target:** Digital Ocean (App Platform or Droplet) - **Services:** PostgreSQL, Redis (optional), Backend API, Frontend SPA ### Why These Choices? **NestJS over Express:** - Built-in structure prevents spaghetti code - Dependency injection, decorators, guards - Excellent TypeScript support - Scales well for complex applications **Prisma over raw SQL:** - Type-safe database queries - Automatic migrations - Prevents SQL injection by default - Auto-completion in IDE **Shadcn UI over Material-UI:** - Modern design (2024-2026 standard) - Lightweight (copy components into project) - Full control over styling - Better performance **TanStack Query:** - Essential for server state management - Automatic caching and refetching - Optimistic updates - Industry standard for React **Auth0:** - Reliable hosted authentication - No self-hosting required - Social login support - Excellent documentation - Free tier for development --- ## Project Structure ``` vip-coordinator/ ├── backend/ # NestJS Backend (port 3000) │ ├── prisma/ │ │ ├── schema.prisma # Database schema (source of truth) │ │ ├── migrations/ # Auto-generated migrations │ │ └── seed.ts # Sample data for development │ ├── src/ │ │ ├── main.ts # App entry point │ │ ├── app.module.ts # Root module │ │ ├── auth/ # Auth0 + JWT authentication │ │ │ ├── auth.module.ts │ │ │ ├── auth.service.ts │ │ │ ├── jwt.strategy.ts │ │ │ ├── guards/ # @Roles(), @Public() guards │ │ │ └── decorators/ # @CurrentUser() decorator │ │ ├── users/ # User management + approval │ │ │ ├── users.module.ts │ │ │ ├── users.service.ts │ │ │ ├── users.controller.ts │ │ │ └── dto/ │ │ ├── vips/ # VIP profile management │ │ ├── drivers/ # Driver resource management │ │ ├── events/ # Schedule + conflict detection │ │ ├── flights/ # Flight tracking API │ │ ├── prisma/ # Prisma service │ │ │ ├── prisma.module.ts │ │ │ └── prisma.service.ts │ │ └── common/ # Shared utilities │ ├── package.json │ └── .env │ ├── frontend/ # React Frontend (port 5173) │ ├── src/ │ │ ├── main.tsx # App entry point │ │ ├── App.tsx # Root component + routing │ │ ├── components/ │ │ │ ├── ui/ # Shadcn UI components │ │ │ ├── auth/ # Login, ProtectedRoute │ │ │ ├── vips/ # VIP forms, lists │ │ │ ├── drivers/ # Driver components │ │ │ └── events/ # Schedule components │ │ ├── pages/ │ │ │ ├── Dashboard.tsx │ │ │ ├── VIPList.tsx │ │ │ ├── VIPDetails.tsx │ │ │ ├── DriverList.tsx │ │ │ ├── SchedulePage.tsx │ │ │ ├── FlightsPage.tsx │ │ │ └── AdminUsersPage.tsx │ │ ├── lib/ │ │ │ ├── api.ts # Axios client │ │ │ └── queryClient.ts # TanStack Query config │ │ ├── hooks/ │ │ │ ├── useAuth.ts # Auth0 wrapper │ │ │ └── usePermissions.ts │ │ └── types/ # TypeScript interfaces │ ├── package.json │ └── .env │ ├── docker-compose.yml # Development environment ├── docker-compose.prod.yml # Production build └── CLAUDE.md # This file (source of truth) ``` --- ## Database Schema (Prisma) ### Core Models ```prisma model User { id String @id @default(uuid()) auth0Id String @unique // Auth0 sub claim email String @unique name String? picture String? role Role @default(COORDINATOR) isApproved Boolean @default(false) driver Driver? // Optional linked driver createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? // Soft delete } model VIP { id String @id @default(uuid()) name String organization String? department Department arrivalMode ArrivalMode expectedArrival DateTime? // For self-driving airportPickup Boolean @default(false) venueTransport Boolean @default(false) notes String? flights Flight[] events ScheduleEvent[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? } model Driver { id String @id @default(uuid()) name String phone String department Department? userId String? @unique user User? @relation(fields: [userId], references: [id]) events ScheduleEvent[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? } model ScheduleEvent { id String @id @default(uuid()) vipId String vip VIP @relation(fields: [vipId], references: [id]) title String location String? startTime DateTime endTime DateTime description String? type EventType @default(TRANSPORT) status EventStatus @default(SCHEDULED) driverId String? driver Driver? @relation(fields: [driverId], references: [id]) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? } model Flight { id String @id @default(uuid()) vipId String vip VIP @relation(fields: [vipId], references: [id]) flightNumber String flightDate DateTime segment Int @default(1) departureAirport String // IATA code (e.g., "JFK") arrivalAirport String // IATA code (e.g., "LAX") scheduledDeparture DateTime? scheduledArrival DateTime? actualDeparture DateTime? actualArrival DateTime? status String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } enum Role { ADMINISTRATOR COORDINATOR DRIVER } enum Department { OFFICE_OF_DEVELOPMENT ADMIN } enum ArrivalMode { FLIGHT SELF_DRIVING } enum EventType { TRANSPORT MEETING EVENT MEAL ACCOMMODATION } enum EventStatus { SCHEDULED IN_PROGRESS COMPLETED CANCELLED } ``` ### Relationships - User ↔ Driver: One-to-one (optional) - VIP ↔ Flight: One-to-many - VIP ↔ ScheduleEvent: One-to-many - Driver ↔ ScheduleEvent: One-to-many ### Soft Delete Pattern All main entities have `deletedAt` field. Always filter: ```typescript where: { deletedAt: null, ...otherConditions } ``` --- ## User Roles & Permissions | Feature | Administrator | Coordinator | Driver | |---------|--------------|-------------|--------| | User Management | ✅ Full CRUD | ❌ None | ❌ None | | VIP Management | ✅ Full CRUD | ✅ Full CRUD | 👁️ View Only | | Driver Management | ✅ Full CRUD | ✅ Full CRUD | 👁️ View Only | | Event Scheduling | ✅ Full CRUD | ✅ Full CRUD | ⚠️ View + Update Status | | Flight Tracking | ✅ Full Access | ✅ Full Access | ❌ None | ### First User Bootstrap - **First user to register becomes Administrator automatically** - `isApproved: true` by default for first user - Subsequent users require admin approval - No manual database editing needed --- ## Development Workflow ### Prerequisites - Node.js 20+ and npm 10+ - Docker Desktop - Auth0 Account (free tier) - Git ### Initial Setup **1. Clone and Install** ```bash git clone cd vip-coordinator # Backend cd backend npm install # Frontend cd ../frontend npm install ``` **2. Configure Auth0** - Create Auth0 account at https://auth0.com - Create new Application (Single Page Application) - Create new API - Note: `Domain`, `Client ID`, `Audience` - Configure callback URLs: - Allowed Callback URLs: `http://localhost:5173/callback` - Allowed Logout URLs: `http://localhost:5173` - Allowed Web Origins: `http://localhost:5173` **3. Environment Variables** **Backend `.env`:** ```env DATABASE_URL="postgresql://postgres:postgres@localhost:5432/vip_coordinator" REDIS_URL="redis://localhost:6379" AUTH0_DOMAIN="your-tenant.us.auth0.com" AUTH0_AUDIENCE="https://your-api-identifier" AVIATIONSTACK_API_KEY="your-api-key" # Optional for flight tracking NODE_ENV=development PORT=3000 ``` **Frontend `.env`:** ```env VITE_API_URL=http://localhost:3000/api/v1 VITE_AUTH0_DOMAIN=your-tenant.us.auth0.com VITE_AUTH0_CLIENT_ID=your-client-id VITE_AUTH0_AUDIENCE=https://your-api-identifier ``` **4. Database Setup** ```bash cd backend # Generate Prisma Client npx prisma generate # Run migrations npx prisma migrate dev --name init # Seed sample data (optional) npx prisma db seed ``` **5. Run Development Servers** **Option A: Docker (Recommended)** ```bash # From project root docker-compose up -d # View logs docker-compose logs -f backend docker-compose logs -f frontend ``` **Option B: Local** ```bash # Terminal 1: PostgreSQL + Redis docker-compose up -d postgres redis # Terminal 2: Backend cd backend npm run start:dev # Terminal 3: Frontend cd frontend npm run dev ``` **6. Access Application** - Frontend: http://localhost:5173 - Backend API: http://localhost:3000/api/v1 - Prisma Studio: `npx prisma studio` (database GUI) ### Common Development Tasks **Database Migrations** ```bash # Create new migration after schema changes npx prisma migrate dev --name describe_your_changes # Reset database (SAFE IN DEV - no important data) npx prisma migrate reset # View database in GUI npx prisma studio ``` **Adding a New Feature Module** **Backend (NestJS):** ```bash cd backend nest g resource --no-spec # Generates module, service, controller ``` 1. Update `prisma/schema.prisma` with new models 2. Run `npx prisma migrate dev` 3. Create DTOs in `src//dto/` 4. Add guards: `@Roles('ADMINISTRATOR', 'COORDINATOR')` 5. Implement service methods using Prisma **Frontend (React):** 1. Create page in `src/pages/Page.tsx` 2. Add route in `App.tsx` 3. Create API hooks using TanStack Query 4. Add navigation link 5. Implement role-based rendering **Code Generation** ```bash # Backend nest g module nest g service nest g controller # Prisma npx prisma generate # After schema changes npx prisma migrate dev # Create migration ``` --- ## Key Patterns & Best Practices ### Backend (NestJS) Patterns **1. Controllers** ```typescript @Controller('vips') @UseGuards(JwtAuthGuard, RolesGuard) export class VipsController { constructor(private vipsService: VipsService) {} @Get() @Roles('ADMINISTRATOR', 'COORDINATOR', 'DRIVER') async findAll(@CurrentUser() user: User) { return this.vipsService.findAll(); } @Post() @Roles('ADMINISTRATOR', 'COORDINATOR') async create(@Body() createVipDto: CreateVipDto, @CurrentUser() user: User) { return this.vipsService.create(createVipDto); } } ``` **2. Services (Prisma)** ```typescript @Injectable() export class VipsService { constructor(private prisma: PrismaService) {} async findAll() { return this.prisma.vip.findMany({ where: { deletedAt: null }, include: { flights: true, events: true }, orderBy: { createdAt: 'desc' }, }); } async create(data: CreateVipDto) { return this.prisma.vip.create({ data: { ...data, // Prisma handles timestamps automatically }, }); } async softDelete(id: string) { return this.prisma.vip.update({ where: { id }, data: { deletedAt: new Date() }, }); } } ``` **3. DTOs with Validation** ```typescript import { IsString, IsEnum, IsOptional, IsBoolean } from 'class-validator'; export class CreateVipDto { @IsString() name: string; @IsEnum(Department) department: Department; @IsEnum(ArrivalMode) arrivalMode: ArrivalMode; @IsOptional() @IsBoolean() airportPickup?: boolean; } ``` **4. Custom Decorators** ```typescript // Get current user from request export const CurrentUser = createParamDecorator( (data: unknown, ctx: ExecutionContext): User => { const request = ctx.switchToHttp().getRequest(); return request.user; }, ); ``` **5. Guards** ```typescript @Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const requiredRoles = this.reflector.get('roles', context.getHandler()); if (!requiredRoles) return true; const { user } = context.switchToHttp().getRequest(); return requiredRoles.includes(user.role); } } ``` ### Frontend (React) Patterns **1. Protected Routes** ```typescript function App() { return ( } /> }> } /> } /> ); } ``` **2. Data Fetching with TanStack Query** ```typescript // Hook function useVIPs() { return useQuery({ queryKey: ['vips'], queryFn: async () => { const { data } = await api.get('/vips'); return data; }, }); } // Component function VIPList() { const { data: vips, isLoading, error } = useVIPs(); if (isLoading) return ; if (error) return ; return ; } ``` **3. Mutations** ```typescript function useCreateVIP() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async (vip: CreateVIPDto) => { const { data } = await api.post('/vips', vip); return data; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['vips'] }); toast.success('VIP created successfully'); }, onError: (error) => { toast.error(error.message); }, }); } ``` **4. Forms with React Hook Form + Zod** ```typescript const vipSchema = z.object({ name: z.string().min(1, 'Name required'), department: z.enum(['OFFICE_OF_DEVELOPMENT', 'ADMIN']), arrivalMode: z.enum(['FLIGHT', 'SELF_DRIVING']), }); type VIPFormData = z.infer; function VIPForm() { const { register, handleSubmit, formState: { errors } } = useForm({ resolver: zodResolver(vipSchema), }); const createVIP = useCreateVIP(); const onSubmit = (data: VIPFormData) => { createVIP.mutate(data); }; return (
); } ``` **5. Role-Based Rendering** ```typescript function usePermissions() { const { user } = useAuth0(); return { canManageUsers: user?.role === 'ADMINISTRATOR', canEditVIPs: ['ADMINISTRATOR', 'COORDINATOR'].includes(user?.role), isDriver: user?.role === 'DRIVER', }; } // Usage function VIPList() { const { canEditVIPs } = usePermissions(); return (
{canEditVIPs && }
); } ``` ### Error Handling **Backend:** ```typescript // Built-in HTTP exceptions throw new NotFoundException(`VIP with ID ${id} not found`); throw new BadRequestException('Invalid flight number format'); throw new UnauthorizedException('User not approved'); throw new ForbiddenException('Insufficient permissions'); // Custom exception filter (optional) @Catch(HttpException) export class HttpExceptionFilter implements ExceptionFilter { catch(exception: HttpException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); const status = exception.getStatus(); response.status(status).json({ statusCode: status, message: exception.message, timestamp: new Date().toISOString(), }); } } ``` **Frontend:** ```typescript // Global error boundary }> // Query error handling const { data, error } = useQuery({ queryKey: ['vips'], queryFn: fetchVIPs, onError: (error) => { console.error('[VIP] Failed to fetch:', error); toast.error('Failed to load VIPs. Please try again.'); }, }); ``` ### Logging **Backend (NestJS Logger):** ```typescript @Injectable() export class VipsService { private logger = new Logger(VipsService.name); async create(data: CreateVipDto) { this.logger.log(`Creating VIP: ${data.name}`); try { const vip = await this.prisma.vip.create({ data }); this.logger.log(`VIP created: ${vip.id}`); return vip; } catch (error) { this.logger.error(`Failed to create VIP: ${error.message}`, error.stack); throw error; } } } ``` **Frontend:** ```typescript // Prefix all logs with feature area console.log('[AUTH] User logged in:', user); console.error('[API] Request failed:', error); console.warn('[SCHEDULE] Conflict detected:', conflict); console.debug('[FLIGHT] Status updated:', flight); ``` --- ## Working with Claude AI ### What Claude CANNOT Do **⚠️ Browser Testing Limitations:** - Cannot see your browser window or UI - Cannot view browser console directly - Cannot see network requests in DevTools - Cannot click buttons or interact with the app ### How to Help Claude Debug **✅ Good Feedback Examples:** 1. **Console Errors:** ``` I clicked Login and got this error: ``` [AUTH] Failed to authenticate POST http://localhost:3000/api/v1/auth/login 401 Unauthorized: Invalid credentials ``` ``` 2. **Network Errors:** ``` When I try to create a VIP, the request fails: Request: POST /api/v1/vips Status: 500 Response: { "message": "Prisma validation error" } ``` 3. **UI Issues:** ``` The VIP list page shows a blank screen. Console shows: TypeError: Cannot read property 'map' of undefined at VIPList.tsx:45 ``` **❌ Unhelpful Feedback:** - "It doesn't work" - "There's an error" - "The button is broken" ### Effective Workflow 1. **Claude makes changes** → Writes code 2. **You run the app** → Test locally 3. **You share feedback** → Console logs, screenshots, error messages 4. **Claude debugs** → Fixes based on your feedback 5. **Repeat** until working ### Tips for Success - Run `docker-compose logs -f backend` to watch backend logs - Keep browser DevTools open (F12) - Share full error messages (not just summaries) - Take screenshots when UI looks wrong - Copy/paste network request/response bodies --- ## Deployment (Digital Ocean) ### Option 1: App Platform (Easiest) **Pros:** - Managed PostgreSQL database - Auto-scaling - Zero-downtime deployments - SSL certificates automatic **Setup:** 1. Push code to GitHub 2. Create DO App Platform app 3. Connect GitHub repository 4. Configure components: - **Backend:** Node.js (port 3000) - **Frontend:** Static Site (Vite build) - **Database:** Managed PostgreSQL 5. Set environment variables in DO dashboard 6. Deploy **Cost:** ~$12/month (basic tier) ### Option 2: Droplet + Docker (More Control) **Pros:** - Full control - Cheaper for small apps - Run everything on one server **Setup:** ```bash # On Digital Ocean Droplet (Ubuntu 22.04) apt update && apt upgrade -y apt install docker.io docker-compose -y # Clone repository git clone cd vip-coordinator # Set environment variables cp .env.example .env nano .env # Edit with production values # Run with Docker Compose docker-compose -f docker-compose.prod.yml up -d # Set up nginx reverse proxy apt install nginx certbot -y # Configure nginx for SSL ``` **Cost:** ~$6/month (basic droplet) ### Environment Variables (Production) **Backend:** ```env DATABASE_URL="postgresql://user:pass@db-host:5432/vip_coordinator" AUTH0_DOMAIN="your-tenant.auth0.com" AUTH0_AUDIENCE="https://api.yourapp.com" NODE_ENV=production PORT=3000 ``` **Frontend:** ```env VITE_API_URL=https://api.yourapp.com/api/v1 VITE_AUTH0_DOMAIN=your-tenant.auth0.com VITE_AUTH0_CLIENT_ID=your-production-client-id VITE_AUTH0_AUDIENCE=https://api.yourapp.com ``` ### Auth0 Production Setup 1. Create **Production** Auth0 application (separate from dev) 2. Update callback URLs to production domain 3. Configure custom domain (optional) 4. Enable social logins if needed ### Database Backups **Managed Database (DO):** - Daily automatic backups included - Point-in-time recovery **Self-hosted:** ```bash # Backup script pg_dump -U postgres vip_coordinator > backup_$(date +%Y%m%d).sql # Cron job (daily at 2 AM) 0 2 * * * /usr/bin/pg_dump -U postgres vip_coordinator > /backups/backup_$(date +\%Y\%m\%d).sql ``` --- ## Testing Strategy ### Backend Testing **Unit Tests (Services):** ```typescript describe('VipsService', () => { it('should create a VIP', async () => { const vip = await service.create({ name: 'John Doe', ... }); expect(vip.name).toBe('John Doe'); }); }); ``` **Integration Tests (Controllers):** ```typescript describe('VipsController', () => { it('GET /vips should return all VIPs', async () => { const response = await request(app.getHttpServer()) .get('/api/v1/vips') .set('Authorization', `Bearer ${token}`) .expect(200); expect(response.body).toBeInstanceOf(Array); }); }); ``` ### Frontend Testing **Component Tests (Vitest + Testing Library):** ```typescript test('VIPList renders VIPs', async () => { render(); await waitFor(() => { expect(screen.getByText('John Doe')).toBeInTheDocument(); }); }); ``` **E2E Tests (Playwright) - Recommended:** ```typescript test('admin can create VIP', async ({ page }) => { await page.goto('http://localhost:5173/login'); await page.click('text=Login'); // ... auth flow await page.goto('/vips'); await page.click('text=Add VIP'); await page.fill('[name=name]', 'Jane Smith'); await page.click('text=Submit'); await expect(page.getByText('VIP created')).toBeVisible(); }); ``` ### Running Tests ```bash # Backend cd backend npm test npm run test:watch npm run test:cov # Frontend cd frontend npm test npm run test:ui # E2E npm run test:e2e ``` --- ## Security Best Practices ### Backend Security 1. **Always validate input:** ```typescript @Post() async create(@Body() dto: CreateVipDto) { // DTO with class-validator return this.service.create(dto); } ``` 2. **Use guards everywhere:** ```typescript @UseGuards(JwtAuthGuard, RolesGuard) @Roles('ADMINISTRATOR') ``` 3. **Soft deletes (preserve data):** ```typescript async delete(id: string) { return this.prisma.vip.update({ where: { id }, data: { deletedAt: new Date() }, }); } ``` 4. **Prisma prevents SQL injection automatically** ### Frontend Security 1. **Never store tokens in localStorage** (Auth0 handles this) 2. **Always use HTTPS in production** 3. **Sanitize user input before display** 4. **Check permissions on backend, not just frontend** ### Auth0 Security - Enable MFA for admin accounts - Use Auth0 Actions to add custom claims - Rotate client secrets regularly - Monitor Auth0 logs for suspicious activity --- ## Common Issues & Solutions ### Issue: "Cannot connect to database" **Solution:** ```bash # Check PostgreSQL is running docker ps | grep postgres # Check connection string in .env echo $DATABASE_URL # Test connection docker-compose exec backend npx prisma db pull ``` ### Issue: "Auth0 redirect loop" **Solution:** - Verify `AUTH0_DOMAIN` and `AUTH0_CLIENT_ID` match Auth0 dashboard - Check callback URLs in Auth0 settings - Clear browser cache and cookies ### Issue: "Prisma Client not generated" **Solution:** ```bash cd backend npx prisma generate npm run build ``` ### Issue: "Port already in use" **Solution:** ```bash # Windows netstat -ano | findstr ":3000" taskkill /PID /F # Mac/Linux lsof -ti:3000 | xargs kill -9 ``` ### Issue: "First user can't login (not approved)" **Solution:** First user is auto-approved. If this fails: ```sql -- Manually approve first user UPDATE "User" SET "isApproved" = true WHERE email = 'admin@example.com'; ``` Or check `backend/src/auth/auth.service.ts` first-user logic. --- ## Development Mode Permissions Claude AI has full permission to: - ✅ **Nuke and rebuild** the database without asking - ✅ **Make breaking changes** to the codebase - ✅ **Delete/rewrite entire files** if it improves the code - ✅ **Install new packages** to solve problems properly - ✅ **Start fresh** if something is fundamentally broken - ✅ **Change architecture** if current approach is flawed **Focus:** Getting it working correctly > preserving broken code No production data exists. Feel free to reset everything. --- ## Quick Reference ### Useful Commands ```bash # Development npm run start:dev # Backend dev server npm run dev # Frontend dev server docker-compose up -d # Start all services # Database npx prisma migrate dev # Create migration npx prisma studio # Database GUI npx prisma migrate reset # Reset database # Production docker-compose -f docker-compose.prod.yml up -d npm run build # Build frontend npm run start:prod # Production server # Testing npm test # Run tests npm run test:watch # Watch mode npm run test:e2e # E2E tests ``` ### API Endpoints All endpoints prefixed with `/api/v1`: ``` POST /auth/login # Login with Auth0 GET /auth/profile # Get current user GET /users # List users (admin only) PATCH /users/:id/approve # Approve user (admin only) GET /vips # List VIPs POST /vips # Create VIP GET /vips/:id # Get VIP details PATCH /vips/:id # Update VIP DELETE /vips/:id # Soft delete VIP GET /drivers # List drivers POST /drivers # Create driver GET /drivers/:id # Get driver + schedule PATCH /drivers/:id # Update driver DELETE /drivers/:id # Soft delete driver GET /events # List events POST /events # Create event (with conflict check) GET /events/:id # Get event PATCH /events/:id # Update event PATCH /events/:id/status # Update status (driver can do this) DELETE /events/:id # Cancel event GET /flights/:number # Get flight status POST /flights/batch # Batch flight lookup ``` ### Key Files - **Backend Entry:** [backend/src/main.ts](backend/src/main.ts) - **Frontend Entry:** [frontend/src/main.tsx](frontend/src/main.tsx) - **Database Schema:** [backend/prisma/schema.prisma](backend/prisma/schema.prisma) - **Auth Guard:** [backend/src/auth/guards/jwt-auth.guard.ts](backend/src/auth/guards/jwt-auth.guard.ts) - **API Client:** [frontend/src/lib/api.ts](frontend/src/lib/api.ts) - **Protected Routes:** [frontend/src/components/auth/ProtectedRoute.tsx](frontend/src/components/auth/ProtectedRoute.tsx) --- **This document is the SOURCE OF TRUTH for the VIP Coordinator project.** When code conflicts with this document, update the code to match this spec (not vice versa).