A travel itinerary planning app with a React frontend and a Node.js REST API backend.
- Itinerary planning — Organize trips day by day on a drag-and-drop kanban board; add attractions with notes, Google Maps links, reference websites, and photos, then define transport connections between them.
- Itinerary export — Generate a formatted Word (.docx) document from any trip, with an editable Markdown preview step before download. The export includes styled day headers, transport tables, embedded images, and clickable hyperlinks.
- Packing checklist — Manage a reusable packing template; each trip gets its own copy with multiple occasion columns so you can track what to pack for each part of the journey.
tripdeck/
├── client/ # React frontend (Vite + TypeScript + Tailwind)
│ ├── public/
│ ├── src/
│ │ ├── components/ # Reusable UI components
│ │ ├── context/ # React context (theme)
│ │ ├── hooks/ # Custom React hooks
│ │ ├── pages/ # Route-level page components
│ │ ├── types/ # TypeScript type definitions
│ │ └── utils/ # API client and export utilities
│ ├── Dockerfile # Multi-stage build: Vite → nginx
│ ├── nginx.conf.template # nginx config template (port + proxy via envsubst)
│ ├── package.json
│ └── vite.config.ts
├── server/ # Node.js REST API backend (Express + TypeScript)
│ ├── src/
│ │ ├── config/ # Database connection setup
│ │ ├── controllers/ # Handles API business logic and responses
│ │ ├── db/ # Schema definitions and table initialization
│ │ ├── middleware/ # Express middleware (multer file upload)
│ │ ├── repositories/ # Database query layer (MySQL2)
│ │ ├── routes/ # Defines API endpoints and URL mapping
│ │ ├── types/ # Request/response type definitions
│ │ └── index.ts # Express server entry point
│ ├── swagger/ # Auto-generated Swagger spec (output.json)
│ ├── uploads/ # Uploaded image files (git-ignored, UUID filenames)
│ ├── Dockerfile # Multi-stage build: tsc → production Node.js
│ ├── package.json
│ └── tsconfig.json
├── docker-compose.yml # Two-service deployment (backend + frontend, host network)
├── export_docker.bat # Copies deployment files to ./docker/ and injects .env.production
├── .env.example # Environment variable reference
├── package.json # Workspace root — orchestrates client + server
└── .github/workflows/ # CI: lint check, automated version bumping
Run from the workspace root — npm workspaces installs all packages in one step:
npm installCopy .env.example to .env at the workspace root:
cp .env.example .env# MySQL connection — required
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=your_password
DB_NAME=tripdeck
# Backend API endpoint — leave empty in local development (Vite proxy handles routing)
# Set to the server's domain when the frontend and backend are on different origins
# Example: http://192.168.1.100
VITE_API_DOMAIN=
VITE_API_PORT=3001
# Frontend dev server port
FRONTEND_PORT=3000The database and all tables are created automatically on first server start.
Run both the frontend and backend concurrently from the workspace root:
npm run dev| Service | URL |
|---|---|
| Frontend (Vite) | http://localhost:5173 |
| Backend (Express) | http://localhost:3001 |
Or start each independently:
npm run dev -w client # frontend only
npm run dev -w server # backend onlynpm run buildOutputs:
client/dist/— static frontend bundleserver/dist/— compiled Node.js server
npm run start| Command | Description |
|---|---|
npm run dev |
Start both frontend and backend in watch mode |
npm run build |
Build client and server for production |
npm run start |
Start the production server |
npm run swagger |
Generate / update server/swagger/output.json from route annotations |
npm run lint |
Run ESLint across client and server |
npm run lint:fix |
Auto-fix all fixable ESLint issues across client and server |
npm run lint:check |
ESLint strict check — fails on any warning (used in CI) |
npm run format |
Format all files with Prettier |
npm run format:check |
Check formatting without making changes (used in CI) |
npm run dev -w client
npm run build -w client
npm run lint -w client
npm run lint:fix -w client
npm run lint:check -w client # Fails on any warning
npm run format -w client
npm run format:check -w client
npm run format:diff -w clientnpm run dev -w server # tsx watch — auto-restarts on changes
npm run build -w server # tsc — compiles to server/dist/
npm run start -w server # node dist/index.js
npm run swagger -w server # Generate / update server/swagger/output.json
npm run lint -w server
npm run lint:fix -w server
npm run lint:check -w server # Fails on any warning
npm run format -w server
npm run format:check -w server
npm run format:diff -w serverThe backend exposes an interactive Swagger UI generated by swagger-autogen.
Generate or update the spec (run whenever routes or #swagger.* annotations change):
npm run swaggerThis scans server/swagger/entry.ts and writes the result to server/swagger/output.json.
View the docs (requires the backend to be running):
http://localhost:3001/api/docs
The
server/swagger/output.jsonfile is committed to the repository so the server can start without requiring a priornpm run swaggercall. Re-run the command after any route changes to keep it in sync.
Both client and server have full ESLint + Prettier coverage:
| Tool | Client | Server |
|---|---|---|
| ESLint | TypeScript, React hooks, Tailwind CSS, import order, Prettier | TypeScript, import order, Prettier |
| Prettier | All .ts, .tsx, .css, .json |
All .ts |
The CI workflow (lint.yml) runs three checks on every push or PR to main:
- Client ESLint —
npm run lint:check -w client(zero warnings allowed) - Server ESLint —
npm run lint:check -w server(zero warnings allowed) - Root Prettier —
npm run format:check(covers CSS, JSON, and all source files)
The full interactive API reference is available via Swagger UI while the backend is running:
http://localhost:3001/api/docs