Cleanup: Fix formatting of Markdown files

Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
Michael Mayer 2026-02-14 12:10:43 +01:00
parent d0b09206fb
commit cd7affffeb
18 changed files with 113 additions and 118 deletions

View file

@ -1,4 +1,4 @@
# Backend Translations
## Backend Translations
PhotoPrism uses [gettext](https://en.wikipedia.org/wiki/Gettext) for localizing frontend and backend.
It's one of the most widely adopted standards for translating user interfaces.

View file

@ -1,4 +1,4 @@
# Dockerfiles for Development and Production
## Dockerfiles for Development & Production
[**Dockerfiles**](https://docs.docker.com/engine/reference/builder/) are text documents that contain all commands a user could call in a terminal to assemble an application image.
@ -6,7 +6,7 @@
See our [Getting Started FAQ](https://docs.photoprism.app/getting-started/faq/#how-can-i-install-photoprism-without-docker) for alternative installation methods, for example using the [*tar.gz* packages](https://github.com/photoprism/photoprism/blob/develop/setup/pkg/linux/README.md) we provide for download at [dl.photoprism.app/pkg/linux/](https://dl.photoprism.app/pkg/linux/README.html).
## What are the benefits of using Docker? ##
### What Are the Benefits of Using Docker?
**(1) Docker uses standard features of the Linux kernel.** Containers are nothing new; [Solaris Zones](https://en.wikipedia.org/wiki/Solaris_Containers) were released about 20 years ago and the chroot system call was introduced during [development of Version 7 Unix in 1979](https://en.wikipedia.org/wiki/Chroot). It is used ever since for hosting applications exposed to the public Internet. Modern Linux containers are an incremental improvement of this, based on standard functionality that is part of the kernel.
@ -16,6 +16,6 @@ See our [Getting Started FAQ](https://docs.photoprism.app/getting-started/faq/#h
**(4) Running applications in containers is more secure.** Last but not least, virtually all file format parsers have vulnerabilities that just haven't been discovered yet. This is a known risk that can affect you even if your computer is not directly connected to the Internet. Running apps in a container with limited host access is an easy way to improve security without compromising performance and usability.
## Why not use virtual machines instead? ##
### Why Not Use Virtual Machines Instead?
A virtual machine with a dedicated operating system environment provides even more security, but usually has side effects such as lower performance and more difficult handling. Using a VM, however, doesn't prevent you from running containerized apps to get the best of both worlds. This is essentially what happens when you install Docker on [virtual cloud servers](https://docs.photoprism.app/getting-started/cloud/digitalocean/) and operating systems other than Linux.

View file

@ -1,8 +1,8 @@
# View Helper Guidelines
## View Helper Guidelines
**Last Updated:** February 8, 2026
**Last Updated:** February 14, 2026
## Focus Management
### Focus Management
PhotoPrism uses a shared view helper to maintain predictable focus across pages and dialogs:
@ -10,7 +10,7 @@ PhotoPrism uses a shared view helper to maintain predictable focus across pages
This helper tracks the currently active component, applies focus when views change, and traps focus inside open dialogs, ensuring that tabbing never leaks into the page behind an overlay. The following guidelines explain how to work with the helper when building UI functionality.
### Session Storage Namespacing Notes
#### Session Storage Namespacing Notes
When integrating third-party clients (for example mobile webviews) that pre-populate browser storage, keep the following behavior in mind:
@ -19,7 +19,7 @@ When integrating third-party clients (for example mobile webviews) that pre-popu
- Legacy compatibility keys (`authToken` and `sessionId`) are only migrated by the startup bridge when both values are present.
- Preferred integration contract for external clients is to set both `session.token` and `session.id` together.
### Tabindex Cheat Sheet
#### Tabindex Cheat Sheet
| Value | When to use it | Effect |
|------------|---------------------------------------------------------|------------------------------------------------------------------------------------------------|
@ -27,12 +27,12 @@ When integrating third-party clients (for example mobile webviews) that pre-popu
| `-1` | Programmatic focus targets (dialog wrappers, sentinels) | Element can receive focus via script but is skipped while tabbing |
| *positive* | **Avoid** | Custom tab order becomes hard to maintain; the view helper no longer knows the “first” element |
**Tips**
##### Tips
- Root page containers (`<div class="p-page ...">`) should use `tabindex="-1"` so the view helper can focus them when a route becomes active, then immediately move focus to the first interactive control.
- Leave buttons, inputs, and links at the default `tabindex="0"` (or no attribute) so the browser controls the natural order.
### Dialog Implementation Checklist
#### Dialog Implementation Checklist
Vuetify dialogs are teleported to the overlay container, so consistent refs and lifecycle hooks are essential.
@ -90,7 +90,7 @@ Vuetify dialogs are teleported to the overlay container, so consistent refs and
Only add local `@focusout` handlers if a dialog needs custom behaviour. If you do, always call `ev.preventDefault()` when you redirect focus so you do not fight the global handler.
### Keyboard Event Handling
#### Keyboard Event Handling
Dialogs and page shells often react to keyboard shortcuts (Escape to close, Enter to confirm, etc.). To keep those handlers compatible with text inputs and other interactive children:
@ -130,7 +130,7 @@ Example page container:
Both snippets allow focused inputs to veto shortcuts by calling `event.stopPropagation()` or `event.preventDefault()` before the key reaches the container listener, keeping focus management predictable across the app.
#### Global Shortcut Forwarding
##### Global Shortcut Forwarding
`common/view.js` registers a single `keydown` listener that forwards shortcut keys to the active component:
@ -156,7 +156,7 @@ onKeyDown(ev) {
- Persistent dialogs that must suppress Vuetifys rejection animation should still attach a direct `@keydown.esc.exact` handler; `onShortCut(ev)` alone does not override the built-in dialog behaviour.
- Return `true` from `onShortCut(ev)` after handling a shortcut to signal `preventDefault()`. Return `false` to fall back to the browsers native behaviour.
### Example: Delete Confirmation Dialog
#### Example: Delete Confirmation Dialog
```vue
<template>
@ -221,21 +221,21 @@ This pattern ensures:
- Focus defaults to the `Cancel` button (first tabbable control).
- Tabbing continues to cycle between `Cancel` and `Delete` until the dialog closes.
### Troubleshooting Checklist
#### Troubleshooting Checklist
**Focus escapes the dialog when tabbing**
##### Focus Escapes the Dialog When Tabbing
- Verify the dialog calls `$view.enter(this)` / `$view.leave(this)`.
- Confirm the dialog template has `ref="dialog"`; if you teleport manually, expose `contentEl`.
- Ensure there is at least one control with `tabindex="0"` inside the card. Pure static content cannot trap focus.
**Focus lands on the overlay instead of a button**
##### Focus Lands on the Overlay Instead of a Button
- Check for stray `tabindex="-1"` on child elements. Only the outer container should use `-1`.
- Use the browser console with `trace` logging enabled (`this.$config.get("trace")`) to see which elements receive `document.focusin/out`.
**Custom focusout handler keeps fighting the trap**
##### Custom Focusout Handler Keeps Fighting the Trap
- Make sure the handler checks `this.$view.isActive(this)` and calls `ev.preventDefault()` when redirecting focus.
- Consider removing the custom handler if the global trap already matches the desired behaviour.
**Nested dialogs (dialog inside dialog)**
##### Nested Dialogs (Dialog Inside Dialog)
- Each dialog must have `ref="dialog"` so the helper can distinguish them.
- The helper chooses the currently active component (`this.$view.getCurrent()`) as the trap owner, so opening a second dialog automatically pauses the first ones trap.

View file

@ -1,4 +1,4 @@
# Frontend Translations
## Frontend Translations
PhotoPrism uses [gettext](https://en.wikipedia.org/wiki/Gettext) for localizing frontend and backend.
It's one of the most widely adopted standards for translating user interfaces.

View file

@ -1,8 +1,8 @@
# Frontend Tests and Linting
## Frontend Tests & Linting
**Last Updated:** February 11, 2026
**Last Updated:** February 14, 2026
## Purpose
### Purpose
This guide documents the frontend test and lint workflows for PhotoPrism.
It is intended for both humans and coding agents.
@ -14,7 +14,7 @@ Use this file when you need to:
- lint/format frontend code;
- evaluate frontend tool upgrades safely.
## Quick Start
### Quick Start
From the repository root:
@ -33,7 +33,7 @@ From `frontend/`:
- `npm run lint` runs ESLint.
- `npm run fmt` runs ESLint with `--fix`.
## Test Suite Layout
### Test Suite Layout
- Unit and component tests: `frontend/tests/vitest/**/*`
- Vitest setup: `frontend/tests/vitest/setup.js`
@ -43,7 +43,7 @@ From `frontend/`:
- Acceptance config: `frontend/testcaferc.json` and `frontend/tests/testcafeconfig.json`
- Upload fixtures: `frontend/tests/upload-files/**/*`
## Overlay Test Notes (Plus and Pro)
### Overlay Test Notes (Plus & Pro)
Plus and Pro frontend overlays reuse the same frontend test and lint toolchain:
@ -54,7 +54,7 @@ Plus and Pro frontend overlays reuse the same frontend test and lint toolchain:
When evaluating frontend tooling changes, test at least one CE run plus Plus and Pro overlay runs.
## Tool Versions
### Tool Versions
Current frontend tool versions are defined in `frontend/package.json` unless stated otherwise.
@ -84,9 +84,9 @@ Current frontend tool versions are defined in `frontend/package.json` unless sta
Note: TestCafe is available in the development environment but is currently not pinned as a direct dependency in `frontend/package.json`. Verify with `testcafe --version`.
## Upgrade Guidance
### Upgrade Guidance
### General Upgrade Flow
#### General Upgrade Flow
1. Review release notes and migration guides for each tool.
2. Check peer dependency compatibility before installing:
@ -101,7 +101,7 @@ Note: TestCafe is available in the development environment but is currently not
5. If dependencies changed, regenerate notices with `make notice`.
6. Revert the trial changes if validation fails.
### ESLint v10 Status (As of February 11, 2026)
#### ESLint v10 Status (As of February 11, 2026)
A trial upgrade from ESLint v9 to ESLint v10 is currently not safe for this repository.
@ -121,7 +121,7 @@ Current recommendation:
- stay on ESLint v9 until `eslint-plugin-vuetify` and related plugins officially support ESLint v10;
- re-run the validation flow above before attempting another upgrade.
## See Also
### See Also
- Frontend architecture map: `frontend/CODEMAP.md`
- Frontend focus and dialog behavior: `frontend/src/common/README.md`

View file

@ -1,6 +1,6 @@
## Face Detection and Embedding Guidelines
## Face Detection & Embedding Guidelines
**Last Updated:** December 23, 2025
**Last Updated:** February 14, 2026
### Overview

View file

@ -1,10 +1,10 @@
# API Package Guide
## API Package Guide
## Overview
### Overview
The API package exposes PhotoPrisms HTTP endpoints via Gin handlers. Each file under `internal/api` contains the handlers, request/response DTOs, and Swagger annotations for a specific feature area. Handlers remain thin: they validate input, enforce security or ACL checks, and delegate domain work to services in `internal/photoprism`, `internal/service`, or other internal packages. Keep exported types aligned with the REST schema and avoid embedding business logic directly in handlers.
## Routing & Wiring
### Routing & Wiring
- Register handlers in `internal/server/routes.go` by attaching them to the proper router group (for example, `APIv1 := router.Group(conf.BaseUri("/api/v1"), Api(conf))`).
- Group endpoints by resource to match existing patterns: sessions, cluster, photos, labels, files, downloads, metadata, and technical routes.
@ -12,7 +12,7 @@ The API package exposes PhotoPrisms HTTP endpoints via Gin handlers. Each fil
- Use `conf.BaseUri()` when constructing route prefixes so configuration overrides propagate consistently.
- When new endpoints require feature toggles, gate them in the router rather than inside the handler so disabled routes remain undiscoverable.
## Handler Implementation Patterns
### Handler Implementation Patterns
- Accept and return JSON using the shared response helpers. Set `header.ContentTypeJSON` and ensure responses include proper cache headers (`no-store` for sensitive payloads).
- Parse parameters with Gin binding and validate inputs before delegating work. For complex payloads, define dedicated request structs with validation tags.
@ -21,7 +21,7 @@ The API package exposes PhotoPrisms HTTP endpoints via Gin handlers. Each fil
- Surface pagination consistently with `count`, `offset`, and `limit` following the defaults (100 max 1000). Validate `offset >= 0` and clamp `count` to the allowed range.
- When responses need role-specific fields, build DTOs that redact sensitive data for non-admin roles so the handler stays deterministic.
## Security & Middleware
### Security & Middleware
- Authenticate requests using the standard middleware (`AuthRequired`) and check roles via helpers in `internal/auth/acl` (`acl.ParseRole`, `acl.ScopePermits`, `acl.ScopeAttrPermits`).
- Never log secrets or tokens. Prefer structured logging through `event.Log` and redact sensitive values before logging.
@ -29,7 +29,7 @@ The API package exposes PhotoPrisms HTTP endpoints via Gin handlers. Each fil
- Derive client IPs through `api.ClientIP` and extract bearer tokens with `header.BearerToken` or the helper setters. Use constant-time comparison for tokens and secrets.
- For downloads or proxy endpoints, validate URLs against allowed schemes (`http`, `https`) and reject private or loopback addresses unless explicitly required.
## Audit Logging
### Audit Logging
- Emit security events via `event.Audit*` (`AuditInfo`, `AuditWarn`, `AuditErr`, `AuditDebug`) and always build the slice as **Who → What → Outcome**.
- **Who:** `ClientIP(c)` followed by the most specific actor context (`"session %s"`, `"client %s"`, `"user %s"`).
@ -56,14 +56,14 @@ The API package exposes PhotoPrisms HTTP endpoints via Gin handlers. Each fil
```
- See `specs/common/audit-logs.md` for the full conventions and additional examples that agents should follow.
## Swagger Documentation
### Swagger Documentation
- Annotate handlers with Swagger comments that include full `/api/v1/...` paths, request/response schemas, and security definitions. Only annotate routes that are externally accessible.
- Regenerate docs after adding or updating handlers: `make fmt-go swag-fmt swag`. This formats Go files, normalizes annotations, and updates `internal/api/swagger.json`. Do not edit the generated JSON manually.
- When adding new DTOs, keep field names aligned with the JSON schema and update client documentation if serialized names change.
- Use enum annotations sparingly and ensure they reflect actual runtime constraints to avoid misleading generated clients.
## Testing Strategy
### Testing Strategy
- Build tests around the API harness (`NewApiTest`) to obtain a configured Gin router, config, and dependencies. This isolates filesystem paths and avoids polluting global state.
- Wrap requests with helper functions (for example, `PerformRequestJSON`, `PerformAuthenticatedRequest`) to capture status codes, headers, and payloads. Assert headers using constants from `pkg/http/header`.
@ -71,14 +71,14 @@ The API package exposes PhotoPrisms HTTP endpoints via Gin handlers. Each fil
- Stub external dependencies (`httptest.Server`) for remote calls and set `AllowPrivate=true` explicitly when the test server binds to loopback addresses.
- Structure tests with table-driven subtests (`t.Run("CaseName", ...)`) and use PascalCase names. Provide cleanup functions (`t.Cleanup`) to remove temporary files or databases created during tests.
## Focused Test Runs
### Focused Test Runs
- Fast iteration: `go test ./internal/api -run '<Package|HandlerName>' -count=1`
- Cluster endpoints: `go test ./internal/api -run 'Cluster' -count=1`
- Downloads and zip streaming: `go test ./internal/api -run 'Download|Archive' -count=1`
- Combined CLI and API validation: pair `go test ./internal/commands -run 'Cluster' -count=1` with the matching API suite to ensure DTOs remain compatible.
## Preflight Checklist
### Preflight Checklist
- Format and regenerate documentation: `make fmt-go swag-fmt swag`
- Compile backend: `go build ./...`

View file

@ -1,10 +1,10 @@
# Commands Package Guide
## Commands Package Guide
## Overview
### Overview
The `commands` package hosts the CLI implementation for the PhotoPrism binary. Command wiring begins in `commands.go`, where each `*cli.Command` is registered on the shared slice consumed by `cmd/photoprism/photoprism.go`. Supporting utilities such as flag builders, shared error handling, and helper structs are colocated with their related command files. Keep commands cohesive: each file should focus on a single functional area (for example, `download.go` for the downloader entry point and `download_impl.go` for reusable logic). Whenever you introduce new commands, align naming with existing patterns and expose `--json` or `--yes` options when automation benefits from them.
## How Commands Are Registered
### How Commands Are Registered
- Add a new `*cli.Command` to the `PhotoPrism` slice in `commands.go`.
- Provide a localized `Before` hook when a command needs configuration loading or authentication checks that differ from the defaults.
@ -12,7 +12,7 @@ The `commands` package hosts the CLI implementation for the PhotoPrism binary. C
- Prefer storing command-specific implementations in `<name>_impl.go` files that can be imported in tests. Invoke the implementation from the `Action` function to avoid duplicating logic between CLI entry points and tests.
- When adding commonly reused flags, call the shared helper constructors in `flags.go` (`YesFlag()`, `DryRunFlag()`, role helpers, etc.) so identical options behave consistently across commands. If you need a new reusable flag, add it to `flags.go` first and then consume it from each command instead of hand-coding variants.
## Command Implementation Patterns
### Command Implementation Patterns
- Construct filesystem paths with `filepath.Join` and rely on permission constants from `pkg/fs` (`fs.ModeDir`, `fs.ModeFile`, and friends) when writing to disk.
- Follow the overwrite policy used by media helpers: require explicit confirmation (`force` flags) before replacing non-empty files. Where replacements are expected, open destinations with `O_WRONLY|O_CREATE|O_TRUNC`.
@ -20,14 +20,14 @@ The `commands` package hosts the CLI implementation for the PhotoPrism binary. C
- When integrating configuration options, call the accessors on `*config.Config` (for example, `conf.ClusterUUID()`) rather than mutating option structs directly.
- For HTTP interactions, depend on the safe download helpers in `pkg/http/safe` or the specialized wrappers in `internal/thumb/avatar` to inherit timeout, size, and SSRF protection defaults.
## Configuration & Flags Integration
### Configuration & Flags Integration
- Define new options in `internal/config/options.go` with the appropriate struct tags (`yaml`, `json`, `flag`) so they propagate to YAML, CLI, and API layers consistently.
- Surface CLI flags in `internal/config/flags.go` to keep environment variable mappings aligned. Commands should call `conf.ApplyCliContext()` once to hydrate configuration from parsed flags.
- Respect precedence rules: defaults < CLI/environment < `options.yml`. Commands that generate configuration must set `c.Options().OptionsYaml` before persisting so changes appear in reports.
- When emitting command catalogs or help output, reuse the catalog builders in `internal/commands/catalog` instead of crafting ad-hoc Markdown or JSON.
## Testing Strategy
### Testing Strategy
- Place tests beside their sources (`<name>_test.go`) and group related assertions using `t.Run("CaseName", ...)` subtests. Subtest names should use PascalCase for readability.
- Execute focused suites with `go test ./internal/commands -run '<Name>' -count=1` during development. For broader coverage, `make test-go` exercises backend packages under SQLite.
@ -36,7 +36,7 @@ The `commands` package hosts the CLI implementation for the PhotoPrism binary. C
- Initialize test directories via `conf.InitializeTestData()` when constructing custom configs so Originals, Import, Cache, and Temp paths exist before tests interact with the filesystem.
- Prefer deterministic fixtures: generate entity IDs via helpers such as `rnd.GenerateUID(entity.PhotoUID)` or `rnd.UUIDv7()` instead of hard-coded strings.
## Focused Test Runs
### Focused Test Runs
- Download workflow: `go test ./internal/commands -run 'DownloadImpl|DownloadHelp' -count=1`
- Auth and user management: `go test ./internal/commands -run 'Auth|Users' -count=1`
@ -44,14 +44,14 @@ The `commands` package hosts the CLI implementation for the PhotoPrism binary. C
- Full package smoke test: `go test ./internal/commands -count=1`
- Backend-wide validation: `go test ./internal/service/cluster/registry -count=1` and `go test ./internal/api -run 'Cluster' -count=1` ensure CLI and API stay in sync before release.
## CLI & Test Utilities
### CLI & Test Utilities
- Stub external binaries such as `yt-dlp` with lightweight shell scripts that honor `--dump-single-json` and `--print` requests. Support environment variables like `YTDLP_ARGS_LOG`, `YTDLP_OUTPUT_FILE`, and `YTDLP_DUMMY_CONTENT` to capture arguments, create deterministic artifacts, and avoid duplicate detection in importer flows.
- Disable FFmpeg during tests that focus on command construction by setting `conf.Options().FFmpegBin = "/bin/false"` and `conf.Settings().Index.Convert = false`.
- When asserting HTTP responses, rely on header constants from `pkg/http/header` (for example, `header.ContentTypeZip`) to keep expectations aligned with middleware.
- For role and scope checks, reuse helpers in `internal/auth/acl` such as `acl.ParseRole`, `acl.ScopePermits`, and `acl.ScopeAttrPermits` instead of duplicating logic inside commands.
## Preflight Checklist
### Preflight Checklist
- Formatting and Swagger: `make fmt-go` and `make swag-fmt swag`
- Build binaries: `go build ./...`

View file

@ -1,6 +1,6 @@
## PhotoPrism — Config Package
**Last Updated:** February 8, 2026
**Last Updated:** February 14, 2026
### Overview
@ -8,7 +8,7 @@ PhotoPrisms [runtime configuration](https://docs.photoprism.app/developer-gui
Client config values are derived from the runtime configuration and exposed to the frontend via `GET /api/v1/config`. This includes a `storageNamespace` value (SHA-256 hash of `SiteUrl`) used by the browser to scope local storage keys on shared domains.
### Storage Namespace and Legacy Session Compatibility
### Storage Namespace & Legacy Session Compatibility
- `storageNamespace` is deterministic per `SiteUrl` (`SHA-256(SiteUrl)`) and is used by the frontend storage wrappers to isolate data on shared domains.
- Frontend reads from namespaced keys first and then falls back to legacy global keys; when a legacy value is found, it is migrated to the active namespace on read.
@ -16,7 +16,7 @@ Client config values are derived from the runtime configuration and exposed to t
- Writing only a token is not enough to restore an authenticated user session in current frontend logic, because session restore requires both token and session id.
- Older compatibility keys (`authToken` / `sessionId`) are only auto-migrated when both are present.
### Sources and Precedence
### Sources & Precedence
PhotoPrism loads configuration in the following order:

View file

@ -1,18 +1,18 @@
# Database Schema
## Database Schema
*This schema description is for illustrative purposes only, e.g. to generate visual relationship diagrams. It should not be used to update or replace an existing production database.*
## Entity-Relationship Diagram
### Entity-Relationship Diagram
↪ [docs.photoprism.app/developer-guide/database/schema/](https://docs.photoprism.app/developer-guide/database/schema/)
## Mermaid Markup
### Mermaid Markup
With [Mermaid.js](https://mermaid-js.github.io/) you can generate visual diagrams from this markup file:
↪ [mariadb.mmd](mariadb.mmd)
## MariaDB SQL Dump
### MariaDB SQL Dump
An SQL schema dump can be created using the command shown below, for example:
@ -33,7 +33,7 @@ cat mariadb.sql | grep -v '^\/\*![0-9]\{5\}.*\/;$' > photoprism-mariadb-database
Please note that the dump we provide is only updated at irregular intervals and should therefore not be used to update or replace an existing production database.
## Schema Migrations
### Schema Migrations
↪ [docs.photoprism.app/developer-guide/database/migrations/](https://docs.photoprism.app/developer-guide/database/migrations/)

View file

@ -1,4 +1,4 @@
# Metadata Test Files
## Metadata Test Files
You may use [ImageMagick](http://www.imagemagick.org/Usage/resize/#resample)
to create smaller versions of images to be stored in this repository:

View file

@ -1,16 +1,16 @@
# Provisioner Package Guide
## Provisioner Package Guide
## Overview
### Overview
The provisioner package manages per-node MariaDB schemas and users for cluster deployments. It derives deterministic identifiers from the cluster UUID and node name using a configurable prefix (default `cluster_`), creates or rotates credentials via the admin DSN, and exposes helpers (`EnsureCredentials`, `DropCredentials`, `GenerateCredentials`) that API and CLI layers can reuse when onboarding or rotating nodes.
## Development Workflow
### Development Workflow
- Configuration lives in `database.go`. The admin connection string is `ProvisionDSN` (default `root:photoprism@tcp(mariadb:4001)/photoprism?...`). Adjust only when running against a different host or password.
- `EnsureCredentials` accepts node UUID and name, creates the schema if needed, and returns credentials plus rotation metadata. `DropCredentials` revokes grants, drops the user, and removes the schema. Both functions require a context; prefer `context.WithTimeout` in callers.
- Identifier generation is centralized in `GenerateCredentials`. Call it instead of handcrafting database or user names so tests, CLI, and API stay aligned. The resulting identifiers follow `<prefix>d<hmac11>` for schemas and `<prefix>u<hmac11>` for users. Portal deployments may override the prefix via the `database-provision-prefix` flag; defaults are `cluster_d…` / `cluster_u…`.
## Testing Guidelines
### Testing Guidelines
- Run `go test ./internal/service/cluster/provisioner -count=1` for both unit coverage and the lightweight MariaDB integration checks. No environment variables are required; tests connect to the static `ProvisionDSN` and will skip themselves only if that connection is unavailable.
- The provisioner targets the shared MariaDB instance used by remote cluster nodes. This DB is independent from the Portals main database (which may be SQLite), so exercising the package does not require altering application database settings.
@ -26,7 +26,7 @@ The provisioner package manages per-node MariaDB schemas and users for cluster d
```
- If the response does not return the schema/user (for example, redacted paths), synthesize them via `GenerateCredentials(conf, uuid, name)` before scheduling cleanup.
## MariaDB Troubleshooting
### MariaDB Troubleshooting
- Connect from the dev container using `mariadb` (already configured to reach `mariadb:4001`). Common snippets:
```bash
@ -60,22 +60,22 @@ The provisioner package manages per-node MariaDB schemas and users for cluster d
```
- Stubborn objects usually indicate the cleanup hook was skipped. Check test logs for failures before the `t.Cleanup` runs, and rerun the suite after manual cleanup to confirm the fix.
## Avoiding Leftovers
### Avoiding Leftovers
- Always pair credential creation with `DropCredentials` inside `t.Cleanup` for tests and defer blocks for ad-hoc scripts.
- When troubleshooting API or CLI flows, capture the node UUID and name from the response and call `GenerateCredentials` to identify which schema/user to drop once finished.
- Before committing, run `SHOW DATABASES LIKE 'cluster_d%';` and `SELECT User FROM mysql.user WHERE User LIKE 'cluster_u%';` to verify the MariaDB instance is clean.
## Focused Commands
### Focused Commands
- Fast pass: `go test ./internal/service/cluster/provisioner -count=1`
- End-to-end sanity with API: `go test ./internal/api -run 'ClusterNodesRegister' -count=1` (ensures the API cleanup helper stays aligned with the provisioner)
## ProxySQL Integration
### ProxySQL Integration
Use ProxySQL to verify tenant provisioning stays in sync with the proxy in addition to MariaDB. The unit test suite ships with an opt-in integration test (`TestEnsureCredentials_ProxySQLIntegration`) that exercises the full flow once ProxySQL is available locally.
### One-Time Setup (inside the dev container)
#### One-Time Setup (inside the dev container)
1. Download and install ProxySQL (v3.0.2 shown here):
```bash
@ -94,7 +94,7 @@ Use ProxySQL to verify tenant provisioning stays in sync with the proxy in addit
The bundled MariaDB instance (credentials in `.my.cnf` at the repo root) is sufficient as a backend; no extra ProxySQL configuration is required for the integration test.
### Running the Integration Test
#### Running the Integration Test
1. When ProxySQL is running, toggle the test via an environment variable:
```bash
@ -103,7 +103,7 @@ The bundled MariaDB instance (credentials in `.my.cnf` at the repo root) is suff
- Override the admin DSN with `PHOTOPRISM_TEST_PROXYSQL_DSN=user:pass@tcp(host:6032)/` if you changed the default credentials or port.
2. The test provisions a tenant, verifies the ProxySQL `mysql_users` row, reruns the idempotent ensure path, and exercises `DropCredentials`. Cleanup hooks remove both the MariaDB schema/user and the ProxySQL account.
### Tearing Down / Restarting
#### Tearing Down / Restarting
- Stop ProxySQL when finished:
```bash

View file

@ -1,8 +1,8 @@
## PhotoPrism — Media Package
**Last Updated:** November 22, 2025
**Last Updated:** February 14, 2026
### Apple iPhone and iPad
### Apple iPhone & iPad
[iOS Live Photos](https://developer.apple.com/live-photos/) consist of a JPEG/HEIC image and a QuickTime AVC/HEVC video, which are both required for viewing.
@ -25,7 +25,7 @@ The image part of these files can be opened in any image viewer that supports JP
| Working with Motion Photos | Jan 2019 | https://medium.com/android-news/working-with-motion-photos-da0aa49b50c |
| Google: Behind the Motion Photos Technology in Pixel 2 | Mar 2018 | https://blog.research.google/2018/03/behind-motion-photos-technology-in.html |
### Software Libraries and References
### Software Libraries & References
| Title | URL |
|------------------------------------------------------|-------------------------------------------------------------------------|

View file

@ -1,7 +1,6 @@
Video File Support
==================
## Video File Support
## Codecs and Containers
### Codecs & Containers
For maximum browser compatibility, PhotoPrism can transcode video codecs and containers [supported by FFmpeg](https://www.ffmpeg.org/documentation.html) to [MPEG-4 AVC](https://en.wikipedia.org/wiki/MPEG-4).
@ -19,11 +18,11 @@ Please Note:
2. HEVC/H.265 video files can have a `.mp4` file extension too, which is often associated with AVC only. This is because MP4 is a *container* format, meaning that the actual video content may be compressed with H.264, H.265, or something else. The file extension doesn't really tell you anything other than that it's probably a video file.
3. In case [FFmpeg is disabled](https://docs.photoprism.app/user-guide/settings/advanced/#disable-ffmpeg) or not installed, videos cannot be indexed because still images cannot be created. You should also have [Exiftool enabled](https://docs.photoprism.app/getting-started/config-options/#feature-flags) to extract metadata such as duration, resolution, and codec.
## Hybrid Photo/Video Formats
### Hybrid Photo/Video Formats
For more information on hybrid photo/video file formats, e.g. Apple Live Photos and Samsung/Google Motion Photos, see [github.com/photoprism/photoprism/tree/develop/pkg/media](https://github.com/photoprism/photoprism/tree/develop/pkg/media) and [docs.photoprism.app/developer-guide/media/live](https://docs.photoprism.app/developer-guide/media/live/).
## Standard Resolutions
### Standard Resolutions
The [`PHOTOPRISM_FFMPEG_SIZE`](../../getting-started/config-options.md#file-converters) config option allows to limit the resolution of [transcoded videos](../../getting-started/advanced/transcoding.md). It accepts the following standard sizes, while other values are automatically adjusted to the next supported size:
@ -38,7 +37,7 @@ The [`PHOTOPRISM_FFMPEG_SIZE`](../../getting-started/config-options.md#file-conv
| 4096 | DCI 4K, Retina 4K |
| 7680 | 8K Ultra HD 2 |
## Technical References and Tutorials
### Technical References & Tutorials
| Title | URL |
|-------------------------------------|-----------------------------------------------------------------------------|

View file

@ -1,4 +1,4 @@
# Package Clusters
## Package Clusters
Implements the following clustering algorithms:
@ -13,18 +13,18 @@ It was forked from the following repositories, which don't seem to be maintained
This package also provides utilities for importing data and estimating the optimal number of clusters.
## About
### About
This library was built out of necessity for a collection of performant cluster analysis utilities for Golang. Go, thanks to its numerous advantages (single binary distribution, relative performance, growing community) seems to become an attractive alternative to languages commonly used in statistical computations and machine learning, yet it still lacks crucial tools and libraries. I use the [*floats* package](https://github.com/gonum/gonum/tree/master/floats) from the robust Gonum library to perform optimized vector calculations in tight loops.
## Installation
### Installation
If you have Go 1.7+
```bash
go get github.com/photoprism/photoprism/pkg/alg
```
## Usage
### Usage
The currently supported hard clustering algorithms are represented by the *HardClusterer* interface, which defines several common operations. To show an example we create, train and use a KMeans++ clusterer:
@ -129,6 +129,6 @@ if e != nil {
}
```
## Licence
### License
MIT

View file

@ -1,17 +1,14 @@
PhotoPrism 1-Click App for DigitalOcean
=======================================
## PhotoPrism 1-Click App for DigitalOcean
Privately browse, organize, and share your photo collection.
DESCRIPTION
---------------------------------------
### Description
PhotoPrism® is a privately hosted app for browsing, organizing, and sharing your photo collection. It makes use of the latest technologies to tag and find pictures automatically without getting in your way. Say goodbye to uploading your visual memories to the cloud!
To learn more, visit https://www.photoprism.app/ or try our [demo](https://try.photoprism.app/).
SOFTWARE INCLUDED
---------------------------------------
### Software Included
- [PhotoPrism latest](https://docs.photoprism.app/release-notes/), AGPL 3
- [Docker CE latest](https://docs.docker.com/engine/release-notes/), Apache 2
@ -19,8 +16,7 @@ SOFTWARE INCLUDED
- [MariaDB 11](https://mariadb.com/kb/en/release-notes/), GPL 2
- [Watchtower latest](https://github.com/nicholas-fedor/watchtower/releases), Apache 2
GETTING STARTED
---------------------------------------
### Getting Started
It may take a few minutes until your Droplet is provisioned, and all services have been initialized.
@ -53,7 +49,7 @@ docker compose stop
docker compose up -d
```
## Using Let's Encrypt HTTPS ##
### Using Let's Encrypt HTTPS
By default, a self-signed certificate will be used for HTTPS connections. Browsers are going to show a security warning because of that. Depending on your settings, they may also refuse connecting at all.
@ -85,6 +81,6 @@ https://photos.yourdomain.com/
Note the first request may still fail while Traefik gets and installs the new certificate. Try again after 30 seconds.
## System Requirements ##
### System Requirements
We recommend hosting PhotoPrism on a server with at least 2 cores and 4 GB of memory. Indexing and searching may be slow on smaller Droplets, depending on how many and what types of files you upload.

View file

@ -1,4 +1,4 @@
# PhotoPrism® Installation Packages
## PhotoPrism® Installation Packages
As an alternative to our [Docker images](https://docs.photoprism.app/getting-started/docker-compose/), you can use the packages available at [**dl.photoprism.app/pkg/linux/**](https://dl.photoprism.app/pkg/linux/) to install PhotoPrism on compatible Linux distributions without [building it from source](https://docs.photoprism.app/getting-started/faq/#building-from-source).
@ -6,9 +6,9 @@ These [binary installation packages](https://dl.photoprism.app/pkg/linux/) are i
Also note that the minimum required glibc version is 2.35, so for example Ubuntu 22.04 and Debian Bookworm will work, but older Linux distributions may not be compatible.
## Usage
### Usage
### Installation Using *tar.gz* Archives
#### Installation Using *tar.gz* Archives
You can download and install PhotoPrism in `/opt/photoprism` by running the following commands:
@ -24,7 +24,7 @@ If your server has an **ARM-based CPU**, please make sure to install `arm64.tar.
Since the packages currently do not include a default configuration, we recommend that you create a [`defaults.yml`](https://docs.photoprism.app/getting-started/config-files/defaults/) in `/etc/photoprism` next, in which you configure the paths and other settings that you want to use for your instance.
### *.deb* Packages for Ubuntu / Debian Linux
#### *.deb* Packages for Ubuntu / Debian Linux
As an alternative to the plain *tar.gz* archives, that you need to unpack manually, we also offer *.deb* packages for Debian-based distributions such as Ubuntu Linux. They install PhotoPrism under `/opt/photoprism`, add a `/usr/local/bin/photoprism` symlink, create `/etc/photoprism/defaults.yml`, and pull in the runtime libraries listed in the [Dependencies](#dependencies) section.
@ -44,7 +44,7 @@ sudo apt install --no-install-recommends ./arm64.deb
Omit `--no-install-recommends` if you want APT to install MariaDB, Darktable, RawTherapee, ImageMagick, and other recommended extras automatically.
### *.rpm* Packages for Fedora / RHEL / openSUSE
#### *.rpm* Packages for Fedora / RHEL / openSUSE
For RPM-based distributions we publish *.rpm* packages that mirror the layout described above. Install the latest release on **x86_64** hardware with:
@ -60,23 +60,23 @@ sudo dnf install https://dl.photoprism.app/pkg/linux/rpm/aarch64.rpm
Replace `dnf` with `zypper` on openSUSE (use `--allow-unsigned-rpm` when required). On distributions that do not ship FFmpeg in the base repositories, enable the appropriate multimedia repository (EPEL, RPM Fusion, Packman, …) before installing the dependencies below.
### AUR Packages for Arch Linux
#### AUR Packages for Arch Linux
Thomas Eizinger additionally maintains [AUR packages for installation on Arch Linux](https://aur.archlinux.org/packages/photoprism-bin). They are based on our *tar.gz* packages and have a systemd integration so that PhotoPrism can be started and restarted automatically.
[Learn more ](https://aur.archlinux.org/packages/photoprism-bin)
## Updates
### Updates
To update your installation, please stop all running PhotoPrism instances and make sure that there are [no media, database, or custom config files](#configuration) in the `/opt/photoprism` directory. You can then delete its contents with the command `sudo rm -rf /opt/photoprism/*` and install a new version as shown above.
If you have used a *.deb* package for installation, you may need to remove the currently installed `photoprism` package by running `sudo dpkg -r photoprism` before you can install a new version with `sudo apt install ./package.deb` or `sudo dpkg -i package.deb`.
## Dependencies
### Dependencies
PhotoPrism packages bundle TensorFlow 2.18.0 and, starting with the December 2025 builds, ONNX Runtime 1.23.2 as described in [`ai/face/README.md`](https://github.com/photoprism/photoprism/blob/develop/internal/ai/face/README.md). The shared libraries for both frameworks are shipped inside `/opt/photoprism/lib`, so no additional system packages are needed to switch `PHOTOPRISM_FACE_ENGINE` to `onnx`. The binaries still rely on glibc ≥ 2.35 and the standard C/C++ runtime libraries (`libstdc++6`, `libgcc_s1`, `libgomp1`, …) provided by your distribution.
### Required Runtime Packages
#### Required Runtime Packages
Install the following packages **before** running PhotoPrism so that thumbnailing, metadata extraction, and the SQLite fallback database work out of the box:
@ -88,7 +88,7 @@ Install the following packages **before** running PhotoPrism so that thumbnailin
These packages pull in the full libvips stack (GLib, libjpeg/libtiff/libwebp, archive/zstd, etc.) that the PhotoPrism binary links against. Run `ldd /opt/photoprism/bin/photoprism` if you need to diagnose missing libraries on custom distributions.
### Recommended Extras
#### Recommended Extras
For extended RAW processing, HEIF/HEIC support, and database scalability we recommend installing:
@ -104,7 +104,7 @@ We publish the same libheif builds that ship in our Docker images. They include
Keep in mind that even if all dependencies are installed, it is possible that you are using a version that is not fully compatible with your pictures, phone, or camera. Our team cannot [provide support](https://www.photoprism.app/kb/getting-support) in these cases if the same issue does not occur with our [official Docker images](https://docs.photoprism.app/getting-started/docker-compose/). Details on the packages and package versions we use can be found in the Dockerfiles available in our [public project repository](https://github.com/photoprism/photoprism/tree/develop/docker).
## Configuration
### Configuration
After unpacking the binaries you only need a writable configuration and storage location. The typical workflow is:
@ -120,7 +120,7 @@ After unpacking the binaries you only need a writable configuration and storage
Run `photoprism --help` in a terminal to get an [overview of the command flags and environment variables](https://docs.photoprism.app/getting-started/config-options/) available for configuration. Their current values can always be displayed with the `photoprism config` command.
### Precedence
#### Precedence
PhotoPrism reads settings in the following order (later entries override earlier ones):
@ -136,7 +136,7 @@ If no explicit *originals*, *import* and/or *assets* path has been configured, a
All configuration changes—whether made [via UI](https://docs.photoprism.app/user-guide/settings/advanced/), [config files](https://docs.photoprism.app/getting-started/config-files/), or [environment variables](https://docs.photoprism.app/getting-started/config-options/)—**require a restart** to take effect when PhotoPrism runs as a standalone process.
### `defaults.yml`
#### `defaults.yml`
Packages install a starter `/etc/photoprism/defaults.yml`. Adjust it with root privileges to set global defaults such as filesystem locations, database options, and network ports. If you delete or leave that file empty, PhotoPrism automatically falls back to `<config-path>/defaults.yml`, so copying the sample there keeps the same behavior without touching `/etc`. When specifying strings you can use `~` as the current users home directory and relative paths starting with `./`:
@ -158,7 +158,7 @@ For a list of supported options and their names, see <https://docs.photoprism.ap
When specifying values, make sure that the data type is the [same as in the documentation](https://docs.photoprism.app/getting-started/config-files/#config-options), e.g. *bool* values must be either `true` or `false` and *int* values must be whole numbers without any quotes like in the example above.
### `options.yml`
#### `options.yml`
Default config values can be overridden by values [specified in an `options.yml` file](https://docs.photoprism.app/getting-started/config-files/) as well as with command flags and environment variables. To load values from an existing `options.yml` file, you can specify its storage path (excluding the filename) by setting the `ConfigPath` option in your `defaults.yml` file, using the `--config-path` command flag, or with the `PHOTOPRISM_CONFIG_PATH` environment variable.
@ -166,7 +166,7 @@ The values in an `options.yml` file are not global and can be used to customize
Tip: when running PhotoPrism as a systemd service, export environment variables in the service unit or in `/etc/default/photoprism`. For interactive shells, specify the corresponding flags or prefix commands with variables (for example `PHOTOPRISM_DEBUG=true photoprism index`). Use the smallest scope that fits your deployment so updates stay manageable.
## Documentation
### Documentation
For detailed information on specific features and related resources, see our [Knowledge Base](https://www.photoprism.app/kb), or check the [User Guide](https://docs.photoprism.app/user-guide/) for help [navigating the user interface](https://docs.photoprism.app/user-guide/navigate/), a [complete list of config options](https://docs.photoprism.app/getting-started/config-options/), and [other installation methods](https://docs.photoprism.app/getting-started/):
@ -174,7 +174,7 @@ For detailed information on specific features and related resources, see our [Kn
- [PhotoPrism® Developer Guide](https://docs.photoprism.app/developer-guide/)
- [PhotoPrism® Knowledge Base](https://www.photoprism.app/kb)
## Getting Support
### Getting Support
If you need help installing our software at home, you are welcome to post your question in [GitHub Discussions](https://link.photoprism.app/discussions) or ask in our [Community Chat](https://link.photoprism.app/chat). Common problems can be quickly diagnosed and solved using our [Troubleshooting Checklists](https://docs.photoprism.app/getting-started/troubleshooting/). [Silver, Gold, and Platinum](https://link.photoprism.app/membership) members are also welcome to email us for technical support and advice.

View file

@ -1,4 +1,4 @@
# PhotoPrism Setup (RedHat, CentOS, Fedora, and AlmaLinux)
## PhotoPrism Setup (RedHat, CentOS, Fedora, & AlmaLinux)
[Podman](https://podman.io/) is supported as a replacement for Docker on Red Hat Enterprise Linux® and compatible Linux distributions such as CentOS, Fedora, AlmaLinux, and Rocky Linux. The following installs the `podman` and `podman-compose` commands if they are not already installed:
@ -22,21 +22,21 @@ curl -sSf https://dl.photoprism.app/podman/install.sh | bash
Please keep in mind to replace the `docker` and `docker compose` commands with `podman` and `podman-compose` when following the examples in our documentation.
## Documentation
### Documentation
### Getting Started
#### Getting Started
↪ https://docs.photoprism.app/getting-started/
### Knowledge Base
#### Knowledge Base
↪ https://www.photoprism.app/kb
### Compliance FAQ
#### Compliance FAQ
↪ https://www.photoprism.app/kb/compliance-faq
### Firewall Settings
#### Firewall Settings
↪ https://docs.photoprism.app/getting-started/troubleshooting/firewall/