Commit Graph

1064 Commits

Author SHA1 Message Date
Paul Nothaft aa8cca165d Merge pull request #514 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.51.2-beta.0
v3.51.2-beta.0
2026-05-17 01:02:48 +02:00
github-actions[bot] 5a9ca4ad57 chore(beta): release 3.51.2-beta.0 2026-05-16 23:02:10 +00:00
Paul Nothaft aac60fa895 Merge pull request #513 from the-luap/fix/bug-batch
fix/feat: bug batch — drag-drop, lightbox, likes, downloads, upload, i18n (#504-510)
2026-05-17 01:01:49 +02:00
Paul Nothaft 51890e1aa5 fix(i18n): drive customer "Preferred language" select from SUPPORTED_LANGUAGES (#510)
Audit follow-up to the Spanish-locale commit: `CustomerDetailPage` had
a hardcoded `<option>` list for the customer's preferred-language
selector — 5 entries (en/de/nl/pt/ru) that were missing both fr (an
existing gap) and es (the new one). Every other language selector in
the frontend (the navbar `LanguageSelector`, the `GeneralTab` default-
language dropdown, the `EmailConfigPage` per-language tabs) already
reads from the shared `SUPPORTED_LANGUAGES` constant, so adding es
there was enough for those. This one had drifted.

Now mapped from `SUPPORTED_LANGUAGES` so future locales only need to
touch one place.
2026-05-17 00:57:03 +02:00
Paul Nothaft 1e7806961f Merge pull request #512 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.51.1-beta.0
v3.51.1-beta.0
2026-05-17 00:53:34 +02:00
github-actions[bot] 2e828fcf9f chore(beta): release 3.51.1-beta.0 2026-05-16 22:53:14 +00:00
Paul Nothaft 99e60a2433 Merge pull request #511 from the-luap/fix/install-postgres-log-noise
fix(install): silence clean-install postgres log noise (#484)
2026-05-17 00:52:48 +02:00
Paul Nothaft 061712ebf1 feat(i18n): add Spanish (es) locale (#510)
Contributed by @AloePacci on issue #510. Drops their es.json into the
existing locale set, registers Spanish in the language selector with a
flag SVG matching the inline style of the other six locales, and
extends the email pipeline so es-language guests receive a localised
email subject/body where available.

Coverage:
- frontend/src/i18n/locales/es.json — 2132 translated keys. ~824
  EN keys are not yet covered; i18next's `fallbackLng: 'en'` handles
  those at runtime so the UI never renders a missing key. fr/nl/pt/ru
  have a similar (smaller) gap and ship the same way.
- LanguageSelector.tsx — added the ESFlag inline SVG (red/yellow/red
  horizontal bands, official #AA151B + #F1BF00; no coat of arms to
  stay consistent with the other simple flag components) and a new
  entry in SUPPORTED_LANGUAGES.
- emailProcessor.js — added .es to the domain-language heuristic, and
  an `es:` row to the three inline-translated snippets
  (passwordSecurityI18n / noPasswordI18n / passwordSetAtCreationI18n).
- 106_seed_es_email_template_translations.js (new) — idempotent
  seeder for the four customer-facing templates AloePacci translated:
  gallery_created, expiration_warning, gallery_expired, archive_complete.
  Mirrors the pattern from 099. Template keys without an `es` row fall
  back to `en` via the existing resolution chain in
  emailProcessor.processTemplate — no functional gap, just untranslated
  copy until someone fills them in.

What I deliberately did NOT take from the contribution: the proposed
in-place edit of migration 075 (history mutation — won't reseed for
existing installs anyway) and the whitespace/`gallery_list_html`-drop
churn in emailProcessor.js (would have regressed the #354 follow-up).
The semantic additions from those files are preserved via 106 and the
targeted edits above.
2026-05-17 00:50:51 +02:00
Paul Nothaft 98f3c3df41 fix(upload): restore configurable batch-size for reverse proxies (#509)
Regression of #208. PR #214 (commit 02a46e0, re-merged at 9b7495e)
shipped the configurable `general_max_upload_batch_size_mb` setting so
users behind Cloudflare Tunnel and other reverse proxies with
per-request size caps could lower the chunked-upload size below their
proxy's limit. Six days later the "Merge main into beta for
release/beta-to-main" commit (28793bb) resolved its conflict by
keeping main's older tree — which silently deleted the migration
(072), the setting input on Settings → General, the i18n strings, the
`useSettingsState` field, and the read in PhotoUpload.tsx, putting the
hardcoded 500MB chunk back. Galleries fronted by Cloudflare have
quietly been broken on batch uploads since then.

Re-applying exactly the same change set:

- `backend/migrations/core/072_add_max_upload_batch_size.js`
  recreated, with a comment pointing at the regression in case the
  same merge accident happens again.
- `frontend/src/components/admin/PhotoUpload.tsx` line 168 now reads
  the setting from query cache and falls back to 95MB (Cloudflare-safe
  headroom under 100MB).
- `useSettingsState.ts`, `GeneralTab.tsx`, `en.json`, `de.json` —
  added the field to the state type + defaults + load path + the
  Site-Configuration input.

Existing installs are safe either way:
- Ran original 072 then lost the file: migrations table still has the
  filename, so the runner skips re-applying. The setting row in
  `app_settings` is also untouched (the deletion was source-only, no
  down migration ran). Now the new code starts reading it again.
- Installed after the regression: migrations runner picks up the new
  072 normally and seeds the setting at 95.
2026-05-17 00:42:22 +02:00
Paul Nothaft 33de294d57 feat(lightbox): surface original camera filenames (#508)
Photographers running the gallery as a client-selection tool want to
map a guest's picks back to source files for retouching. The
`general_use_original_filenames_for_downloads` toggle (#493) already
does this on the download side; this extends the same toggle to the
in-lightbox view so the camera filename is visible alongside the
photo while it's being looked at.

Tied to the same toggle on purpose — one switch controls both
surfaces. Off by default; existing galleries keep showing only the
position counter.

Wiring:
- gallery.js serializes `photos[].original_filename` and surfaces the
  resolved toggle as `event.use_original_filenames` so the client can
  decide whether to render it.
- The bespoke `PhotoLightbox` renders the original filename (falling
  back to the storage filename only for pre-migration-062 uploads) in
  a muted line under the position counter, truncated to keep the
  toolbar tidy.
- `GalleryStoryLayout` mounts the same `PhotoLightbox`, so its
  rendering follows along.
- `GalleryPremiumLayout` uses `yet-another-react-lightbox` instead;
  added the Captions plugin and a `title` field on the slides so the
  same name appears as a caption when the toggle is on.

The remaining layouts feed back into the main `PhotoLightbox` via
`PhotoGridWithLayouts`, so the prop reaches them through the layout
props bag.
2026-05-17 00:35:16 +02:00
Paul Nothaft 38343e62de fix(downloads): apply original-filename toggle to individual downloads too (#507)
Follow-up to #498. The toggle reached zip downloads but single-photo
downloads still landed on disk with the renamed `event_individual_NNN.jpg`
even when the admin had flipped the setting on. Two reasons, fixed
in lockstep:

- Frontend overrode the server's Content-Disposition with a hardcoded
  `<a download="X">` attribute (`gallery.service.ts`, `photos.service.ts`)
  where X was the sanitized `photo.filename` known to the client. So
  the backend's correctly-formed `Content-Disposition` never reached
  the disk write. Added `parseContentDispositionFilename` (RFC 5987 +
  plain `filename=` fallback) and let the server name win when present.
- `secureImages.js` (enhanced/maximum protection's secure-download
  route) was missed in #498 and still emitted a hardcoded
  `filename="${photo.filename}"` regardless of the toggle. Wired it
  through `getUseOriginalFilenames` + `buildContentDisposition` so it
  matches the regular gallery download path.

Also exposed `Content-Disposition` via CORS so split (cross-origin)
frontend deployments can still read it from JavaScript. Same-origin
Docker deploys already had access; this is a defensive addition for
the split case.
2026-05-17 00:25:12 +02:00
Paul Nothaft 9d2db9a73b fix(gallery): hide Like button when guest feedback is off (#506)
Four gallery layouts were rendering the per-photo Like button without
gating on the master "Guest Feedback" toggle, so a guest still saw a
heart icon and could submit likes on events where the host had turned
feedback off. The other layouts (Grid / Justified / Masonry / Story)
already gated correctly with `feedbackEnabled && allowLikes` —
Rekoo-PS's note that "it's hidden in some themes" matches that split.

- CarouselGalleryLayout, MosaicGalleryLayout, TimelineGalleryLayout:
  the existing conditional checked only `feedbackOptions?.allowLikes`,
  missing the `feedbackEnabled` master gate. Added it inline.
- GalleryPremiumLayout: the per-card Like button rendered
  unconditionally because PhotoCard never received the allow-likes
  signal. Added an `allowLikes` prop on PhotoCardProps, plumbed
  `feedbackOptions?.allowLikes` down from the parent, and wrapped the
  button in `feedbackEnabled && allowLikes`.

The follow-up "default guest-feedback ON" request from Rekoo-PS in
the comments is a separate feature (admin > General > Event Creation
default) and out of scope for this fix.
2026-05-17 00:13:21 +02:00
Paul Nothaft d2d55098d6 fix(lightbox): align swipe-neighbour height + stop black flash on commit (#505)
Two adjacent swipe-time defects, one diagnosis each:

1. Height differed between current and neighbouring slides during a
   swipe but matched when the arrow buttons advanced the carousel.
   Cause: neighbour slides wrap their image in a div with extra `px-2`
   horizontal padding while the current slide does not. `object-contain`
   then sees a narrower container on neighbours, so wide images cap on
   width first and render shorter than the same image at the current
   position. Removed the padding so both slots share the same container
   geometry. Arrow-button navigation looked fine because it never
   showed the neighbour layout side-by-side.

2. The image flashed black for ~100–400 ms each time a swipe committed
   to the next slide. Cause: the 3-slide track has no React keys, so
   React reconciled slides by position. After commit the photo at every
   position changed (`prev → current → next` shifts left), every slot's
   `<AuthenticatedImage>` saw a new `src` prop, and its fetch effect
   restarted from the placeholder state — including the slot that was
   the user's "next" slide a moment ago and held a fully-loaded image.
   Added a stable `key` derived from `photo.id` so React MOVES existing
   DOM nodes across slots instead of refetching. 2-photo galleries are
   a key-collision edge case (`prev === next`), so they fall back to
   slot-prefixed keys to keep siblings unique; behaviour there is no
   worse than today.
2026-05-17 00:09:15 +02:00
Paul Nothaft 577c4bdf29 fix(upload): wire drag-and-drop on admin + user upload zones (#504)
The dashed-border upload area in `PhotoUpload` (admin) and
`UserPhotoUpload` (gallery user-upload) is styled and labelled as a
drop zone — every locale's `upload.clickToUpload` already reads
"Click to upload or drag and drop" or its translation — but neither
component had any `onDragOver` / `onDragEnter` / `onDragLeave` /
`onDrop` handlers. Files dropped on the zone fell through to the
browser's default behaviour (open the image in a new tab), which is
what Rekoo-PS reported.

Added native HTML5 drag-and-drop wiring on both components, plumbed
through the same filter/limit/toast pipeline used by the click path
(`addFiles` helper). Visual highlight on drag-over via an `isDragOver`
flag; the listener guards against the `dragleave` strobing that fires
on every child node. Also reset the `<input>` value after onChange so
re-picking the same file still triggers an upload — matches the
new drop-then-pick mental model.
2026-05-17 00:02:39 +02:00
Paul Nothaft 86b33d4dda fix(install): silence clean-install postgres log noise (#484)
Two latent install-time issues that emitted scary postgres ERROR lines
on every fresh start but didn't actually break anything. MrGabri flagged
them after #494 had already cleared the FK-ordering crash.

1. Migration 035 builds three `CREATE INDEX` statements against
   `backup_runs(created_at, …)`, but 029 creates the table with
   `started_at` and no `created_at`. The wrapping try/catch silently
   swallowed the resulting `column "created_at" does not exist` ERROR,
   so the migration "succeeded" without ever creating the indexes.
   Switched 035 to reference `started_at` (same chronological semantics)
   and added migration 105 to create the same indexes idempotently for
   deployments whose 035 already ran and silently failed.

2. `run-migrations-safe.js` snapshots `appliedFilenames` *before*
   `detectExistingSchema()` runs. When `detectExistingSchema()` inserts a
   row for e.g. `004_add_categories_and_cms.js` (because its tables exist
   from a partially-completed prior install), the subsequent migration
   loop still doesn't know about that insert, attempts the legacy
   migration anyway, and its transaction-internal
   `insert into migrations` conflicts with the row already there.
   Re-query the applied set after detectExistingSchema so the loop sees
   the corrected snapshot.

No behavioural change for healthy installs. New installs no longer log
the `column "created_at" does not exist` or `duplicate key value
violates unique constraint "migrations_filename_unique"` ERRORs.
2026-05-16 23:56:05 +02:00
Paul Nothaft 3a490844e1 Merge pull request #499 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.51.0-beta.0
v3.51.0-beta.0
2026-05-14 23:30:58 +02:00
github-actions[bot] 72c2b5c796 chore(beta): release 3.51.0-beta.0 2026-05-14 21:25:07 +00:00
Paul Nothaft 826e43ebac Merge pull request #498 from the-luap/feat/lightbox-preview-tier-492
feat(downloads): preserve original camera filenames on download (opt-in) (#493)
2026-05-14 23:24:41 +02:00
Paul Nothaft 019b0c0301 Merge pull request #497 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.50.0-beta.0
v3.50.0-beta.0
2026-05-14 23:22:44 +02:00
Paul Nothaft 7eeef2ba98 feat(downloads): preserve original camera filenames on download (opt-in) (#493)
New Settings → General toggle `Use original filenames on download` (off by
default). When on, single-photo downloads, bulk/selection zips, and per-event
archive zips surface `photos.original_filename` instead of the sanitized
storage filename. Storage paths are unchanged.

- Content-Disposition uses RFC 5987 (`filename=` ASCII + `filename*=UTF-8''…`)
  so unicode camera filenames survive while header-injection bytes are stripped.
- Zip entries are deduplicated with a deterministic `_1` / `_2` suffix on
  collision (folder structure preserved in archive zips).
- Pre-generated download-all zips and the in-memory setting cache are
  invalidated when the toggle flips so the next download rebuilds with the
  new names.
- Falls back to the storage filename whenever `original_filename` is null
  (legacy uploads predating migration 062).
2026-05-14 23:11:00 +02:00
github-actions[bot] 365582e678 chore(beta): release 3.50.0-beta.0 2026-05-14 20:44:57 +00:00
Paul Nothaft 3083c748b9 Merge pull request #496 from the-luap/feat/lightbox-preview-tier-492
feat(lightbox): medium-resolution preview tier (#492)
2026-05-14 22:44:35 +02:00
Paul Nothaft 61f1d13210 feat(lightbox): medium-resolution preview tier (#492)
Adds an opt-in lightbox preview tier so guests open photos against an
aspect-preserved ~1920px JPEG (~200–500 KB) instead of the full original
(often 5–12 MB). Originals are still served on Download.

Backend:
  - imageProcessor: generatePreviewImage / isPreviewValid / ensurePreviewImage
    using fit:'inside' + withoutEnlargement (longEdge 1920, q85, mozjpeg)
  - migration 104: photos.preview_path + lightbox_preview_enabled setting
    (off by default, JSON-stringified for SQLite/Postgres parity)
  - GET /api/gallery/:slug/preview/:photoId — gallery-auth, lazy generation,
    ETag based on mtime+photoId+watermarkHash
  - preview_url surfaced in the photo response only when the toggle is on
  - admin /thumbnails/regenerate-previews mirrors regenerate-thumbnails,
    skipping videos
  - backup walk + archive cleanup + photo-delete now include previews/

Frontend:
  - PhotoLightbox uses photo.preview_url ?? photo.url (null-safe fallback)
  - ThumbnailsTab gets a Lightbox Preview Tier card: opt-in toggle +
    Regenerate All Previews button (gated until the toggle is on)
  - en/de locale strings; nl/pt/ru/fr fall back to en

Tested end-to-end: 11 MB / 4000×3000 source → 985 KB / 1920×1440 preview,
381 ms first call, 7 ms cached, ~91% byte reduction.
2026-05-14 22:30:39 +02:00
Paul Nothaft 06b33ced94 Merge pull request #495 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.49.6-beta.0
v3.49.6-beta.0
2026-05-14 21:37:55 +02:00
github-actions[bot] d4198e1bbc chore(beta): release 3.49.6-beta.0 2026-05-14 19:37:31 +00:00
Paul Nothaft 62b3ed6364 Merge pull request #494 from the-luap/fix/postgres-fresh-install-fk-order
fix(install): defer events.hero_photo_id FK to break circular reference (#484)
2026-05-14 21:37:00 +02:00
Paul Nothaft 87834a7fff fix(install): defer events.hero_photo_id FK to break circular reference (#484)
Real root cause behind MrGabri's fresh-Postgres install crash, surfaced
by his second log dump after #488 silenced the FATAL noise:

  Initial setup failed: error: alter table "events" add constraint
  "events_hero_photo_id_foreign" foreign key ("hero_photo_id")
  references "photos" ("id") on delete SET NULL
  - relation "photos" does not exist

initializeDatabase() in src/database/db.js declared the FK inline at
events createTable (line 89), but the photos table is created later
in the same function (line 203). On Postgres this is a hard error —
the referenced table must exist at FK-declaration time. SQLite
silently tolerated it because its FK enforcement is lazy and the
inline declaration just became a column with no FK metadata.

Why no existing Postgres install hit it: initializeDatabase only
runs the createTable block on `if (!hasEventsTable)`. Once a
deployment has the events table from any prior run, the path is
skipped. So the bug only ever fires on a truly fresh Postgres
install — which is exactly MrGabri's scenario, and which our smoke
suite never exercises (it runs against a long-lived dev stack).

Fix:

- events createTable: drop the inline FK; column declared as a plain
  integer with an explainer comment.
- After both tables exist (post photos createTable): db.schema
  .alterTable('events').foreign('hero_photo_id').references...
  Wrapped in a try/catch that swallows "already exists" so re-runs
  on installs that previously got into a half-state don't fail boot.

Verified by docker compose down -v + up against the dev stack — no
FK error, all migrations apply, FK present in pg_constraint with
the expected definition.
2026-05-14 21:21:23 +02:00
Paul Nothaft 4225cd153f Merge pull request #491 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.49.5-beta.0
v3.49.5-beta.0
2026-05-14 21:02:58 +02:00
github-actions[bot] 1e4f762871 chore(beta): release 3.49.5-beta.0 2026-05-14 19:02:43 +00:00
Paul Nothaft d300426390 Merge pull request #490 from the-luap/fix/admin-users-sqlite-date-crash
fix(admin-users): normalise date fields to ISO across DB drivers (#485)
2026-05-14 21:02:13 +02:00
Paul Nothaft b6b58d0659 fix(admin-users): normalise date fields to ISO across DB drivers (#485)
Admin > Users page crashed with "TypeError: e.split is not a function"
on native installs (SQLite default). Reported by @blazmaric in #485
with a clean diagnosis: SQLite returns lastLogin / createdAt /
updatedAt as integer milliseconds since epoch, while Postgres
returns ISO strings via the standard JSON serialiser. The page used
parseISO() on the raw value and parseISO trips on numbers.

Fix at both layers — defence in depth:

- backend/src/routes/adminUsers.js: new toIso() helper applied in
  transformUser + transformInvitation. Coerces Date / number /
  numeric-string / null to a single ISO 8601 string contract before
  the response leaves the API. Protects every consumer (frontend
  AND external API tokens / n8n) regardless of which DB driver is
  underneath.
- frontend/src/services/userManagement.service.ts: same helper as
  defence-in-depth for stale backends mid-deploy and any cached
  pre-fix response shape. Also surfaced an existing
  transformInvitation gap — invitations endpoints were returning
  raw response.data.invitations without going through the
  transformer.

10 unit tests pin the toIso contract: all known driver shapes
(Date, number, numeric-string, ISO-string, null/undefined/empty)
plus the full transformer paths for transformUser and
transformInvitation.

Out of scope: same epoch-ms surface may exist on other admin pages
that were never tested against SQLite (events list, customers,
webhooks, api tokens, activity log). Worth a follow-up audit pass
to apply toIso() in every snake_case→camelCase transformer the
admin routes use, but the immediate Users-page crash is the only
reported one and shipping that fix unblocks @blazmaric.
2026-05-14 20:53:10 +02:00
Paul Nothaft a135544cab Merge pull request #489 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.49.4-beta.0
v3.49.4-beta.0
2026-05-14 20:50:23 +02:00
github-actions[bot] 57ea08e1ed chore(beta): release 3.49.4-beta.0 2026-05-14 18:49:31 +00:00
Paul Nothaft d39406b241 Merge pull request #488 from the-luap/fix/install-healthcheck-noise-and-stale-workers
fix(install): silence pg healthcheck noise + drop legacy workers container (#484)
2026-05-14 20:49:01 +02:00
Paul Nothaft d4155c4611 fix(install): drop racy migration step + add missing frontend container (#484)
Two follow-up fixes inside the same install-experience surface as
the previous commit:

1. **Removed `docker compose exec -T backend npm run migrate`** in
   both install_docker and update_docker_installation. The backend
   container's wait-for-db.sh already runs `npm run migrate:safe`
   on startup; the script was racing it with a separate (and
   non-safe) `npm run migrate`. That race is the most likely
   actual mechanism behind #484's "relation 'photos' does not
   exist" error on the second install attempt — partial schema
   visible to one of the two parallel migrators. Replaced with a
   bounded wait for the backend container to become healthy
   (Docker healthcheck reports green only after wait-for-db.sh
   finishes its migration pass).

2. **Added the missing frontend container** to the script-generated
   compose. The script previously generated a postgres + redis +
   backend stack with no frontend at all (backend on host port
   3001), while the documented production install
   (docker-compose.production.yml) ships postgres + redis +
   backend + frontend (nginx /api proxy on host port 3000). That
   shape divergence is half of issue B in #484 — script-installed
   admins had no frontend container and were left wondering where
   the UI lived. Aligning both compose files on the same shape
   eliminates the divergence; the frontend uses curl in its
   healthcheck (frontend/Dockerfile explicitly `apk add curl`)
   unlike the backend.

The remaining piece of issue B — picking ONE canonical install
path (build-from-source script vs. prebuilt-image production
compose) and deprecating the other — is a deployment-strategy
call that deserves its own design pass. Both paths now produce
architecturally-equivalent stacks.
2026-05-14 20:35:54 +02:00
Paul Nothaft 0b0b1bb2d5 fix(install): silence pg healthcheck noise + drop legacy workers container (#484)
Three install-experience bugs that compounded into MrGabri's "fresh
install fails" report:

1. **postgres healthcheck noise.** `pg_isready -U <user>` without
   -d defaults to probing a database whose name matches the user.
   Since DB_NAME defaults to picpeak_prod (not picpeak), every
   healthcheck interval logged
     FATAL: database "picpeak" does not exist
   into postgres logs even though the install was working
   correctly. Reporter saw the FATAL, assumed broken, restarted
   with DB_NAME=picpeak, hit a tainted-state migration error on
   the second try, filed a bug. Fixed in both
   docker-compose.production.yml and the inline compose generated
   by scripts/picpeak-setup.sh — pin -d to ${DB_NAME} so the
   probe hits the real database.

2. **backend container shows perpetually `unhealthy`.** Both
   compose files used `curl -f` for the backend healthcheck, but
   backend/Dockerfile only installs dumb-init + postgresql-client +
   ffmpeg — no curl. Switch to wget --no-verbose --tries=1 --spider
   to match what backend/Dockerfile's own HEALTHCHECK already
   does. Now docker ps, docker compose ps, and the backend image's
   built-in healthcheck all agree.

3. **stale separate `workers` container.** scripts/picpeak-setup.sh
   still generated a second container running `npm run workers`
   alongside the backend, but workers (fileWatcher,
   expirationChecker, emailQueueProcessor, backgroundProcessor,
   webhookWorker) have been started by server.js in-process for
   a while — see the comment at line ~895 of the same script for
   the systemd-side cleanup. The duplicate container caused two
   file watchers and two expiration checkers to compete for the
   same DB rows. Removed from the generated compose; install +
   upgrade paths now stop and rm any pre-existing picpeak-workers
   container.

Doesn't address issue B's bigger architecture mismatch (the script
generates a build-from-source compose with no frontend container,
while docker-compose.production.yml uses prebuilt images with a
separate frontend container). That deserves its own design pass
to pick a canonical install path and align — out of scope here.
2026-05-14 20:31:25 +02:00
Paul Nothaft 409ddf9c93 Merge pull request #487 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.49.3-beta.0
v3.49.3-beta.0
2026-05-14 20:24:30 +02:00
github-actions[bot] bc58520cd2 chore(beta): release 3.49.3-beta.0 2026-05-14 18:18:43 +00:00
Paul Nothaft d1034ce1c6 Merge pull request #486 from the-luap/fix/promo-banner-alignment
fix(promo-banner): center by default + admin alignment selector (#482)
2026-05-14 20:18:07 +02:00
Paul Nothaft a803491cf4 fix(promo-banner): center by default + admin alignment selector (#482)
The gallery promotional banner (#440) read as visually offset from
the gallery footer because:

  - Footer used `container text-center px-4` (full container width,
    centered text).
  - Promo block used `container py-4 sm:py-6` with an inner
    `max-w-3xl mx-auto` wrapper holding left-aligned text — a
    narrower column with left-aligned content sitting in the
    middle of the page.

Two issues compounded: the column was narrower than the footer AND
its text alignment differed. Reported by Rekoo-PS in #482 with a
screenshot showing the misalignment, with a request for an admin
alignment option.

Fix:

- Drop the inner max-w-3xl wrapper. Promo content now spans the
  same .container width as the footer, eliminating the
  narrower-column visual.
- Default text alignment changed from left → center to match the
  footer.
- New `branding_promo_alignment` setting ('left' | 'center' | 'right',
  default 'center'). Surfaced as a dropdown next to the existing
  Position dropdown on the BrandingPage. Live preview block on the
  BrandingPage mirrors the gallery render so admins see what
  guests will see.
- Also replaced the no-op `prose-sm` prose-modifier with a real
  `prose prose-sm` outer class so the existing `prose-a:text-accent`
  modifier actually takes effect (it didn't before — modifiers
  without an outer .prose are silently ignored by Tailwind
  Typography).

Migration 103 seeds the new setting at 'center' so existing
installs that have a promo banner today see the corrected
alignment immediately on next deploy.

i18n: en + de hand-translated; nl/pt/ru/fr machine-translated and
flagged for native review per project convention.
2026-05-14 20:10:14 +02:00
Paul Nothaft 3869e5c0dc Merge pull request #481 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.49.2-beta.0
v3.49.2-beta.0
2026-05-13 18:48:12 +02:00
github-actions[bot] 1cbb0c4cff chore(beta): release 3.49.2-beta.0 2026-05-13 16:46:19 +00:00
Paul Nothaft 6750f5d3b0 Merge pull request #480 from the-luap/fix/ci-trivy-platform-pin
fix(ci): pin TRIVY_PLATFORM per matrix arch (post-#477 follow-up)
2026-05-13 18:45:53 +02:00
Paul Nothaft c3256dc6bf fix(ci): pin TRIVY_PLATFORM per matrix arch (post-#477 follow-up)
PR #477 moved Trivy from the merge-* job into the per-arch build-*
matrix scanning by digest. The amd64 leg works; the arm64 leg
crashes with:

  remote error: no child with platform linux/amd64 in index
  ghcr.io/.../<image>@sha256:<digest>

Root cause: docker/build-push-action wraps every push in an OCI
index — the actual image manifest sits next to a SLSA provenance
attestation manifest as siblings under the digest. Trivy's remote
backend defaults to linux/amd64 when resolving an index, so:

  - amd64 leg → looks for amd64 child → finds the amd64 image → ok.
  - arm64 leg → looks for amd64 child → finds NO amd64 child
    (the only platform child is arm64) → fails.

Fix: set TRIVY_PLATFORM = ${{ matrix.platform }} on each leg's
Trivy step. Each scanner then asks for its own arch and finds it.
SLSA provenance attestation stays attached to the per-arch images
— a real win for supply-chain visibility we'd lose if we'd
disabled provenance instead.

amd64 was the only thing keeping CI partly green; this restores
full green across both legs without touching the build artifact
shape.
2026-05-13 18:41:49 +02:00
Paul Nothaft f9284010b7 Merge pull request #479 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.49.1-beta.0
v3.49.1-beta.0
2026-05-13 18:35:45 +02:00
github-actions[bot] e5ef893395 chore(beta): release 3.49.1-beta.0 2026-05-13 16:31:12 +00:00
Paul Nothaft 1144e9d162 Merge pull request #477 from the-luap/fix/ci-trivy-multi-arch-scan
fix(ci): scan multi-arch images per-arch by digest, pin trivy-action (#476)
2026-05-13 18:30:41 +02:00
Paul Nothaft f53b10dc2c Merge pull request #478 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.49.0-beta.0
v3.49.0-beta.0
2026-05-13 18:30:12 +02:00
github-actions[bot] b3c6508712 chore(beta): release 3.49.0-beta.0 2026-05-13 16:18:38 +00:00
Paul Nothaft d856340f0d Merge pull request #475 from the-luap/feat/og-share-cover-photo
feat(og): per-event opt-in to use hero photo as social-share preview (#474)
2026-05-13 18:18:02 +02:00