Skip to content

Design: Trip Management (CRUD + List/Detail UI)

Date: 2025-11-17 Author: Jake Celentano (via Claude Code) Status: Proposal Project: trip-planner


Problem Statement

The trip-planner app currently has no way for users to create or manage trips. The AI chat interface exists but has no trip context, meaning: - Chat messages aren't associated with specific trips - Users can't save/load trip planning sessions - No persistence of trip metadata (dates, budget, constraints) - Map has no trip locations to display

This makes the app non-functional for its core purpose.

Goals

  • [ ] Users can create new trips with basic metadata
  • [ ] Users can view a list of their trips
  • [ ] Users can select a trip to plan/view
  • [ ] Chat interface receives tripId context
  • [ ] Trip data persists in Supabase

Non-Goals

  • Advanced trip collaboration/sharing (future)
  • Trip templates or AI-generated trips (future)
  • Complex budget tracking (separate feature)
  • Calendar integration (future)

Proposed Solution

High-Level Architecture

┌─────────────────┐
│  Homepage       │
│  (Trip List)    │
└────────┬────────┘
         ├──> Create Trip Form (Dialog/Modal)
         └──> Trip Detail Page
              ├─ Chat Interface (with tripId)
              ├─ Map (with trip locations)
              └─ Trip Metadata (editable)

Components

1. Trip List Component (/app/page.tsx or /app/trips/page.tsx) - Responsibility: Display user's trips, create new trip button - Tech: Server Component (fetches trips from Supabase) - Dependencies: Supabase server client

2. Create Trip Dialog (components/trips/CreateTripDialog.tsx) - Responsibility: Form to create new trip - Tech: Client Component with form state - Dependencies: None (calls API route)

3. Trip Detail Page (/app/trips/[id]/page.tsx) - Responsibility: Show trip with chat/map - Tech: Server Component (fetches trip data) - Dependencies: ChatInterface, TripMap components

4. API Route (/app/api/trips/route.ts) - Responsibility: CRUD operations for trips - Tech: Next.js API route with Supabase - Dependencies: Supabase server client, auth

Data Model

Existing trips table (already created in migration):

CREATE TABLE trips (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL,
  title TEXT NOT NULL,
  description TEXT,
  start_date DATE,
  end_date DATE,
  budget_amount DECIMAL(10, 2),
  budget_currency TEXT DEFAULT 'USD',
  status TEXT DEFAULT 'planning',
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

No schema changes needed - table already exists from initial migration.

API Design

// POST /api/trips - Create trip
{
  title: string
  description?: string
  start_date?: string  // ISO date
  end_date?: string
  budget_amount?: number
  budget_currency?: string
}

// GET /api/trips - List user's trips
Response: Trip[]

// GET /api/trips/[id] - Get single trip (optional, can use Server Component)
Response: Trip

// PATCH /api/trips/[id] - Update trip
{
  title?: string
  description?: string
  // ... other fields
}

// DELETE /api/trips/[id] - Delete trip
Response: { success: boolean }

Alternatives Considered

Option 1: Everything on Homepage (Chat + List)

Pros: - Single page, no navigation - Simple for users

Cons: - Cluttered UI - Hard to focus on one trip - No deep linking

Verdict: Rejected - too cramped

Option 2: Separate Routes (/trips and /trips/[id]) ← Chosen

Pros: - Clean separation of concerns - Deep linkable URLs - Can expand each page independently - Follows Next.js conventions

Cons: - Requires navigation/routing

Verdict: Accepted - better UX and maintainability

Option 3: Modal-based (all on one page with dialogs)

Pros: - No page transitions - Modern SPA feel

Cons: - Complex state management - Hard to bookmark specific trip - Accessibility concerns

Verdict: Rejected - over-engineered for MVP

Implementation Plan

Phase 1: API Layer (1.5h)

  • [ ] Create /app/api/trips/route.ts (30 min)
  • GET (list trips)
  • POST (create trip)
  • [ ] Create /app/api/trips/[id]/route.ts (30 min)
  • GET (single trip - optional)
  • PATCH (update trip)
  • DELETE (delete trip)
  • [ ] Test with curl/Postman (30 min)

Phase 2: Trip List UI (1.5h)

  • [ ] Create /app/trips/page.tsx (45 min)
  • Fetch trips from API
  • Display as cards/list
  • Create trip button
  • [ ] Create components/trips/TripCard.tsx (30 min)
  • Display trip metadata
  • Click → navigate to detail
  • [ ] Create components/trips/CreateTripDialog.tsx (15 min)
  • Form with title, dates, budget
  • Submit → POST to API

Phase 3: Trip Detail Page (1.5h)

  • [ ] Create /app/trips/[id]/page.tsx (30 min)
  • Fetch trip data
  • Render ChatInterface with tripId
  • Render TripMap with trip locations (empty for now)
  • [ ] Update ChatInterface to accept tripId prop (15 min)
  • Pass to /api/chat body
  • [ ] Create trip metadata display (30 min)
  • Editable fields (stretch goal)
  • [ ] Navigation between list and detail (15 min)

Phase 4: Integration & Polish (30 min)

  • [ ] Update homepage to redirect to /trips (5 min)
  • [ ] Add loading states (10 min)
  • [ ] Error handling (10 min)
  • [ ] Basic styling polish (5 min)

Total estimate: ~5 hours

Risks & Mitigations

Risk Impact Probability Mitigation
RLS policies block queries High Medium Test auth flow thoroughly, verify user_id
Date validation issues Medium Low Use HTML5 date inputs, validate on backend
No auth = can't test High Low Use placeholder user_id for now, add auth later

Testing Strategy

Manual testing (current standard): - Create trip with valid data → verify in Supabase - Create trip with missing required fields → verify error - List trips → verify user sees only their trips - Update trip → verify changes persist - Delete trip → verify trip removed - Select trip → verify chat receives tripId

Future (when testing added): - Unit tests for API routes - Component tests for forms

Observability

Not critical for MVP - no custom metrics needed yet.

Monitor: - Check Supabase logs for query errors - Check Next.js console for API errors

Rollout Plan

  1. Implement in LXC dev environment
  2. Test manually with real user flows
  3. Commit and push to GitHub
  4. (Optional) Deploy to k8s production

No production deployment required yet - dev-only feature for now.

Success Metrics

  • [ ] Can create a trip with title and dates
  • [ ] Trip appears in list
  • [ ] Can navigate to trip detail page
  • [ ] Chat interface shows trip context
  • [ ] Changes persist across page refreshes

Open Questions

  • [ ] Do we need auth now or use placeholder user_id? → Use placeholder for now
  • [ ] Should trips be deletable or just archived? → Allow delete for MVP
  • [ ] Do we show empty state when no trips exist? → Yes, with "Create your first trip" CTA

Status: Ready for implementation Next Step: Phase 1 - API Layer