RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Diff/photoprism-photoprism-claude-claude ↔ photoprism-photoprism-internal-service-cluster-agents

Comparison

A · CLAUDE.md · photoprism/photoprismB · AGENTS.md · photoprism/photoprism
What each file covers, counted
DimensionSharedOnly in AOnly in BOverlap
Sections01460%
Commands13972%
Section tags38027%

What each file covers

Sections

0 shared · 14 only in A · 6 only in B
  • − CLAUDE.md
  • − Build Commands
  • − Testing
  • − Formatting & Linting
  • − Continuous Integration
  • − Schema Migrations
  • − or via Makefile:
  • − Architecture Overview
  • − Backend (`internal/`, `pkg/`, `cmd/`)
  • − Frontend (`frontend/`)
  • − API Conventions
  • − Config & Flags
  • − Verify Before Propagating
  • − Detailed Rules
  • + Cluster Guidelines
  • + Bootstrap & Registration
  • + Registry, DTOs & Provisioning
  • + Cluster API & Theme Changes
  • + Cluster Tests
  • + Cluster Preflight

Commands

1 shared · 39 only in A · 7 only in B
  • − go test ./internal/api -run 'TestFunctionName' -count=1
  • − go test ./internal/photoprism -run 'TestMediaFile_' -count=1
  • − go test ./internal/entity/... -count=1 -tags="slow,develop"
  • − go run cmd/photoprism/photoprism.go migrations ls
  • − go run cmd/photoprism/photoprism.go migrations run
  • − make migrate
  • − make help
  • − make list
  • − make build-go
  • − make build-all
  • − make build-js
  • − make watch-js
  • − make dep
  • − make dep-js
  • − npm ci
  • − npm rebuild --ignore-scripts=false <pkg>
  • − npm rebuild
  • − make docker-build
  • − docker compose up
  • − make terminal
  • − make test
  • − make test-go
  • − make test-js
  • − make test-short
  • − make vitest-watch
  • − make vitest-coverage
  • − make reset-testdb
  • − make test-pkg
  • − make test-api
  • − make test-entity
  • − make test-commands
  • − make test-photoprism
  • − make test-ai
  • − make fmt
  • − make fmt-go
  • − make fmt-js
  • − make fmt-swag
  • − make swag
  • − make lint-go
  • + node.uuid
  • + make -C portal test-start
  • + make -C portal test-env NODES=2
  • + make fmt-go swag-fmt swag
  • + go test ./internal/service/cluster/registry -count=1
  • + go test ./internal/api -run 'Cluster' -count=1
  • + go test ./internal/commands -run 'ClusterRegister|ClusterNodesRotate' -count=1
  •   go build ./...

Section tags

3 shared · 8 only in A · 0 only in B
  • − lint-format
  • − code-style
  • − architecture
  • − types
  • − git-pr
  • − database
  • − do-not
  • − agent-behaviour
  •   build
  •   test
  •   api

Line diff

+34 added−145 removed12 unchanged7.6% identical
photoprism/photoprism · .claude/CLAUDE.md
@@ −1 @@
1# CLAUDE.md
2 
3This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. Detailed rules are in `.claude/rules/*.md` files organized by topic.
4 
5## Build Commands
6 
7Run `make help` for an overview of the most common targets, and `make list` to list all of them. Key commands:
 
 
 
 
8 
9**Backend (Go):**
10- `make build-go` — build the `photoprism` binary (develop mode)
11- `make build-all` — build backend + frontend
12- `go build ./...` — compile all Go packages
13 
14**Frontend (Vue 3):**
15- `make build-js` — production build of the frontend
16- `make watch-js` — watch mode for frontend development (Ctrl+C to stop)
 
 
 
 
 
 
17 
18**Dependencies:**
19- `make dep` — install all dependencies (TensorFlow models, ONNX models, JS packages)
20- `make dep-js` — install JS dependencies only (`npm ci`). The `photoprism/develop` image and the repo `Makefile` both set `NPM_CONFIG_IGNORE_SCRIPTS=true`, so install scripts are skipped automatically; when running npm directly in an env without that default, pass `--ignore-scripts`. Rebuild native addons with `npm rebuild --ignore-scripts=false <pkg>` — a bare `npm rebuild` no-ops wherever the env default is active.
21 
22**Docker dev environment:**
23- `make docker-build` — build local Docker image
24- `docker compose up` — start dev environment (app at http://localhost:2342/)
25- `make terminal` — open shell in dev container
26 
27## Testing
28 
29**Run all tests:**
30- `make test` — runs both JS and Go tests
31- `make test-go` — all Go tests (slow, ~20 min)
32- `make test-js` — frontend unit tests (Vitest)
33- `make test-short` — short Go tests in parallel (~5 min)
34 
35**Run targeted Go tests:**
36```bash
37go test ./internal/api -run 'TestFunctionName' -count=1
38go test ./internal/photoprism -run 'TestMediaFile_' -count=1
39go test ./internal/entity/... -count=1 -tags="slow,develop"
40```
41 
42**Run targeted JS tests:**
43- `make vitest-watch` — Vitest in watch mode
44- `make vitest-coverage` — Vitest with coverage report
45 
46**Reset test databases before running Go tests:**
47- `make reset-testdb` — clears SQLite test DBs and MariaDB testdb
48 
49**Subset targets:** `make test-pkg`, `make test-api`, `make test-entity`, `make test-commands`, `make test-photoprism`, `make test-ai`
50 
51## Formatting & Linting
52 
53Available targets: `make fmt` (everything), `make fmt-go`, `make fmt-js`, `make fmt-swag` / `make swag` (Swagger), `make lint-go`, `make lint-js`. Detailed conventions live in `.claude/rules/go-code-style.md` and `.claude/rules/frontend-rules.md`.
54 
55When creating or editing shell scripts, run `shellcheck <file>` and resolve warnings. When editing Markdown files that contain tables, format them with `npx --yes markdown-table-formatter <filename>`.
56 
57The curated `make help` overviews are maintained by hand in a `HELP_TEXT` block per Makefile. After renaming or removing a target, run `make check-make-help` (also part of `make lint`) to confirm that no overview still advertises it.
58 
59## Continuous Integration
60 
61**GitHub Actions is not enabled for this repository.** The workflow files under `.github/workflows/` do not execute, so pushes and pull requests produce no check runs. Treat them as dormant configuration: do not diagnose the absence of runs as a broken workflow, do not propose enabling Actions, and do not add workflows or bot configuration that assumes they will run. Ask a maintainer before changing anything under `.github/workflows/`.
62 
63The `make` targets above are the authoritative build, format, and test gate — run them locally and report the output rather than relying on a hosted runner.
64 
65## Schema Migrations
66 
67If a change touches database schema, check migrations:
68```bash
69go run cmd/photoprism/photoprism.go migrations ls
70go run cmd/photoprism/photoprism.go migrations run
71# or via Makefile:
72make migrate
73```
74 
75Migration files live in `internal/entity/migrate/`.
76 
77## Architecture Overview
78 
79PhotoPrism is a self-hosted photo management app. The backend is Go, the frontend is Vue 3 + Vuetify 3, and the database is MariaDB or SQLite (via GORM).
80 
81### Backend (`internal/`, `pkg/`, `cmd/`)
82 
83| Package | Purpose |
84|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
85| `internal/photoprism` | **Core application logic**: indexing originals, metadata extraction, thumbnail generation, import/stacking, converter orchestration (FFmpeg/ImageMagick/ExifTool). Entry point for workers and CLI. |
86| `internal/entity` | **Database models** (GORM): Photo, File, Album, Label, Face, User, Session, etc. Contains fixtures for tests and migration helpers. |
87| `internal/entity/query` | Database query helpers used by the API and core packages. |
88| `internal/api` | **REST API handlers** (Gin): thin handlers that validate input, enforce ACL/auth, delegate to services. Annotated with Swagger comments. |
89| `internal/server` | HTTP server setup, routing (Gin engine), WebDAV, static assets, middleware wiring. Routes are registered in `routes.go`. |
90| `internal/config` | Application configuration: CLI flags, env vars, client config sent to the frontend. |
91| `internal/workers` | Background workers: indexing scheduler, metadata sync, sharing, backup, vision jobs. |
92| `internal/commands` | CLI command implementations (`github.com/urfave/cli/v2`). |
93| `internal/auth` | Authentication: ACL (`auth/acl`), JWT (`auth/jwt`), OIDC (`auth/oidc`), session management. |
94| `internal/form` | Request form/binding structs for the API layer. |
95| `internal/meta` | Metadata extraction from EXIF, XMP, JSON sidecars. |
96| `internal/ffmpeg` | FFmpeg/transcoding helpers. |
97| `internal/thumb` | Thumbnail generation helpers. |
98| `internal/ai` | AI/vision model integration (TensorFlow, ONNX). |
99| `internal/service` | Services: maps geocoding, hub (membership), cluster, WebDAV client, CIDR helpers. |
100| `internal/event` | Event bus for structured logging and audit events. |
101| `pkg/` | Standalone, reusable packages: `fs`, `geo`, `media`, `txt`, `clean`, `rnd`, `i18n`, `http`, `time`, etc. No dependency on `internal/`. |
102 
103**Request flow:** HTTP request → Gin middleware (auth, rate limiting) → `internal/api` handler → `internal/photoprism` or `internal/entity` → response.
104 
105**Audit logging convention** (`event.AuditInfo/Warn/Err`): slices must follow the pattern **Who → What → Outcome**:
106- Who: `ClientIP(c)` + actor context (`"session %s"`, `"user %s"`)
107- What: resource constant + action segments
108- Outcome: single token like `status.Succeeded`, `status.Failed`, `status.Denied`, `status.Error(err)`
109 
110### Frontend (`frontend/`)
111 
112Vue 3 app using the Options API and Vuetify 3.
113 
114| Directory | Purpose |
115|---------------------------|-------------------------------------------------------------------------------------------------|
116| `frontend/src/model/` | Client-side models mirroring API responses (Photo, Album, File, User, etc.) |
117| `frontend/src/app/` | App bootstrap, routing (`routes.js`), and the `$session` reactive singleton |
118| `frontend/src/page/` | Page-level components |
119| `frontend/src/component/` | Reusable UI components |
120| `frontend/src/common/` | Shared utilities, the API client (`$api`), and reactive singletons (`$config`, `$view`, `$log`) |
121| `frontend/src/locales/` | i18n translation files |
122| `frontend/tests/` | Vitest unit tests + TestCafe acceptance tests |
123 
124State management uses reactive singleton modules in `src/common/` and `src/app/`, not Vuex or Pinia. Frontend code-style, formatting, testing, translation, and Playwright rules live in `.claude/rules/frontend-rules.md`.
125 
126### API Conventions
127 
128- REST API v1 base path: `/api/v1/` (configured via `conf.BaseUri()`)
129- Authentication: Bearer token (`Authorization` header) or `X-Auth-Token` header
130- Pagination: `count`, `offset`, `limit` parameters (default 100, max 1000)
131- After adding/changing API handlers, regenerate Swagger docs: `make fmt-go swag-fmt swag`
132- New routes must be registered in `internal/server/routes.go`
133 
134### Config & Flags
135 
136Verify config option names before using them:
137```bash
138./photoprism --help
139./photoprism show config-options
140./photoprism show config-yaml
141```
142 
143### Verify Before Propagating
144 
145Before promoting a claim from `CLAUDE.md`, `AGENTS.md`, a memory entry, or another spec into a new rule, spec, code comment, or commit message, verify it against the current code (grep imports, list directories, read the cited file). Stale documentation silently turns into stale rules and stale specs that future sessions will trust. When the claim names a package, function, file, or framework, the cost of one grep is much smaller than the cost of repeating an error across multiple files.
146 
147### Detailed Rules
148 
149Topic-specific conventions live under `.claude/rules/` and are loaded alongside this file:
150 
151- `code-comments.md` — shared JS/Go doc comment rules (length cap, what to omit); referenced by both style files.
152- `go-code-style.md`, `go-testing.md` — Go style, package boundaries, test patterns, fixtures.
153- `frontend-rules.md` — JS/Vue code style, formatting, dependencies, tests, Playwright, translations.
154- `commit-and-docs-style.md` — commit-message format, GitHub issue templates, spec heading style.
155- `safety-and-security.md` — Git/data safety, destructive commands, file I/O and archive-extraction policies, HTTP download helpers.
156- `api-and-config.md`, `cluster-operations.md`, `import-index-download.md`, `build-and-runtime.md`, `sources-of-truth.md` — domain-specific guidance.
157 
photoprism/photoprism · internal/service/cluster/AGENTS.md
@@ +1 @@
1# Cluster Guidelines
2 
3**Last Updated:** April 9, 2026
4 
5## Bootstrap & Registration
6 
7- Keep bootstrap code decoupled: do not import `internal/service/cluster/node/*` from `internal/config` or the cluster root; nodes talk to the Portal over HTTP(S) and use `internal/service/cluster/const.go`.
8- On `401` or `403`, bootstrap refreshes node OAuth credentials by rotating the secret and retrying; log that at info level. If the secret file cannot be written, keep the rotated value in memory.
9- Portal validation may accept HTTP advertise URLs only for loopback or cluster-internal domains such as `*.svc`, `*.cluster.local`, and `*.internal`; all other advertise URLs must use HTTPS.
10- Registration flow: send `rotate=true` only for MySQL or MariaDB nodes without credentials, treat `401`, `403`, and `404` as terminal, include `ClientID` plus `ClientSecret` when renaming an existing node, and persist only newly generated secrets or DB settings.
11- Config init order for cluster-aware startup is: load `options.yml` with `c.initSettings()`, run `EarlyExt().InitEarly(c)`, connect or register the DB, then invoke `Ext().Init(c)`.
12 
13## Registry, DTOs & Provisioning
 
 
 
14 
15- Use `NewClientRegistryWithConfig`; the file-backed registry is legacy.
16- Nodes are keyed by UUID v7 at `/api/v1/cluster/nodes/{uuid}`. Keep the registry interface UUID-first: `Get`, `FindByNodeUUID`, `FindByClientID`, `RotateSecret`, and `DeleteAllByUUID`.
17- CLI lookups should resolve `uuid -> ClientID -> name`.
18- DTOs normalize `Database.{Name,User,Driver,RotatedAt}` and expose `ClientSecret` only during creation or rotation.
19- `nodes rm --all-ids` must clean duplicate client rows.
20- Registry files live under `conf.PortalConfigPath()/nodes/` with mode `0600`, and `ClientData` no longer stores `NodeUUID`.
21- Database and user names use UUID-based HMACs in `<prefix>d<hmac11>` and `<prefix>u<hmac11>` form; the prefix defaults to `cluster_` and may be overridden only by the portal-only `database-provision-prefix` flag.
22- `BuildDSN` accepts a `driver` but falls back to MySQL format with a warning when the driver is unsupported.
23- If Postgres provisioning is added, extend both `BuildDSN` and `provisioner.DatabaseDriver`, add validations, and return `driver=postgres` consistently in API and CLI output.
24 
25## Cluster API & Theme Changes
 
 
26 
27- When renaming or adding cluster response fields, update DTOs in `internal/service/cluster/response.go`, handlers, Swagger, tests, specs, and grep for old and new field names.
28- The theme endpoint `GET /api/v1/cluster/theme` streams a zip from `conf.ThemePath()`. Reinstall only when `app.js` is missing and use the shared helpers in `pkg/http/header`.
29- Admin responses may include `AdvertiseUrl` and `Database`; client and user sessions must remain redacted.
 
30 
31## Cluster Tests
32 
33- Generate OAuth client IDs with `rnd.GenerateUID(entity.ClientUID)` and node UUIDs with `rnd.UUIDv7()`; treat `node.uuid` as required in responses.
34- Cluster registry tests under `internal/service/cluster/registry` intentionally use a full `config.TestConfig()` because they persist `entity.Client` rows. Do not switch them to minimal config helpers unless the tests stop touching the database.
35- Exercise Portal endpoints with `httptest`, guard extraction paths with `pkg/fs.Unzip` size caps, and confirm admin-only fields disappear for client or user sessions.
36- Portal proxy URI validation must use the Portal test environment with `NODES=2` and verify both instance routes when changing `PHOTOPRISM_PORTAL_PROXY_URI` or matching node `PHOTOPRISM_SITE_URL` prefixes; use `PORTAL_TEST_ENV_ARGS=--proxy-uri=/instance/` to regenerate consistent `.env` values.
37- Before `make -C portal test-start`, run a full rebuild with `make -C portal test-env NODES=2`; avoid `--no-build` refreshes unless you are intentionally validating env-only changes.
38 
39## Cluster Preflight
 
 
 
 
 
40 
41- `go build ./...`
42- `make fmt-go swag-fmt swag`
43- `go test ./internal/service/cluster/registry -count=1`
44- `go test ./internal/api -run 'Cluster' -count=1`
45- `go test ./internal/commands -run 'ClusterRegister|ClusterNodesRotate' -count=1`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46 
@@ −1 +1 @@
1−# CLAUDE.md
1+# Cluster Guidelines
22  
3−This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. Detailed rules are in `.claude/rules/*.md` files organized by topic.
3+**Last Updated:** April 9, 2026
44  
5−## Build Commands
5+## Bootstrap & Registration
66  
7−Run `make help` for an overview of the most common targets, and `make list` to list all of them. Key commands:
7+- Keep bootstrap code decoupled: do not import `internal/service/cluster/node/*` from `internal/config` or the cluster root; nodes talk to the Portal over HTTP(S) and use `internal/service/cluster/const.go`.
8+- On `401` or `403`, bootstrap refreshes node OAuth credentials by rotating the secret and retrying; log that at info level. If the secret file cannot be written, keep the rotated value in memory.
9+- Portal validation may accept HTTP advertise URLs only for loopback or cluster-internal domains such as `*.svc`, `*.cluster.local`, and `*.internal`; all other advertise URLs must use HTTPS.
10+- Registration flow: send `rotate=true` only for MySQL or MariaDB nodes without credentials, treat `401`, `403`, and `404` as terminal, include `ClientID` plus `ClientSecret` when renaming an existing node, and persist only newly generated secrets or DB settings.
11+- Config init order for cluster-aware startup is: load `options.yml` with `c.initSettings()`, run `EarlyExt().InitEarly(c)`, connect or register the DB, then invoke `Ext().Init(c)`.
812  
9−**Backend (Go):**
10−- `make build-go` — build the `photoprism` binary (develop mode)
11−- `make build-all` — build backend + frontend
12−- `go build ./...` — compile all Go packages
13+## Registry, DTOs & Provisioning
1314  
14−**Frontend (Vue 3):**
15−- `make build-js` — production build of the frontend
16−- `make watch-js` — watch mode for frontend development (Ctrl+C to stop)
15+- Use `NewClientRegistryWithConfig`; the file-backed registry is legacy.
16+- Nodes are keyed by UUID v7 at `/api/v1/cluster/nodes/{uuid}`. Keep the registry interface UUID-first: `Get`, `FindByNodeUUID`, `FindByClientID`, `RotateSecret`, and `DeleteAllByUUID`.
17+- CLI lookups should resolve `uuid -> ClientID -> name`.
18+- DTOs normalize `Database.{Name,User,Driver,RotatedAt}` and expose `ClientSecret` only during creation or rotation.
19+- `nodes rm --all-ids` must clean duplicate client rows.
20+- Registry files live under `conf.PortalConfigPath()/nodes/` with mode `0600`, and `ClientData` no longer stores `NodeUUID`.
21+- Database and user names use UUID-based HMACs in `<prefix>d<hmac11>` and `<prefix>u<hmac11>` form; the prefix defaults to `cluster_` and may be overridden only by the portal-only `database-provision-prefix` flag.
22+- `BuildDSN` accepts a `driver` but falls back to MySQL format with a warning when the driver is unsupported.
23+- If Postgres provisioning is added, extend both `BuildDSN` and `provisioner.DatabaseDriver`, add validations, and return `driver=postgres` consistently in API and CLI output.
1724  
18−**Dependencies:**
19−- `make dep` — install all dependencies (TensorFlow models, ONNX models, JS packages)
20−- `make dep-js` — install JS dependencies only (`npm ci`). The `photoprism/develop` image and the repo `Makefile` both set `NPM_CONFIG_IGNORE_SCRIPTS=true`, so install scripts are skipped automatically; when running npm directly in an env without that default, pass `--ignore-scripts`. Rebuild native addons with `npm rebuild --ignore-scripts=false <pkg>` — a bare `npm rebuild` no-ops wherever the env default is active.
25+## Cluster API & Theme Changes
2126  
22−**Docker dev environment:**
23−- `make docker-build` — build local Docker image
24−- `docker compose up` — start dev environment (app at http://localhost:2342/)
25−- `make terminal` — open shell in dev container
27+- When renaming or adding cluster response fields, update DTOs in `internal/service/cluster/response.go`, handlers, Swagger, tests, specs, and grep for old and new field names.
28+- The theme endpoint `GET /api/v1/cluster/theme` streams a zip from `conf.ThemePath()`. Reinstall only when `app.js` is missing and use the shared helpers in `pkg/http/header`.
29+- Admin responses may include `AdvertiseUrl` and `Database`; client and user sessions must remain redacted.
2630  
27−## Testing
31+## Cluster Tests
2832  
29−**Run all tests:**
30−- `make test` — runs both JS and Go tests
31−- `make test-go` — all Go tests (slow, ~20 min)
32−- `make test-js` — frontend unit tests (Vitest)
33−- `make test-short` — short Go tests in parallel (~5 min)
33+- Generate OAuth client IDs with `rnd.GenerateUID(entity.ClientUID)` and node UUIDs with `rnd.UUIDv7()`; treat `node.uuid` as required in responses.
34+- Cluster registry tests under `internal/service/cluster/registry` intentionally use a full `config.TestConfig()` because they persist `entity.Client` rows. Do not switch them to minimal config helpers unless the tests stop touching the database.
35+- Exercise Portal endpoints with `httptest`, guard extraction paths with `pkg/fs.Unzip` size caps, and confirm admin-only fields disappear for client or user sessions.
36+- Portal proxy URI validation must use the Portal test environment with `NODES=2` and verify both instance routes when changing `PHOTOPRISM_PORTAL_PROXY_URI` or matching node `PHOTOPRISM_SITE_URL` prefixes; use `PORTAL_TEST_ENV_ARGS=--proxy-uri=/instance/` to regenerate consistent `.env` values.
37+- Before `make -C portal test-start`, run a full rebuild with `make -C portal test-env NODES=2`; avoid `--no-build` refreshes unless you are intentionally validating env-only changes.
3438  
35−**Run targeted Go tests:**
36−```bash
37−go test ./internal/api -run 'TestFunctionName' -count=1
38−go test ./internal/photoprism -run 'TestMediaFile_' -count=1
39−go test ./internal/entity/... -count=1 -tags="slow,develop"
40−```
39+## Cluster Preflight
4140  
42−**Run targeted JS tests:**
43−- `make vitest-watch` — Vitest in watch mode
44−- `make vitest-coverage` — Vitest with coverage report
45− 
46−**Reset test databases before running Go tests:**
47−- `make reset-testdb` — clears SQLite test DBs and MariaDB testdb
48− 
49−**Subset targets:** `make test-pkg`, `make test-api`, `make test-entity`, `make test-commands`, `make test-photoprism`, `make test-ai`
50− 
51−## Formatting & Linting
52− 
53−Available targets: `make fmt` (everything), `make fmt-go`, `make fmt-js`, `make fmt-swag` / `make swag` (Swagger), `make lint-go`, `make lint-js`. Detailed conventions live in `.claude/rules/go-code-style.md` and `.claude/rules/frontend-rules.md`.
54− 
55−When creating or editing shell scripts, run `shellcheck <file>` and resolve warnings. When editing Markdown files that contain tables, format them with `npx --yes markdown-table-formatter <filename>`.
56− 
57−The curated `make help` overviews are maintained by hand in a `HELP_TEXT` block per Makefile. After renaming or removing a target, run `make check-make-help` (also part of `make lint`) to confirm that no overview still advertises it.
58− 
59−## Continuous Integration
60− 
61−**GitHub Actions is not enabled for this repository.** The workflow files under `.github/workflows/` do not execute, so pushes and pull requests produce no check runs. Treat them as dormant configuration: do not diagnose the absence of runs as a broken workflow, do not propose enabling Actions, and do not add workflows or bot configuration that assumes they will run. Ask a maintainer before changing anything under `.github/workflows/`.
62− 
63−The `make` targets above are the authoritative build, format, and test gate — run them locally and report the output rather than relying on a hosted runner.
64− 
65−## Schema Migrations
66− 
67−If a change touches database schema, check migrations:
68−```bash
69−go run cmd/photoprism/photoprism.go migrations ls
70−go run cmd/photoprism/photoprism.go migrations run
71−# or via Makefile:
72−make migrate
73−```
74− 
75−Migration files live in `internal/entity/migrate/`.
76− 
77−## Architecture Overview
78− 
79−PhotoPrism is a self-hosted photo management app. The backend is Go, the frontend is Vue 3 + Vuetify 3, and the database is MariaDB or SQLite (via GORM).
80− 
81−### Backend (`internal/`, `pkg/`, `cmd/`)
82− 
83−| Package | Purpose |
84−|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
85−| `internal/photoprism` | **Core application logic**: indexing originals, metadata extraction, thumbnail generation, import/stacking, converter orchestration (FFmpeg/ImageMagick/ExifTool). Entry point for workers and CLI. |
86−| `internal/entity` | **Database models** (GORM): Photo, File, Album, Label, Face, User, Session, etc. Contains fixtures for tests and migration helpers. |
87−| `internal/entity/query` | Database query helpers used by the API and core packages. |
88−| `internal/api` | **REST API handlers** (Gin): thin handlers that validate input, enforce ACL/auth, delegate to services. Annotated with Swagger comments. |
89−| `internal/server` | HTTP server setup, routing (Gin engine), WebDAV, static assets, middleware wiring. Routes are registered in `routes.go`. |
90−| `internal/config` | Application configuration: CLI flags, env vars, client config sent to the frontend. |
91−| `internal/workers` | Background workers: indexing scheduler, metadata sync, sharing, backup, vision jobs. |
92−| `internal/commands` | CLI command implementations (`github.com/urfave/cli/v2`). |
93−| `internal/auth` | Authentication: ACL (`auth/acl`), JWT (`auth/jwt`), OIDC (`auth/oidc`), session management. |
94−| `internal/form` | Request form/binding structs for the API layer. |
95−| `internal/meta` | Metadata extraction from EXIF, XMP, JSON sidecars. |
96−| `internal/ffmpeg` | FFmpeg/transcoding helpers. |
97−| `internal/thumb` | Thumbnail generation helpers. |
98−| `internal/ai` | AI/vision model integration (TensorFlow, ONNX). |
99−| `internal/service` | Services: maps geocoding, hub (membership), cluster, WebDAV client, CIDR helpers. |
100−| `internal/event` | Event bus for structured logging and audit events. |
101−| `pkg/` | Standalone, reusable packages: `fs`, `geo`, `media`, `txt`, `clean`, `rnd`, `i18n`, `http`, `time`, etc. No dependency on `internal/`. |
102− 
103−**Request flow:** HTTP request → Gin middleware (auth, rate limiting) → `internal/api` handler → `internal/photoprism` or `internal/entity` → response.
104− 
105−**Audit logging convention** (`event.AuditInfo/Warn/Err`): slices must follow the pattern **Who → What → Outcome**:
106−- Who: `ClientIP(c)` + actor context (`"session %s"`, `"user %s"`)
107−- What: resource constant + action segments
108−- Outcome: single token like `status.Succeeded`, `status.Failed`, `status.Denied`, `status.Error(err)`
109− 
110−### Frontend (`frontend/`)
111− 
112−Vue 3 app using the Options API and Vuetify 3.
113− 
114−| Directory | Purpose |
115−|---------------------------|-------------------------------------------------------------------------------------------------|
116−| `frontend/src/model/` | Client-side models mirroring API responses (Photo, Album, File, User, etc.) |
117−| `frontend/src/app/` | App bootstrap, routing (`routes.js`), and the `$session` reactive singleton |
118−| `frontend/src/page/` | Page-level components |
119−| `frontend/src/component/` | Reusable UI components |
120−| `frontend/src/common/` | Shared utilities, the API client (`$api`), and reactive singletons (`$config`, `$view`, `$log`) |
121−| `frontend/src/locales/` | i18n translation files |
122−| `frontend/tests/` | Vitest unit tests + TestCafe acceptance tests |
123− 
124−State management uses reactive singleton modules in `src/common/` and `src/app/`, not Vuex or Pinia. Frontend code-style, formatting, testing, translation, and Playwright rules live in `.claude/rules/frontend-rules.md`.
125− 
126−### API Conventions
127− 
128−- REST API v1 base path: `/api/v1/` (configured via `conf.BaseUri()`)
129−- Authentication: Bearer token (`Authorization` header) or `X-Auth-Token` header
130−- Pagination: `count`, `offset`, `limit` parameters (default 100, max 1000)
131−- After adding/changing API handlers, regenerate Swagger docs: `make fmt-go swag-fmt swag`
132−- New routes must be registered in `internal/server/routes.go`
133− 
134−### Config & Flags
135− 
136−Verify config option names before using them:
137−```bash
138−./photoprism --help
139−./photoprism show config-options
140−./photoprism show config-yaml
141−```
142− 
143−### Verify Before Propagating
144− 
145−Before promoting a claim from `CLAUDE.md`, `AGENTS.md`, a memory entry, or another spec into a new rule, spec, code comment, or commit message, verify it against the current code (grep imports, list directories, read the cited file). Stale documentation silently turns into stale rules and stale specs that future sessions will trust. When the claim names a package, function, file, or framework, the cost of one grep is much smaller than the cost of repeating an error across multiple files.
146− 
147−### Detailed Rules
148− 
149−Topic-specific conventions live under `.claude/rules/` and are loaded alongside this file:
150− 
151−- `code-comments.md` — shared JS/Go doc comment rules (length cap, what to omit); referenced by both style files.
152−- `go-code-style.md`, `go-testing.md` — Go style, package boundaries, test patterns, fixtures.
153−- `frontend-rules.md` — JS/Vue code style, formatting, dependencies, tests, Playwright, translations.
154−- `commit-and-docs-style.md` — commit-message format, GitHub issue templates, spec heading style.
155−- `safety-and-security.md` — Git/data safety, destructive commands, file I/O and archive-extraction policies, HTTP download helpers.
156−- `api-and-config.md`, `cluster-operations.md`, `import-index-download.md`, `build-and-runtime.md`, `sources-of-truth.md` — domain-specific guidance.
41+- `go build ./...`
42+- `make fmt-go swag-fmt swag`
43+- `go test ./internal/service/cluster/registry -count=1`
44+- `go test ./internal/api -run 'Cluster' -count=1`
45+- `go test ./internal/commands -run 'ClusterRegister|ClusterNodesRotate' -count=1`
15746  
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack