Compare commits

..
5 Commits
Author SHA1 Message Date
Do SikiandClaude Sonnet 5 d699bf4787 sync: mark MITHOME-95 done in TODO.md
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
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 12:34:24 +02:00
Do SikiandClaude Sonnet 5 758ee2cfed docs(agent): refresh architecture/CLAUDE.md docs for Payload CMS (MITHOME-95)
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
The Content layer description across the AI-agent steering docs still
described the pre-migration JSON system as the live, current mechanism
— rule #1 in CLAUDE.md and the Content row in architecture.md
explicitly told future work (and future agent sessions) to edit
proto/src/content/pages/*.json directly, which the live site hasn't
read since MITHOME-91.

Rewrote, per the ticket's named targets:
- .agent/steering/architecture.md: system overview, the Content layer
  table row, rule #1, and the Content Management code example now
  describe Payload Globals/Collections + the payload-content.ts Local
  API adapter, with /admin as the editing surface.
- CLAUDE.md: Stack line now names Payload CMS, rule #1 rewritten the
  same way, and the project-structure tree gets the (frontend)/(payload)
  route groups, globals/, collections/, and payload.config.ts that were
  entirely missing from it.

Also fixed directly-adjacent staleness found while doing this pass —
same "how is content edited" documentation debt, just not literally
named in the ticket:
- .agent/AGENTS.md: same project-structure tree gap as CLAUDE.md.
- .agent/workflows/new-feature.md: step 3 told contributors to edit
  the JSON file directly; now points at the Payload config + admin.
- .agent/workflows/review.md: the example "flag hardcoded text" review
  comment suggested moving it into the JSON file.
- .agent/steering/development-rules.md: the TRADEOFF code example
  literally used "JSON content management vs CMS" as a live open
  decision — that decision is resolved, updated the example to match.
- README.md: the entire "Tartalomkezelés" section and a "CMS
  Publikálás gomb" paragraph described the retired content-editor.js
  workflow (git-push-based publish, JSON directory tour) as current;
  also dropped a dead link to docs/felhasznaloi-utmutato.md, deleted
  in MITHOME-93.

Doc-only change, no proto/ source touched — no gate to run beyond a
sanity re-read of each edited file.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 12:33:33 +02:00
Do SikiandClaude Sonnet 5 3573d2accb sync: mark MITHOME-96 done, log partners grid fix in TODO.md
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
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 16:49:42 +02:00
Do SikiandClaude Sonnet 5 1bf32dd076 fix(web): arrange partner logos in a grid, max 3 per row
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
User request: the partner logos were laid out with flex-wrap, which
doesn't align items into clean rows/columns. Switched to CSS grid
(grid-cols-1 sm:grid-cols-2 md:grid-cols-3), so it never exceeds 3
columns regardless of viewport width or partner count.

w-fit + mx-auto (not inline-grid + mx-auto) so the grid centers
correctly even with fewer partners than 3 — auto margins don't center
inline-level boxes, but do for block-level ones sized to their content.

Verified live in the browser at 1200px width with 5 temporary test
partners (reusing an existing Media doc, deleted after): renders as a
3-then-2 grid, centered, no console errors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 16:38:05 +02:00
Do SikiandClaude Sonnet 5 e2b0c62628 test(cms): Payload config + Local API tests, fix stale Docker tests (MITHOME-96)
Adds the two test categories the ticket asked for, replacing the old
content-JSON-schema-only testing story now that Payload is the real
source of truth:

1. src/payload-config.test.ts — fast, DB-free unit tests over the
   Collection/Global config objects themselves. WHY not importing
   payload.config.ts directly: it pulls in the real `payload` and
   `@payloadcms/db-mongodb` packages as values (not just types), which
   are ESM-only and Jest's default transformIgnorePatterns skips
   node_modules entirely — confirmed by trying it
   (`SyntaxError: Cannot use import statement outside a module` from
   payload's own dist). Individual collection/global files only ever
   `import type` from 'payload' (erased at compile time), so they're
   safely importable in isolation. Two of the assertions are
   deliberate regression guards for real bugs found earlier this
   session (MITHOME-121): Media.access.read must stay public, and
   Partners.logo must stay optional.

2. scripts/test-payload-local-api.ts (npm run test:payload) — exercises
   every src/lib/payload-content.ts getter plus a full
   create/findByID/delete cycle against a real, already-migrated
   MongoDB. WHY a plain node script instead of a Jest integration
   config: same ESM problem as above, and Payload's dependency graph
   is too broad to safely add to transformIgnorePatterns — this
   follows the same working `node --import tsx` pattern already used
   by migrate-content-to-payload.ts. Not wired into
   pre-deploy-tests.sh (needs a live, pre-migrated MongoDB, same
   reasoning as the removed CMS integration tests); run manually or
   before a release.

3. Fixed the pre-existing (Docker-stack-gated, so silently never
   caught) staleness in integration.test.ts and e2e-docker.test.ts:
   unprefixed routes (/rolunk) → locale-prefixed (/hu/rolunk), and
   Mongo assertions against the old site_config/contact_submissions
   collections → the real globals/legal-pages/partners/
   contact-submissions collections Payload actually uses. Also fixed
   an unrelated stale error-message assertion for spam detection that
   never matched the route's real string.

Verified: full gate green (tsc, lint, 63 unit tests — 13 new — build),
and separately ran test:payload live against the dev MongoDB (8/8
passed, including the write/read/delete cycle actually hitting Mongo).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 16:37:57 +02:00
15 changed files with 427 additions and 79 deletions
+8 -3
View File
@@ -80,10 +80,15 @@ sync: update Plane issues + TODO [leírás]
websitedev/ websitedev/
├── proto/ # Fő Next.js alkalmazás (itt futtatsd a parancsokat!) ├── proto/ # Fő Next.js alkalmazás (itt futtatsd a parancsokat!)
│ ├── src/ │ ├── src/
│ │ ├── app/ # Next.js App Router (pages és API routes) │ │ ├── app/
│ │ │ ├── (frontend)/ # Publikus oldalak: [locale]/[slug] catch-all
│ │ │ └── (payload)/ # Payload admin (/admin) + REST/GraphQL API
│ │ ├── components/ # React komponensek (Header, Footer, ThemeProvider) │ │ ├── components/ # React komponensek (Header, Footer, ThemeProvider)
│ │ ├── content/ # JSON tartalom-kezelő rendszer │ │ ├── globals/ # Payload Globals (Home, About, Services, Contact, Common)
│ │ ├── lib/ # Utility könyvtárak (MongoDB, Logger, Site Config) │ │ ├── collections/ # Payload Collections (LegalPages, Partners, Media, ContactSubmissions, Users)
│ │ ├── payload.config.ts # Payload CMS konfiguráció
│ │ ├── content/ # RÉGI JSON rendszer — csak migrációs seed + teszt-fixture (MITHOME-91/93/96)
│ │ ├── lib/ # payload-content.ts (Local API adapter), MongoDB health-check, Logger
│ │ ├── config/ # Statikus site konfiguráció │ │ ├── config/ # Statikus site konfiguráció
│ │ └── types/ # TypeScript típusdefiníciók │ │ └── types/ # TypeScript típusdefiníciók
│ └── public/ # Statikus fájlok │ └── public/ # Statikus fájlok
+17 -9
View File
@@ -8,11 +8,12 @@ Ez a fájl minden interakcióban automatikusan betöltődik az AI számára a pr
## Rendszer áttekintés ## Rendszer áttekintés
A projekt egy **Next.js 15 alapú marketing weboldal** a mozdIT Bt. számára, App Router architektúrával, TypeScript-tel és Tailwind CSS 4-gyel. A projekt egy **Next.js 15 alapú marketing weboldal** a mozdIT Bt. számára, App Router architektúrával, TypeScript-tel és Tailwind CSS 4-gyel, **Payload CMS**-sel (self-hosted, `/admin`) mint tartalomkezelő réteggel (MITHOME-85 epic).
- **Frontend**: Next.js 15 App Router (SSR/SSG), React 19, Tailwind CSS 4 - **Frontend**: Next.js 15 App Router (dinamikus renderelés — lásd MITHOME-97 WHY: SSG helyett, hogy egy admin publikálás azonnal látszódjon), React 19, Tailwind CSS 4
- **Backend**: Next.js API Routes (`/api/*`) - **CMS**: Payload CMS — Globals (Home/About/Services/Contact/Common) + Collections (LegalPages/Partners/Media/ContactSubmissions/Users), hu/en lokalizáció, draft/publish + verziózás
- **Adatbázis**: MongoDB (Mongoose ODM) — site config és contact form logok - **Backend**: Next.js API Routes (`/api/*`), Payload REST/GraphQL API + Local API
- **Adatbázis**: MongoDB — Payload-collection-önként (mongooseAdapter), plusz egy vékony natív `mongodb` driveres réteg (`proto/src/lib/mongodb.ts`) csak az `/api/health` connectivity-ellenőrzéséhez
- **Logging**: Winston + Loki (strukturált naplózás) - **Logging**: Winston + Loki (strukturált naplózás)
- **Infrastructure**: Docker + Docker Compose, natív deploy (`deploy.sh`) - **Infrastructure**: Docker + Docker Compose, natív deploy (`deploy.sh`)
@@ -24,13 +25,13 @@ A projekt egy **Next.js 15 alapú marketing weboldal** a mozdIT Bt. számára, A
| **Component** | Újrahasználható UI elemek | `proto/src/components/` | | **Component** | Újrahasználható UI elemek | `proto/src/components/` |
| **API Route** | Route handling, validáció | `proto/src/app/api/` | | **API Route** | Route handling, validáció | `proto/src/app/api/` |
| **Service/Lib** | Üzleti logika, DB kapcsolat | `proto/src/lib/` | | **Service/Lib** | Üzleti logika, DB kapcsolat | `proto/src/lib/` |
| **Content** | JSON alapú tartalom | `proto/src/content/` | | **Content** | Payload CMS Globals/Collections (admin: `/admin`), Local API adapter | `proto/src/globals/`, `proto/src/collections/`, `proto/src/lib/payload-content.ts` |
| **Config** | Statikus site konfiguráció | `proto/src/config/` | | **Config** | Statikus site konfiguráció | `proto/src/config/` |
| **Agent / Tools** | AI ügynökök eszközei | `.agent/` | | **Agent / Tools** | AI ügynökök eszközei | `.agent/` |
## Fontos Architektúra Szabályok ## Fontos Architektúra Szabályok
1. **Tartalom JSON-ban**: SOHA ne égess be szöveget közvetlenül komponensbe — használd a `src/content/` rendszert. 1. **Tartalom Payload-ban**: SOHA ne égess be szöveget közvetlenül komponensbe — a tartalom Payload Global/Collection mezőkben él, az ügyfél a `/admin` felületen szerkeszti, a frontend a `src/lib/payload-content.ts` adapteren (Payload Local API) keresztül olvassa. (Kivétel: `proto/src/content/*.json` még mindig létezik, de csak a `migrate-content-to-payload.ts` seed-script forrásaként és néhány komponens-teszt fixture-jeként — élő oldal nem olvassa közvetlenül, lásd MITHOME-91/93/96.)
2. **Stateless API**: A backend API teljesen stateless — session-t a kliens kezel. 2. **Stateless API**: A backend API teljesen stateless — session-t a kliens kezel.
3. **Observability**: Minden hiba legyen logolva Winstonnal. API válaszok egységes formátumban: `{ success, data, error }`. 3. **Observability**: Minden hiba legyen logolva Winstonnal. API válaszok egységes formátumban: `{ success, data, error }`.
4. **Security-by-design**: Input validáció minden API route-on, secrets csak env változókból. 4. **Security-by-design**: Input validáció minden API route-on, secrets csak env változókból.
@@ -55,14 +56,21 @@ A projekt egy **Next.js 15 alapú marketing weboldal** a mozdIT Bt. számára, A
## Content Management ## Content Management
```typescript ```typescript
// Helyes: content rendszer használata // Helyes: Payload Local API adapter használata (Server Component-ben)
import { content, getPageContent } from '@/content' import { getAboutContent } from '@/lib/payload-content'
const pageData = content.pages.about const about = await getAboutContent(locale) // locale: 'hu' | 'en'
// TILOS: közvetlen szöveg komponensben // TILOS: közvetlen szöveg komponensben
<h1>Rólunk</h1> <h1>Rólunk</h1>
``` ```
Az ügyfél a tartalmat a Payload admin felületen (`/admin`) szerkeszti —
Global (pl. Home, About) vagy Collection (pl. LegalPages, Partners) dokumentum
formájában, "Save Draft"/"Publish changes" munkafolyamattal (MITHOME-92). Új
mező felvételekor a megfelelő `proto/src/globals/*.ts` vagy
`proto/src/collections/*.ts` fájlt bővítsd, majd generáld újra a típusokat
(`payload generate:types`).
## Dependency szabályok ## Dependency szabályok
- Új NPM package bevezetéséhez **jóváhagyás szükséges** - Új NPM package bevezetéséhez **jóváhagyás szükséges**
+3 -2
View File
@@ -142,8 +142,9 @@ const rateLimitStore = new Map<string, number[]>();
// DECISION: fire-and-forget MongoDB write — ne várakozzon a válasz a cache írásra // DECISION: fire-and-forget MongoDB write — ne várakozzon a válasz a cache írásra
dbClient.logContact(data).catch(() => null); dbClient.logContact(data).catch(() => null);
// TRADEOFF: JSON content management vs CMS — könnyebb deploy, de nem non-tech szerkeszthető // TRADEOFF: Payload Local API vs statikus JSON import — élő, adminból
const content = await import('@/content/pages/home.json'); // szerkeszthető tartalom, cserébe minden kérésnél DB-olvasás kell (MITHOME-97)
const content = await getHomeContent(locale);
``` ```
## Pre-modification kockázatbecslés ## Pre-modification kockázatbecslés
+21 -2
View File
@@ -44,6 +44,7 @@ npm run test:coverage # lefedettség riport
npm run test:browser # browser integration npm run test:browser # browser integration
npm run test:integration # Docker integration (Docker kell!) npm run test:integration # Docker integration (Docker kell!)
npm run test:e2e # E2E tesztek (Docker kell!) npm run test:e2e # E2E tesztek (Docker kell!)
npm run test:payload # Payload Local API integráció (élő MongoDB + migrált tartalom kell!)
npm run test:all # teljes proto suite npm run test:all # teljes proto suite
npm run test:smoke:staging # Playwright smoke a staging ellen npm run test:smoke:staging # Playwright smoke a staging ellen
``` ```
@@ -84,5 +85,23 @@ Plane-sync unit tesztek. Bármelyik hibája megszakítja a kiadást.
> serializer, optimista zárolás, verziók panel, logó feltöltés, login/logout, > serializer, optimista zárolás, verziók panel, logó feltöltés, login/logout,
> guide, publish) a Payload CMS-re állás után (MITHOME-93) eltávolítottuk — > guide, publish) a Payload CMS-re állás után (MITHOME-93) eltávolítottuk —
> a Payload admin felület a saját upstream tesztelésével fedett, ezt itt nem > a Payload admin felület a saját upstream tesztelésével fedett, ezt itt nem
> duplikáljuk. Payload collection/global konfigurációk saját tesztlefedettsége > duplikáljuk.
> külön feladat (MITHOME-96), még nincs implementálva. >
> **MITHOME-96**: Payload collection/global config tesztek —
> `src/payload-config.test.ts` (a `npm test`/pre-deploy suite része, nincs
> hozzá élő DB, csak a Collection/Global config objektumokat vizsgálja —
> köztük két, MITHOME-121-ben talált éles hibára regresszió-őrt: a Media
> publikus olvashatósága, a Partners.logo opcionalitása). A Local API elleni,
> élő MongoDB-t igénylő tesztek külön scriptben vannak
> (`scripts/test-payload-local-api.ts`, `npm run test:payload`) — WHY nem
> Jest: a `payload` csomag ESM-only dist-et ad ki, amit a next/jest
> transzform alapból nem fordít le (a teljes függőségi fa
> `transformIgnorePatterns`-be vétele törékeny lenne), ezért ugyanazt a
> bevált `node --import tsx` mintát követi, mint `migrate-content-to-payload.ts`.
> Nincs a `pre-deploy-tests.sh`-ban (élő, migrált tartalmú MongoDB kell hozzá,
> mint a régi, eltávolított CMS-teszteknek is), de a `npm run test:payload`
> paranccsal bármikor lefuttatható egy futó dev MongoDB ellen. A régi,
> Docker-stack-hez kötött `integration.test.ts`/`e2e-docker.test.ts` is
> frissítve lett a locale-prefixes útvonalakra és a Payload collection-nevekre
> (korábban a pre-Payload, unprefixelt útvonalakra és `site_config`/
> `contact_submissions` nyers Mongo collection-ökre hivatkoztak).
+6 -2
View File
@@ -55,8 +55,12 @@ git checkout -b feature/[leíró-feature-neve]
``` ```
### 3. Content frissítés (ha szöveges tartalom kell) ### 3. Content frissítés (ha szöveges tartalom kell)
- Módosítsd a megfelelő `proto/src/content/pages/*.json` fájlt - Új mező esetén bővítsd a megfelelő `proto/src/globals/*.ts` vagy
- Frissítsd a `types.ts`-t ha új content struktúra kell `proto/src/collections/*.ts` Payload config fájlt, majd generáld újra a
típusokat (`payload generate:types`)
- Meglévő mező szövegét az ügyfél a Payload admin felületen (`/admin`)
szerkeszti — ne írj bele közvetlenül `proto/src/content/*.json`-ba (az már
csak a migrációs seed-script forrása, élő oldal nem olvassa, MITHOME-91/93)
### 4. UI / Komponens implementáció (ha szükséges) ### 4. UI / Komponens implementáció (ha szükséges)
- Server Component alapértelmezetten — csak indokolt esetben `"use client"` - Server Component alapértelmezetten — csak indokolt esetben `"use client"`
+2 -1
View File
@@ -74,7 +74,8 @@ description: Kód review checklist — PR előtt és review során
✅ JÓ: ✅ JÓ:
[BLOCK] Ez hardcoded szöveget tartalmaz a komponensben. [BLOCK] Ez hardcoded szöveget tartalmaz a komponensben.
Át kell tenni: proto/src/content/pages/home.json → content.pages.home.* Át kell tenni Payload mezőbe (proto/src/globals/*.ts vagy collections/*.ts),
és a payload-content.ts adapteren keresztül kell beolvasni.
[SUGGEST] Ezt a logikát érdemes egy helper funkcióba kiszervezni, [SUGGEST] Ezt a logikát érdemes egy helper funkcióba kiszervezni,
ha több helyen is szükség lesz rá. ha több helyen is szükség lesz rá.
+13 -7
View File
@@ -10,14 +10,14 @@
- **Projekt**: mozdIT Bt. weboldal (websitedev) - **Projekt**: mozdIT Bt. weboldal (websitedev)
- **Plane workspace**: `developments``pm.llmdev.mozdit.hu` - **Plane workspace**: `developments``pm.llmdev.mozdit.hu`
- **Stack**: Next.js 15, React 19, TypeScript, Tailwind CSS 4, MongoDB, Winston - **Stack**: Next.js 15, React 19, TypeScript, Tailwind CSS 4, Payload CMS (self-hosted, `/admin`), MongoDB, Winston
- **Fő könyvtár**: `proto/`**minden parancsot innen futtatunk** - **Fő könyvtár**: `proto/`**minden parancsot innen futtatunk**
--- ---
## Gyors referencia — Alapszabályok ## Gyors referencia — Alapszabályok
1. **Szöveg sosem kerülhet közvetlenül komponensbe**`proto/src/content/pages/*.json` 1. **Szöveg sosem kerülhet közvetlenül komponensbe**Payload CMS Global/Collection mező (admin: `/admin`), a frontend `proto/src/lib/payload-content.ts`-en át olvassa. (`proto/src/content/pages/*.json` már csak a migrációs seed-script forrása + teszt-fixture, élő oldal nem használja — MITHOME-91/93/96.)
2. **Feladatok**: `TODO.md` (Plane tükörképe), szinkron: `node plane-sync.js` 2. **Feladatok**: `TODO.md` (Plane tükörképe), szinkron: `node plane-sync.js`
3. **Tesztek**: minden feature-höz kötelező; commit előtt `npm test` zöld 3. **Tesztek**: minden feature-höz kötelező; commit előtt `npm test` zöld
4. **Commit**: Conventional Commits (`feat:`, `fix:`, `docs:`, `chore:`) 4. **Commit**: Conventional Commits (`feat:`, `fix:`, `docs:`, `chore:`)
@@ -47,12 +47,17 @@ node plane-sync.js # Plane szinkronizáció
websitedev/ websitedev/
├── proto/ # Fő Next.js alkalmazás ├── proto/ # Fő Next.js alkalmazás
│ └── src/ │ └── src/
│ ├── app/ # App Router: oldalak és API route-ok │ ├── app/
│ │ ├── (frontend)/ # Publikus oldalak: [locale]/[slug] catch-all
│ │ └── (payload)/ # Payload admin (/admin) + REST/GraphQL API
│ ├── components/ # React komponensek (PascalCase.tsx) │ ├── components/ # React komponensek (PascalCase.tsx)
│ ├── content/ # JSON tartalom-kezelő rendszer │ ├── globals/ # Payload Globals (Home, About, Services, Contact, Common)
├── common.json # Közös szövegek │ ├── collections/ # Payload Collections (LegalPages, Partners, Media, ContactSubmissions, Users)
│ └── pages/ # Oldal-specifikus JSONok ├── payload.config.ts # Payload CMS konfiguráció
│ ├── lib/ # MongoDB, Logger, Site Config │ ├── content/ # RÉGI JSON rendszer — csak migrációs seed + teszt-fixture (MITHOME-91/93/96)
│ │ ├── common.json
│ │ └── pages/
│ ├── lib/ # payload-content.ts (Local API adapter), MongoDB health-check, Logger
│ ├── config/ # Statikus site konfiguráció │ ├── config/ # Statikus site konfiguráció
│ └── types/ # TypeScript típusok │ └── types/ # TypeScript típusok
├── docs/ # Projekt dokumentáció (Magyar) ├── docs/ # Projekt dokumentáció (Magyar)
@@ -77,6 +82,7 @@ Szükséges változók (`.env` és `proto/.env.local`):
- `NEXT_PUBLIC_CONTACT_EMAIL` — Kapcsolati email cím - `NEXT_PUBLIC_CONTACT_EMAIL` — Kapcsolati email cím
- `PLANE_API_KEY` — Plane szinkronizációhoz (a `.mcp.json`-ban is lehet) - `PLANE_API_KEY` — Plane szinkronizációhoz (a `.mcp.json`-ban is lehet)
- `PAYLOAD_SECRET` — Payload CMS JWT/session aláíráshoz (MITHOME-86); környezetenként egyedi, erős érték - `PAYLOAD_SECRET` — Payload CMS JWT/session aláíráshoz (MITHOME-86); környezetenként egyedi, erős érték
- `ADMIN_EMAIL` / `ADMIN_PASSWORD` — staging/production: `deploy.sh` ezekkel hoz létre egy ismert admin usert egy vadonatúj adatbázison (MITHOME-97 follow-up), csak akkor, ha a `users` collection még üres
--- ---
+13 -12
View File
@@ -39,32 +39,33 @@ scripts/pre-deploy-tests.sh
./deploy.sh production # éles (szerveren, staging ellenőrzése után) ./deploy.sh production # éles (szerveren, staging ellenőrzése után)
``` ```
A CMS „Publikálás" gombja szintén commitol + pushol + deployol (csak a beállított környezetre). Részletek: `.agent/workflows/deploy.md`, `docs/helyi-staging-deploy.md`. A Payload admin (`/admin`) draft/publish + verziózás munkafolyamata (MITHOME-92) nem jár git commit-tal vagy automatikus deployjal — a tartalom közvetlenül a MongoDB-be íródik. Kódváltozás (Globals/Collections séma, frontend) továbbra is a fenti git-alapú deploy folyamaton megy át. Részletek: `.agent/workflows/deploy.md`.
## Tartalomkezelés ## Tartalomkezelés
A weboldal szövegei és a CMS a `proto/src/content/` JSON-fájljaiból jönnek: A weboldal szövegei Payload CMS Globals/Collections mezőkben élnek, az ügyfél a `/admin` felületen szerkeszti őket:
``` ```
proto/src/content/ proto/src/globals/ # Home, About, Services, Contact, Common
├── schema.js # közös séma-validátor (Next + CMS) proto/src/collections/ # LegalPages, Partners, Media, ContactSubmissions, Users
├── types.ts # TypeScript típusok proto/src/payload.config.ts
├── index.ts # tartalom-betöltő
├── common.json # közös szövegek (gombok, lábléc, a11y)
└── pages/ # oldalankénti tartalom (home, about, services, …)
``` ```
Használat: Használat Server Component-ből (a Payload Local API-n keresztül):
```typescript ```typescript
import { content, getPageContent } from '@/content' import { getAboutContent } from '@/lib/payload-content'
const about = content.pages.about const about = await getAboutContent(locale) // locale: 'hu' | 'en'
``` ```
A régi, JSON-alapú content rendszer (`proto/src/content/`) már csak a
`migrate-content-to-payload.ts` seed-script forrásaként és néhány
komponens-teszt fixture-jeként él tovább — élő oldal nem olvassa (MITHOME-91/93).
## Dokumentáció ## Dokumentáció
- **Agent-szabályok**: `.agent/AGENTS.md`, `.agent/steering/`, `.agent/workflows/` - **Agent-szabályok**: `.agent/AGENTS.md`, `.agent/steering/`, `.agent/workflows/`
- **CMS felhasználói útmutató**: `docs/felhasznaloi-utmutato.md` (a CMS-ben a ❓ Súgó is ezt rendereli) - **nginx vhost-ok**: `docs/nginx-vhosts.md`
- **Plane szinkron**: `PLANE-SYNC-GUIDE.md` - **Plane szinkron**: `PLANE-SYNC-GUIDE.md`
- **Staging deploy**: `docs/helyi-staging-deploy.md` - **Staging deploy**: `docs/helyi-staging-deploy.md`
- **Gitea runner**: `docs/gitea-runner-telepites.md` - **Gitea runner**: `docs/gitea-runner-telepites.md`
+5 -2
View File
@@ -115,8 +115,8 @@ Cél: az ügyfél önállóan, admin felületen szerkeszthesse a tartalmat — a
| MITHOME-92 | Draft/preview és verziózás bekapcsolása (Verziók panel utódja) | ✅ | | MITHOME-92 | Draft/preview és verziózás bekapcsolása (Verziók panel utódja) | ✅ |
| MITHOME-93 | Régi egyedi CMS (content-editor.js) leépítése | ✅ | | MITHOME-93 | Régi egyedi CMS (content-editor.js) leépítése | ✅ |
| MITHOME-94 | Opcionális: ContactSubmissions collection a Mongoose modell helyett | ✅ | | MITHOME-94 | Opcionális: ContactSubmissions collection a Mongoose modell helyett | ✅ |
| MITHOME-95 | .agent/ és CLAUDE.md dokumentáció frissítése Payload architektúrára | 📋 | | MITHOME-95 | .agent/ és CLAUDE.md dokumentáció frissítése Payload architektúrára | |
| MITHOME-96 | Tesztek migrálása: content schema tesztek helyett Payload collection/global tesztek | 📋 | | MITHOME-96 | Tesztek migrálása: content schema tesztek helyett Payload collection/global tesztek | |
| MITHOME-97 | Deploy/Docker frissítés: PAYLOAD_SECRET, admin bundle, Dockerfile/deploy.sh | ✅ | | MITHOME-97 | Deploy/Docker frissítés: PAYLOAD_SECRET, admin bundle, Dockerfile/deploy.sh | ✅ |
| MITHOME-117 | Vizuális design-védelem: színek/design tokenek változatlansága (MITHOME-91/93 elfogadási kritériuma) | 📋 | | MITHOME-117 | Vizuális design-védelem: színek/design tokenek változatlansága (MITHOME-91/93 elfogadási kritériuma) | 📋 |
| MITHOME-102 | ContactSubmissions afterChange hook: PLATFM-2-kompatibilis esemény-emisszió (függ: MITHOME-94) | 📋 | | MITHOME-102 | ContactSubmissions afterChange hook: PLATFM-2-kompatibilis esemény-emisszió (függ: MITHOME-94) | 📋 |
@@ -208,6 +208,9 @@ docker-compose -f docker-compose.dev.yml down
--- ---
## Frissítési Napló ## Frissítési Napló
- **2026-09-13**: MITHOME-95 (dokumentáció frissítése) kész — `.agent/steering/architecture.md` és `CLAUDE.md` már a Payload Global/Collection + `/admin` + `payload-content.ts` Local API adaptert írja le a régi JSON rendszer helyett (rendszer-áttekintés, Content sor/szabály, kódpélda, projekt-struktúra fa). Emellett javítva több, ugyanebbe a dokumentációs adósságba tartozó, de a ticketben nem nevesített hely is: `.agent/AGENTS.md` projekt-fája, `new-feature.md`/`review.md` workflow-ok, `development-rules.md` TRADEOFF példakódja, és a `README.md` teljes "Tartalomkezelés" szekciója + egy halott link a MITHOME-93-ban törölt CMS-útmutatóra. Tisztán dokumentáció-változtatás.
- **2026-09-12**: Felhasználói kérésre a főoldal "Partnereink" szekciója flex-wrap helyett CSS grid-re váltott (max 3 oszlop, `grid-cols-1 sm:grid-cols-2 md:grid-cols-3`, `w-fit mx-auto` a középre igazításhoz kevesebb partnernél is) — élőben ellenőrizve 5 teszt-partnerrel (3+2-es elrendezés, középre igazítva).
- **2026-09-12**: MITHOME-96 (tesztek migrálása) kész — `src/payload-config.test.ts` (gyors, DB nélküli config-tesztek, két regresszió-őrrel a MITHOME-121-es hibákra) + `scripts/test-payload-local-api.ts`/`npm run test:payload` (élő MongoDB elleni Local API teszt, sima node script Jest helyett — a Payload csomag ESM-only, Jest alapból nem fordítja). Emellett javítva a régi, Docker-stack-hez kötött `integration.test.ts`/`e2e-docker.test.ts` eddig észrevétlen elavulása (unprefixelt útvonalak, `site_config`/`contact_submissions` nyers Mongo collection-ök a valódi Payload collection-ök helyett). Gate zöld (63 unit teszt), `test:payload` külön lefuttatva élőben (8/8).
- **2026-09-12**: MITHOME-94 (ContactSubmissions collection) kész — a `/api/contact` a nyers, Payload-on kívüli Mongo collection helyett most a Payload Local API-n keresztül egy `ContactSubmissions` collection-be ír (name/email/subject/message/gdprConsent/status), amit az ügyfél az adminban lát. Rate limiting/validáció/spam-szűrés változatlanul a route-on maradt. Nincs egyedi access-blokk — a Payload alapértelmezése (csak bejelentkezett usernek REST-en) pont a kívánt, a route saját írása a Local API-n (`overrideAccess: true`) nem ütközik ezzel. Talált és dokumentált teszt-gotcha: a next/jest SWC transform lecseréli a `@payload-config` alias-t valódi relatív útvonalra, ezért a mockot is a feloldott útvonalra kell tenni (`jest.mock('../../../payload.config', ...)`), nem az alias-ra. Élesben ellenőrizve mindkét helyen (helyi dev valódi űrlap-küldéssel + staging curl-lal). - **2026-09-12**: MITHOME-94 (ContactSubmissions collection) kész — a `/api/contact` a nyers, Payload-on kívüli Mongo collection helyett most a Payload Local API-n keresztül egy `ContactSubmissions` collection-be ír (name/email/subject/message/gdprConsent/status), amit az ügyfél az adminban lát. Rate limiting/validáció/spam-szűrés változatlanul a route-on maradt. Nincs egyedi access-blokk — a Payload alapértelmezése (csak bejelentkezett usernek REST-en) pont a kívánt, a route saját írása a Local API-n (`overrideAccess: true`) nem ütközik ezzel. Talált és dokumentált teszt-gotcha: a next/jest SWC transform lecseréli a `@payload-config` alias-t valódi relatív útvonalra, ezért a mockot is a feloldott útvonalra kell tenni (`jest.mock('../../../payload.config', ...)`), nem az alias-ra. Élesben ellenőrizve mindkét helyen (helyi dev valódi űrlap-küldéssel + staging curl-lal).
- **2026-09-12**: MITHOME-97 follow-up #3 — a felhasználó kérdésére ("el lehet jutni a honlapra az admin oldalról?") kiderült, hogy nem: az admin navigációban csak belső linkek voltak. Hozzáadva egy "🌐 Honlap megnyitása" link a keresősáv mellé (`QuickSearch.tsx`), ami `NEXT_PUBLIC_SITE_URL`-re mutat — környezetenként automatikusan helyes cím. Élesben ellenőrizve, staging-re deployolva. - **2026-09-12**: MITHOME-97 follow-up #3 — a felhasználó kérdésére ("el lehet jutni a honlapra az admin oldalról?") kiderült, hogy nem: az admin navigációban csak belső linkek voltak. Hozzáadva egy "🌐 Honlap megnyitása" link a keresősáv mellé (`QuickSearch.tsx`), ami `NEXT_PUBLIC_SITE_URL`-re mutat — környezetenként automatikusan helyes cím. Élesben ellenőrizve, staging-re deployolva.
- **2026-09-12**: MITHOME-121 kész — a felhasználó kérésére a Partners `logo` mezője opcionálissá vált (`required: true` törölve; a frontend már eleve kiszűrte a logó nélküli partnereket). Eközben egy valódi, MITHOME-89 óta jelen lévő hiba is előkerült: a `Media` collection sosem kapott explicit `access.read`-et, így a Payload alapértelmezett "csak bejelentkezett user" szabálya miatt a `/api/media/file/*` route mindig 403-at adott — a Next.js image-optimizer emiatt sosem tudta betölteni a partner logókat a publikus oldalon (törött kép ikon, senki nem vette észre). Javítva: `access: { read: () => true }`. Staging-en emellett egy második, kapcsolódó hibát is találtam: a médiafájl fizikai byte-jai elvesztek egy korábbi (a `media_data_staging` volume bevezetése előtti) konténer-újraépítéskor — az árva Media rekord törlésével és a migráció volume-mountolt konténerből való újrafuttatásával helyreállítva. Élesben ellenőrizve mindkét helyen (helyi dev + staging). - **2026-09-12**: MITHOME-121 kész — a felhasználó kérésére a Partners `logo` mezője opcionálissá vált (`required: true` törölve; a frontend már eleve kiszűrte a logó nélküli partnereket). Eközben egy valódi, MITHOME-89 óta jelen lévő hiba is előkerült: a `Media` collection sosem kapott explicit `access.read`-et, így a Payload alapértelmezett "csak bejelentkezett user" szabálya miatt a `/api/media/file/*` route mindig 403-at adott — a Next.js image-optimizer emiatt sosem tudta betölteni a partner logókat a publikus oldalon (törött kép ikon, senki nem vette észre). Javítva: `access: { read: () => true }`. Staging-en emellett egy második, kapcsolódó hibát is találtam: a médiafájl fizikai byte-jai elvesztek egy korábbi (a `media_data_staging` volume bevezetése előtti) konténer-újraépítéskor — az árva Media rekord törlésével és a migráció volume-mountolt konténerből való újrafuttatásával helyreállítva. Élesben ellenőrizve mindkét helyen (helyi dev + staging).
+2 -1
View File
@@ -28,7 +28,8 @@
"docker:dev:logs": "cd .. && docker-compose -f docker-compose.dev.yml logs -f app", "docker:dev:logs": "cd .. && docker-compose -f docker-compose.dev.yml logs -f app",
"docker:build": "docker build -t mozdit-app .", "docker:build": "docker build -t mozdit-app .",
"docker:run": "docker run -p 3000:3000 --env-file .env.local mozdit-app", "docker:run": "docker run -p 3000:3000 --env-file .env.local mozdit-app",
"migrate:content": "node --env-file=.env.local --import tsx scripts/migrate-content-to-payload.ts" "migrate:content": "node --env-file=.env.local --import tsx scripts/migrate-content-to-payload.ts",
"test:payload": "node --env-file=.env.local --import tsx scripts/test-payload-local-api.ts"
}, },
"dependencies": { "dependencies": {
"@payloadcms/db-mongodb": "^3.88.0", "@payloadcms/db-mongodb": "^3.88.0",
+134
View File
@@ -0,0 +1,134 @@
/**
* MITHOME-96 — Payload Local API integrációs teszt.
*
* Ez a "Local API integrációs tesztek" rész a ticketből: valódi, futó
* MongoDB-vel ellenőrzi, hogy a src/lib/payload-content.ts adapter-réteg
* ténylegesen jó alakú adatot ad vissza a Globals/Collections-ökből — nem
* mock-olt Payload-dal, hanem éles Local API hívásokkal.
*
* WHY sima node script és nem Jest teszt: a Payload csomag (és több
* függősége, pl. @payloadcms/richtext-lexical) ESM-only dist-et ad ki —
* Jest (a next/jest SWC transformjával is) alapból nem transzformálja a
* node_modules-t, így `import { getPayload } from 'payload'` egy Jest
* tesztben `SyntaxError: Cannot use import statement outside a module`-lel
* bukik (kipróbálva). A `transformIgnorePatterns` kiterjesztése a teljes
* Payload-függőségi fára törékeny és karbantartás-igényes lenne — ehelyett
* ugyanazt a bevált mintát követjük, mint a migrate-content-to-payload.ts /
* export-content-snapshot.ts scriptek: `node --import tsx`, valódi Node
* ESM-mel, semmilyen Jest-transzform nem kell.
*
* Futtatás (proto/ mappából, futó MongoDB-vel, migrált tartalommal):
* MONGODB_URI="mongodb://admin:password123@localhost:27018/mozdit?authSource=admin" \
* npm run test:payload
*/
import assert from 'assert/strict'
import { getPayload } from 'payload'
import config from '../src/payload.config'
import {
getCommonContent,
getHomeContent,
getAboutContent,
getServicesContent,
getContactContent,
getLegalPage,
getPartners,
} from '../src/lib/payload-content'
let passed = 0
async function test(name: string, fn: () => Promise<void>) {
try {
await fn()
passed++
console.log(`${name}`)
} catch (error) {
console.error(`${name}`)
throw error
}
}
async function run() {
const payload = await getPayload({ config })
await test('getCommonContent visszaad hu és en tartalmat', async () => {
const hu = await getCommonContent('hu')
const en = await getCommonContent('en')
assert.ok(hu.buttons.webmail, 'hiányzó hu webmail gomb szöveg')
assert.ok(en.buttons.webmail, 'hiányzó en webmail gomb szöveg')
})
await test('getHomeContent unwrap-eli a trustBullets és services.items.features tömböket', async () => {
const home = await getHomeContent('hu')
assert.ok(Array.isArray(home.hero.trustBullets))
assert.ok(home.hero.trustBullets.every((v) => typeof v === 'string'))
for (const item of home.services.items) {
assert.ok(Array.isArray(item.features))
assert.ok(item.features.every((v) => typeof v === 'string'))
}
})
await test('getAboutContent unwrap-eli a story és team paragraphs tömböket', async () => {
const about = await getAboutContent('hu')
assert.ok(Array.isArray(about.story.paragraphs))
assert.ok(Array.isArray(about.team.paragraphs))
})
await test('getServicesContent unwrap-eli a specs.items tömböket', async () => {
const services = await getServicesContent('hu')
for (const service of services.details.services) {
assert.ok(Array.isArray(service.specs.items))
}
})
await test('getContactContent visszaadja a form mezőket', async () => {
const contact = await getContactContent('hu')
assert.ok(contact.form.fields.email.label)
})
await test('getLegalPage megtalálja mindkét jogi oldalt', async () => {
const privacy = await getLegalPage('adatvedelem', 'hu')
const terms = await getLegalPage('hasznalati-feltetelek', 'hu')
assert.equal(privacy?.slug, 'adatvedelem')
assert.equal(terms?.slug, 'hasznalati-feltetelek')
})
await test('getPartners csak logóval rendelkező partnereket ad vissza', async () => {
const partners = await getPartners()
for (const partner of partners) {
assert.ok(partner.logo.url)
assert.ok(partner.name)
}
})
await test('create/findByID/delete ciklus működik (contact-submissions)', async () => {
const created = await payload.create({
collection: 'contact-submissions',
data: {
name: 'Local API Test',
email: 'local-api-test@example.com',
subject: 'MITHOME-96 Local API teszt',
message: 'Ez a rekord a test-payload-local-api.ts futása során jön létre és törlődik.',
gdprConsent: true,
status: 'new',
},
})
assert.ok(created.id)
const found = await payload.findByID({ collection: 'contact-submissions', id: created.id })
assert.equal(found.email, 'local-api-test@example.com')
await payload.delete({ collection: 'contact-submissions', id: created.id })
await assert.rejects(
payload.findByID({ collection: 'contact-submissions', id: created.id })
)
})
console.log(`\n${passed}/${passed} Payload Local API teszt zöld.`)
process.exit(0)
}
run().catch((error) => {
console.error('\nPayload Local API teszt sikertelen:', error)
process.exit(1)
})
+13 -9
View File
@@ -1,6 +1,10 @@
/** /**
* End-to-End tests for the Docker environment * End-to-End tests for the Docker environment
* These tests verify the full application flow in the Docker stack * These tests verify the full application flow in the Docker stack
*
* MITHOME-96: routes are locale-prefixed (/hu/..., /en/...) since the
* Payload CMS migration (MITHOME-91/114) — updated from the old unprefixed
* paths.
*/ */
describe('Docker E2E Tests', () => { describe('Docker E2E Tests', () => {
@@ -27,24 +31,24 @@ describe('Docker E2E Tests', () => {
expect(html).toContain('mozdIT Bt.') expect(html).toContain('mozdIT Bt.')
// Test navigation links exist in homepage // Test navigation links exist in homepage
expect(html).toContain('href="/rolunk"') expect(html).toContain('href="/hu/rolunk"')
expect(html).toContain('href="/szolgaltatasok"') expect(html).toContain('href="/hu/szolgaltatasok"')
expect(html).toContain('href="/kapcsolat"') expect(html).toContain('href="/hu/kapcsolat"')
// Test about page // Test about page
response = await fetch(`${APP_URL}/rolunk`) response = await fetch(`${APP_URL}/hu/rolunk`)
expect(response.status).toBe(200) expect(response.status).toBe(200)
html = await response.text() html = await response.text()
expect(html).toContain('Rólunk') expect(html).toContain('Rólunk')
// Test services page // Test services page
response = await fetch(`${APP_URL}/szolgaltatasok`) response = await fetch(`${APP_URL}/hu/szolgaltatasok`)
expect(response.status).toBe(200) expect(response.status).toBe(200)
html = await response.text() html = await response.text()
expect(html).toContain('Szolgáltatásaink') expect(html).toContain('Szolgáltatásaink')
// Test contact page // Test contact page
response = await fetch(`${APP_URL}/kapcsolat`) response = await fetch(`${APP_URL}/hu/kapcsolat`)
expect(response.status).toBe(200) expect(response.status).toBe(200)
html = await response.text() html = await response.text()
expect(html).toContain('Kapcsolat') expect(html).toContain('Kapcsolat')
@@ -210,9 +214,9 @@ describe('Docker E2E Tests', () => {
const pages = [ const pages = [
{ url: '', title: 'mozdIT Bt.' }, { url: '', title: 'mozdIT Bt.' },
{ url: '/rolunk', title: 'Rólunk' }, { url: '/hu/rolunk', title: 'Rólunk' },
{ url: '/szolgaltatasok', title: 'Szolgáltatásaink' }, { url: '/hu/szolgaltatasok', title: 'Szolgáltatásaink' },
{ url: '/kapcsolat', title: 'Kapcsolatfelvétel' } { url: '/hu/kapcsolat', title: 'Kapcsolat' }
] ]
for (const page of pages) { for (const page of pages) {
+31 -21
View File
@@ -1,6 +1,14 @@
/** /**
* Integration tests for the Docker development environment * Integration tests for the Docker development environment
* These tests run against the real services in the Docker stack * These tests run against the real services in the Docker stack
*
* MITHOME-96: updated for the Payload CMS migration (MITHOME-85 epic) —
* routes are now locale-prefixed (/hu/..., /en/...) and content lives in
* Payload collections/globals (`globals`, `legal-pages`, `partners`,
* `contact-submissions`), not the old raw `site_config`/`contact_submissions`
* Mongoose collections. Assumes the Docker dev DB already has content
* migrated (`npm run migrate:content`) — see docs/backups for a snapshot if
* you need to reseed a throwaway environment.
*/ */
import { MongoClient, ObjectId } from 'mongodb' import { MongoClient, ObjectId } from 'mongodb'
@@ -74,12 +82,16 @@ describe('Docker Environment Integration Tests', () => {
const collections = await mozditDb.listCollections().toArray() const collections = await mozditDb.listCollections().toArray()
const collectionNames = collections.map(c => c.name) const collectionNames = collections.map(c => c.name)
expect(collectionNames).toContain('site_config') // Payload Globals (Home/About/Services/Contact/Common) live in a
expect(collectionNames).toContain('contact_submissions') // single `globals` collection, one document per global.
expect(collectionNames).toContain('globals')
expect(collectionNames).toContain('legal-pages')
expect(collectionNames).toContain('partners')
expect(collectionNames).toContain('contact-submissions')
expect(collectionNames).toContain('users') expect(collectionNames).toContain('users')
}) })
it('should verify site config data exists', async () => { it('should verify the Home global exists and is published', async () => {
if (process.env.NODE_ENV === 'test' && !process.env.INTEGRATION_TESTS) { if (process.env.NODE_ENV === 'test' && !process.env.INTEGRATION_TESTS) {
return return
} }
@@ -90,15 +102,12 @@ describe('Docker Environment Integration Tests', () => {
} }
const mozditDb = mongoClient.db('mozdit') const mozditDb = mongoClient.db('mozdit')
const siteConfig = await mozditDb.collection('site_config').findOne() const home = await mozditDb.collection('globals').findOne({ globalType: 'home' })
if (!siteConfig) throw new Error('site_config document not found') if (!home) throw new Error('Home global document not found')
expect(siteConfig).toBeTruthy() expect(home).toHaveProperty('_status', 'published')
expect(siteConfig).toHaveProperty('type', 'site_config') expect(home).toHaveProperty('hero')
expect(siteConfig).toHaveProperty('environment', 'development') expect(home.hero).toHaveProperty('title')
expect(siteConfig).toHaveProperty('data')
expect(siteConfig.data).toHaveProperty('general')
expect(siteConfig.data.general).toHaveProperty('name', 'mozdIT Bt.')
}) })
it('should access Mongo Express UI', async () => { it('should access Mongo Express UI', async () => {
@@ -179,7 +188,7 @@ describe('Docker Environment Integration Tests', () => {
} }
const savedSubmission = await mongoClient const savedSubmission = await mongoClient
.db('mozdit') .db('mozdit')
.collection('contact_submissions') .collection('contact-submissions')
.findOne({ _id: new ObjectId(result.submissionId) }) .findOne({ _id: new ObjectId(result.submissionId) })
expect(savedSubmission).toEqual(expect.objectContaining({ expect(savedSubmission).toEqual(expect.objectContaining({
name: contactData.name, name: contactData.name,
@@ -256,7 +265,7 @@ describe('Docker Environment Integration Tests', () => {
const result = await response.json() const result = await response.json()
if (response.status === 400) { if (response.status === 400) {
expect(result).toHaveProperty('error', 'Spam gyanús tartalom észlelve') expect(result).toHaveProperty('error', 'Az üzenet spam gyanús tartalmat tartalmaz.')
} else if (response.status === 429) { } else if (response.status === 429) {
expect(result).toHaveProperty('error') expect(result).toHaveProperty('error')
expect(result.error).toContain('Túl sok') expect(result.error).toContain('Túl sok')
@@ -270,13 +279,14 @@ describe('Docker Environment Integration Tests', () => {
return return
} }
// MITHOME-91/114: bare "/" 307-redirects to "/hu" — fetch follows
// redirects by default, so this still lands on the real homepage.
const response = await fetch(DOCKER_SERVICES.app) const response = await fetch(DOCKER_SERVICES.app)
expect(response.status).toBe(200) expect(response.status).toBe(200)
const html = await response.text() const html = await response.text()
expect(html).toContain('mozdIT Bt.') expect(html).toContain('mozdIT Bt.')
expect(html).toContain('Megbízható web és emailszolgáltatás') expect(html).toContain('Megbízható web- és email szolgáltatás')
expect(html).toContain('Webmail Ugrás')
}) })
it('should load about page', async () => { it('should load about page', async () => {
@@ -284,7 +294,7 @@ describe('Docker Environment Integration Tests', () => {
return return
} }
const response = await fetch(`${DOCKER_SERVICES.app}/rolunk`) const response = await fetch(`${DOCKER_SERVICES.app}/hu/rolunk`)
expect(response.status).toBe(200) expect(response.status).toBe(200)
const html = await response.text() const html = await response.text()
@@ -297,14 +307,14 @@ describe('Docker Environment Integration Tests', () => {
return return
} }
const response = await fetch(`${DOCKER_SERVICES.app}/szolgaltatasok`) const response = await fetch(`${DOCKER_SERVICES.app}/hu/szolgaltatasok`)
expect(response.status).toBe(200) expect(response.status).toBe(200)
const html = await response.text() const html = await response.text()
expect(html).toContain('Szolgáltatásaink') expect(html).toContain('Szolgáltatásaink')
expect(html).toContain('Web Hosting') expect(html).toContain('Webtárhely')
expect(html).toContain('Email Szolgáltatás') expect(html).toContain('E-mail szolgáltatás')
expect(html).toContain('DNS Adminisztráció') expect(html).toContain('DNS adminisztráció')
}) })
it('should load contact page', async () => { it('should load contact page', async () => {
@@ -312,7 +322,7 @@ describe('Docker Environment Integration Tests', () => {
return return
} }
const response = await fetch(`${DOCKER_SERVICES.app}/kapcsolat`) const response = await fetch(`${DOCKER_SERVICES.app}/hu/kapcsolat`)
expect(response.status).toBe(200) expect(response.status).toBe(200)
const html = await response.text() const html = await response.text()
+7 -1
View File
@@ -237,7 +237,13 @@ export default function HomeView({ content: pageContent, partners, locale }: Hom
<p className="text-center mb-10" style={{ color: 'var(--color-foreground-muted)' }}> <p className="text-center mb-10" style={{ color: 'var(--color-foreground-muted)' }}>
{partnersCopy.subtitle} {partnersCopy.subtitle}
</p> </p>
<div className="flex flex-wrap justify-center items-center gap-10"> {/* WHY grid + w-fit + mx-auto: a felhasználó kérésére valódi
mátrix (max 3 oszlop), nem folyó flex-wrap. `w-fit` zsugorítja
a rácsot a tényleges (legfeljebb 3 oszlopnyi) tartalom
szélességére, a `mx-auto` pedig ettől tudja középre venni —
sima `inline-grid`-en az auto margó nem középre igazítana,
mert az egy inline-szintű doboz. */}
<div className="grid w-fit grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-10 justify-items-center mx-auto">
{partners.map((partner) => ( {partners.map((partner) => (
<a <a
key={partner.name} key={partner.name}
+145
View File
@@ -0,0 +1,145 @@
/**
* MITHOME-96 — Payload collection/global config tesztek.
*
* WHY nem a teljes payload.config.ts-t importáljuk: az a valódi `payload` és
* `@payloadcms/db-mongodb` csomagokat importálja értékként (nem csak
* típusként), amik ESM-only, natív node_modules-forrást futtatnak — Jest
* (a next/jest transzformmal is) nem tudja lefordítani őket anélkül, hogy a
* teljes payload-függőségi fát is a transformIgnorePatterns kivételévé
* tennénk (próbáltuk: `SyntaxError: Cannot use import statement outside a
* module` a payload csomag saját forrásából). Az egyes Collection/Global
* fájlok viszont csak `import type` formában hivatkoznak a `payload`
* csomagra — ez típus-only import, a build kitörli, így ezek a fájlok
* önmagukban, gyors unit tesztként importálhatók, élő MongoDB/PAYLOAD_SECRET
* nélkül. Ez fedi le a ticket "Payload config tesztek" részét; a Local API
* ellen futó, élő adatbázist igénylő tesztek külön (integrációs) fájlban
* vannak — lásd src/__tests__/payload-local-api.test.ts.
*
* Ezek a tesztek szándékosan regresszió-őrök is: mindkettő egy-egy valódi,
* élesben megtalált hibát rögzít (MITHOME-121: Media publikus olvasása,
* Partners.logo opcionalitása), hogy soha többé ne térjenek vissza észrevétlenül.
*/
import { Users } from './collections/Users'
import { LegalPages } from './collections/LegalPages'
import { Media } from './collections/Media'
import { Partners } from './collections/Partners'
import { ContactSubmissions } from './collections/ContactSubmissions'
import { Home } from './globals/Home'
import { About } from './globals/About'
import { Services } from './globals/Services'
import { Contact } from './globals/Contact'
import { Common } from './globals/Common'
type FieldLike = { name?: string; required?: boolean; type?: string }
function findField(fields: unknown[], name: string): FieldLike | undefined {
return (fields as FieldLike[]).find((f) => f.name === name)
}
describe('Payload collections', () => {
it('all collection slugs are present and unique', () => {
const slugs = [Users, LegalPages, Media, Partners, ContactSubmissions].map((c) => c.slug)
expect(slugs).toEqual(['users', 'legal-pages', 'media', 'partners', 'contact-submissions'])
expect(new Set(slugs).size).toBe(slugs.length)
})
describe('Media', () => {
// Regresszió-őr — MITHOME-121: a Media collection read access-e sokáig
// (MITHOME-89 óta) alapértelmezetten csak bejelentkezett usernek volt
// engedélyezett, emiatt a partner logók sosem töltődtek be a publikus
// oldalon (403 -> a Next.js image-optimizer "nem érvényes kép" hibája).
it('allows public (unauthenticated) read access', () => {
expect(Media.access?.read).toBeDefined()
const result = Media.access!.read!({ req: { user: null } } as never)
expect(result).toBe(true)
})
it('only accepts image uploads', () => {
expect(Media.upload).toEqual(expect.objectContaining({ mimeTypes: ['image/*'] }))
})
})
describe('Partners', () => {
it('requires name and url', () => {
expect(findField(Partners.fields, 'name')?.required).toBe(true)
expect(findField(Partners.fields, 'url')?.required).toBe(true)
})
// Regresszió-őr — MITHOME-121: a felhasználó kérésére a logo mező
// opcionálissá vált, hogy egy partner logó nélkül is menthető legyen.
it('does not require a logo', () => {
const logo = findField(Partners.fields, 'logo')
expect(logo).toBeDefined()
expect(logo?.required).not.toBe(true)
})
})
describe('ContactSubmissions', () => {
// WHY nincs egyedi access blokk itt tesztelve mint "hiányzik": a Payload
// defaultAccess (csak bejelentkezett user) itt a kívánt viselkedés —
// lásd a collection saját WHY-kommentjét. Nincs mit tesztelni rajta
// (nincs felülírás), de a mezőszerkezetet igen.
it('requires the core submission fields', () => {
for (const name of ['name', 'email', 'subject', 'message', 'gdprConsent']) {
expect(findField(ContactSubmissions.fields, name)?.required).toBe(true)
}
})
it('defaults status to "new"', () => {
const status = findField(ContactSubmissions.fields, 'status') as FieldLike & {
defaultValue?: string
options?: { value: string }[]
}
expect(status?.defaultValue).toBe('new')
expect(status?.options?.map((o) => o.value)).toEqual(['new', 'read', 'replied', 'archived'])
})
})
describe('LegalPages', () => {
it('has a required, unique slug field', () => {
const slug = findField(LegalPages.fields, 'slug') as FieldLike & { unique?: boolean }
expect(slug?.required).toBe(true)
expect(slug?.unique).toBe(true)
})
})
describe('Users', () => {
it('locks accounts after 5 failed attempts for 10 minutes', () => {
expect(Users.auth).toEqual(
expect.objectContaining({ maxLoginAttempts: 5, lockTime: 10 * 60 * 1000 })
)
})
it('requires an authenticated user for every access-controlled operation', () => {
const access = Users.access!
for (const op of ['create', 'read', 'update', 'delete', 'unlock'] as const) {
expect(access[op]!({ req: { user: null } } as never)).toBe(false)
expect(access[op]!({ req: { user: {} } } as never)).toBe(true)
}
})
})
})
describe('Payload globals', () => {
it('all global slugs are present and unique', () => {
const slugs = [Home, About, Services, Contact, Common].map((g) => g.slug)
expect(slugs).toEqual(['home', 'about', 'services', 'contact', 'common'])
expect(new Set(slugs).size).toBe(slugs.length)
})
it('Home does not duplicate the Partners collection', () => {
// MITHOME-89 döntés: a partnerek önálló collection-ök, a Home global
// szándékosan nem tartalmaz "partners" mezőt.
expect(findField(Home.fields, 'partners')).toBeUndefined()
})
it('Common.buttons.* fields are localized (MITHOME-110 bizonyíték)', () => {
const buttonsGroup = findField(Common.fields, 'buttons') as FieldLike & {
fields?: (FieldLike & { localized?: boolean })[]
}
expect(buttonsGroup?.fields?.length).toBeGreaterThan(0)
for (const field of buttonsGroup!.fields!) {
expect(field.localized).toBe(true)
}
})
})