---
title: Shumiland — Project Overview
tags:
  - project
  - active
  - nextjs
  - payload-cms
aliases:
  - Shumiland
  - shumi
---

# Shumiland

Сайт дитячого парку розваг «Шуміленд» (Київ, Бориспіль).

**URL:** https://shumi.ai-impress.com  
**Admin:** https://shumi.ai-impress.com/admin  
**Repo:** https://git.ai-impress.com/Aimpress/Shumiland  
**Server:** `aimpress` → `/opt/03-business/shumiland`

---

## Tech Stack

| Layer | Tech |
|-------|------|
| Framework | Next.js 16 (App Router, standalone output) |
| CMS | Payload CMS 3.84 (Postgres adapter) |
| DB | PostgreSQL 16 (Docker volume `shumiland-postgres-data`) |
| Email | Resend adapter (`RESEND_API_KEY`) |
| Styling | Tailwind CSS v4 |
| Package manager | pnpm 11 |
| Node.js | 22-alpine (app), alpine 3 (migrator) |
| Deploy | Docker Compose + Traefik |

---

## Deployment

```bash
# Full deploy
ssh aimpress "cd /opt/03-business/shumiland && git pull origin main && \
  docker compose -f docker-compose.prod.yml build app migrate && \
  docker compose -f docker-compose.prod.yml up -d --force-recreate migrate && \
  docker wait shumiland-migrate && \
  docker compose -f docker-compose.prod.yml up -d --force-recreate app"

# App only (no schema changes)
ssh aimpress "cd /opt/03-business/shumiland && git pull origin main && \
  docker compose -f docker-compose.prod.yml build app && \
  docker compose -f docker-compose.prod.yml up -d --force-recreate app"

# Logs
ssh aimpress "docker logs shumiland-app --tail=30"
ssh aimpress "docker logs shumiland-migrate --tail=20"
```

---

## Migration Workflow

> **Migrator uses psql (alpine + postgresql-client), NOT payload migrate.**
> tsx@4.21.0 + Node.js v22 has unfixable ESM/CJS interop bugs.

Add new schema changes as SQL files in `migrations/`:
```bash
# New migration file
migrations/0002_<name>.sql  # Use IF NOT EXISTS / ADD COLUMN IF NOT EXISTS
```

The migrator runs all `*.sql` files in sorted order on every deploy. Files are idempotent.

---

## Key Files

| File | Purpose |
|------|---------|
| `payload.config.ts` | Payload config — collections, globals, plugins |
| `src/app/(payload)/admin/importMap.js` | **Manually maintained** — add entries when adding new Payload plugins or upload fields |
| `Dockerfile` | Multi-stage Next.js build (no generate:importmap step — tsx bug) |
| `Dockerfile.migrator` | Alpine + psql, runs `migrations/*.sql` |
| `docker-compose.prod.yml` | Prod compose: postgres → migrate → app |
| `.env.production` | Prod env vars (on server only) |
| `migrations/0001_new_collections.sql` | Idempotent SQL for all collections |

---

## importMap Rule

> When adding a new Payload plugin or upload field to `payload.config.ts`, manually add entries to `src/app/(payload)/admin/importMap.js`.

Hash formula: `exportName + '_' + md5(componentPath)`

Example (SEO plugin added 2026-05-13):
```
md5('@payloadcms/plugin-seo/client') = a8a977ebc872c5d5ea7ee689724c0860
```

---

## Collections & Globals

**Collections:** Users, Media, Pages, BlogPosts, Categories, Tags, Tariffs, Leads, Orders, Locations, Reviews, BirthdayPackages

**Globals:** HomePage, CheckoutPage, ThankYouPage, Header, Footer, SiteSettings, DyvoLisPage, GroupVisitsPage

**SEO plugin** enabled on: `pages`, `blog-posts`, `locations`

---

## Known Issues / Gotchas

- **tsx@4.21.0 + Node.js v22 bug:** Cannot run `payload generate:importmap` or `payload migrate` in Docker. importMap.js is manually committed; migrations are raw SQL via psql.
- **revalidate=60** on `/lokatsii/page.tsx` — was 3600, reduced to avoid stale ISR cache after deploy.
- **Tailwind v4 cascade bug:** see `tech_gotchas.md` in memory.
- **push: true removed** — schema sync is now manual SQL migrations.

---

## Sessions Log

| Date | Work Done |
|------|-----------|
| 2026-05-10 | Hero, LocationsSlider, WhyParents, Gallery, Reviews UI polish |
| 2026-05-12 | Payload upgrade 3.33→3.84, SEO plugin, CMS pages connected |
| 2026-05-13 | Fixed importMap (SEO plugin), psql migrator (tsx v22 bug), deployed successfully |
