diff --git a/AGENTS.md b/AGENTS.md index 0a1463950..b6e22ded0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # PhotoPrism® Repository Guidelines -**Last Updated:** October 21, 2025 +**Last Updated:** October 28, 2025 ## Purpose @@ -420,6 +420,8 @@ Note: Across our public documentation, official images, and in production, the c ### Cluster Operations - Keep bootstrap code decoupled: avoid importing `internal/service/cluster/node/*` from `internal/config` or the cluster root, let nodes talk to the Portal over HTTP(S), and rely on constants from `internal/service/cluster/const.go`. +- Bootstrap refreshes node OAuth credentials on 401/403 responses (rotate secret + retry) and logs the refresh at info level; if the secret file cannot be written, the value stays cached in memory so the current process can continue. +- Portal validation now accepts HTTP advertise URLs only for loopback hosts or cluster-internal domains (`*.svc`, `*.cluster.local`, `*.internal`); everything else must use HTTPS. - Config init order: load `options.yml` (`c.initSettings()`), run `EarlyExt().InitEarly(c)`, connect/register the DB, then invoke `Ext().Init(c)`. - Theme endpoint: `GET /api/v1/cluster/theme` streams a zip from `conf.ThemePath()`; only reinstall when `app.js` is missing and always use the header helpers in `pkg/http/header`. - Registration flow: send `rotate=true` only for MySQL/MariaDB nodes without credentials, treat 401/403/404 as terminal, include `ClientID` + `ClientSecret` when renaming an existing node, and persist only newly generated secrets or DB settings. diff --git a/CODEMAP.md b/CODEMAP.md index 69815fbbd..73c119eb6 100644 --- a/CODEMAP.md +++ b/CODEMAP.md @@ -1,6 +1,6 @@ PhotoPrism — Backend CODEMAP -**Last Updated:** October 21, 2025 +**Last Updated:** October 28, 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. @@ -103,6 +103,8 @@ Background Workers Cluster / Portal - Node types: `internal/service/cluster/const.go` (`cluster.RoleInstance`, `cluster.RolePortal`, `cluster.RoleService`). - Node bootstrap & registration: `internal/service/cluster/node/*` (HTTP to Portal; do not import Portal internals). + - Registration now retries once on 401/403 by rotating the node client secret with the join token and persists the new credentials (falling back to in-memory storage if the secrets directory is read-only). + - Theme sync logs explicitly when refresh/rotation occurs so operators can trace credential churn in standard log levels. - Registry/provisioner: `internal/service/cluster/registry/*`, `internal/service/cluster/provisioner/*`. - Theme endpoint (server): GET `/api/v1/cluster/theme`; client/CLI installs theme only if missing or no `app.js`. - See specs cheat sheet: `specs/portal/README.md`.