Base URL defaults to http://127.0.0.1:8080. Application, API, and upload routes are unauthenticated. Mutating requests require the CSRF token returned by GET /api/csrf-token in the X-CSRF-Token header. Every Flask response includes Cache-Control: no-store.
Returns the complete normalized logbook JSON document. A missing or malformed data file returns normalized defaults rather than an HTTP error.
Replaces the complete logbook document.
Imports are recursively checked before normalization. Validation errors identify the failing JSON path. Legacy documents without schemaVersion are treated as version 0 and migrated to version 1; versions newer than the server supports are rejected.
Required top-level JSON types:
- Body must be an object.
trips,lures, andflashersmust be arrays.reels,rods, androdReelCombos, when present, must be arrays.people, when present, must be an array.spots, when present, must be an array of uniquely identified/named records with valid coordinates and a radius from 25 through 10,000 meters.expeditions, when present, must be an array of uniquely identified records with a name and ordered ISO start/end dates.
Success: 200 {"ok": true}. Shape failure: 400 {"error": "..."}. Validation is not recursive; see DATA_MODEL.md.
Returns normalized JSON as attachment fishing-logbook.json. Uploaded files are not embedded.
These routes accept only allowlisted query keys and use a 20-second upstream timeout.
Proxies Open-Meteo Historical Weather. Required: numeric latitude, numeric longitude, start_date, end_date. Allowed: timezone, cell_selection, temperature/wind/precipitation units, hourly, and daily. Defaults timezone=auto and cell_selection=nearest.
Proxies Open-Meteo Forecast with the same coordinate validation and allowlist. Unlike archive, server code does not require dates; the browser supplies them.
Proxies Open-Meteo Marine. Coordinates are required and date fields are optional at the route level. If hourly is omitted, wave height, direction, and period are requested. When the nearest-cell response has no numeric wave height, the server retries without cell_selection.
Proxies SunriseSunset.io. Required: numeric lat, numeric lng, and date. Optional: timezone, time_format; the latter defaults to 24.
Proxy errors return an upstream status where available or 503 for network/timeout failures. The response body is { "error": "..." } on handled errors.
Allowed categories: catch-photos, trip-photos, lures, flashers, reels, rods, queue.
Allowed image extensions: AVIF, GIF, HEIC/HEIF, JPEG, PNG, WebP. Allowed video extensions: MOV, MP4/M4V, WebM, AVI, MPEG/MPG, and 3GP. Extension matching is case-normalized. The app does not enforce an application-level upload size limit.
Multipart fields:
file: required binary upload.metadata: optional JSON string; malformed JSON becomes an empty object.
The server assigns a UUID filename, stores metadata, and tries to make a JPEG image preview. Returns a media reference with original/stored names, paths, URLs, media type, and preview fields. Invalid category returns 404; missing/unsupported file returns 400.
Returns { "photos": [...] }, newest modified first.
JSON body: { "filename": "...", "targetCategory": "..." }. Moves a queued file, sidecar, and preview to a non-queue category under a new UUID name. Returns the new media reference.
Deletes queued media, sidecar, and preview. It is idempotent and returns { "ok": true } even when files are absent.
category may be all or one allowed upload category. Returns { "media": [...] } with metadata, byte size, modified timestamp, category, and download URL. Invalid categories return 400.
Returns non-queue disk items not recursively referenced by the current logbook as { "media": [...] }.
Deletes a non-queue upload only when it exists and is not referenced. Returns 400 for invalid/queue categories, 404 when absent, 409 when referenced, or 200 {"ok": true}.
GET /uploads/<category>/<filename>GET /uploads/<category>/_previews/<filename>
Files are served from their category paths. Category validation occurs through the media path helper.
/redirects to/trips./trips,/expeditions,/stats,/map,/gear,/gallery,/settingsrendertemplates/index.htmland its feature partials./static/<path:filename>serves only.cssand.jsfiles beneathstatic/./favicon.icoreturns 204.
refresh_all_trip_weather() in backend/weather_service.py reads the logbook, refreshes every trip with request caches, records per-trip errors, and writes the result. It is not connected to HTTP, CLI, cron, or app startup and therefore is not a public API.