A full-stack travel memory app for documenting trips and places on an interactive map.
It combines a public browsing experience with a role-based admin panel for managing trips, places, uploads, users, and groups.
Most travel journals are list-first. This project is map-first.
Instead of storing memories as disconnected posts, Travel Map organizes them around geography, routes, timelines, and grouped place collections. It is designed for personal archives, travel blogs, family trip logs, and private shared memory spaces.
- Interactive map-based browsing for places and trips
- Public pages for map view, places, trips, and timeline browsing
- Rich place records with summary, description, images, tags, companions, rating, and trip ordering
- Trip records with date ranges, cover images, tags, and optional route display
- Role-based admin dashboard
- Persisted authentication with seeded first admin user
- User roles:
viewer,editor,admin - Group management and user-to-group assignment
- Visibility modes for content, including support for authenticated/group-aware access
- Local image uploads served by the backend
- SQL migration system with automatic migration run on backend startup
- Docker Compose setup for local full-stack development
- Next.js 15
- React 19
- TypeScript
- Tailwind CSS
- MapLibre via
mapcn
- FastAPI
- Pydantic v2
- PostgreSQL
psycopg- SQL migration files tracked in
backend/migrations
- Docker Compose
unittestfor backend tests
/map-first landing page with search and trip filtering/placespaginated place browsing with facets/tripstrip browsing/timelinecombined chronological view of trips and places
/admin/loginsign-in page/adminoverview dashboard/admin/placesmanage places/admin/tripsmanage trips/admin/usersmanage users and groups as an admin
.
├── backend/ FastAPI app, migrations, tests, media storage
├── frontend/ Next.js app
├── docs/ Architecture notes
└── docker-compose.yml Local development stack
This is the fastest way to run the full stack locally.
docker compose up --buildServices:
- Frontend:
http://localhost:3000 - Backend API:
http://localhost:8000 - PostgreSQL:
localhost:5432
Default development credentials from docker-compose.yml:
- Admin email:
admin@example.com - Admin password:
change-me
Change those before using the project outside local development.
cp backend/.env.example backend/.envImportant backend environment variables:
APP_ENV=development
DATABASE_URL=postgresql+psycopg://postgres:postgres@localhost:5432/travel_map
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=change-me
ADMIN_NAME=Admin
SESSION_SECRET=change-me-long-random-secret
SESSION_TTL_SECONDS=86400
PASSWORD_SALT=travel-map-salt
MEDIA_ROOT=./media
MEDIA_URL_PREFIX=/media
MAX_UPLOAD_BYTES=10485760cp frontend/.env.example frontend/.env.localFrontend environment variables:
NEXT_PUBLIC_API_BASE_URL=http://localhost:8000
NEXT_PUBLIC_MAPCN_STYLE_URL=
NEXT_PUBLIC_MAPCN_ACCESS_TOKEN=The map style variables are optional and depend on the map style/provider you want to use with mapcn.
Backend:
cd backend
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtFrontend:
cd frontend
npm installUse your local PostgreSQL instance, or start only the database through Docker:
docker compose up dbcd backend
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reloadcd frontend
npm run dev- Migrations live in
backend/migrations - The backend runs migrations automatically on startup
- Applied migrations are tracked in the
schema_migrationstable - You can also run migrations manually:
cd backend
python run_migrations.py- On first startup, the app seeds an admin user from
ADMIN_EMAIL,ADMIN_PASSWORD, andADMIN_NAMEif it does not already exist
The app uses backend-issued signed session tokens and role-based access control.
viewer: can access read-only admin viewseditor: can create and update places, trips, and uploadsadmin: can manage users, groups, and destructive actions
- Groups are stored in PostgreSQL
- Users can belong to one or more groups
- Content supports visibility and group assignment fields
- Group-aware viewing is already wired into listing behavior for authenticated users
- Uploads are stored locally under
backend/mediaby default - Files are served by the FastAPI backend under
/media/<filename> - Supported image types include
jpeg,png,webp,gif, andavif - Default upload limit is
10 MBper file
Selected backend routes:
GET /healthGET /api/placesGET /api/places/queryGET /api/tripsGET /api/trips/queryPOST /api/auth/loginGET /api/auth/meGET /api/admin/placesGET /api/admin/tripsGET /api/admin/users
Frontend production build:
cd frontend
npm run buildBackend syntax verification:
cd backend
python -m compileall app run_migrations.py testsBackend tests:
docker compose exec backend python -m unittest discover -s tests -vThis project is already usable for local development and open-source collaboration, with a working frontend, backend, auth system, admin panel, migrations, uploads, and backend test coverage.
Areas that still look active or evolving:
- deeper group-based visibility rules
- more complete admin filtering/faceting
- broader frontend integration or end-to-end tests
- production hardening for storage, auditability, and deployment
Contributions are welcome.
This project is licensed under the MIT License. See the LICENSE file for details.



