# Design ## Context See `proposal.md` - Why. Relevant current state: - `storage.Signer.URL` builds `baseURL + "/api/objects/?e&s"` (`signer.go`), with `baseURL` from `cfg.Server.BaseURL` (`APP_BASE_URL`, default `http://localhost:8080`). - That absolute URL is the only use of `Server.BaseURL`; SSE and API traffic are already root-relative (`/api/...`). - `photos.Service.attachURLs` runs outside an HTTP request, so it cannot see the request host to derive a base. ## Goals / Non-Goals **Goals:** - Photo/preview URLs work on any host or reverse proxy with no per-deployment base URL. - Preserve signing, expiry, quantization and caching behavior exactly. **Non-Goals:** - Serving the app under a URL subpath. - Absolute URL generation for non-browser consumers (no such consumer today). - Changing the object route, storage backends, or delivery semantics. ## Decisions ### Emit origin-relative (path-only) object URLs `Signer.URL(key)` returns `"/api/objects/?e=&s="`. A leading slash makes it origin-relative: the browser resolves it against the page's scheme/host/port, which is exactly the backend that served the page. - Alternative considered: keep absolute URLs and require operators to set `APP_BASE_URL`. Rejected - this is the current footgun; a wrong or default value silently breaks all images. - Alternative considered: derive the base from the request (`Host`, `X-Forwarded-Proto`). Rejected - URLs are minted in `attachURLs`/SSE paths that have no request; threading a base through every service is invasive for no benefit once URLs are relative. - Alternative considered: document-relative URLs without a leading slash. Rejected - the app and its API calls already use root-relative paths, so root-relative is consistent. ### Remove the base URL from the signer and config Drop the `baseURL` field and parameter from `Signer`/`NewSigner`, stop reading `cfg.Server.BaseURL` in `storage.Open`, and remove `Server.BaseURL` from config, `.env.example` and the README. Leaving a now-unused variable would invite the same misconfiguration. ### Verification unchanged `VerifyRequest` checks the key and query (`e`, `s`) only; it never used the host, so signing and validation are untouched. ## Risks / Trade-offs - [Subpath deployment (`https://host/galo/`) would break with root-relative URLs] -> The app already assumes root (`/api/...`); subpath support would be a separate change adding a base-path prefix. Documented as out of scope. - [Non-browser clients need a base to resolve object URLs] -> None consume them today; if one appears, it resolves against the instance base like any HTTP client. - [Tests that assumed an absolute URL] -> They parse the URL and use `Path`/`RawQuery`; update `NewSigner` call sites to drop the base argument. ## Migration Plan Remove `APP_BASE_URL` from the server environment and deploy the backend. No data or schema change. Rollback is reverting the deploy. ## Open Questions None blocking.