# AdventureLog Setup Summary ## What It Is AdventureLog is a self-hosted travel logging app with a SvelteKit frontend and Django/PostGIS backend. Live at: **https://go.jgitta.com** — version **v0.12.1**. --- ## Infrastructure | Component | Detail | |-----------|--------| | Host | siklos (192.168.88.27) | | Portainer Stack | #47 — `adventurelog` (endpoint 3) | | Frontend container | `adventurelog-frontend` — port 8015 (SvelteKit SSR) | | Backend container | `adventurelog-backend` — port 8016 (Django/nginx → gunicorn :8000) | | Database container | `adventurelog-db` (PostGIS 16-3.5) | | Data volumes | `/srv/docker/adventurelog/postgres_data/` and `/srv/docker/adventurelog/media/` | | Reverse proxy | Caddy VM (192.168.88.110) — `go.jgitta.com` in `/etc/caddy/sites/infrastructure.caddy` | --- ## Caddy Routing (final, verified 2026-07-02) Use the **split** config below. The browser holds a valid Django session, so routing reads directly to Django works. Routing reads through the SvelteKit frontend instead reintroduces a trailing-slash redirect that breaks the category dropdown — do **not** switch to the official docs' single-proxy config. The key fix: the app requests `/api/...` **without a trailing slash**; Django (DRF) then answers `301` to add it, and that redirect breaks the browser fetch (empty search / empty categories). The `@api_read` block rewrites the path to add the slash **internally**, so Django answers `200` directly with no redirect. ```caddy go.jgitta.com { import headers_base encode zstd gzip header { X-Frame-Options "SAMEORIGIN" Permissions-Policy "geolocation=(self), microphone=(), camera=()" } # GET/HEAD/OPTIONS /api/* -> Django directly (browser sends session cookie) @api_read { method GET HEAD OPTIONS; path /api/* } handle @api_read { # DRF needs a trailing slash; add it internally to avoid a 301 that breaks the fetch @api_noslash path_regexp apinoslash ^(/api/(?:.*/)?[^/.]+)$ rewrite @api_noslash {re.apinoslash.1}/ reverse_proxy http://192.168.88.27:8016 { import proxy_timeouts header_up Accept "application/json" } } # POST/PUT/DELETE /api/* + pages -> SvelteKit frontend @frontend { not path /media* /admin* /static* /accounts* } handle @frontend { reverse_proxy http://192.168.88.27:8015 { import proxy_timeouts } } # Django: media, admin, static, auth pages handle { reverse_proxy http://192.168.88.27:8016 { import proxy_timeouts } } } ``` `geolocation=(self)` (inline) is required for the "Use My Location" button. Backup of prior config: `/etc/caddy/sites/infrastructure.caddy.bak-20260702-041914`. --- ## Geocoding — Google Maps (enabled 2026-07-02) Switched from public OpenStreetMap/Nominatim to Google Maps. Nominatim was flaky: the app fires one search per keystroke, and public Nominatim returned inconsistent/empty results for partial queries and rate-limited the rapid autocomplete. - `GOOGLE_MAPS_API_KEY` is set in Portainer stack #47 (env + `server` service in compose). - Google Cloud account: **jgitta@gmail.com**. Required APIs enabled: **Geocoding API** and **Places API (New)**. - Provider is automatic: key present → Google (`search_google`, `reverse_geocode_google`); otherwise OSM. Google also enriches locations (photos, rating, website, phone, description). --- ## Portainer Environment Variables (stack #47) | Variable | Value | |----------|-------| | PUBLIC_SERVER_URL | http://server:8000 | | ORIGIN / PUBLIC_URL / CSRF_TRUSTED_ORIGINS / FRONTEND_URL | https://go.jgitta.com | | FRONTEND_PORT / BACKEND_PORT | 8015 / 8016 | | BODY_SIZE_LIMIT | Infinity | | POSTGRES_DB / POSTGRES_USER | adventurelog / adventure | | DEBUG / DISABLE_REGISTRATION | False / False | | GOOGLE_MAPS_API_KEY | (set — Google Maps enabled) | Secrets (DB password, SECRET_KEY, admin creds, Google key) live in Portainer. `DJANGO_ADMIN_PASSWORD` is only the bootstrap password; the live admin password was changed in-app. --- ## Known Bug (reported upstream) Selecting a location **search result** overwrites the location **Name** with the reverse-geocoded nearest-object name instead of keeping the search result's name. With OSM this produced "39" (a campsite tagged near Elk Rock State Park's center). The app reverse-geocodes the selected result's coordinates and lets that name win. Workaround: retype the Name after selecting. Report drafted in `AdventureLog-BugReport-location-name-overwrite.md`. --- ## Admin / Notes - Admin: https://go.jgitta.com/admin (user `admin`). Django shell: `docker exec -it adventurelog-backend python manage.py shell`. - Images run `:latest` with Watchtower auto-update — an update on 2026-07-02 changed frontend behavior mid-debug. Consider pinning versions. - Not configured: B2/Kopia backup for this stack, Strava.