PhotoPrism — Backend CODEMAP **Last Updated:** November 22, 2025 Purpose - Give agents and contributors a fast, reliable map of where things live and how they fit together, so you can add features, fix bugs, and write tests without spelunking. - Sources of truth: prefer Makefile targets and the Developer Guide linked in AGENTS.md. Quick Start - Inside dev container (recommended): - Install deps: `make dep` - Build backend: `make build-go` - Lint Go (golangci-lint): `make lint-go` (uses `.golangci.yml`; prints findings without failing) or run both stacks with `make lint` - Run server: `./photoprism start` - Open: http://localhost:2342/ or https://app.localssl.dev/ (Traefik required) - On host (manages Docker): - Build image: `make docker-build` - Start services: `docker compose up -d` - Logs: `docker compose logs -f --tail=100 photoprism` Executables & Entry Points - CLI app (binary name across docs/images is `photoprism`): - Main: `cmd/photoprism/photoprism.go` - Commands registry: `internal/commands/commands.go` (array `commands.PhotoPrism`) - Catalog helpers: `internal/commands/catalog` (DTOs and builders to enumerate commands/flags; Markdown renderer) - Web server: - Startup: `internal/commands/start.go` → `server.Start` (starts HTTP(S), workers, session cleanup) - HTTP server: `internal/server/start.go` (compression, security, healthz, readiness, TLS/AutoTLS/unix socket) - Routes: `internal/server/routes.go` (registers all v1 API groups + UI, WebDAV, sharing, .well-known) - API group: `APIv1 = router.Group(conf.BaseUri("/api/v1"), Api(conf))` High-Level Package Map (Go) - `internal/api` — Gin handlers and Swagger annotations; only glue, no business logic - `internal/commands` — CLI command definitions and orchestration (`start`, `index`, `import`, `migrate`, etc.); `commands.go` wires them into the app and subpackages like `catalog` emit CLI documentation. - `internal/server` — HTTP server, middleware, routing, static/ui/webdav - `internal/config` — configuration, flags/env/options, client config, DB init/migrate - `internal/entity` — GORM v1 models, queries, search helpers, migrations - `internal/photoprism` — core domain logic (indexing, import, faces, thumbnails, cleanup) - `internal/ai/vision` — multi-engine computer vision pipeline (models, adapters, schema). Adapter docs: [`internal/ai/vision/openai/README.md`](internal/ai/vision/openai/README.md) and [`internal/ai/vision/ollama/README.md`](internal/ai/vision/ollama/README.md). - `internal/workers` — background schedulers (index, vision, sync, meta, backup) - `internal/auth` — ACL, sessions, OIDC - `internal/service` — cluster/portal, maps, hub, webdav - `internal/event` — logging, pub/sub, audit; canonical outcome tokens live in `pkg/log/status` (use helpers like `status.Error(err)` when the sanitized message should be the outcome). Docs: `internal/event/README.md`. - `internal/ffmpeg`, `internal/thumb`, `internal/meta`, `internal/form`, `internal/mutex` — media, thumbs, metadata, forms, coordination. Docs: `internal/ffmpeg/README.md`, `internal/meta/README.md`. - `pkg/*` — reusable utilities (must never import from `internal/*`), e.g. `pkg/clean`, `pkg/enum`, `pkg/fs`, `pkg/txt`, `pkg/http/header` Templates & Static Assets - Entry HTML lives in `assets/templates/index.gohtml`, which includes the splash markup from `app.gohtml` and the SPA loader from `app.js.gohtml`. - The browser check logic resides in `assets/static/js/browser-check.js` and is included via `app.js.gohtml`; it performs capability checks (Promise, fetch, AbortController, `script.noModule`, etc.) before the main bundle runs. Update this file (and the partial) in lockstep with the templates in private repos (`pro/assets/templates/index.gohtml`, `plus/assets/templates/index.gohtml`) because they import the same partial, and keep the `