Deleting an image in the library removed the row and the result file on
the spot. One slip and a result was gone, including what it had cost to
generate. Now a delete moves the image into the trash:
- It disappears from the library, from every share link, from ZIPs, from
deliveries, the backup mirror, print sources and the print history —
and comes back unchanged when restored.
- The toast offers "Undo" for seven seconds. A trash view lists what is
in there with the days left, restore, delete for good, empty.
- Maintenance removes images for good after `settings.trash_days`
(default 30, set in Admin -> Storage). 0 switches the trash off.
- An image trashed while it is still queued is skipped by the worker
instead of being generated — and billed — for nobody.
- Deleting for good removes only files no other image still uses. An
alternative version shares its source with the original; before, the
retention cleanup could take the source of the other one with it. This
includes combine sources, which live in jsonb, not in an array.
While going through every query that touches images, it turned out that
only the file route checked who may see an image. Renaming, deleting,
retrying, generating an alternative, reusing and zipping took any id from
any signed-in account. On a single-user install that changes nothing; on
a family install one account could delete another's images. One rule now
lives in src/lib/itemaccess.ts: read your own (or everything in a shared
library, never a private session), change only your own; admins all.
A refused id answers 404 like a missing one.
Also: a favicon and an iPhone home-screen icon. There was none, so the
tab showed a blank page and /favicon.ico bounced to the login.
Verified against a real Postgres with two accounts and real files on
disk: 35 end-to-end checks (access, share links, restore, purge with
shared sources, expiry through maintenance, trash switched off). In the
browser, English and German: delete, undo, trash view, restore, no
horizontal scroll at 390 px. Unit tests: 130 (4 new).
A self-hosted print studio: images at exact physical sizes, sheet layout with
crop marks, tiling, 1:1 PDF. Everything else — image generation, delivery,
share links, mail, Telegram — is an optional module that is off by default.
This is the neutral public twin of a private tool. Compared to that original:
- optional modules behind KLARBILD_MODULES; the default install is print-only
- English interface with German as a full second language (1,038 strings);
the English sentence is the translation key
- no built-in accounts — first boot creates one admin from ADMIN_USERNAME /
ADMIN_PASSWORD, or generates a password and logs it once
- delivery and backup targets are generic SFTP/FTPS endpoints, off by default
- English routes, English identifiers, English comments throughout
- two compose files: print-only by default, everything in the full one
- AGPL-3.0, CI (build, tests, type check, secret scan), CONTRIBUTING, SECURITY
124 tests green, type check clean, verified end to end against a live instance.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nh4A79bbqT9dcd2inzYUdg