Files
homelab-configs/AdventureLog-Setup-Summary.md

4.8 KiB

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.

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.