フェリシア — 琉璃雏菊(蓝费莉菊)
A map-based travel journal. The map is the index; the mementos are the stories.
Each journey is drawn on a world map as an orange route line. Along it sit mementos — the little things that anchor a memory (a train ticket, a temple stamp, a plush, a receipt) — each a collectible stub that animates open into an essay and a photo gallery.
Modeled on liuaaron.com · "Aaron's Waypoints."
- 🗺️ The map is the index. One glance says everywhere I've been and which trip to revisit. You navigate spatially, not through a feed.
- 🎫 Mementos, not tickets. Physical stubs are dying, so a memento is
kind-tagged (goods · live · transit · stamp · receipt · souvenir) and rendered from data, template-first — not scanned. - 📍 A place is a visit. Following how Dawarich and Google Timeline model location (
points → tracks → visits @ places → trips), a place is a dwell-time visit derived from your track. Several memories can stack at one place. - ✍️ Auto-ingest, then author. A pipeline seeds ingested fields (track, photos, stubs); you author the essay, curation, and animation. Re-import is field-scoped and never clobbers what you wrote.
- 🌏 Japanese-first, with English and Chinese alongside.
The public reader renders the same { journey, visit, memento } contract four ways. The
production catalog under publication/journeys/ is the publication source, and the
on-screen switcher is deep-linkable.
| Front door | Route | What it is | |
|---|---|---|---|
| 🗺️ | Atlas | / |
map-and-story reader: journey rail → route map → memento detail. The default. |
| 🗄️ | Cabinet | #cabinet |
Memento-first shelf; a "greatest-hits" browse across every trip. |
| 📓 | Techo (手帳) | #techo |
Warm paper notebook: a journal-index spread, then the trip on a real map with mementos clustered by place/visit — open a place to read its memories. |
| 🌐 | Cartography (世界地図) | #cartography |
Full-map atlas index across every journey; mementos render as kind-designed collectible stubs (one stub design per registry kind). |
The production catalog contains sanitized, published journey inputs; the same shape is served by the working backend.
flowchart LR
subgraph S["Sources (self-hosted)"]
daw["Dawarich\ntrack + visits"]
imm["Immich\nphotos"]
end
daw & imm --> imp["waypoints importer\n(Go)"]
imp --> db[("SQLite local / Postgres\njourneys · mementos")]
imp --> r2[["R2 / S3\nEXIF-stripped photos"]]
db --> api["HTTP API (Go, chi)\n/api/v1 · GeoJSON"]
r2 --> api
api --> web["Reader hosts\nCartography · Cabinet · Techo · Atlas (MapLibre)"]
- Ingest —
waypointspulls the track + visits from Dawarich and photos from Immich, joins on timestamp, EXIF-strips + resizes to R2, and seeds stub mementos. Raw GPS never lands in a public file. - Serve — the API layer depends on runtime ports; SQLite is the default local provider and PostgreSQL remains available for deployments that need it.
- Read — any number of frontends project the same contract. Adding a design is one registry entry, not a schema change.
Standing on a lot of excellent open source. 🙏
🖥️ Web Svelte 5 · TypeScript · Vite · MapLibre GL JS · Tailwind CSS · Bun · basemaps by CARTO + OpenStreetMap
⚙️ Backend Go · chi · pgx · sqlc · orb · goose · minio-go · imaging · gpxgo · tzf · koanf · go-toml · anthropic-sdk-go
🗃️ Data & storage PostgreSQL · PostGIS · Cloudflare R2 (S3-compatible; MinIO/B2 swappable)
📥 Ingestion sources (self-hosted) Dawarich (GPS track + visits) · Immich (photos)
🧰 Tooling mise · golangci-lint · Docker Compose · Cloudflare Tunnel · MkDocs Material · uv
The public reader runs on the production catalog — no database or keys are needed for a local reader preview.
make web-dev # Vite dev server → http://localhost:5173Then use the switcher at the bottom (地図 / コレクション / 手帳 / 世界地図), or jump straight in:
/ (Atlas) · #cabinet · #techo · #cartography. Toggle language (日本語 / EN / 中文) and light/dark in each design's header.
make web-check # svelte-check + eslint
make check # Go workspace checks + uv feature-contract testsThe complete toolchain comes from mise (
mise install). Everything routes throughmake <target>.
Your journal is authored locally and only the compiled site is published — there is no hosted admin, and drafts, originals, and the SQLite journal never leave your machine.
make admin # authoring GUI on 127.0.0.1 — import, curate, write, publish
BASE_PATH=/my-travels/ make site-build # deployable site → apps/felicia-public-site/distThen push that directory to the repository serving your GitHub Pages site. Full walkthrough —
both the local-authoring route and the CI route, base-path table, and troubleshooting:
docs/publish.md.
journal → journeys → mementos, with a derived visit/place layer and canonical media:
memento— one uniform table,kind-tagged, kind-specifics in akind_datajsonb. New kinds = a new enum value, not a new table.place = visit— a derived dwell-time cluster (consumed from Dawarich, or clustered from a GPX fallback); mementos anchor to the nearest visit.- Provenance is load-bearing — every field is
INGESTED / OVERRIDABLE / AUTHORED; the importer is field-scoped and re-import is always safe. - Media — images, videos, audio, documents, links, and provider-approved embeds are canonical asset kinds attached to memories.
- Locales — system-owned UI labels use static
ja/en/zhcatalogs; user content is rendered exactly as authored.
Full detail: docs/research/data-model.md · docs/research/backend-stack.md.
Implementation stage (research trail continues). The backend pipeline, live API, CLI, and static compiler are built and tested; GitHub Pages publication runs the real SQLite pipeline end to end (PR #55); the admin authoring GUI MVP is complete (epic FELICIA-ADMIN-01). Auditing that flow against a real trip found four P0 data-integrity defects — a second trip overwrote the first, re-import destroyed authored fields, the artifact shipped an unrounded GPS trace, and media keys collided on basename — all now fixed and covered by provider-parity tests. Remaining gaps: deferred AI enrichment/object storage seams and the dynamic form engine.
Single source of truth for delivery status:
docs/roadmap.md; target end-to-end journey:
docs/roadmap/user-journey.md.
- 🧭 North star —
docs/direction.md - 🔬 Research trail —
docs/research/ - 🗄️ Parked drafts —
docs/archive/
Preview locally: make docs (uv-backed MkDocs Material).
- liuaaron.com — the "Aaron's Waypoints" reference that started it all.
- Dawarich & Immich — the self-hosted sources felicia is built to sit on.
- CARTO & OpenStreetMap contributors — the basemaps.
GNU AGPL-3.0 — network copyleft, matching the self-hosted sources felicia builds on (Dawarich and Immich are both AGPL-3.0). If you run a modified felicia as a network service, you must offer your users its source.