feat(cms): enable draft/publish + version history on Globals/Collections (MITHOME-92)
CI Pipeline with Test Management / 🧪 Run Tests & Generate Reports (push) Canceled after 0s
Test Reporting & Gherkin Analysis / 🧪 Run Tests & Generate Reports (push) Canceled after 0s
CI Pipeline with Test Management / 🐳 Docker Integration Tests (push) Canceled after 0s
CI Pipeline with Test Management / 🏗️ Build Docker Image (push) Canceled after 0s
CI Pipeline with Test Management / 📊 Generate Test Summary (push) Canceled after 0s
Test Reporting & Gherkin Analysis / 📊 Analyze Test Coverage (push) Canceled after 0s
Test Reporting & Gherkin Analysis / 🔄 Sync with Linear (push) Canceled after 0s
Test Reporting & Gherkin Analysis / ⚡ Performance Monitoring (push) Canceled after 0s

Adds versions.drafts to all content-bearing Globals (Home, About,
Services, Contact, Common) and Collections (LegalPages, Partners) via
shared config in src/lib/payload-versions.ts. Media and Users are
deliberately excluded (no draft workflow needed for uploads/auth).

This is the direct successor to the old custom CMS's "Verziók panel"
(MITHOME-64): the Payload admin now shows Save Draft / Publish changes
and a Versions tab with history/diff/restore per document.

Fixes a real bug found during manual verification: Payload's `_status`
field defaults to 'draft' when a create/update call's data omits it,
and that value is preserved on subsequent updates rather than being
overwritten. Since migrate-content-to-payload.ts never passed
`_status`, every migrated document ended up in draft status, which
would have broken public pages once combined with any future explicit
draft read. Fixed by explicitly setting `_status: 'published'` on
every write in the migration script.

Verified live in the browser:
- Payload admin: Home global shows Status: Published, Save Draft /
  Publish changes buttons, Versions tab with history (draft -> current).
- Saving a draft edit (title change, not published) does NOT change
  what /hu and /en render — confirmed by reloading the public page
  before publishing.
- Publishing the change updates the public page as expected.
- Full gate green: tsc, lint, tests (58 passed), production build.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Do Siki
2026-09-11 21:36:03 +02:00
co-authored by Claude Sonnet 5
parent b5590175b7
commit d445f0f31a
9 changed files with 64 additions and 11 deletions
+17 -9
View File
@@ -12,6 +12,14 @@
* írja a Payload-ban lévő korábbi állapotot. NEM törli/nem érinti a JSON
* fájlokat.
*
* MITHOME-92 tapasztalat: a versions.drafts bekapcsolása után a `_status`
* mező defaultValue-ja 'draft' — ha egy create/update hívás data-jában
* nincs explicit `_status`, ÚJ dokumentum létrehozásakor 'draft' lesz, és
* frissítéskor a meglévő (draft) érték marad meg (nem íródik felül
* automatikusan 'published'-re). Ezért itt minden Globals/LegalPages/
* Partners írás explicit `_status: 'published'`-t ad át — a migrációs
* script eredménye mindig publikált tartalom legyen, sosem draft.
*
* MITHOME-110 tapasztalat: ha egy mezőt utólag `localized: true`-ra
* állítasz (MITHOME-111/112 retrofit), a korábban beírt érték a régi,
* nem-lokalizált tárolási alakban marad, és `locale: defaultLocale`-lal
@@ -112,12 +120,12 @@ async function upsertLegalPage(payload: Payload, slug: string, json: LegalPageJs
await payload.update({
collection: 'legal-pages',
id: existing.docs[0].id,
data: { slug, ...json },
data: { slug, ...json, _status: 'published' },
})
} else {
await payload.create({
collection: 'legal-pages',
data: { slug, ...json },
data: { slug, ...json, _status: 'published' },
})
}
}
@@ -160,12 +168,12 @@ async function upsertPartner(payload: Payload, partner: PartnerJson) {
await payload.update({
collection: 'partners',
id: existingPartner.docs[0].id,
data: { name: partner.name, url: partner.url, logo: mediaId },
data: { name: partner.name, url: partner.url, logo: mediaId, _status: 'published' },
})
} else {
await payload.create({
collection: 'partners',
data: { name: partner.name, url: partner.url, logo: mediaId },
data: { name: partner.name, url: partner.url, logo: mediaId, _status: 'published' },
})
}
}
@@ -173,19 +181,19 @@ async function upsertPartner(payload: Payload, partner: PartnerJson) {
async function run() {
const payload = await getPayload({ config })
await payload.updateGlobal({ slug: 'home', data: buildHomeData(homeJson) })
await payload.updateGlobal({ slug: 'home', data: { ...buildHomeData(homeJson), _status: 'published' } })
payload.logger.info('Home global migrálva')
await payload.updateGlobal({ slug: 'about', data: buildAboutData(aboutJson) })
await payload.updateGlobal({ slug: 'about', data: { ...buildAboutData(aboutJson), _status: 'published' } })
payload.logger.info('About global migrálva')
await payload.updateGlobal({ slug: 'services', data: buildServicesData(servicesJson) })
await payload.updateGlobal({ slug: 'services', data: { ...buildServicesData(servicesJson), _status: 'published' } })
payload.logger.info('Services global migrálva')
await payload.updateGlobal({ slug: 'contact', data: contactJson })
await payload.updateGlobal({ slug: 'contact', data: { ...contactJson, _status: 'published' } })
payload.logger.info('Contact global migrálva')
await payload.updateGlobal({ slug: 'common', data: commonJson })
await payload.updateGlobal({ slug: 'common', data: { ...commonJson, _status: 'published' } })
payload.logger.info('Common global migrálva')
await upsertLegalPage(payload, 'adatvedelem', adatvedelemJson)
+5 -2
View File
@@ -1,11 +1,13 @@
import type { CollectionConfig } from 'payload'
import { collectionVersions } from '../lib/payload-versions'
/**
* Mirrors LegalPageContent (proto/src/content/types.ts) — MITHOME-88.
* Slug-alapú collection a jogi oldalaknak (adatvedelem, hasznalati-feltetelek).
*
* WHY `content` textarea és nem lexical richText: a jelenlegi frontend
* (proto/src/app/(frontend)/adatvedelem/page.tsx) a szekció-tartalmat egy
* WHY `content` textarea és nem lexical richText: a frontend
* (proto/src/components/views/LegalPageView.tsx) a szekció-tartalmat egy
* kézzel írt regex-alapú "•"/"**bold**" -> HTML konverzióval rendereli, nem
* valódi Markdown- vagy richText-parserrel. Ugyanaz a döntés, mint a
* Contact global gdpr.label mezőjénél (MITHOME-87) — a bootstrap szinten
@@ -17,6 +19,7 @@ export const LegalPages: CollectionConfig = {
useAsTitle: 'title',
group: 'Oldalak',
},
versions: collectionVersions,
fields: [
{
name: 'slug',
+3
View File
@@ -1,5 +1,7 @@
import type { CollectionConfig } from 'payload'
import { collectionVersions } from '../lib/payload-versions'
/**
* Mirrors home.json `partners.items` (proto/src/content/pages/home.json) —
* MITHOME-89 (MVP). Korábban a Home Global szándékosan NEM tartalmazta ezt
@@ -12,6 +14,7 @@ export const Partners: CollectionConfig = {
useAsTitle: 'name',
group: 'Oldalak',
},
versions: collectionVersions,
fields: [
{ name: 'name', type: 'text', required: true },
{ name: 'url', type: 'text', required: true },
+2
View File
@@ -1,6 +1,7 @@
import type { GlobalConfig } from 'payload'
import { stringArrayField } from './fields/stringArray'
import { globalVersions } from '../lib/payload-versions'
/** Mirrors AboutPageContent (proto/src/content/types.ts) — MITHOME-87. */
export const About: GlobalConfig = {
@@ -8,6 +9,7 @@ export const About: GlobalConfig = {
admin: {
group: 'Oldalak',
},
versions: globalVersions,
fields: [
{
name: 'meta',
+3
View File
@@ -1,5 +1,7 @@
import type { GlobalConfig } from 'payload'
import { globalVersions } from '../lib/payload-versions'
/**
* Mirrors CommonContent (proto/src/content/types.ts) — MITHOME-87.
*
@@ -14,6 +16,7 @@ export const Common: GlobalConfig = {
admin: {
group: 'Oldalak',
},
versions: globalVersions,
fields: [
{
name: 'buttons',
+3
View File
@@ -1,5 +1,7 @@
import type { GlobalConfig } from 'payload'
import { globalVersions } from '../lib/payload-versions'
/**
* Mirrors ContactPageContent (proto/src/content/types.ts) — MITHOME-87.
*
@@ -14,6 +16,7 @@ export const Contact: GlobalConfig = {
admin: {
group: 'Oldalak',
},
versions: globalVersions,
fields: [
{
name: 'meta',
+2
View File
@@ -1,6 +1,7 @@
import type { GlobalConfig } from 'payload'
import { stringArrayField } from './fields/stringArray'
import { globalVersions } from '../lib/payload-versions'
/**
* Mirrors HomePageContent (proto/src/content/types.ts) — MITHOME-87.
@@ -15,6 +16,7 @@ export const Home: GlobalConfig = {
admin: {
group: 'Oldalak',
},
versions: globalVersions,
fields: [
{
name: 'hero',
+2
View File
@@ -1,6 +1,7 @@
import type { GlobalConfig } from 'payload'
import { stringArrayField } from './fields/stringArray'
import { globalVersions } from '../lib/payload-versions'
/** Mirrors ServicesPageContent (proto/src/content/types.ts) — MITHOME-87. */
export const Services: GlobalConfig = {
@@ -8,6 +9,7 @@ export const Services: GlobalConfig = {
admin: {
group: 'Oldalak',
},
versions: globalVersions,
fields: [
{
name: 'meta',
+27
View File
@@ -0,0 +1,27 @@
import type { GlobalConfig, CollectionConfig } from 'payload'
/**
* MITHOME-92: közös draft/verziózás beállítás — ez az elődje a régi egyedi
* CMS "Verziók panel"-jének (MITHOME-64: mentéslista, diff-nézet, egy-
* kattintásos visszaállítás). A Payload beépített verziózása/draft-rendszere
* ugyanezt adja natívan (Payload admin "Versions" fül minden dokumentumon),
* nem kellett újraépíteni.
*
* WHY `autosave` nincs bekapcsolva: az ügyfél explicit "Save Draft" /
* "Publish" gombokkal dolgozzon, ne automatikus mentés — ugyanaz a
* szándékos, kézi mentés-modell, mint a régi CMS-nél volt.
*
* WHY a Local API hívásaink (src/lib/payload-content.ts) nem törnek el
* ettől: `findGlobal`/`find` alapból a PUBLISHED verziót adja vissza, amíg
* explicit `draft: true` paramétert nem adunk át — ezt sehol nem tesszük,
* így a publikus oldal renderelése változatlan marad.
*/
export const globalVersions: GlobalConfig['versions'] = {
drafts: true,
max: 50,
}
export const collectionVersions: CollectionConfig['versions'] = {
drafts: true,
maxPerDoc: 50,
}