Atlas is a self-hosted travel app for one user or a small household. It manages a trip end-to-end: the planning, the documents you receive by email, the day-of-departure checklist, and the trip itself. Boarding passes, hotel confirmations, and PKPasses are parsed locally by a small LLM, so flights, hotels, and transit show up as segments without manual entry. Trips also include activities, undated wishlist items, freeform notes, and two map views — a per-trip map with flight arcs and a global map of every country you've been to. All extraction, geocoding, and tile serving happens on your own hardware. Built for homelab self-hosting on the same machine you already run Nextcloud, Immich, or Plex on.
- Trips & itineraries — flights, hotels, activities, transit, and notes in one timeline.
- Document extraction — local PDF → OCR → LLM pipeline. Files stay on your disk.
- Maps — global countries-visited choropleth plus per-trip flight arcs and pins. Self-hosted basemap.
- Passwordless auth — passkeys via PocketID (OIDC).
- Wishlist mode — undated activities pinned to a trip, promoted to the itinerary when scheduled.
- Multi-leg flights — one document, one PNR, many segments. Edits propagate in a single transaction.
- Backups — daily Postgres + document snapshots, ready for offsite rsync.
- Notifications — opt-in pushes through your own ntfy server: reminders before flights, trains, hotel check-in and check-out, and plans, and a note when a document finishes reading.
- Installable (PWA) — add to your home screen for a full-screen, app-like launch; pages you've opened stay viewable offline.
- Create a trip with a title and dates.
- Upload everything from your inbox — boarding passes, hotel confirmations, train tickets, PKPasses.
- Run extraction. Ollama parses each file locally; segments auto-generate and link back.
- Itinerary usually complete in minutes.
- Add activities or wishlist items for anything not yet booked.
Atlas is a Progressive Web App, so it installs to your phone's home screen and launches full-screen without browser chrome.
- Android (Chrome): open Atlas, then "Install app" from the menu (or the install prompt).
- iOS (Safari): open Atlas, tap Share → Add to Home Screen. iOS has no install prompt, so this step is manual.
Once installed, a small service worker caches what you open, so an itinerary you loaded before takeoff stays viewable offline. Offline is read-only (adding or editing a segment needs the server), and the trip-map basemap isn't available offline (tiles are too large to cache) — the trip map shows an offline notice, while flight arcs, pins, and the countries-visited map still render.
The service worker is hand-rolled rather than generated by a PWA build plugin:
those plugins are webpack-based, and Atlas builds with Turbopack (Next 16's
default). Once a Turbopack-native precaching plugin is stable (most likely a
stable @serwist/turbopack, or first-party Next support), we'll migrate to it
for full offline precaching — see ADR-0017.
Global map of everywhere you've been.
Tabbed itinerary with a country filter for multi-country trips.
Uploaded files with extraction status and parsed fields.
Click a pin to zoom in on a city and see its details.
| Layer | Choice |
|---|---|
| Framework | Next.js 16 (App Router, RSC) |
| Language | TypeScript (strict) |
| Styling | Tailwind CSS + shadcn/ui |
| Database | PostgreSQL 18 + Drizzle ORM |
| Storage | Local filesystem (swappable interface) |
| Maps | MapLibre GL JS + Protomaps PMTiles |
| Auth | Auth.js + PocketID (OIDC, passkeys) |
| Extraction | pdf-parse → Tesseract/Paddle → Ollama |
| Geocoding | Nominatim with a DB-backed cache |
| Notifications | ntfy (self-hosted) |
| Testing | Vitest + Playwright |
| Containers | Docker + Docker Compose |
The full rationale and architectural rules live in CLAUDE.md.
Decisions of consequence are recorded as ADRs in docs/adr/.
Each release publishes two images from one version: the app at
ghcr.io/sebbogit/atlas and the pg-boss worker at
ghcr.io/sebbogit/atlas:<tag>-worker.
Create a .env (start from .env.example) with at least a
POSTGRES_PASSWORD, your PocketID OIDC settings, and ATLAS_IMAGE_TAG (pin a
release, e.g. 2.0.1).
The repo ships a
docker-compose.yml plus a hardened
docker-compose.prod.yml overlay (resource limits,
runtime confinement, scheduled backups). For a production deployment, use those
and follow docs/DEPLOYMENT.md (PocketID, basemap,
Ollama, reverse proxy, backups):
docker compose -f docker-compose.yml -f docker-compose.prod.yml --profile backup up -dOpen http://localhost:3000. The map stays blank until you fetch the basemap, and extraction needs an Ollama host — both are covered in the deploy guide.
Requires: Node.js 24, pnpm 9.15+, Docker with Compose v2.
git clone https://github.com/SebboGit/atlas.git
cd atlas
pnpm install
cp .env.example .env
# Edit .env
pnpm dev:up # one-shot: postgres → migrate → seed → next devOpen http://localhost:3000. For the development workflow, conventions, and
gates, see docs/DEVELOPMENT.md.
Everything stateful lives under ./data/:
data/
├── documents/ User-uploaded files (immutable originals)
├── tiles/ Protomaps PMTiles basemap (regenerable, not backed up)
└── backups/
├── db/ ZSTD-compressed Postgres dumps
└── documents/ Timestamped document snapshots
| Doc | What's in it |
|---|---|
docs/DEPLOYMENT.md |
End-to-end deployment: PocketID, basemap, Ollama, reverse proxy, backups |
docs/DEVELOPMENT.md |
Dev setup, quality gates, conventions, git workflow |
docs/ARCHITECTURE.md |
High-level system design |
docs/DOMAIN_MODEL.md |
Entities, relationships, invariants |
docs/THREAT_MODEL.md |
Assets, trust boundaries, and the threats Atlas defends against |
docs/adr/ |
Architecture Decision Records |
CLAUDE.md |
Canonical rules and conventions (the source of truth) |
Atlas is stable. Trips, segments, documents and extraction, both map surfaces, search, stats, and the wishlist are all implemented, and releases follow Semantic Versioning.
- Use, modify, fork, redistribute — fine, for any noncommercial purpose.
- Charities, schools, universities, public bodies — fine.
- Selling it, paid hosting, shipping it as part of a paid product — not fine.
Unclear use case? Open a discussion before acting.




