GlobeTrotter is a monolithic Flask application that serves as the starting point for a semester-long capstone project.
Students build the monolith first, then refactor it into microservices, and finally deploy it to the cloud with resilience patterns using Docker, Kubernetes, and cloud-native tooling.
.
├── app/
│ ├── __init__.py # Flask app factory
│ ├── models.py # Data models and JSON file I/O
│ ├── auth.py # Registration, login, JWT handling
│ ├── destinations.py # Destination search endpoint
│ ├── recommendations.py # Personalised recommendations endpoint
│ ├── itineraries.py # Create / list itineraries
│ └── main.py # App entry point
├── data/
│ ├── destinations.json # Static destination catalogue (seed data)
│ ├── users.json # Created at runtime
│ └── itineraries.json # Created at runtime
├── tests/ # Placeholder for future tests
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
└── README.md
| Method | Endpoint | Auth required | Description |
|---|---|---|---|
| POST | /register |
No | Register a new user |
| POST | /login |
No | Authenticate and receive a JWT token |
| GET | /destinations |
No | Search the destination catalogue |
| GET | /recommendations |
Yes (JWT) | Get personalised recommendations |
| POST | /itineraries |
Yes (JWT) | Create a new itinerary |
| GET | /itineraries |
Yes (JWT) | List all itineraries for the logged-in user |
Protected routes expect the header:
Authorization: Bearer <your-token>
# Register
curl -X POST http://localhost:5000/register \
-H "Content-Type: application/json" \
-d '{"username": "alice", "password": "s3cr3t", "preferences": ["beach", "food"]}'
# Login
curl -X POST http://localhost:5000/login \
-H "Content-Type: application/json" \
-d '{"username": "alice", "password": "s3cr3t"}'
# Save the returned token: TOKEN=<value from .token field>
# Search destinations
curl "http://localhost:5000/destinations?tag=beach&max_cost=100"
# Personalised recommendations
curl http://localhost:5000/recommendations \
-H "Authorization: Bearer $TOKEN"
# Create an itinerary
curl -X POST http://localhost:5000/itineraries \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"title": "Beach Escape", "destinations": ["Bali"], "start_date": "2025-07-01", "end_date": "2025-07-14"}'
# List itineraries
curl http://localhost:5000/itineraries \
-H "Authorization: Bearer $TOKEN"- Python 3.9+
- pip
# 1. Install dependencies
pip install -r requirements.txt
# 2. Start the server
python app/main.pyThe API will be available at http://localhost:5000.
# Build and start
docker-compose up --build
# Stop
docker-compose downThe data/ directory is mounted into the container, so JSON files persist between runs.
All data is persisted in plain JSON files inside the data/ directory:
| File | Purpose |
|---|---|
data/destinations.json |
Static catalogue of travel destinations (seed data) |
data/users.json |
Registered users (created at runtime) |
data/itineraries.json |
User itineraries (created at runtime) |
Note:
data/*.json(exceptdestinations.json) are excluded from version control via.gitignore.
| Environment Variable | Default | Description |
|---|---|---|
SECRET_KEY |
globetrotter-secret-change-in-prod |
JWT signing key – must be overridden in production |
FLASK_DEBUG |
0 |
Set to 1 to enable Flask debug mode (development only) |
PORT |
5000 |
Port the app listens on |
Important: Always set
SECRET_KEYto a long, random value in production (e.g.python -c "import secrets; print(secrets.token_hex(32))").