Files
picpeak/backend/migrations
Paul Nothaft b48fa62eea feat(gallery): info banner above the photo grid (#932) (#1063)
* feat(gallery): info banner above the photo grid (#932)

A short informational note rendered at the TOP of a gallery, above the
photos. Distinct from the promotional banner (#440), which stays by the
footer for marketing copy — the reporter's case is an onboarding hint ("use
the menu button to filter"), which is useless below a gallery the guest has
to scroll past first.

Mirrors the promo feature's shape rather than inventing a second one: a
global default in Settings → Branding (branding_info_markdown) plus a
per-event inherit/custom/off override. Markdown via the existing
MarkdownContent sanitiser — no raw HTML, no CSS injection. Empty global
default means nothing renders, so upgrading changes nothing visible.

Deliberately NOT included: an alignment knob (this is short helper copy, not
marketing layout) and guest dismissal — the issue lists dismissal as a
nice-to-have, and it needs per-guest persistence that is its own decision.

Migration 176 is idempotent (hasColumn / existing-key guarded).

Note on the payload plumbing: the per-event fields travel in the /photos
response, not just /info. GalleryAuthContext seeds its cached event from the
gallery LOGIN response — a small identity subset — so anything absent there
is undefined right after a guest signs in. /photos is the payload that
refreshes on every gallery load, which is why the fields were added there
and why GalleryView reads them from `data.event`. Verified in a browser
across all three modes; reading them from the context event instead silently
collapsed every override back to 'inherit'.

* fix(branding): map branding_info_markdown on read so saving can't wipe it (#932)

External review caught this. BrandingSettings declared no info_markdown and
formatBrandingSettings never mapped branding_info_markdown, so BrandingPage's
hydration — setBrandingSettings(prev => ({ ...prev, ...formatted })) — kept
the empty-string initializer instead of the persisted value. The form loaded
blank and the next Save posted '' back, wiping a configured banner. Silently:
the gallery keeps rendering the old copy until that save lands.

This is the same bug the footer/promo fields hit in #441 + #440 / #460, which
the read mapper still carries a comment about. Add the field to the interface
and the mapper, and pin the round-trip for the whole editable branding set so
the next field added is caught by a test rather than by a user losing copy.

Verified: the new test fails 3/4 with the mapper line removed.

* fix(gallery): honour the info-banner override in the reveal-hidden view (#932)

External review, round 2. The hidden-until-reveal branch renders GalleryLayout
with the context `event`, which is seeded from the gallery login response and
carries no banner fields — so while a gallery was hidden, a per-event 'off'
silently resolved to 'inherit' and the global banner appeared on a gallery the
admin had muted.

Resolve the fields there the same way the main render path does. The two
full-page layouts (gallery-premium, gallery-story) are deliberately left alone:
they return before GalleryLayout and render no header, footer or promo banner
either — injecting a wrapper into layouts documented as having 'their own
integrated UI' would be a design change, not a fix.

---------

Co-authored-by: Paul Nothaft <paul@MacStudio-von-Paul.local>
2026-08-16 21:33:13 +02:00
..

Database Migrations

This directory contains database migrations for the PicPeak photo sharing platform.

Directory Structure

/core

Essential migrations that are always run for new deployments. These include:

  • init.js - Initial database schema creation
  • Backup service tables (029-035)
  • Gallery feedback tables (033)
  • Pre-generated watermarks (061)

/legacy

Migrations needed only when upgrading from older versions. New deployments can skip these as the core schema already includes all necessary tables and columns.

For New Deployments

If you're deploying this application for the first time:

  1. The initializeDatabase() function in src/database/db.js will create all necessary tables
  2. Only migrations in the /core directory will be run
  3. This ensures a clean, optimized database schema

For Existing Deployments

If you're upgrading from an older version:

  1. All migrations (both core and legacy) will be run in sequence
  2. The migration system tracks which migrations have been applied
  3. Only new migrations will be executed

Running Migrations

# Development
npm run migrate

# Production
npm run migrate:prod

Note on Duplicate Migration Numbers

The legacy directory contains renamed duplicates:

  • 014_add_host_name_to_events_duplicate.js (was duplicate of 014)
  • 027_add_rate_limit_settings_duplicate.js (was duplicate of 027)

These have been renamed to avoid conflicts while preserving the migration history.