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>
218 lines
7.4 KiB
TypeScript
218 lines
7.4 KiB
TypeScript
/**
|
|
* MITHOME-87/88: egyszeri migrációs script — a proto/src/content/pages/*.json
|
|
* + common.json tartalmát átemeli a Payload Globals-ekbe (Home, About,
|
|
* Services, Contact, Common) és a LegalPages collection-be a Local API-n
|
|
* keresztül.
|
|
*
|
|
* Futtatás (proto/ mappából, futó MongoDB-vel és beállított env-ekkel):
|
|
* node --env-file=.env.local --import tsx scripts/migrate-content-to-payload.ts
|
|
*
|
|
* Idempotens: updateGlobal-t / slug-alapú upsert-et hív, tetszőlegesen
|
|
* többször futtatható — mindig a JSON az aktuális "forrás igazság", felül-
|
|
* í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
|
|
* nem olvasható vissza (üresnek látszik) — ilyenkor ezt a scriptet újra
|
|
* kell futtatni, hogy a defaultLocale (hu) alá újra beírja az értéket a
|
|
* lokalizált alakban. Explicit `locale` paramétert egyik updateGlobal/
|
|
* update hívás sem ad meg itt, ezért mindig a `defaultLocale` (hu) alá ír.
|
|
*/
|
|
import path from 'path'
|
|
import { fileURLToPath } from 'url'
|
|
import { getPayload, type Payload } from 'payload'
|
|
import config from '../src/payload.config'
|
|
|
|
import homeJson from '../src/content/pages/home.json'
|
|
import aboutJson from '../src/content/pages/about.json'
|
|
import servicesJson from '../src/content/pages/services.json'
|
|
import contactJson from '../src/content/pages/contact.json'
|
|
import commonJson from '../src/content/common.json'
|
|
import adatvedelemJson from '../src/content/pages/adatvedelem.json'
|
|
import hasznalatiFeltetelekJson from '../src/content/pages/hasznalati-feltetelek.json'
|
|
|
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
const publicDir = path.resolve(scriptDir, '../public')
|
|
|
|
/** string[] -> [{ value: string }] — lásd src/globals/fields/stringArray.ts */
|
|
function toStringArray(items: readonly string[]): { value: string }[] {
|
|
return items.map((value) => ({ value }))
|
|
}
|
|
|
|
function buildHomeData(json: typeof homeJson) {
|
|
const { hero, about, services, cta, serviceFeatures } = json
|
|
return {
|
|
hero: {
|
|
...hero,
|
|
trustBullets: toStringArray(hero.trustBullets),
|
|
},
|
|
about,
|
|
services: {
|
|
...services,
|
|
items: services.items.map((item) => ({
|
|
...item,
|
|
features: toStringArray(item.features),
|
|
})),
|
|
},
|
|
cta,
|
|
serviceFeatures,
|
|
}
|
|
}
|
|
|
|
function buildAboutData(json: typeof aboutJson) {
|
|
const { meta, hero, story, mission, team, cta } = json
|
|
return {
|
|
meta,
|
|
hero,
|
|
story: { ...story, paragraphs: toStringArray(story.paragraphs) },
|
|
mission,
|
|
team: { ...team, paragraphs: toStringArray(team.paragraphs) },
|
|
cta,
|
|
}
|
|
}
|
|
|
|
function buildServicesData(json: typeof servicesJson) {
|
|
const { meta, hero, details, support, cta } = json
|
|
return {
|
|
meta,
|
|
hero,
|
|
details: {
|
|
...details,
|
|
services: details.services.map((service) => ({
|
|
...service,
|
|
specs: {
|
|
...service.specs,
|
|
items: toStringArray(service.specs.items),
|
|
},
|
|
})),
|
|
},
|
|
support,
|
|
cta,
|
|
}
|
|
}
|
|
|
|
type LegalPageJson = {
|
|
title: string
|
|
lastUpdated: string
|
|
sections: { id: string; title: string; content: string }[]
|
|
}
|
|
|
|
/** Collections have no per-document "known slug" API like Globals do —
|
|
* find-by-slug, then update or create. Idempotent across re-runs. */
|
|
async function upsertLegalPage(payload: Payload, slug: string, json: LegalPageJson) {
|
|
const existing = await payload.find({
|
|
collection: 'legal-pages',
|
|
where: { slug: { equals: slug } },
|
|
limit: 1,
|
|
})
|
|
|
|
if (existing.docs.length > 0) {
|
|
await payload.update({
|
|
collection: 'legal-pages',
|
|
id: existing.docs[0].id,
|
|
data: { slug, ...json, _status: 'published' },
|
|
})
|
|
} else {
|
|
await payload.create({
|
|
collection: 'legal-pages',
|
|
data: { slug, ...json, _status: 'published' },
|
|
})
|
|
}
|
|
}
|
|
|
|
type PartnerJson = { name: string; url: string; logo: string }
|
|
|
|
/**
|
|
* MITHOME-89 (MVP): a home.json partners.items publikus /partners/*.png
|
|
* útvonalait tölti fel Media collection dokumentumként, majd Partner
|
|
* rekordot hoz létre/frissít rá hivatkozva. Idempotens: a Media dokumentumot
|
|
* `alt` (== partner név) alapján, a Partnert `name` alapján keresi.
|
|
*/
|
|
async function upsertPartner(payload: Payload, partner: PartnerJson) {
|
|
const existingMedia = await payload.find({
|
|
collection: 'media',
|
|
where: { alt: { equals: partner.name } },
|
|
limit: 1,
|
|
})
|
|
|
|
let mediaId: string | number
|
|
if (existingMedia.docs.length > 0) {
|
|
mediaId = existingMedia.docs[0].id
|
|
} else {
|
|
const filePath = path.resolve(publicDir, partner.logo.replace(/^\//, ''))
|
|
const created = await payload.create({
|
|
collection: 'media',
|
|
data: { alt: partner.name },
|
|
filePath,
|
|
})
|
|
mediaId = created.id
|
|
}
|
|
|
|
const existingPartner = await payload.find({
|
|
collection: 'partners',
|
|
where: { name: { equals: partner.name } },
|
|
limit: 1,
|
|
})
|
|
|
|
if (existingPartner.docs.length > 0) {
|
|
await payload.update({
|
|
collection: 'partners',
|
|
id: existingPartner.docs[0].id,
|
|
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, _status: 'published' },
|
|
})
|
|
}
|
|
}
|
|
|
|
async function run() {
|
|
const payload = await getPayload({ config })
|
|
|
|
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), _status: 'published' } })
|
|
payload.logger.info('About global migrálva')
|
|
|
|
await payload.updateGlobal({ slug: 'services', data: { ...buildServicesData(servicesJson), _status: 'published' } })
|
|
payload.logger.info('Services global migrálva')
|
|
|
|
await payload.updateGlobal({ slug: 'contact', data: { ...contactJson, _status: 'published' } })
|
|
payload.logger.info('Contact global migrálva')
|
|
|
|
await payload.updateGlobal({ slug: 'common', data: { ...commonJson, _status: 'published' } })
|
|
payload.logger.info('Common global migrálva')
|
|
|
|
await upsertLegalPage(payload, 'adatvedelem', adatvedelemJson)
|
|
payload.logger.info('LegalPages/adatvedelem migrálva')
|
|
|
|
await upsertLegalPage(payload, 'hasznalati-feltetelek', hasznalatiFeltetelekJson)
|
|
payload.logger.info('LegalPages/hasznalati-feltetelek migrálva')
|
|
|
|
for (const partner of homeJson.partners.items) {
|
|
await upsertPartner(payload, partner)
|
|
payload.logger.info(`Partners/${partner.name} migrálva`)
|
|
}
|
|
|
|
payload.logger.info('MITHOME-87/88/89 migráció kész.')
|
|
process.exit(0)
|
|
}
|
|
|
|
run().catch((error) => {
|
|
console.error('Migráció sikertelen:', error)
|
|
process.exit(1)
|
|
})
|