Tables group_visits_page, birthday_page and their _v counterparts were missing from the DB
despite prior migrations being marked applied. The updated migration uses CREATE TABLE IF NOT EXISTS,
DO/EXCEPTION blocks for enum types and FK constraints, and ADD COLUMN IF NOT EXISTS to recover
the full schema before adding form_id relationship columns.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Creates forms, form_submissions and all related block tables for the @payloadcms/plugin-form-builder integration.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Inserts the ДивоЛіс location into locations table with showDetailPage=true
plus heroTips and whyVisitItems child records. Idempotent (ON CONFLICT/DELETE+INSERT).
Run by the psql migrator on next deploy.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- migrations/0002_delta.sql: idempotent SQL extracted from 20260515_162527.ts
(redirects table, locations detail fields, globals versioning, new pages)
so the psql migrator container applies it on next deploy
- Dockerfile: ARG/ENV NEXT_PUBLIC_SITE_URL in builder stage so the URL is
baked into the Next.js bundle (fixes postMessage origin warning in admin)
- docker-compose.prod.yml: pass build arg NEXT_PUBLIC_SITE_URL=https://shumi.ai-impress.com
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
postMessage with empty string origin throws "Invalid target origin ''"
Use same fallback as payload.config.ts — http://localhost:3000.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
payload-types.ts was gitignored so Docker builder had no file to compile
against — caused TS2307 "Cannot find module @/payload-types" in production
build. Regenerated types from current schema and removed from .gitignore
so it is always available in the build context.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
payload.config.ts used explicit .js extensions on local imports which Turbopack
and webpack cannot resolve to .ts files without extensionAliases config. Revert
to extension-less imports (original pattern from first Payload commit) that both
bundlers handle natively.
Also fix two TypeScript strict-mode errors:
- seed/route.ts: doc.id (number) cast to string via String() instead of `as string`
- getHomeData.ts: Payload HomePage vs HomePageGlobal cast via `as unknown as`
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Install @payloadcms/plugin-redirects, configure for 'pages' collection
with 301/302 types. Create src/middleware.ts that reads the redirects
collection via REST API (cached 5 min) and applies them before Next.js
renders — editors can manage redirects from the CMS admin.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Enable versions with draft autosave (interval 2000ms, max 20) for
HomePage, GroupVisitsPage, BirthdayPage, TicketsPage, LocationsPage,
BlogIndexPage — editors can now save drafts without publishing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New BirthdayPage global: hero, form titles, meta SEO for /dni-narodzhennia
- New TicketsPage global: hero, section titles, meta SEO for /kvytky
- SiteSettings: add tariffCategoryLabels array (key→label mapping for ezy API categories)
- DyvoLisPage + GroupVisitsPage: add metaTitle/metaDescription + revalidate hook
- /kvytky: fetch birthday packages from CMS, groups from CMS, category labels from SiteSettings
- /grupovi-vidviduvannia: remove DEFAULT_GROUPS fallback, CMS-driven meta
- /dni-narodzhennia: connect to BirthdayPage global (hero, form titles, meta)
- /lokatsii/dyvolis: use CMS meta description from DyvoLisPage global
- pnpm override tsx→4.22.0 for Node.js v26 compatibility
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Switch to getcall widget script, position button bottom-right, apply
Shumiland brand colors (green #396817 / orange #f28b4a), and use
Shumi mascot photo as button icon.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
tsx@4.21.0 + Node.js v22 has two unfixable interop bugs:
- --import tsx/esm hook: importSyncForRequire fails on @/ path aliases
- tsx runner: @next/env has __esModule:true but no .default export → TypeError
Solution: run SQL migrations directly via psql (alpine + postgresql-client).
All migration files use IF NOT EXISTS guards so they're idempotent on re-run.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
NODE_OPTIONS="--import tsx/esm" registers tsx as a hook, which exposes the
tsx@4.21.0 + Node.js v22 importSyncForRequire bug (named export not found).
Running tsx directly as the process runner handles TypeScript module loading
at a higher level, avoiding the CJS/ESM interop conflict.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
tsx@4.21.0 + Node.js v22 ESM/CJS interop bug prevents running `payload generate:importmap`
at Docker build time. Removed the failing RUN step and manually added the 5 SEO plugin
client components using the correct MD5-hashed identifier format.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove push:true from postgres adapter (unreliable for new columns)
- Remove profile:tools from migrate service so it runs on every deploy
- Add restart:no to migrate service (one-shot runner)
- App now depends on migrate with service_completed_successfully condition:
postgres healthy → migrate applies pending → app starts
Workflow for future schema changes:
1. Add field to collection/global TypeScript
2. ssh server: docker-compose run --rm migrate migrate:create --name <field>
3. git pull the generated .ts migration file
4. commit + push → next deploy applies it automatically
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add galleryImages array field to DyvoLisPage global so the photo gallery
is editable from Payload admin. Component falls back to 24 static images
when no CMS images are uploaded. Fix eslint flat-config error caused by
referencing @typescript-eslint plugin without an explicit import.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add Dockerfile.migrator (node:22-alpine + full source) and
docker-compose.prod.yml `migrate` service (profile: tools) so
migrations can be generated and applied on the server without
Node.js v26/tsx compatibility issues.
Workflow:
# generate migration:
docker compose --profile tools run --rm migrate migrate:create --name <desc>
# apply pending migrations:
docker compose --profile tools run --rm migrate
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously name/phone were only in Lead, email only in Order — two
unlinked records. Now Order has all contact fields, enabling standalone
CRM view per purchase.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Combo bundle tariffs moved to their own 'combo' category via DB.
Static sections for Дні народження (3 packages) and Групові відвідування
(3 types) added at the bottom with "Дізнатися ціну" buttons linking to
the respective booking forms.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dyvolis tariffs (ezy_id 2001/2002) exist in DB but ezy returns only
the "Online" 3xxx-series tariffs from its activity endpoint. The merge
loop silently dropped anything not in the ezy response, leaving the
DyvoLis ticket section empty.
Now after building the ezy-merged list, DB-visible tariffs absent from
ezy are appended so every visible tariff shows up regardless of which
ezy activity it belongs to.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Hero: move cat panel right (left 15%, ellipse 20%) so it doesn't
cover the left text column; adjust badge text Х→60+ with proper
font size (50px) for 3-character label
- Gallery: replace 4 placeholder images with 24 real Dyvolis park
photos (March 2026 shoot)
- WhyVisit carousel: use 5 real park photos as posters, increase
card size from 505px to 600px with 4:3 aspect ratio
- Header: replace 3-SVG fallback logo with full-color brand PNG
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix negative clamp for marginRight: was returning -40px at 1440px
instead of -101px (min/max were backwards for CSS negative clamp)
- Fix badge size: 11.11vw now hits 160px at lg (1440px)
- Fix font: 6.67vw now hits 96px at lg (was 86px)
- Fix paddingLeft of tip box: 10.28vw hits 148px at lg (was 137px)
- Add favicon.ico (multi-size 16/32/48/64) and icon.png (512x512)
from the colorful Shumiland Ш brand mark (cropped from Figma asset)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>