-- Users Table
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
first_name VARCHAR(100),
last_name VARCHAR(100),
profile_photo_url VARCHAR(500),
language_preference VARCHAR(10) DEFAULT 'en',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Trips Table
CREATE TABLE trips (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
description TEXT,
start_date DATE NOT NULL,
end_date DATE NOT NULL,
cover_photo_url VARCHAR(500),
is_public BOOLEAN DEFAULT false,
total_budget DECIMAL(10,2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Cities Table
CREATE TABLE cities (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
country VARCHAR(100) NOT NULL,
country_code VARCHAR(3),
latitude DECIMAL(10, 8),
longitude DECIMAL(11, 8),
cost_index INTEGER, -- 1-5 scale
popularity_score INTEGER, -- 1-100 scale
timezone VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Trip Stops Table
CREATE TABLE trip_stops (
id SERIAL PRIMARY KEY,
trip_id INTEGER REFERENCES trips(id) ON DELETE CASCADE,
city_id INTEGER REFERENCES cities(id),
arrival_date DATE NOT NULL,
departure_date DATE NOT NULL,
order_index INTEGER NOT NULL,
notes TEXT,
accommodation_budget DECIMAL(8,2),
transport_budget DECIMAL(8,2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Activities Table
CREATE TABLE activities (
id SERIAL PRIMARY KEY,
city_id INTEGER REFERENCES cities(id),
name VARCHAR(255) NOT NULL,
description TEXT,
category VARCHAR(100), -- sightseeing, food, adventure, etc.
estimated_cost DECIMAL(8,2),
estimated_duration INTEGER, -- in minutes
rating DECIMAL(3,2), -- 1.00-5.00
image_url VARCHAR(500),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Trip Activities Table (Many-to-Many)
CREATE TABLE trip_activities (
id SERIAL PRIMARY KEY,
trip_stop_id INTEGER REFERENCES trip_stops(id) ON DELETE CASCADE,
activity_id INTEGER REFERENCES activities(id),
scheduled_date DATE,
scheduled_time TIME,
actual_cost DECIMAL(8,2),
notes TEXT,
completed BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Budget Items Table
CREATE TABLE budget_items (
id SERIAL PRIMARY KEY,
trip_id INTEGER REFERENCES trips(id) ON DELETE CASCADE,
category VARCHAR(100) NOT NULL, -- transport, accommodation, food, activities, misc
item_name VARCHAR(255),
estimated_cost DECIMAL(8,2),
actual_cost DECIMAL(8,2),
date_incurred DATE,
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Shared Trips Table
CREATE TABLE shared_trips (
id SERIAL PRIMARY KEY,
trip_id INTEGER REFERENCES trips(id) ON DELETE CASCADE,
shared_by_user_id INTEGER REFERENCES users(id),
share_token VARCHAR(255) UNIQUE,
is_public BOOLEAN DEFAULT true,
view_count INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP
);
src/
├── components/
│ ├── common/
│ │ ├── Header.jsx
│ │ ├── Footer.jsx
│ │ ├── Loading.jsx
│ │ └── ErrorBoundary.jsx
│ ├── auth/
│ │ ├── LoginForm.jsx
│ │ ├── RegisterForm.jsx
│ │ └── ProtectedRoute.jsx
│ ├── trips/
│ │ ├── TripCard.jsx
│ │ ├── TripForm.jsx
│ │ ├── TripList.jsx
│ │ └── TripDashboard.jsx
│ ├── itinerary/
│ │ ├── ItineraryBuilder.jsx
│ │ ├── ItineraryView.jsx
│ │ ├── StopCard.jsx
│ │ └── ActivityCard.jsx
│ ├── search/
│ │ ├── CitySearch.jsx
│ │ ├── ActivitySearch.jsx
│ │ └── SearchFilters.jsx
│ ├── budget/
│ │ ├── BudgetOverview.jsx
│ │ ├── BudgetBreakdown.jsx
│ │ └── CostChart.jsx
│ └── calendar/
│ ├── TripCalendar.jsx
│ ├── Timeline.jsx
│ └── DayView.jsx
├── pages/
│ ├── Login.jsx
│ ├── Dashboard.jsx
│ ├── CreateTrip.jsx
│ ├── TripDetails.jsx
│ ├── SharedTrip.jsx
│ └── Profile.jsx
├── hooks/
│ ├── useAuth.js
│ ├── useTrips.js
│ └── useBudget.js
├── services/
│ ├── api.js
│ ├── auth.js
│ └── localStorage.js
└── utils/
├── dateHelpers.js
├── budgetCalculations.js
└── validators.js