dorfteich/packages/shared/i18n/en
Claude Opus 5 76a5e92f2e
All checks were successful
CI / Lint, typecheck, test (pull_request) Successful in 7m10s
CI / Build container images (pull_request) Successful in 4m12s
CI / Auth e2e pack (pull_request) Successful in 9m33s
CI / Import/export fidelity gate (pull_request) Successful in 1m16s
An instance had no way to look like itself: the top bar said "Dorfteich"
whatever the operator called their instance, `instance.name` was never
rendered in the running app at all, and there was no favicon anywhere —
`index.html` had no `<link rel="icon">` and `public/` held only fonts and
theme-init.js.

Where the line is drawn, and why:

- **The api never decodes an image.** Cropping, scaling and the conversion
  to PNG happen on a canvas in the browser; the api checks the PNG
  signature, reads the IHDR dimensions at their fixed offsets and enforces
  the caps. An image library would put a decoder in front of
  attacker-supplied bytes AND would have to be carried through the
  `--network none` offline build. Reading two big-endian integers is not
  decoding.
- **SVG is refused**, with its own error message rather than a generic
  "not a PNG": it can carry script, and serving it from our own origin
  would be a cross-site-scripting vector. An operator who tried one should
  learn that it is deliberate.
- **The crop is driven by number inputs, not by dragging.** A drag-only
  cropper excludes keyboard and switch users outright; a number input is
  arrow-key operable and screen-reader readable without any custom aria.
  The resulting pixel size is stated in text, not only drawn as a frame.
- **The variant is chosen by CSS, not JavaScript.** `theme-init.js` has
  already resolved `data-theme` before first paint, so the correct logo is
  the one painted rather than the one that appears after a flash. Without a
  dark variant the LIGHT logo carries both themes — the operator's own
  asset shown unchanged beats one they did not choose (the rule #307
  extends to ponds). The settings screen warns; it never blocks.
- **The favicon link is static, its resource dynamic.** index.html stays a
  static file and the api answers with the uploaded icon or a shipped
  default — that route must never 404, or the browser keeps its generic
  icon for good. The default is generated by a script from Node's own zlib
  (`gen-default-favicon.mjs`), for the same offline-build reason.
- Both favicon sizes are uploaded together: one source, one crop, so the
  tab icon and the home-screen icon can never disagree.
- Branding is served WITHOUT a session, because the login screen carries it
  and the browser fetches the favicon before anyone signs in. The admin
  screen says so — an operator may not expect their logo to be public.
- The metadata is not writable through the settings endpoint: it describes
  bytes on disk, and hand-writing it would claim an asset that is not
  there.

`./data/branding` follows the three-step rule #303 paid for: env default +
`data-dirs.ts` entry, compose volume (repo AND the stages on ONE), and the
`mkdir`/`chown` line in the api Dockerfile. `data-dirs.test.ts` is new and
closes the hole that made #303's variant invisible: the nightly archive
skips a missing directory WORDLESSLY, so the fence now demands that every
`*_DIR` the backup env declares actually travels in the archive. Verified
against the real defect — removing the line fails it by name.

Audit catalogue v1.7 (`branding.changed`), carrying `scope` from the start
so #307 is the same event with a different scope, not a second id.

Verified: api suite 103 files green (a lone `public-api` ECONNRESET under
local parallel load, green in isolation — the documented local flake);
branding suite 12 tests against a real directory; crop arithmetic unit
tests; a11y pack 11/11 in both schemes; /admin measured at 320px with the
new section (overflow 0); and the whole flow walked in the browser: upload
→ crop 780×180 → stored as 512×118 → logo in the sidebar linking home with
the instance name as its accessible name → topbar wordmark following
`instance.name` → light logo still shown under `data-theme="dark"`.
2026-08-01 19:28:11 +02:00
..
access.json Add effective-permissions inspector (#57) 2026-07-10 00:00:27 +02:00
apiTokens.json #200: hard instance-wide plugins.enabled kill switch 2026-07-31 04:42:42 +02:00
auth.json #214: OIDC Authorization Code with PKCE, Keycloak as reference IdP 2026-07-31 12:44:52 +02:00
branding.json An instance had no way to look like itself: the top bar said "Dorfteich" 2026-08-01 19:28:11 +02:00
comments.json Add the comments panel, unread badge, and comment-policy setting (#92) 2026-07-11 22:07:16 +02:00
common.json #206: show the VS-NfD marking in web view header and footer 2026-07-31 06:18:47 +02:00
editor.json #166: Skip-Link, verstecktes Seiten-h1, Resizer in die Nav-Landmarke 2026-07-21 14:26:54 +02:00
errors.json An instance had no way to look like itself: the top bar said "Dorfteich" 2026-08-01 19:28:11 +02:00
export.json Add PDF export via Gotenberg (#67) 2026-07-10 12:11:12 +02:00
files.json #213: warn on uploads to classified pages; instance policy can block 2026-07-31 07:33:34 +02:00
font.json #304: custom fonts in the pickers, an admin screen, and the licence page 2026-08-01 18:32:46 +02:00
graph.json #169: Nicht-Text-Inhalte — Task-Checkboxen, Wissensgraph 2026-07-21 14:35:16 +02:00
import.json Vault import: always show the label section, create labels inline 2026-07-15 10:58:50 +02:00
labels.json Add label UI: tree management, page assignment, and sidebar filter (#44) 2026-07-09 11:41:42 +02:00
legal.json Add instance legal pages with public rendering and footer links (#82) 2026-07-11 16:40:04 +02:00
links.json Add backlinks panel and phantom-pages view (#48) 2026-07-09 13:05:32 +02:00
mails.json Backup mirror to BASEL: rsync of the sets after every successful run (#84) 2026-07-12 12:20:32 +02:00
members.json Add pond member management UI (#54) 2026-07-09 20:22:52 +02:00
notifications.json #300: route icon-only controls through IconButton/IconLink 2026-08-01 06:56:13 +02:00
plugins.json #232: plugin allowlist with SHA-256 hash pinning 2026-07-31 21:26:36 +02:00
ponds.json #302: configurable pond start page, created with every new pond 2026-08-01 08:06:35 +02:00
public.json Add public read access and server-rendered page HTML (#56) 2026-07-09 23:46:25 +02:00
quotas.json #168: Formulare — Fehler-Verdrahtung und Namenslücken 2026-07-21 14:26:54 +02:00
search.json Polish round 2: content footer, dismissable menus, manual versions, substring search, icon actions in settings (M10 follow-up) 2026-07-12 07:13:34 +02:00
settings.json #245: mode hidden — hide profile-violating options, mark the hiding 2026-07-31 19:27:17 +02:00
setup.json Add the first-run setup wizard UI (#81) 2026-07-11 16:05:01 +02:00
system.json #192: deploy-level backup target allowlist 2026-07-30 12:17:14 +02:00
tasks.json #168: Formulare — Fehler-Verdrahtung und Namenslücken 2026-07-21 14:26:54 +02:00
users.json Add Site-Admin user management (#59) 2026-07-10 00:31:41 +02:00
watches.json Add watches: follow pages and ponds with auto-watch preferences (#93) 2026-07-11 22:59:11 +02:00