feat(cms): Payload CMS bootstrap — config, MongoDB adapter, admin routes (MITHOME-86)

Alapinstalláció a Payload CMS-re való áttéréshez (EPIC MITHOME-85):

- payload@3.88.0, @payloadcms/next, @payloadcms/db-mongodb,
  @payloadcms/richtext-lexical, graphql, sharp telepítve
- src/payload.config.ts: mongooseAdapter a meglévő MONGODB_URI-ra
  (ugyanaz az adatbázis, mint a Mongoose/mongodb rétegnek), lexical
  editor, PAYLOAD_SECRET env-ből
- src/collections/Users.ts: minimális auth collection — Payload nem
  tud admin felületet renderelni auth collection nélkül. Ez csak a
  bootstraphez kell; a valódi access control/jelszó-politika MITHOME-90
  feladata.
- App Router route group (src/app/(payload)/): admin UI
  ([[...segments]]), REST (api/[...slug]), GraphQL + playground route-ok,
  root layout — a szokásos Payload v3 Next.js integrációs minta szerint
- next.config.ts: withPayload() wrapper a route handler bundling-hoz
- tsconfig.json: @payload-config path alias -> src/payload.config.ts
  (ez oldja fel a webpack/turbopack importot is, nem csak a type-checket)
- PAYLOAD_SECRET env var: generált dev érték a .env.local-ban
  (gitignore-olt), changeme placeholder + generálási megjegyzés a
  staging/production .env példafájlokban, dokumentálva a CLAUDE.md
  env-lista részében

Ismert, még nem javított biztonsági advisory a felvett payload@3.88.0-ban
(GHSA-jg8r-5jh2-v2xj, moderate, CWE-307: az admin account-unlock alapból
más fiókok lockoutját is felold hitelesített usernek) — nincs újabb
patch-elt verzió jelenleg, nyomon követve MITHOME-90 alatt.

Ellenőrizve ezen a commiton: npm run build, npm run lint, tsc --noEmit,
npm test (58 passed) — mind zöld. Az admin bejelentkezés/DB-kapcsolat
élő tesztje MongoDB-t igényel (jelen környezetben Docker daemon nem fut,
ez lokálisan `docker compose -f docker-compose.dev.yml up -d mongodb`
után `npm run dev` + http://localhost:3000/admin-mal ellenőrizhető).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Do Siki
2026-09-10 03:14:51 +02:00
co-authored by Claude Sonnet 5
parent 30364fcab7
commit 1600d99c5d
16 changed files with 3894 additions and 85 deletions
@@ -0,0 +1,17 @@
import type { Metadata } from 'next'
import config from '@payload-config'
import { NotFoundPage, generatePageMetadata } from '@payloadcms/next/views'
import { importMap } from '../importMap'
type Args = {
params: Promise<{ segments: string[] }>
searchParams: Promise<{ [key: string]: string | string[] }>
}
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
generatePageMetadata({ config, params, searchParams })
const NotFound = ({ params, searchParams }: Args) =>
NotFoundPage({ config, params, searchParams, importMap })
export default NotFound
@@ -0,0 +1,16 @@
import type { Metadata } from 'next'
import config from '@payload-config'
import { RootPage, generatePageMetadata } from '@payloadcms/next/views'
import { importMap } from '../importMap'
type Args = {
params: Promise<{ segments: string[] }>
searchParams: Promise<{ [key: string]: string | string[] }>
}
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
generatePageMetadata({ config, params, searchParams })
const Page = ({ params, searchParams }: Args) => RootPage({ config, params, searchParams, importMap })
export default Page
@@ -0,0 +1,4 @@
// Auto-generated by Payload (`npx payload generate:importmap`).
// Kept empty until a collection/global config references a custom admin
// component — regenerate with the CLI command whenever one does.
export const importMap = {}
@@ -0,0 +1,16 @@
import config from '@payload-config'
import {
REST_DELETE,
REST_GET,
REST_OPTIONS,
REST_PATCH,
REST_POST,
REST_PUT,
} from '@payloadcms/next/routes'
export const GET = REST_GET(config)
export const POST = REST_POST(config)
export const DELETE = REST_DELETE(config)
export const PATCH = REST_PATCH(config)
export const PUT = REST_PUT(config)
export const OPTIONS = REST_OPTIONS(config)
@@ -0,0 +1,4 @@
import config from '@payload-config'
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes'
export const GET = GRAPHQL_PLAYGROUND_GET(config)
@@ -0,0 +1,4 @@
import config from '@payload-config'
import { GRAPHQL_POST } from '@payloadcms/next/routes'
export const POST = GRAPHQL_POST(config)
+29
View File
@@ -0,0 +1,29 @@
import type { ServerFunctionClient } from 'payload'
import config from '@payload-config'
import { handleServerFunctions, RootLayout } from '@payloadcms/next/layouts'
import React from 'react'
import { importMap } from './admin/importMap'
import '@payloadcms/next/css'
type Args = {
children: React.ReactNode
}
const serverFunction: ServerFunctionClient = async function (args) {
'use server'
return handleServerFunctions({
...args,
config,
importMap,
})
}
const Layout = ({ children }: Args) => (
<RootLayout config={config} importMap={importMap} serverFunction={serverFunction}>
{children}
</RootLayout>
)
export default Layout
+15
View File
@@ -0,0 +1,15 @@
import type { CollectionConfig } from 'payload'
/**
* Admin bejelentkezés (MITHOME-86 bootstrap). A teljes access control /
* jelszó-politika finomítása MITHOME-90 feladata — itt csak a Payload
* indulásához szükséges minimális auth collection.
*/
export const Users: CollectionConfig = {
slug: 'users',
auth: true,
admin: {
useAsTitle: 'email',
},
fields: [],
}
+48
View File
@@ -0,0 +1,48 @@
/**
* Payload CMS configuration (MITHOME-86 — alapinstalláció).
*
* WHY a saját MongoDB kapcsolatot használjuk: a projekt már MongoDB-t futtat
* (proto/src/lib/mongodb.ts) — Payload a `mongooseAdapter`-en keresztül
* ugyanabba az adatbázisba ír, nincs szükség külön DB-re/szerverre.
*
* Ez a fájl jelenleg csak a bootstrap-hez szükséges minimumot tartalmazza
* (Users collection az admin bejelentkezéshez — Payload nem tud admin
* felületet renderelni auth collection nélkül). A tényleges tartalom-
* collectionök/globalok (Home, About, Services, Contact, Common, LegalPages,
* Partners, Media) a MITHOME-87..90 ticketekben kerülnek be.
*/
import path from 'path'
import { fileURLToPath } from 'url'
import { buildConfig } from 'payload'
import { mongooseAdapter } from '@payloadcms/db-mongodb'
import { lexicalEditor } from '@payloadcms/richtext-lexical'
import sharp from 'sharp'
import { Users } from './collections/Users'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
export default buildConfig({
// Admin felület — bejelentkezés az Users collection-nel (MITHOME-90-ben
// finomodik: access control, jelszó-politika stb.)
admin: {
user: Users.slug,
},
editor: lexicalEditor(),
collections: [Users],
secret: process.env.PAYLOAD_SECRET || '',
typescript: {
outputFile: path.resolve(dirname, 'payload-types.ts'),
},
db: mongooseAdapter({
url: process.env.MONGODB_URI || '',
}),
sharp,
})