Commit Graph

6 Commits

Author SHA1 Message Date
Claudio
2a75896274 sidecar: declarative USER_BASEPATHS reconciler
PhotoPrism's OSS edition has no way to map OIDC claims to BasePath, so
every freshly-registered OIDC user lands with BasePath="" and either
sees the whole library (admin) or nothing (guest) — never their own
subfolder.

Introduces a sidecar-driven reconciler with a single env knob the
admin sets in docker-compose / .env.photoprism:

  USER_BASEPATHS="test:test, alice:family/alice, bob:bob"

(`user:originals-relative-path` pairs, comma-separated.) On boot and
every 60s thereafter the sidecar:
  - mkdir -p's the target subdirectory under ORIGINALS_ROOT so
    PhotoPrism's path: ACL filter has somewhere real to point;
  - UPDATEs photoprism.auth_users.base_path for the matching row
    where it differs (idempotent, missing users skipped — they
    materialise on first OIDC login and the next pass catches them).

The reconciler uses a separate gorm connection scoped to the
`photoprism` schema with PhotoPrism's own DB user, since the existing
`sidecar` user only has grants on `mule_sidecar.*`. Connection stays
dormant when PP_DB_PASSWORD is empty — the feature is opt-in via env.

Compose changes: thread PP_DB_* + USER_BASEPATHS through to the
sidecar service. New users.go file isolates the reconciler logic;
main.go calls startUserBasepathReconciler() during boot.
2026-05-18 20:25:19 +00:00
Claudio
3d8e050af4 fix(compose): cap indexer concurrency to keep shared hosts alive
Default PHOTOPRISM_INDEX_WORKERS is NumCPU/2 (3 on the M0 6-core test
LXC). Each worker forks TF + ffmpeg + libvips, so a fresh index of
~1.2k photos pushed the LXC's load avg above 50 and starved the
Proxmox host. Pin to PP_WORKERS / PP_INDEX_WORKERS (default 2) so
the indexer is calm by default; bump in .env.photoprism on dedicated
boxes.
2026-05-17 23:13:36 +02:00
Claudio
cce1d876c3 fix(compose): pass OIDC env vars under the names PhotoPrism actually reads
The compose file was using PHOTOPRISM_OIDC_ISSUER_URL / _CLIENT_ID /
_CLIENT_SECRET / _PROVIDER_NAME / _REDIRECT_URI, but PhotoPrism's CLI
flags are --oidc-uri / --oidc-client / --oidc-secret / --oidc-provider —
so the env vars it parses are PHOTOPRISM_OIDC_URI / _CLIENT / _SECRET /
_PROVIDER. With the old names PhotoPrism silently ignored them, OIDC
stayed dormant, and `photoprism show config` reported blank oidc-uri /
oidc-client even though everything else looked configured.

Confirmed on the M0 LXC: renaming the env vars makes the Authentik
"Sign in" button appear on /library/login, /api/v1/oidc/login emits a
proper 302 to the IdP authorize endpoint, and the callback creates the
OIDC user + session in the DB.

The user-facing `.env.photoprism` keys are unchanged (OIDC_PROVIDER_NAME,
OIDC_ISSUER_URL, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET); the compose file
just maps them to the correct PHOTOPRISM_* targets. OIDC_REDIRECT_URI
is removed because PhotoPrism derives the redirect from PHOTOPRISM_SITE_URL.
2026-05-17 22:56:07 +02:00
4362e475a7 build(sidecar): containerize + delete the Node prototype
- New sidecar/Dockerfile: multi-stage golang:1.25-alpine → distroless/
  static, ~12 MB final image, static CGO-free binary.
- Wire pp-sidecar into docker-compose.photoprism.yml so the whole
  stack (mariadb + photoprism + sidecar) starts with one
  `podman-compose up`. Container reaches mariadb + photoprism on the
  internal network; the host gets 127.0.0.1:8000 for Vite's proxy.
- New SIDECAR_LISTEN_ADDR env var (default 127.0.0.1 for the host-mode
  dev loop) so the container can bind 0.0.0.0:8000 and let the port
  mapping reach it. Without this the loopback bind was invisible to
  the host.
- Delete sidecar/legacy/server.mjs — the Node prototype's archival
  window is over; git history is its home now.
- Update sidecar/README with compose-first bringup; keep the host
  `go build` flow as the fast-iteration loop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 17:23:36 +02:00
032dce6c85 feat(sidecar): port Node prototype to Go + Gin + GORM + MariaDB
Replace the Node prototype (server.mjs) with the stack the merge plan
calls for: Go 1.25, Gin for routing, GORM + MariaDB for persistence.
Same wire contract on /api/sidecar/* so the SvelteKit client doesn't
change.

- Marks move from a JSON file on disk to mule_sidecar.marks (auto-
  migrated by GORM on first boot). The Node prototype's marks.json
  was dev-only; not migrated.
- Folder/rename/heap-convert/duplicates handlers reproduce the
  prototype's behaviour, including the path-traversal defence
  (resolveUnderRoot + EvalSymlinks), the size-bucket prefilter for
  the duplicate hasher, and the background reindex fire-and-forget
  pattern.
- Auth model unchanged: requireSession middleware proxies the
  caller's X-Auth-Token to PhotoPrism's /api/v1/photos?count=1
  before any destructive op.
- Expose pp-mariadb on 127.0.0.1:3306 in docker-compose so the
  host Go process can reach mule_sidecar.* without joining the
  container network.
- Archive the Node prototype under sidecar/legacy/server.mjs for
  one cycle as reference.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 17:15:47 +02:00
8c2526d982 feat: PhotoPrism M0 bring-up — compose stack, web client, sidecar, migrate
Replace the legacy mule-image backend with PhotoPrism plus a thin
SvelteKit client and a Node sidecar for endpoints PhotoPrism doesn't
expose (file rename), and add a two-phase migrator (metadata via PUT,
heaps → albums) for the existing Postgres library.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 16:06:58 +02:00