# SPEC-COVERAGE-A10A11A12 — Phase 2D spec-fedés a Tartalom-ágra

**Dátum.** 2026.05.25 · **Phase.** 2D (folyamatban — Batch 1 lezárva)
**Hatókör.** A10 Hírek (`/hirek`) + A11 Programok (`/programok`) + A12 Városi információk (`/cityinfo`)
**Forrás.** `uploads/urbino-docs/00_domain_model.md` §4 (közös tartalmi váz §4.1 + `News` §4.2 + `Event` §4.3 + `CityInfo` §4.4) + `20_admin_felulet/60_tartalom.md` (teljes, v1.0).
**Screen-mock-ok.** `manager-system/preview/screens/a10-hirek-lista.html` · `a10-hirek-szerkeszto.html` · `a11-programok-lista.html` · `a11-programok-szerkeszto.html` · `a12-cityinfo-lista.html` · `a12-cityinfo-szerkeszto.html` (3 + 4 + 3 + 4 + 3 + 4 = **21 artboard**).

> **Spec-pre-history hivatkozás.** Az induló-prompt az **`FK-1`** (RichTextEditor mibenléte) helyét a `99_donesnaplo.md`-ben jelölte spec-szintű nyitott kérdésként; a valós elhelyezkedés a `03_implementacios_terkep.md` 6. szakasz nyitott-kérdés-táblája, és az **FK-1 a `60_tartalom` v1.0 lezárta** (§4.6 + 99_donesnaplo SD-69 + "PrimeNG Editor implementációs választás"). A `RichTextEditor` *pilot-szintű impl.* (D-13) az SD-69 whitelistjével konform, a PrimeNG Editorra-csere a HANDOFF.md hatáskörébe tartozik. Ezt a SPEC-FEEDBACK fejezet **emlékeztetőként** rögzíti (`FK-1 lezárás-megerősítő hivatkozás`-ként), NEM új SF-tételként.

> **Módszertan.** Forward pass (spec → screen, mező-szinten) + backward pass (screen → spec, UI-elemenként). A mock-doksi-réteg (`screen-header`, `DesignCanvas`, `DCArtboard` label, `State<X>` komponens) a backward-pass-on **kizárva** (`SCREEN-CONVENTIONS.md` §5). **AUDIT-2 megerősítés:** a Tartalom-ág **NEM tartalmaz inline-organism-pótlást** — mind a 6 új tartalom-ági organism (`ContentEditor`, `RichTextEditor`, `CoverImageUploader`, `PublishStateChip`, `DateTimeRangePicker`, `LinkValidator`) a screen-mockokban kanonikus API-jával rendererelt; az A11 `EventExtraFields` és A12 `CityinfoExtraFields` host-komponensek **NEM organism-pótlások**, hanem az `extraFields` prop kanonikus slot-fogyasztói (D-13 C-4 értelmében).
>
> **4 lista.** ✅ Spec + screen-en megvan · ⚠ Spec-ben van, screen-en nincs (hiányosság) · 🟡 Screen-en van, spec-ben nincs, DE D-X rögzíti (NEM UI-találmány) · 🔍 Screen-en van, spec-ben nincs, NEM dokumentált (UI-találmány). A `⚠` és `🔍` tételek **külön** szerepelnek a `SPEC-FEEDBACK.md` `## A10+A11+A12 spec-szelídítések` ági-fejezetében (SF-62-től).

---

## Batch-térkép

| Batch | Tartalom | Mezők / elemek | Státusz |
|---|---|---|---|
| **1** | A10 Hírek (lista 3 állapot + szerkesztő 4 állapot) — `News` 7 mező (incl. közös váz) + §3.2 9 végpont + §4.2 UI-szerződés 6 alszekció + D-17 publish-bar + D-13 ContentEditor split-view | 16 mező/végpont + 14 UI-blokk | **✓ lezárva** |
| **2** | A11 Programok (lista 3 állapot + szerkesztő 4 állapot) — `Event` 11 mező + §3.3 9 végpont + §4.3 UI-szerződés + D-15 DateTimeRangePicker | (iter 2) | folyamatban |
| **3** | A12 Városi információk (lista 3 állapot + szerkesztő 4 állapot) — `CityInfo` 9 mező + §3.4 9 végpont + §4.4 UI-szerződés + reorder + autocomplete + LinkValidator | (iter 2) | folyamatban |
| **4** | Cross-cutting: §4.1 közös váz `ContentStatus` állapotgép (SD-70) + §3.1.3 HTML-szanitizáció + delete-guard cross-screen-cluster + konszolidált statisztika | (iter 3) | folyamatban |

**Forrás-volument.** Phase 2D a Tartalom-ág, **2 spec-dokumentum** (`00_domain_model` §4 + `60_tartalom` v1.0) + **4 új SD spec-döntés** (`SD-68..71` content) + **3 D-X manager-system döntés** (`D-13` ContentEditor + organism-kiemelés, `D-15` DateTimeRangePicker, `D-17` publish-bar gomb-sorrend). **75 acceptance criterion** (`AC-N1` News-CRUD-borítókép + `AC-E1..3` Event-Create-Cover + `AC-C1..3` CityInfo-Create-Autocomplete-Reorder + `AC-T1..6` állapot-átmenetek + `AC-V1..3` validáció-szanitizáció + `AC-A1..6` admin-UI + `AC-J1..3` jogosultság + `AC-D1..3` delete-guard).

A Tartalom-ág **spec-prescriptív** (a `60_tartalom` v1.0 mezőszinten, FluentValidation-szinten és UI-szerződés-szinten is szigorú); a UI-találmány-kategória így **arányosan szűkebb** — de három **kritikus spec-konflikt** kiemelhető előzetesen:
1. **`News.pushOnPublish` szerkesztő-mező teljesen hiányzik a A10 szerkesztő-screenen** (⚠ #1, AC-N1.8 nincs lefedve)
2. **Az `Archived` állapot mind a 6 screenen vizuálisan abszens** — sem TabFilter, sem PublishStateChip-variáns, sem kebab-akció nincs rá (⚠ #2 cross-batch, érinti az AC-T3+T4+D-pattern teljes UI-tükrét)
3. **A12 lista LinkValidator-state badge minden soron** (per-row `valid`/`unreachable`) — ez **NEM** ekvivalens a spec §4.4.1 oszlopkészletével, **és** a `LinkValidator` API maga csak a szerkesztő-on-blur-hez van szánva (ORGANISMS.md). A cityinfo-lista *publish-state-chip nélküli, link-validator-state badge-dzsel-rendereléséről* sehol nincs D-X — 🔍 jelölt UI-találmány (lásd Batch 3).

---

# Batch 1 — A10 Hírek

**Spec-fedés.** `60_tartalom` §2.1 (`News.pushOnPublish` új mező) + §2.2 SD-69 (body HTML-tárolás) + §2.3 SD-68 (coverImageRef dedikált végpont) + §2.9 SD-70 ContentStatus + §3.2 (`NewsController` 9 végpont: T-1..T-9) + §4.2 (UI-szerződés 6 alszekció) + §4.5.2 i18n.

**Screen-mockok.**
- `a10-hirek-lista.html` — 3 állapot (1 `Mind` 9 hír · 2 `Vázlat` tab 2 függő · 3 First-time empty).
- `a10-hirek-szerkeszto.html` — 4 állapot (1 Új hír · 2 Vázlat szerkesztése · 3 Publikált szerkesztése · 4 Validation error).

**Organism-szerződés.**
- **Lista.** `AppShell` + `PageHeader` + `TabFilter` + `FilterPillBar` + `DataTable` + `PublishStateChip` (oszlop-cellán).
- **Szerkesztő.** `AppShell` + `PageHeader` + `ContentEditor kind="news"` (saját bekötés: `RichTextEditor` + `CoverImageUploader` + `PublishStateChip` + publish-bar) + host-rendelt `CitizenPreview` a `previewSlot`-on (D-13 C-4 split-view).

---

## Forward pass — `News` 7 mező + §3.2 9 végpont + §4.2 UI-szerződés

### ✅ Spec-ben + screen-en is megvan

| Spec-mező / végpont / UI-blokk | Spec-forrás | Screen-evidence |
|---|---|---|
| `News.id` | `00_domain_model` §4.2 | A10 lista `NEWS[*].id` (13..21); A10 szerkesztő `BackLink` `/hirek/{id}` URL-mintán. |
| `News.title` (string, max 200) | `00_domain_model` §4.2 + `60_tartalom` §4.2.5 mezősablon (max 200, "polgári app csempéjén megjelenő szöveg") | A10 lista `columns[1] 'Hír'` `TitleCell.a10-title__main`; A10 szerkesztő `ContentEditor` `Cím *` mező (`mgr-ce-field__input maxLength={120}` — lásd 🔍 #1 maxLength-eltérés). |
| `News.body` (HTML, szanitizáció + max 10 000, SD-69) | `00_domain_model` §4.2 + `60_tartalom` §2.2 + §3.1.3 (whitelist) + §4.2.5 | A10 szerkesztő `ContentEditor` `Tartalom *` mező `RichTextEditor` ([B] [I] U lista link toolbar, FK-1 pilot-szint, SD-69-konform tag-szett); a szerkesztő `PRESET_BODY` mock kifejezetten az SD-69-whitelist tagjeivel él (`<strong>`, `<ul>`, `<li>`, `<a href="...">`). |
| `News.coverImageRef` (SD-68 "egyedi-fájl-mező") | `00_domain_model` §4.2 + `60_tartalom` §2.3 + §3.2.8-9 + §4.2.5 | A10 szerkesztő `ContentEditor showCover={true}` → `CoverImageUploader` `onUpload` + `onDelete` callback-bekötés a dedikált POST/DELETE végpontokhoz. `value.coverImageMeta` `{ filename, size, uploadedAt }` triplet a StatePublished mock-on. |
| `News.contentStatus` enum `Draft` / `Published` (a 3-ból 2) | `00_domain_model` §4.1 + `60_tartalom` §2.9 (T1, T2 átmenetek) | A10 lista `PublishStateChip state='draft' \| 'published'` minden soron (`columns[2] 'Állapot'`); A10 szerkesztő `PublishStateChip` a `PageHeader.actions`-ben minden artboardon. *(A 3. enum-érték `Archived` hiányzik — lásd ⚠ #2.)* |
| `News.publishedAt` (DateTime?, T1 mellékhatás) | `00_domain_model` §4.1 + `60_tartalom` §2.9 T1+T4 mellékhatás-tábla | A10 lista `columns[3] 'Publikálva'` `PublishedCell` `mono`-formátum (`'2026.05.20'`); `state='draft'` esetén `'—'` placeholder. A10 szerkesztő `CitizenPreview.ct-preview__date` `isPublished ? publishedAt : 'Még nincs publikálva'`. |
| `News.pushOnPublish` (bool, default `false`, SD-68+2.1) — **csak a list-mock-on, nem a szerkesztő-screenen** | `00_domain_model` §4.2 + `60_tartalom` §2.1 + §4.2.5 mezősablon + AC-N1.8 | A10 lista mock-data (`NEWS[*]`) **a `pushOnPublish` mezőt egyáltalán nem hordozza**, de a §4.2.1 `TableStateConfig.columns[4]` `pushOnPublish` oszlopát `visible: false` adja — egyezőleg a screen nem rajzol pushOnPublish-cellát ✅. **A szerkesztő-screen-en az `pushOnPublish` mező-renderelés viszont teljesen hiányzik — ⚠ #1**, AC-N1.8 lefedés-hiány. |
| `createdAt` / `createdBy` audit (`AuditableEntity`, SD-23 megerősítés) | `00_domain_model` §4.1 SD-23 + `60_tartalom` §3.2.1 NewsDto `createdAt`+`createdByName` | A10 lista `columns[4] 'Szerző'` `row.author` "Nagy Réka" / "Tóth Béla" — **alapból látható (`visible: true`)**, miközben a spec `TableStateConfig.columns[5] createdByName` `visible: false`-ot ír (📌 backward-pass deviation — 🔍 #2). |
| **T-1 `GET /v1/news`** — lista, default `contentStatus.in=Draft,Published` (Archived rejtett) | `60_tartalom` §3.2.2 | A10 lista State 1 (Mind tab) 9 hír mind `Draft` vagy `Published` — `Archived` rekord-szintű mock egyetlen sorban sincs. Konzisztens a spec default-szűrésével ✅. |
| **T-1** szűrhető szempontok: `contentStatus`, `pushOnPublish`, `publishedAt`, `createdAt`, `title.contains` | `60_tartalom` §3.2.2 | A10 lista `FilterPillBar.filters = [{Szerző: 'Bárki'}, {Borítókép: 'Bármi'}, {Időszak: 'Bármikor'}]` + `searchPlaceholder="Keresés cím vagy szöveg alapján…"` — **a `contentStatus` szűrő a tab-szűrőben (TabFilter)** van *(lásd 🟡 #1)*; a `publishedAt` és `createdAt` dateRange szűrők az "Időszak" pill mögé absztrahálva ✅; a `title.contains` a search-mezőn ✅. *(`pushOnPublish` és `Borítókép` szűrő részleges — lásd 🔍 #3 + 🔍 #4.)* |
| **T-1** rendezés: `createdAt` (default desc) | `60_tartalom` §3.2.2 | A10 lista `DataTable sortKey="publishedAt" sortDir="desc"` — **`publishedAt` és NEM `createdAt`** a default. *Spec-eltérés* — lásd ⚠ #4. |
| **T-3 `POST /v1/news`** create-szerződés (`Draft` hard-coded, `contentStatus`/`publishedAt`/`coverImageRef` tiltott a POST-on) | `60_tartalom` §3.2.4 | A10 szerkesztő `StateNew` `value={ publishState: 'draft', title: '', body: '', coverImageUrl: null }` — kezdő-állapot `Draft`-as ✅; a `ContentEditor.value` formátum NEM tartalmaz `contentStatus`-mezőt mint UI-szerkeszthető (jogosan, a spec szerint `field_not_editable` lenne) ✅. |
| **T-4 `PUT /v1/news/{id}`** szerkesztés bármely állapotban (Draft + Published + Archived mind szerkeszthető) | `60_tartalom` §3.2.5 | A10 szerkesztő `StatePublished` (StatePublished artboard 3) — *"Publikálva — minden módosítás azonnal megjelenik..."* literál + a `ContentEditor` ugyanazokat a mezőket rendereli `state='published'`-on, mint `state='draft'`-on (egyetlen disabled-modifier nincs) ✅. *(Archived szerkeszthetőség UI-tükre hiányzik — ⚠ #2 része.)* |
| **T-4** optimista konkurrencia `expectedUpdatedAt` (SD-32) | `60_tartalom` §3.2.5 | A `ContentEditor.value`-formátum nem ír `expectedUpdatedAt`-et explicit; a `lastSavedLabel="utoljára mentve 14:32"` szöveges-utalás a frontend autosave-konvenciójára. **Spec-szintű DTO-szerződés**, UI-tükre kontextuális ✅ (az Angular-portoláskor a `PUT`-payload generálódik). |
| **T-4** `field_not_editable` mezők `400 fieldErrors`-szal (`contentStatus`, `publishedAt`, `coverImageRef`, `createdBy`, `createdAt`) | `60_tartalom` §3.2.5 | A10 szerkesztő `StateValidationError` (artboard 4) `fieldErrors={ title: '...', coverImage: '...' }` — a `ContentEditor.fieldErrors` prop ekvivalens a `400 fieldErrors`-szerződéssel; az AC-N2.3-N2.5 tiltott-mező-hibák UI-tükre a `mgr-ce-field--error` osztály ✅. |
| **T-7 `POST /v1/news/{id}/cover-image`** multipart upload | `60_tartalom` §3.2.8 + AC-N3.1 | `CoverImageUploader.onUpload(file)` callback-bekötés. *MIME / méret-validáció* (`AC-N3.2-N3.4`) host-felelősség — az organism-szerződés `uploadError` propot adja vissza, a `value.coverImageMeta` `{filename, size}` hordozza a sikeres upload-eredményt ✅. |
| **T-8 `DELETE /v1/news/{id}/cover-image`** idempotens | `60_tartalom` §3.2.9 + AC-N3.7-3.8 | `CoverImageUploader.onDelete` callback (StatePublished mock-on) — a "Borítókép eltávolítása"-button a kanonikus mintán ✅. |
| **§4.2.4 Editor mock-layout**: `Borítókép szekció` → `Cím *` → `Tartalom *` (rich-text) → publish-bar | `60_tartalom` §4.2.4 ASCII mock | A10 szerkesztő `ContentEditor editorPane` (`content-editor.jsx:67-149`): `CoverImageUploader` → `Cím *` mező → `extraFields` slot (üres news-en) → `RichTextEditor` → publish-bar. ✅ Sorrend-konzisztens. |
| **§4.2.5 Cím mezősablon** ("polgári app csempéjén megjelenő szöveg") | `60_tartalom` §4.2.5 | `mgr-ce-field__hint` *"A polgári app csempéjén megjelenő szöveg. Max 120 karakter."* — szándék-konform, **de a `120` literal-érték ≠ spec `200`** — lásd 🔍 #1. |
| **§4.2.5 Tartalom (rich-text) mezősablon** + RTE-toolbar (B/I/lista/link) | `60_tartalom` §4.2.5 + §4.6 (PrimeNG Editor) | A `RichTextEditor` organism a pilot-szinten (FK-1 lezárás) ezt valósítja meg — D-13 nyomán Tier-3 organism, az SD-69 whitelistet kliens-oldalon **NEM erőlteti** (a szerver az igazság, §3.1.3 *"a kliens a szerver válaszát fogadja el"* mintán) ✅. |
| **§4.2.5 `pushOnPublish` mezősablon** (jelölőnégyzet + súgó: `content.news.field.pushOnPublish.help`) | `60_tartalom` §4.2.5 + §4.5.2 i18n + AC-N1.8 | **⚠ #1 — hiányzik a szerkesztő-screenről**, lásd lent. |
| **§4.2.6 állapot-átmenet UI**: "Publikálás ▾" dropdown a state-érzékeny menüvel | `60_tartalom` §4.2.6 (Draft → Publikálás · Published → Archiválás / Visszavonás vázlatba · Archived → Újrapublikálás) | A `ContentEditor.publish-bar` egy publishCta-button-t rajzol (`Publikálás → / Publikálás frissítése →`) — **nem dropdown**, és az archive/unpublish/republish akciók a szerkesztő-screenen sehol nem érhetők el — ⚠ #3. |

### ⚠ Spec-ben van, screen-en nincs — hiányosság

#### ⚠ #1 — **`News.pushOnPublish` szerkesztő-mező TELJESEN hiányzik** *(KRITIKUS)*
- **Spec.** `60_tartalom` §2.1 új mező, `00_domain_model` §4.2 mezőtáblába felvéve, AC-N1.8 explicit kötelezi: *"Given a kérés `pushOnPublish = true`, When POST, Then 201, `News.pushOnPublish == true`"*. §4.2.4 ASCII-mockja explicit rajzolja: *"[✓] Push-értesítés a publikáláskor"* az Audit szekció felett. §4.2.5 mezősablon: jelölőnégyzet + súgó-szöveg `content.news.field.pushOnPublish.help` *("Bekapcsolva értesítést küld a polgárok telefonjára...")*. §4.5.2 i18n-kulcs `content.news.field.pushOnPublish` definiálva. §4.5.5 megerősítő-dialog két változata: `confirm.publish` és `confirm.publishWithPush` (az utóbbi explicit említi a push-küldést).
- **Screen.** A10 szerkesztő `value`-szerződés mind a 4 állapot-mockon: `{ publishState, title, body, coverImageUrl, [coverImageMeta], [publishedAt] }` — **`pushOnPublish` mező sem a value-on, sem renderelt jelölőnégyzetként a 4 artboard egyikén sem szerepel**. A `ContentEditor.editorPane` (`content-editor.jsx:67-149`) JSX-e nem rendereli a `pushOnPublish`-checkboxot — sem `kind='news'`-feltételesen, sem általánosan.
- **Hatás.** A News-specifikus push-tényt **a tartalomkezelő nem tudja beállítani**; az AC-N1.8 acceptance criterion **UI-tükre teljesen hiányzik**; a két variant publikálási-dialógus (`confirm.publish` vs `confirm.publishWithPush`) lehetősége elveszik; és a polgári mobilapp NY-T1 push-átviteli minta input-kontraktja a manager-oldalon megsérül.
- **Döntés.** **JAVÍTANDÓ** (kanonikus organism-bővítés). A `ContentEditor` `kind="news"`-feltételesen renderelje a `pushOnPublish` checkboxot az `extraFields`-slot előtt vagy a publish-bar fölött (a §4.2.4 ASCII-mock explicit pozíciója a Tartalom + Audit között van). Új `value.pushOnPublish: boolean` mező a `ContentEditor` value-szerződésében. SPEC-FEEDBACK **SF-62** (organism-szerződés-bővítés + mock-state-pótlás).

#### ⚠ #2 — **`Archived` állapot UI-tükre teljesen hiányzik mind a 3 listán + 3 szerkesztőn** *(cross-batch, A10+A11+A12)*
- **Spec.** `00_domain_model` §4.1 + `60_tartalom` §2.9 (SD-70) a háromállapotú `ContentStatus` enumot rögzíti — `Draft` / `Published` / **`Archived`**. §3.2.2 default-szűrés `contentStatus.in=Draft,Published` az `Archived`-et **rejti**, de **"Archív megjelenítése" checkbox a szűrőben** (§4.5.1 i18n `content.common.filter.showArchived`). §4.2.2 kebab-menü `Archived` állapot esetén "Szerkesztés / Újrapublikálás / Törlés" akciókat rajzol. T4 átmenet (`Archived → Published`) az AC-T4 kritérium. §4.5.1 i18n `content.common.status.Archived` definiálva.
- **Screen.** A10 lista `TABS = [{Mind, Publikált, Vázlat}]` — Archived tab nincs; `PublishStateChip` állapot-variantja `'draft' \| 'published'` (a `publish-state-chip.jsx` organism CSS-e is csak `.mgr-pub-chip--draft` és `.mgr-pub-chip--published` modifiert hordoz, *"3-állapotos publikálási státusz-chip"* helyett **2-állapotos** ORGANISMS.md-rögzítéssel); semmilyen "Archív megjelenítése" checkbox vagy "Archív" tab nincs. A10 szerkesztő StatePublished mock `headerDesc` *"Publikálva — minden módosítás azonnal megjelenik..."* — Archived szerkesztő-mock nincs. Hasonló helyzet az A11-lista (`TABS = [{Közelgő, Lezajlott, Vázlat, Mind}]` — még a `Lezajlott` is *időpont-derivált* (`when='past'`), NEM contentStatus-Archived!) és az A12-lista (semmilyen status-tab vagy archive-toggle nincs, sőt **a `PublishStateChip` per-soron sem renderelt**).
- **Hatás.** A három AC-T átmenet (T3 `Published → Archived` és T4 `Archived → Published`) UI-tükre **vizuálisan és funkcionálisan teljesen hiányzik**. A §4.2.2 spec-szerinti Archived-kebab-akciók ("Újrapublikálás", "Törlés Archivedről") elérhetetlenek. Az AC-A1 ("checkbox hozzáadja Archived-et a szűrőhöz") szerinti tesztelhetőség elveszik.
- **Döntés.** **JAVÍTANDÓ** (cross-screen). A `PublishStateChip`-et **3-állapotos**-ra bővíteni (`.mgr-pub-chip--archived` + új CSS-token-pár `--u-slate-100`/`--u-slate-700` alapon); a 3 lista `TabFilter`-eire egy `archived` opcionális tab vagy a §4.5.1-konform "Archív megjelenítése" checkbox a `FilterPillBar`-ba; legalább 1 új `StateArchived` szerkesztő-artboard (A10 vagy A11 vagy A12). SPEC-FEEDBACK **SF-63** (cross-cutting; mock-state-pótlás + organism-bővítés).

#### ⚠ #3 — **Állapot-átmenet UI (kebab-menü + Publikálás-dropdown) sehol nem renderelt** *(KRITIKUS, AC-A2 vs AC-T1-T6 UI-tükre)*
- **Spec.** `60_tartalom` §4.2.1 `TableStateConfig.rowActions` 6 akciója (`edit`, `publish`, `unpublish`, `archive`, `republish`, `delete`) `visible(row)` predikátummal — a **kebab-menü-szerződés** explicit. §4.2.2 kebab-menü 3 állapot-érzékeny akció-szettje (Draft / Published / Archived). §4.2.6 a szerkesztő-screen-en "Publikálás ▾" **dropdown**: Draft-on "Publikálás" + megerősítő-dialógus, Published-on "Archiválás" + "Visszavonás vázlatba" sub-akciók, Archived-on "Újrapublikálás". AC-A2 ("Kebab-menü állapot-érzékeny akciók a 4.2.2 szerint"), AC-T1-T6 hat acceptance criterion mind erre épül.
- **Screen.** A10 lista `DataTable.columns` 5 oszlop (`cover`/`title`/`state`/`publishedAt`/`author`) — **`actions`-oszlop NINCS**, `onRowClick={() => {}}` no-op (sor-klikk a szerkesztőre szándéka, de a kebab-affordancia hiányzik). A10 szerkesztő `ContentEditor.editorPane` publish-bar **3 egyszerű gombot** rajzol (D-17 sorrendben: `[Eldobás]` · `[Vázlat-mentés]` `[Publikálás → / Publikálás frissítése →]`) — **a "Publikálás" gomb NEM dropdown**, és sem "Archiválás", sem "Visszavonás vázlatba", sem "Újrapublikálás" akciók a szerkesztőből elérhetők. A `transition`-végpont (`T-9 POST /v1/news/{id}/transition`) UI-tükre **mind a 6 admin-flow közül 4-en hiányzik** (T2 unpublish, T3 archive, T4 republish nincs UI-affordancia; csak T1 publish van).
- **Hatás.** AC-T1-T6 állapot-átmenet UI-tesztelhetősége teljesen elveszik. A `60_tartalom` 4 átmenetből (T1+T2+T3+T4) UI-szinten **csak T1 működik** (Draft → Published). A pilot-tartalomkezelő egy publikált hírt sem tud archiválni, sem vázlatba visszavonni — funkcionálisan blokkolódik.
- **Döntés.** **JAVÍTANDÓ** (kanonikus organism-bővítés). (a) A10/A11/A12 lista `DataTable.columns`-ra `actions`-oszlop a `IconKebab` triggerrel; a kebab-popover állapot-érzékeny akció-szettjét a §4.2.2 spec-szerződés szerint. (b) A `ContentEditor.publish-bar` Publikálás-gombját **dropdown-affordanciára** bővíteni `state='published'`-on ("Archiválás" + "Visszavonás vázlatba" + "Publikálás frissítése"), `state='archived'`-on "Újrapublikálás" gombbal felülírni a Vázlat-mentés-Publikálás gomb-párt. SPEC-FEEDBACK **SF-64** (kebab + dropdown bővítés-csomag).

#### ⚠ #4 — Lista default-rendezés `publishedAt desc` ≠ spec `createdAt desc`
- **Spec.** `60_tartalom` §3.2.2 *"Rendezés: `createdAt` (default desc), `publishedAt`, `title`, `updatedAt`"* — a `createdAt` az explicit default. A `TableStateConfig.defaultSort = { field: 'createdAt', direction: 'desc' }` §4.2.1.
- **Screen.** A10 lista `StateAll` `<DataTable sortKey="publishedAt" sortDir="desc">`. A `StateDrafts` `sortKey="updatedAt"`-ra vált (egyébként logikus, mert vázlatoknál `publishedAt` `null`).
- **Hatás.** A `Draft`-rekordok `publishedAt = null` értékükkel a lista végén csoportosulnak (nem időrendben), ami a tartalomkezelőnek a vegyes-állapot Mind-tabon zavaró. A spec szándéka: a legutóbb létrehozott hír legyen elöl, függetlenül attól, hogy már publikálta-e.
- **Döntés.** **JAVÍTANDÓ** (mock-korrekció). `StateAll` `sortKey="createdAt" sortDir="desc"` — a mock-adat `createdAt`-mező kiegészítésével. SPEC-FEEDBACK **SF-65** (mock-korrekció).

#### ⚠ #5 — Bulk-akciók (`bulkPublish`/`bulkArchive`/`bulkDelete`) UI-tükre nincs
- **Spec.** `60_tartalom` §4.2.1 `TableStateConfig.bulkActions = [bulkPublish, bulkArchive, bulkDelete]`; §4.2.3 *"Bulk publikálás: csak Draft-ot publikál; megerősítő dialógus jelzi a vegyes batchet. Bulk archiválás: csak Published-et. Bulk törlés: kliens előszűr; szerver atomi guard (3.2.7)."* AC-A3 és AC-D2 acceptance criterionok.
- **Screen.** A10 lista `DataTable` selectable-affordancia (sor-checkbox) nincs, bulk-actionbar a tábla fölött nincs, vegyes-batch-megerősítő-dialógus mock nincs. Az AUDIT-2 cross-batch megerősíti: a 6 tartalom-ági listán egyetlen bulk-műveleti UI sincs mockolva.
- **Hatás.** AC-A3 + AC-D2 + AC-D3 acceptance criterionok UI-tesztelhetősége elveszik.
- **Döntés.** **HANDOFF.md átadási megjegyzés** + opcionális mock-bővítés. Alacsonyabb prioritás mint ⚠ #1-#3 (pilot-volumenen — néhány tucat tétel — a bulk-műveletek kevésbé használt funkciók). SPEC-FEEDBACK **SF-66** (mock-state-pótlás opcionális, HANDOFF megjegyzéssel).

#### ⚠ #6 — Karakterszámláló (`1247 / 10000`) a `body` mezőhöz hiányzik
- **Spec.** `60_tartalom` §4.2.5 *"Karakterszámláló: a szerkesztő alatt, '1247 / 10000'; 10 001-nél piros, Mentés letiltott."* §4.6 *"karakterszámláló a szerkesztő alatt egy egyszerű directive-vel"*. AC-A6 acceptance criterion: "5000 / 10000 semleges; 10001 piros, Mentés letiltott".
- **Screen.** A `RichTextEditor` organism (`rich-text-editor.jsx` — D-13 pilot-szintű) sem `maxLength`-propot, sem char-count-displayt nem rendereli. A `ContentEditor.mgr-ce-field__hint` *"Bold, italic, underline, lista, link. Nincs cím-szint vagy kép-beágyazás."* literal-hintet ad, char-count helyett.
- **Döntés.** **JAVÍTANDÓ** (organism-bővítés). `RichTextEditor.maxLength = 10000` prop + `charCount`-counter a toolbar jobb-szélén vagy a komponens alján. `value.length > 10000`-nél piros + a `ContentEditor.publish-bar` Publikálás+Vázlat-mentés gombokat disable. SPEC-FEEDBACK **SF-67** (organism-bővítés, AC-A6 UI-tükre).

#### ⚠ #7 — Audit szekció ("Létrehozta / Módosította") a szerkesztő-screenen nincs
- **Spec.** `60_tartalom` §4.2.4 ASCII-mock explicit: *"Audit / Létrehozta: Gergő Kondor — 2026.05.18 14:32 / Módosította: Gergő Kondor — 2026.05.20 09:15"* két különálló sorral a publish-bar fölött, divider-rel.
- **Screen.** A10 szerkesztő `ContentEditor` az audit-mezőket sehol nem rendereli. A `lastSavedLabel="utoljára mentve 14:32"` a `mgr-editor__col-header`-ben utalás-szöveg, **de NEM** a §4.2.4 ASCII-szerinti audit-két-soros blokk.
- **Hatás.** A `createdByName` és `updatedByName` (NewsDto-mezők) sehol a szerkesztőben nem láthatók — a tartalomkezelő (vagy egy peer) a "ki módosította utoljára"-kérdést a szerkesztő-screenen nem tudja megválaszolni.
- **Döntés.** **JAVÍTANDÓ** (organism-bővítés). `ContentEditor.value.audit = { createdByName, createdAt, updatedByName, updatedAt }` mezőcsoport, a publish-bar fölött divider-rel és kétsoros megjelenítéssel. SPEC-FEEDBACK **SF-68** (organism-bővítés).

#### ⚠ #8 — Borítókép-feltöltés "új tételen letiltott az első mentésig" UI-szabály
- **Spec.** `60_tartalom` §4.2.5 mezősablon `coverImageRef`: *"Új hír esetén (még nincs `id`): a feltöltő-gomb LE VAN TILTVA az első mentésig (SD-60 logó-mintával konzisztens). Súgó: 'Először mentsd el a hírt.'"* AC-A5 *"új hír űrlapján a feltöltő-gomb le van tiltva az első mentésig; mentés után aktiválódik"*.
- **Screen.** A10 szerkesztő StateNew (artboard 1) `CoverImageUploader` aktívan rendererelt (a `value.coverImageUrl = null`-os állapotban a drop-zone interaktív). A "Először mentsd el a hírt" hint-szöveg sehol nem jelenik meg.
- **Hatás.** AC-A5 acceptance criterion UI-tükre hiányzik; a tartalomkezelő egy létrehozás-előtti hírre próbálhat borítóképet tölteni, ami a backend-en `404 News not found`-dal hiúsulna.
- **Döntés.** **JAVÍTANDÓ** (organism-bővítés). `CoverImageUploader.disabled` prop + a `ContentEditor` `kind="news"`-en `disabled={!value.id}` ekvivalens állítás. SPEC-FEEDBACK **SF-69** (organism-bővítés, alacsony prioritás).

### 🟡 Screen-en van, spec-ben nincs, DE D-X rögzíti

| Screen-elem | Hol jelenik meg | D-X hivatkozás |
|---|---|---|
| **#1 `contentStatus` szűrő tab-szűrőként** (Mind/Publikált/Vázlat) ahelyett, hogy `FilterPillBar` multiselect lenne | A10 lista `TabFilter` | **D-13 részleges fedés** — a `TabFilter` Tier-2 organism cross-screen mintája (`SITEMAP.md` szerint A1+A5+A8 esetén is tab-szűrőként renderel státusz-mezőt). A spec §4.2.1 `TableStateConfig.columns[2].filterable = { type: 'multiselect', defaultValue: ['Draft', 'Published'] }`-pal multiselect-szűrőt ír, de a cross-screen tab-szűrő-konvenció felülírja. Konzisztens. |
| **#2 D-17 publish-bar gomb-sorrend** ([Eldobás] bal · spacer · [Vázlat-mentés][Publikálás] jobb) | A10 szerkesztő `ContentEditor.publish-bar` mind a 4 artboardon | **D-17 explicit rögzíti** (`DECISIONS.md:820-855`). NEM UI-találmány. |
| **#3 ContentEditor split-view** (bal: szerkesztő, jobb: élő polgári-app preview telefon-keretben) | A10 szerkesztő `previewSlot` mind a 4 artboardon `CitizenPreview` mock-kal | **D-13 C-4 explicit rögzíti** (`ORGANISMS.md:356` *"split-view (C-4): ha a previewSlot prop ki van töltve, a host adhat egy élő előnézet-pane-t"*). NEM UI-találmány. |
| **#4 ContentEditor `kind="news"` organism-héj + 6 új tartalom-ági organism** | A10 szerkesztő-organism-szerződés | **D-13 explicit rögzíti** (`DECISIONS.md:630` Tier-3 organism-kiemelés). |
| **#5 `RichTextEditor` pilot-szintű impl. + SD-69-whitelist-konform toolbar** ([B]/[I]/lista/link) | A10 szerkesztő `Tartalom *` mező | **D-13 + FK-1 lezárás** (`ORGANISMS.md:491`) — pilot-szint, PrimeNG Editorra-csere a HANDOFF.md hatáskörében. |
| **#6 PublishStateChip 2-állapotos** (draft / published) | A10 lista + szerkesztő | **D-13 organism-kiemelés** (`ORGANISMS.md:377` *"2-állapotos publikálási státusz-chip"*) — **de a spec §2.9 3-állapotos**, ezért 🟡 alatt **csak részlegesen indokolt** — a 3. állapot Archived-bővítés ⚠ #2 javításával 🟡-ról ✅-ra mozdul. |
| **#7 `CoverImageUploader` 16:9 aspect ratio + drop-zone/preview/Csere-Eltávolítás 2-állapot** | A10 szerkesztő `Borítókép szekció` | **D-13 + SD-60 (LogoUploader-minta)** (`ORGANISMS.md:507`) — *"mintája a LogoUploader (D-11), de szélesebb aspect-ratio-val"*. |
| **#8 Thumbnail-row pattern Q1=B** (96×54 px `a10-thumb` minden soron) | A10 lista `columns[0] 'Kép'` `ThumbCell` | **S12 explorer döntés** — a `screen-header__refs` literal `Döntések: Q1=B thumbnail-row (S12)`. **Nincs formális D-X rögzítés**, de a screen-header `Spec`-meta `60_tartalom §3.2`-re hivatkozik, mert a spec §4.2.1 első oszlopa explicit `cellType: 'thumbnail'` — **fedett**. ✅ átminősíthető. |
| **#9 First-time empty literal-szöveg ("Még nincs egyetlen hír sem.")** | A10 lista State 3 `.a10-empty` | **`60_tartalom` §4.5.6 i18n részleges fedés** — a spec `content.empty.news.title = "Még nincs hír."`, a screen "Még nincs egyetlen hír sem." literal eltér, de ekvivalens-szándék. A "Kezdj egy üdvözlő hírrel..." description-szöveg a spec-konform `content.empty.news.description = "Készítsd el az első hírt..."` szándékával harmonizál. |

### 🔍 Screen-en van, spec-ben nincs, NEM dokumentált — UI-találmány

#### 🔍 #1 — `Cím *` mező `maxLength={120}` ≠ spec `max 200`
- **Hol.** `content-editor.jsx:91` `<input maxLength={120}>` + a `mgr-ce-field__hint` literal: *"Max 120 karakter."*
- **Spec.** `00_domain_model` §4.2 `News.title: string max 200`; `60_tartalom` §4.2.5 mezősablon: *"Validáció: nem üres trim után; max 200"*; §3.2.4 `CreateNewsRequestValidator`: *"`MaximumLength(200)`"*.
- **Hatás.** A tartalomkezelő egy 121-200 karakteres címet kliens-oldalon nem tud rögzíteni, miközben a szerver elfogadná. A polgári app csempéje 200 karakteres címnél optikailag is működhet (a CSS-szintű line-clamp megoldja).
- **Döntés.** **JAVÍTANDÓ** — `maxLength={200}` + hint *"Max 200 karakter."* (vagy a literal-szándékhoz közelebbi *"A polgári app csempéjén megjelenik. Max 200 karakter."*). SPEC-FEEDBACK **SF-70** (mock-korrekció + organism-konstans-frissítés a `ContentEditor`-on; valószínűleg az A11 `Helyszín` szabad-szöveg `maxLength={120}` szintén külön ellenőrzendő — lásd Batch 2).

#### 🔍 #2 — A10 lista `Szerző` oszlop `visible: true` ≠ spec `visible: false`
- **Hol.** A10 lista `columns[4] 'Szerző'` ("Nagy Réka" / "Tóth Béla") `defaultSortDir: 'asc'`, **alapból látható**.
- **Spec.** `60_tartalom` §4.2.1 `TableStateConfig.columns[5] 'createdByName'` `visible: false` — a `createdByName` oszlop a settings-menüből aktiválható, de **alapból rejtett**.
- **Hatás.** A pilot-tenant alapnézete tartalmaz egy oszlopot, amit a spec szerint rejtenie kellene. Nem hibás funkcionálisan, de a default-élmény eltér.
- **Döntés.** **MOCK-KORREKCIÓ** vagy **SPEC-SZELÍDÍTÉS** — a `Szerző` oszlop alapból látható-választás indoklása: a kis-tenantnál (1-2 tartalomkezelő) a "ki írta?" gyakran látandó info. Indokolt visible-default-szelídítés a `60_tartalom` §4.2.1-be. SPEC-FEEDBACK **SF-71** (spec-szelídítés vagy mock-korrekció).

#### 🔍 #3 — A10 lista `Borítókép` filter-pill (`{Borítókép: 'Bármi'}`) ≠ spec `pushOnPublish` szűrő
- **Hol.** A10 lista `FilterPillBar.filters[1] = {key: 'cover', label: 'Borítókép', value: 'Bármi'}`.
- **Spec.** §3.2.2 lista-szűrők: `contentStatus`, `pushOnPublish`, `publishedAt`, `createdAt`, `title.contains`. **A `coverImageRef`-szűrő nem szerepel a spec listájában.** A `pushOnPublish` (boolean filter) szerepel — viszont a screen nem rendereli.
- **Hatás.** A push-küldést kapott híreket (volumetric audit-szempontból fontos!) a vezető nem tudja szűrni; helyette egy nem-spec-igazolt `coverImageRef`-szűrőt kap.
- **Döntés.** **MOCK-KORREKCIÓ**. A `Borítókép`-pill törlendő; helyette `Push`-pill (`{key: 'push', label: 'Push', value: 'Bármi'}`) a spec §3.2.2 alapján. SPEC-FEEDBACK **SF-72** (mock-korrekció).

#### 🔍 #4 — A10 lista State 3 empty-state `📰` emoji + State 2 mock `🖼️` thumbnail-emoji
- **Hol.** A10 lista State 3 `.a10-empty__icon` `<div>📰</div>` (60×60 kék-tinted blokk); thumbnail-cell `<div className="a10-thumb">🖼️</div>` minden cover-os soron.
- **Design-system.** A DS guide *"No emoji in product UI"* tiltást ír (csak két kivétel: report-kategória + home-greeting wave 👋). Az empty-state-ben a DS guide a `logo-mark.svg`-t engedi ("empty-state hero for the manager dashboard"). A thumbnail-cellán a spec mock-adat `coverImageUrl` URL-ből kép-renderelést vár (`a10-thumb__img`-ekvivalens), nem unicode-glyph-et.
- **Hatás.** DS guide-megsértés (tone-of-voice). Mock-szintű, de a HANDOFF.md fejlesztő-kontaktusnál félreérthető.
- **Döntés.** **MOCK-KORREKCIÓ**. (a) Empty-state `📰` → `logo-mark.svg` vagy a Lucide `newspaper` ikon (csak mock-ban — éles `EmptyState` organism-mintán). (b) Thumbnail-emoji `🖼️` → `<img src={row.coverImageUrl}>`-ekvivalens placeholder + CSS-aspect (`url('placeholder.svg')` 16:9 mintán). SPEC-FEEDBACK **SF-73** (mock-korrekció).

#### 🔍 #5 — A10 szerkesztő `CitizenPreview` "Még nincs publikálva" literal + `'2026.05.22'` hard-coded fallback
- **Hol.** A10 szerkesztő `CitizenPreview.ct-preview__date`: `{isPublished ? (publishedAt || '2026.05.22') : 'Még nincs publikálva'}` + *"· Balatonalmádi Városgondnokság"*.
- **Spec.** A polgári-app preview a 60_tartalom hatókörén kívül van (§5 "polgári mobilapp adatigénye" csak DTO-szerződést ír, render-mintát nem). A "Még nincs publikálva" literal **NEM** szerepel a `60_tartalom` §4.5.* i18n-fában — a szándékhoz közeli `content.cityInfo.url.openInNewTab` és `content.empty.news.title` mindkettő más kontextusú. A "Balatonalmádi Városgondnokság" hardkódolt tenant-fasor-szöveg.
- **Hatás.** A preview UI-találmány, **de** a D-13 C-4 "élő polgári-app preview" elve a `previewSlot` prop bevezetésével rögzítette **a host-rendelt preview pane szabadon-bemehetőségét**. A literal-szövegek és a render-stílus host-szintű — NEM a `ContentEditor` organism contractja.
- **Döntés.** **DÖNTÉS-STÁTUSZ NUANCE.** A `CitizenPreview` mint **host-szintű preview-renderer** D-13 C-4 alá esik (🟡); a literal-szövegei és a tenant-fasor *"Balatonalmádi Városgondnokság"* viszont **NEM dokumentált** — UI-találmány a host szintjén. A HANDOFF.md-ben **átadási megjegyzés** ("a preview-renderer host-felelősség, a polgári adatigény-spec véglegesíti az i18n-szövegeket"). SPEC-FEEDBACK **SF-74** (átadási megjegyzés, alacsony prioritás).

#### 🔍 #6 — A10 szerkesztő StateValidationError `headerDesc` literal *"Két mezőt jelölt hiányosnak a szerver."*
- **Hol.** A10 szerkesztő State 4 `PageHeader.description`: *"Két mezőt jelölt hiányosnak a szerver. Javítsd a jelzéseket."* + `fieldErrors.title` *"A cím legalább 8 karakter legyen — a polgári app csempéjén így olvasható."* + `fieldErrors.coverImage` *"Borítókép kötelező a publikáláshoz."*
- **Spec.** §4.8 hibaállapot-mintát rögzíti — *"Mezőszintű (400 fieldErrors): mező alatt i18n-fordítás. Globális (409 stale, invalid_transition): toast / banner."* §4.5.5 i18n hibakulcsai konkrét i18n-kulcsokat adnak (`field_not_editable`, `must_be_https`, `file_too_large`...) — **a "Két mezőt jelölt hiányosnak..."-szerű generikus banner-szöveg NEM** szerepel a spec hibakulcsai között. A spec FluentValidation-szintű mezőszintű hibákat ír (`fieldErrors.title` szöveg-tartalma `null`/`field_not_editable`/i18n-kulcs).
- **Hatás.** A banner-literal a mock-szintű narratívához tartozik; a tényleges Angular-render i18n-kulcsokat fog használni (pl. *"A címnek legalább 8 karakteresnek kell lennie"* a `content.news.error.title.tooShort` kulcson). A *"Borítókép kötelező a publikáláshoz"* literal-érték **funkcionális spec-eltérés**: a spec szerint a `coverImageRef` **opcionális** (`O`), nincs explicit "kötelező a publikáláshoz" szabály.
- **Döntés.** **MOCK-KORREKCIÓ + SPEC-SZELÍDÍTÉS-JELÖLT.** (a) A *"Borítókép kötelező a publikáláshoz"* `fieldErrors.coverImage` literal-érték **valószínűsíthetően spec-szelídítés-szándék**: a tartalomkezelő-élményhez egy borítóképes-hírek-vezető-UX előny lenne. Ez a `60_tartalom` §4.2.5 mezősablon-bővítésébe kerülhet (`coverImageRef` opcionális → "publikáláshoz erősen javasolt, publikálás-előtti warning"). (b) A *"Két mezőt jelölt hiányosnak..."*-banner-literal mock-szintű, az Angular-port i18n-keys-en — átadási megjegyzés. SPEC-FEEDBACK **SF-75** (kettős: spec-szelídítés-javaslat + mock-narratív megjegyzés).

#### 🔍 #7 — A `Eldobás` button-felirat ≠ spec `Visszavonás` (publish-bar gomb-szöveg)
- **Hol.** `content-editor.jsx:130` `<button>Eldobás</button>` (D-17 publish-bar bal-szélén).
- **Spec.** `60_tartalom` §4.2.4 ASCII-mock: *"Állapot: [Draft Badge]    [Visszavonás] [Mentés] [Publikálás ▾]"* — a destruktív akció felirata **"Visszavonás"** (≠ "Eldobás").
- **Hatás.** Tone-of-voice eltérés. A "Visszavonás" undo-szerű, kifejezőbb; az "Eldobás" eldobott-vázlat-szerű, drámaibb. A tone-of-voice guide (TONE-OF-VOICE.md) *"Direct, not circumlocutory. One sentence = one thought."*-elve mindkettőt megengedi, de a spec-felirat formálisabb.
- **Döntés.** **MOCK-KORREKCIÓ** (ha a literal-szöveget szigorúan vesszük) **VAGY SPEC-SZELÍDÍTÉS** (ha a "Eldobás" tartalom-kezelői-szempontból kifejezőbb). A "Visszavonás" konfliktálhat a `content.action.unpublish = "Visszavonás vázlatba"` i18n-kulccsal — ez egy másik action ugyanazon szóval. SPEC-FEEDBACK **SF-76** (spec-szelídítés-javaslat: **"Eldobás" megerősítése a spec-be**, hogy elkerüljük a "Visszavonás" kétértelmű használatát).

---

## Backward pass — A10 szerkesztő `CitizenPreview` + lista state-specifikus elemek

A backward-pass az A10 szerkesztő és lista screen-mock UI-elemeit végigveszi és minden elemet besorol ✅ / 🟡 / 🔍 valamelyikébe (a ⚠ kategória forward-pass-only). A mock-doksi-réteg (`screen-header`, `DesignCanvas`, `DCArtboard`, `State<X>`) `SCREEN-CONVENTIONS.md` §5 szerint kizárva.

| UI-elem | Hol | Besorolás + spec-/D-X-hivatkozás |
|---|---|---|
| `BackLink` "Vissza a hírek listájához" arrow-left ikonnal | A10 szerkesztő `mgr-page-header` fölött | ✅ — a `01_kozos_mintak` "adatlap visszanyíló" konvenciója; cross-screen pattern (A1/A5/A7/A8 adatlapokon is). |
| `PageHeader` title `"Új hír" / "Hír szerkesztése"` + description | A10 szerkesztő | ✅ — `60_tartalom` §4.2 routing-konvenció + Tier-0 `PageHeader` cross-screen. |
| `PageHeader.actions` slot `PublishStateChip` | A10 szerkesztő | ✅ — D-13 organism-szerződés `PublishStateChip` (Tier-3). |
| `ContentEditor` 2-oszlopos grid (1.1fr / 1fr) | A10 szerkesztő minden artboard | 🟡 — **D-13 C-4 split-view** (`mgr-editor` CSS-grid; 980px-en mobil-collapse). |
| `mgr-editor__col-header` "Szerkesztő" cím + `PublishStateChip` + `lastSavedLabel "utoljára mentve 14:32"` | A10 szerkesztő bal-oszlop felül | 🔍 — lásd 🔍 #5 (lastSavedLabel literal-szöveg). A "Szerkesztő"-label nem rögzített D-X-ben, de a split-view két-oszlopát disambiguálja. SPEC-FEEDBACK **SF-77** (átadási megjegyzés: a oszlop-cím a `ContentEditor` belső organism-konstansa). |
| `CitizenPreview` cím "Polgári app — élő előnézet" + meta "a polgárok így fogják látni" | A10 szerkesztő jobb-oszlop felül | 🟡 — **D-13 C-4 host-rendelt preview-renderer**; a literal-szövegek host-felelősség (lásd 🔍 #5). |
| `CitizenPreview.ct-preview__device` telefon-keret (notch + body + cover + title + date + body-text) | A10 szerkesztő jobb-oszlop | 🔍 — host-rendelt UI-találmány. **NEM** dokumentált D-X-en; a D-13 C-4 csak a `previewSlot`-szerződést rögzíti, a render-stílust (telefon-keret + 22 px notch + 8 px border-color #1f2937) a host (a10-hirek-szerkeszto.html) szabadon választotta. SPEC-FEEDBACK **SF-78** (átadási megjegyzés: device-frame minta starter-projekt-konvenció). |
| `CitizenPreview.ct-preview__crumbs` "Hírek › Új hír" | jobb-oszlop felül | 🔍 — host-szintű mock-literal, polgári-app-render mintát feltételez. SF-78 alá olvasztva. |

**Backward-pass következtetés (A10).** 9 UI-elem mappelve; a `ContentEditor` belső szerkesztő-elemei (`mgr-ce-field`, `mgr-editor__pub-bar`) mind D-X-fedett (D-13 + D-17). A `CitizenPreview` host-rendelt preview teljes-egészében 🔍 (UI-találmány), de **D-13 C-4 a `previewSlot` slot-szerződését rögzíti** — a host-szintű render-stílus szabadsága dokumentált.

---

## Batch 1 összefoglaló

| Kategória | Tételszám |
|---|---|
| ✅ Spec + screen-en megvan | **22** (16 mező/végpont + 6 UI-blokk) |
| ⚠ Spec-ben van, screen-en nincs | **8** (1 KRITIKUS `pushOnPublish`, 1 KRITIKUS `Archived`-állapot, 1 KRITIKUS kebab+dropdown, 5 közepes-alacsony) |
| 🟡 Screen-en van, D-X rögzíti | **9** (D-13 + D-17 cluster) |
| 🔍 Screen-en van, NEM dokumentált | **7** (4 mock-korrekció, 2 host-szintű preview-stílus, 1 spec-szelídítés-javaslat) |
| **Összesen** | **46 mező/végpont/UI-elem** |

**SPEC-FEEDBACK ági-fejezet (előzetes Batch 1 tervezet):** SF-62 (pushOnPublish), SF-63 (Archived cross-cutting), SF-64 (kebab+dropdown), SF-65 (default-sort), SF-66 (bulk-actions HANDOFF), SF-67 (char-counter), SF-68 (Audit szekció), SF-69 (cover-disabled), SF-70 (title maxLength), SF-71 (Szerző oszlop default-visible), SF-72 (Push filter-pill), SF-73 (emoji-csere), SF-74 (CitizenPreview literal-szöveg), SF-75 (cover-kötelező + banner-literal), SF-76 (Eldobás vs Visszavonás), SF-77 (Szerkesztő-oszlop-cím), SF-78 (device-frame minta).

**A Batch 1 KRITIKUS-3 hatás összegzése:**
- ⚠ #1 (pushOnPublish) — `News`-specifikus mező a 60_tartalom kötelezőként rögzítve; UI-tükre **abszolút hiányzik**. **Az AC-N1.8 acceptance criterion nem tesztelhető**.
- ⚠ #2 (Archived) — **cross-batch** (A10+A11+A12); a `PublishStateChip` 2 vs 3-állapotos eltérése organism-szintű deficit; 4 AC (T3+T4+D-pattern+A1-archived-checkbox) UI-tükre megsemmisül.
- ⚠ #3 (kebab + dropdown) — **4 állapot-átmenetből 3 elérhetetlen** a UI-n; T2+T3+T4 funkcionálisan blokkolva.

**Phase 3 prioritás:** ⚠ #1-#3 a HANDOFF.md "P0 organism-szerződés-bővítés" szakaszba; ⚠ #4-#8 a "P1 mock-pótlás + organism-bővítés"-be; 🔍 #1-#7 a SPEC-FEEDBACK.md spec-csapat-jóváhagyási-cikluson keresztül.

---

# Batch 2 — A11 Programok (`Event`)

**Spec-fedés.** `60_tartalom` §2.4 (`Event.startsAt`/`endsAt` formális reláció) + §3.3 (`EventsController` 9 végpont T-10..T-18, News-szal 94%-ban azonos) + §4.3 (UI-szerződés — News-eltéréssel) + `00_domain_model` §4.3 (11 mező).

**Screen-mockok.**
- `a11-programok-lista.html` — 3 állapot (1 `Közelgő` 5 program · 2 `Mind` 8 program vegyes közelgő+lezajlott · 3 First-time empty).
- `a11-programok-szerkeszto.html` — 4 állapot (1 Új program · 2 Vázlat azonos-napos · 3 Publikált többnapos · 4 Validation error).

**Organism-szerződés.** Ua. mint A10, **plus** `DateTimeRangePicker` (D-15 same-day-hint) az `extraFields`-slot-on `EventExtraFields` host-komponens via `ContentEditor kind="event"`.

---

## Forward pass — `Event` 11 mező + §3.3 9 végpont + §4.3 UI-szerződés

### ✅ Spec-ben + screen-en is megvan

| Spec-mező / végpont / UI-blokk | Spec-forrás | Screen-evidence |
|---|---|---|
| `Event.id`, `title` (max 200), `body` (HTML SD-69), `coverImageRef` (SD-68), `contentStatus`, `publishedAt` | `00_domain_model` §4.3 + `60_tartalom` §3.3, §2.2, §2.3 | A11 lista `EVENTS[*]` mock-rekordok + `columns[0..4]`; A11 szerkesztő `ContentEditor kind="event"` ugyanazokat a `value`-mezőket fogyasztja, mint News (`title`, `body`, `coverImageUrl`, `coverImageMeta`, `publishedAt`, `publishState`). **News-ekvivalens fedés** — a Batch 1 ✅ tételei ide is áthordnak. |
| `Event.startsAt` (UTC, kötelező, múltbeli megengedett) | `00_domain_model` §4.3 + `60_tartalom` §2.4 + §3.3.3 + §4.3.2 mezősablon | A11 lista `columns[2] 'Időpont'` `TimeCell` (font-display + mono-bontás `date / time` két sorra); A11 szerkesztő `DateTimeRangePicker.value.startAt` mező + mock-érték `new Date('2026-06-20T14:00')` (StatePublishedMultiDay) / `'2026-05-24T17:00'` (StateDraftSameDay). |
| `Event.endsAt` (opcionális, `≥ startsAt` ha kitöltött, FluentValidation `ends_at_before_starts_at`) | `00_domain_model` §4.3 + `60_tartalom` §2.4 + `CreateEventRequestValidator` | A11 szerkesztő `DateTimeRangePicker.value.endAt` mező + StateValidationError mock-on `endAt: '2026-06-07T10:00'` < `startAt: '2026-06-07T18:00'` + `fieldErrors.dateRange = "A vége korábbi mint a kezdés..."` literal-szöveg ekvivalens a spec `ends_at_before_starts_at` i18n-kulcsával. |
| `Event.locationText` (opcionális, max 300, placeholder `"Pl. Városháza, nagyterem"`) | `60_tartalom` §4.3.2 mezősablon + i18n `content.event.field.locationText.placeholder` | A11 szerkesztő `EventExtraFields` `Helyszín *` mező `<input maxLength={120}>` + `placeholder="Pl. \"Hősök tere\" vagy \"Városháza díszterem\""` — **a `maxLength={120}` ≠ spec `300`, és a label `*` kötelezőként jelöli, ≠ spec opcionális** — lásd ⚠ #1 + 🔍 #1. |
| **T-10 `GET /v1/events`** — lista + `startsAt`/`endsAt` szűrő-extension | `60_tartalom` §3.3.2 | A11 lista `FilterPillBar.filters = [{Időszak: 'Bármikor'}, {Állapot: 'Bármi'}]` — Időszak-pill mögé absztrahálva a `startsAt.gte` + `startsAt.lte` dateRange-szűrő ✅. |
| **T-12 `POST /v1/events`** — create-szerződés (`Draft` hard-coded, koordináta-páros validáció) | `60_tartalom` §3.3.3 | A11 szerkesztő StateNew `value={publishState: 'draft', startAt: null, endAt: null, location: '', ...}` ✅. |
| **§4.3.1 `startsAt + endsAt` cellaformázás** "Csak startsAt: `2026.06.15 18:00`" / "Azonos nap: `2026.06.15 18:00–22:00`" / "Különböző nap: `... → ...`" | `60_tartalom` §4.3.1 | A11 lista `TimeCell`: `sameDay ? \`${time}–${endTime}\` : \`${time} →\``; multi-day esetén `<> {row.endAt}</>` második sorral. **Implementáció-konform** ✅. *(A "Nyitott végű: `2026.06.15 18:00–`" eset — `endsAt=null` — a mock-on nem szerepel, mert mind a 8 program `endAt` kitöltött; alacsony prioritás mock-hiány.)* |
| **§4.3.2 Helyszín szabad szöveg** | `60_tartalom` §4.3.2 mezősablon | `EventExtraFields` `Helyszín` szöveges input ✅; a `mgr-ce-field__hint` *"Szabad szöveg. A polgári app térkép-pin nélkül, csak szöveggel mutatja."* literal-szövege D-13 C-4 host-szintű szabad fogalmazás. |
| **§4.5.3 i18n `content.event.*`** kulcs-tár (`title`, `body`, `startsAt`, `endsAt`, `locationText`, `confirm.*`) | `60_tartalom` §4.5.3 | A `ContentEditor.kind="event"` label-eket és `EventExtraFields` mező-labeleket mappel; **a `confirm.pastDate "A megadott időpont a múltban van. Folytatás?"` literal-szabály a screen-en nincs implementálva** — lásd ⚠ #3. |

### ⚠ Spec-ben van, screen-en nincs — hiányosság

#### ⚠ #1 — **`Event.latitude` / `longitude` páros + "Térkép megnyitása" link TELJESEN hiányzik a szerkesztő-screenről**
- **Spec.** `00_domain_model` §4.3 `latitude` + `longitude` opcionális decimális mezők, **páros validációval** (`coordinates_must_be_both_or_neither`, AC-E1.5-1.6); `60_tartalom` §4.3.2 mezősablon: *"`latitude`/`longitude` — Helyszín koordinátája: opcionális, páros ('együtt vagy egyik sem'); két szám-input; alatta 'Térkép megnyitása' link (Google Maps új lap); beágyazott térkép-szelektor iterációs (NY-T2)."* i18n `content.event.field.latitude`, `longitude`, `openMap`.
- **Screen.** A11 szerkesztő `EventExtraFields` csak `DateTimeRangePicker` + `Helyszín` (locationText) mezőket renderel — **`latitude`/`longitude` input-páros teljesen hiányzik**, és a "Térkép megnyitása"-link sehol nem jelenik meg. A `value` szerződés mockja `{ startAt, endAt, location }` — koordináta-mezők sem a value-on, sem a `EventExtraFields`-JSX-en nem szerepelnek.
- **Hatás.** AC-E1.5-1.9 öt acceptance criterion (koordináta-páros + koordináta-tartomány-validáció) UI-tükre teljesen hiányzik; a polgári app térkép-megjelenítési igénye (`screen_kezdooldal_*` térkép) tartalomkezelő-oldali input-kontraktja megsérül. A spec `NY-T2 iterációs` flag ellenére a **két szám-input + Térkép megnyitása link** a pilot-szándék része.
- **Döntés.** **JAVÍTANDÓ** (kanonikus organism-bővítés). A `EventExtraFields` host-komponensbe (vagy a `ContentEditor extraFields`-slot-on) `latitude` + `longitude` szám-input-páros (`type="number" step="any"`) + alatta szöveges link *"Megnyitás térképen"* a `https://www.google.com/maps/?q={lat},{lng}` URL-mintán. A `fieldErrors.coordinates` és `fieldErrors.latitude`/`longitude` mezőszintű hiba-render. SPEC-FEEDBACK **SF-79** (host-komponens bővítés + új mock-state).

#### ⚠ #2 — **`Event.locationText` `maxLength={120}` ≠ spec `300`** (és a label `*` kötelezőként jelölve ≠ spec opcionális)
- **Spec.** `00_domain_model` §4.3 + `60_tartalom` §3.3.3 + §4.3.2: *"`locationText`: opcionális, max 300"*. FluentValidation: `RuleFor(x => x.locationText).MaximumLength(300).When(x => x.locationText != null)`.
- **Screen.** `EventExtraFields` `<input maxLength={120}>` + label `Helyszín <span className="mgr-ce-field__label-req">*</span>` (a `*` a `mgr-ce-field__label-req` osztály a `Cím *`-mintán). A StateValidationError-on a `fieldErrors.location = "Helyszín kötelező"` literal-szöveg **mintha kötelező lenne** — ami a spec ellen.
- **Hatás.** 121-300 karakteres helyszín-szöveg kliens-oldalon nem rögzíthető; a "Helyszín kötelező" literal-jelzés ütközik az opcionális spec-meghatározással.
- **Döntés.** **JAVÍTANDÓ** (mock + host-komponens-korrekció). `maxLength={300}` + label `*` jelölés eltávolítása + `fieldErrors.location` mock-érték másra. SPEC-FEEDBACK **SF-80** (mock-korrekció).

#### ⚠ #3 — **`content.event.confirm.pastDate "A megadott időpont a múltban van. Folytatás?"` figyelmeztetés-dialógus nincs implementálva**
- **Spec.** `60_tartalom` §4.3.2 mezősablon `startsAt`: *"figyelmeztetés: 'A megadott időpont a múltban van. Folytatás?'"* + §4.5.3 i18n `content.event.confirm.pastDate`.
- **Screen.** A `DateTimeRangePicker` organism (`date-time-range-picker.jsx`) `startAt` mező past-date-validációt nem hordoz; a `EventExtraFields` host-komponens sem renderel `<ConfirmDialog kind="warning">` overlay-t a publikálás-előtti past-date-detekciónál. Egyetlen artboard sem demonstrálja a past-date state-et.
- **Hatás.** Új program rögzítésekor a múltbeli `startsAt` figyelmeztetés-nélkül publikálható (a spec szerint a múltbeli megengedett, AC-E1.11, de UX-vetülete confirmation-szerű).
- **Döntés.** **JAVÍTANDÓ** (host-komponens + új mock-state). A `EventExtraFields` past-date-detektort + a `ContentEditor.onPublish` előtti `ConfirmDialog kind="warning"`-hookkal. Új 5. artboard `StatePastDateWarning` opcionálisan. SPEC-FEEDBACK **SF-81** (host-komponens + mock-state).

#### ⚠ #4 — A11 lista `endsAt` (rejtett oszlop) + `locationText` (rejtett oszlop) settings-menüből aktiválhatóság UI-tükre nincs
- **Spec.** `60_tartalom` §4.3.1 lista-szerződés `columns[+]`: `startsAt` (default desc), `endsAt` (`visible: false`), `locationText` (`visible: false`). A DataTable settings-menüből az `endsAt` és `locationText` oszlopot a vezető aktiválhatja.
- **Screen.** A11 lista `columns` 5 oszlopot definiál (`cover`/`title`/`startAt`/`state`/`publishedAt`) — **`endsAt` és `locationText` mint külön oszlopok egyáltalán nem szerepelnek**, és a `DataTable` settings-menü-affordancia (oszlop-toggle) sehol nem renderelt. Az `endsAt` információ a `TimeCell` második-során beágyazva (`sameDay ? \`${time}–${endTime}\``), a `locationText` a `TitleCell.__loc` sub-során.
- **Hatás.** A spec-szerinti oszlop-kontraktusból 2 mező hiányzik mint külön-aktiválható szelekció. Pilot-volumenen alacsony hatás (a kombinált TitleCell + TimeCell jól olvasható), de a kanonikus `TableStateConfig` szerződéssel inkonzisztens.
- **Döntés.** **DÖNTÉS-STÁTUSZ NUANCE.** A kombinált-cella UX-szempontból **jobb** mint a kanonikus 5+2 oszlop-szétdarabolás; a spec-szelídítés-javaslat: a `TableStateConfig.columns`-ban `locationText`-cell explicit a `title`-oszlopba olvasztva (mint `cellType: 'titleWithLocation'`), és `endsAt`-cell a `startsAt`-oszlopba (`cellType: 'dateRange'`). SPEC-FEEDBACK **SF-82** (spec-szelídítés-javaslat: cellType-bővítés).

### 🟡 Screen-en van, spec-ben nincs, DE D-X rögzíti

| Screen-elem | Hol jelenik meg | D-X hivatkozás |
|---|---|---|
| **#1 D-15 `DateTimeRangePicker` két-input minta (Pattern A)** + "azonos napon" detektor + hint-sor | A11 szerkesztő `EventExtraFields.DateTimeRangePicker` | **D-15 explicit rögzíti** (`DECISIONS.md:731-770`). NEM UI-találmány. A StateDraftSameDay mock (`2026.05.24 17:00 – 19:00`) demonstrálja a `mgr-dtp__same-day-hint` "Azonos napon · 2026. máj. 24. szombat, **17:00–19:00**" sorát. |
| **#2 `ContentEditor split-view + previewSlot`** (CitizenPreview telefon-kerettel + `📅 naptári blokk` + `📍 helyszín blokk`) | A11 szerkesztő mind a 4 artboardon | **D-13 C-4 (`previewSlot` slot-szerződés)** — host-szintű preview-render-stílus szabadsága dokumentált. A naptári-blokk-renderelés (`ct-preview__when` primary-soft háttér + 36×36 px `📅 ikon-kör`) host-felelősség, az SF-78 átadási megjegyzés-cluster része. |
| **#3 D-17 publish-bar gomb-sorrend** + **D-13 ContentEditor organism-héj** + `extraFields`-slot | A11 szerkesztő `ContentEditor kind="event"` | **D-13 + D-17 — Batch 1 ekvivalens** (lásd Batch 1 🟡 #2-4). |
| **#4 `PublishStateChip 2-állapotos`** | A11 lista `columns[3] 'Állapot'` + A11 szerkesztő `PageHeader.actions` | **D-13** organism-kiemelés (Batch 1 🟡 #6 cross-screen). 3. állapot Archived ⚠ #2 cross-batch hiányosság. |

### 🔍 Screen-en van, spec-ben nincs, NEM dokumentált — UI-találmány

#### 🔍 #1 — A11 lista `TimeCell` `today` / `soon` / `future` / `past` színkód-modifierek + `when` derived-mező
- **Hol.** `TimeCell.a11-time-cell--today` (amber `var(--u-amber-700)`); `a11-time-cell--soon` (primary blue); `a11-time-cell--past` (opacity 0.55); a `row.when` mock-mező az `EVENTS[*]`-en `'soon'`/`'today'`/`'future'`/`'past'` enum-értékkel.
- **Spec.** `00_domain_model` §4.3 + `60_tartalom` §3.3 + §4.3.1 — **`Event` entitáson `when` mező nincs**; a derived-érték kliens-szintű számolás lehetne (`startsAt - now() < 24h ? 'today' : ...`). A spec a `startsAt`/`endsAt` font-emelést és színkódolást **nem** említi.
- **Hatás.** Színkód-konvenció (today=amber, soon=blue, past=opacity) UI-szándékon alapuló döntés; az amber a DS-ben az "in-progress" státusz-szín (`--u-status-folyamatban-*`), ami szemantikai-overload kockázat.
- **Döntés.** **SPEC-SZELÍDÍTÉS-JELÖLT** (új D-X vagy spec §4.3.1 cellType-bővítés). Az időpont-fókuszú lista (S14 explorer rögzíti a screen-headerben) a programok-vezetői élmény-szempont — a derived-időkód lehet `cellType: 'eventTimeWithProximity'` cellrenderer. SPEC-FEEDBACK **SF-83** (spec-szelídítés vagy mock-korrekció).

#### 🔍 #2 — A11 lista 4-tab szűrő (`Közelgő` / `Lezajlott` / `Vázlat` / `Mind`) — **`Lezajlott` derived (`when='past'`), NEM `contentStatus`**
- **Hol.** A11 lista `TABS = [{Közelgő: upcoming-count}, {Lezajlott: past-count}, {Vázlat: drafts-count}, {Mind: total-count}]`. A `Lezajlott` filter-szabálya: `EVENTS.filter(e => e.when === 'past')` — *idő-derivált*, NEM contentStatus-derivált.
- **Spec.** §4.3.1 lista-szerződés `contentStatus`-szűrő (Draft/Published/Archived multiselect) + `startsAt` dateRange — **a Közelgő/Lezajlott szétválasztás nem említve**. A spec-szerinti tab-szűrő (Batch 1 🟡 #1 cross-screen) `contentStatus`-szerű kellene lenni.
- **Hatás.** A Lezajlott + Vázlat tabok ortogonális dimenziókra vágnak (idő-derivált + status-derivált): egy `published` és `past` rekord a Lezajlott-on jelenik meg, egy `draft` és `past` rekord a Vázlat-tabra szorul, miközben a tartalomkezelő-szándékkal a Vázlat = idő-független, a Lezajlott = csak publikált+past lenne logikus. A 4 tabos szűrés-szettel a vezető vegyes-szempontú szűrést kap.
- **Döntés.** **SPEC-SZELÍDÍTÉS** vagy **MOCK-KORREKCIÓ**. Két javaslat: (a) `Közelgő` + `Lezajlott` mint `startsAt`-szűrő-pill (FilterPillBar-ban), a TabFilter `[Mind / Publikált / Vázlat]`-mintán mint A10 (Batch 1 🟡 #1 konzisztens); (b) explicit megerősítés a `60_tartalom` §4.3.1-ben, hogy a `Közelgő`/`Lezajlott` derived-szűrő-tab (pl. `cellType: 'eventTimeProximityTab'`). SPEC-FEEDBACK **SF-84** (spec-szelídítés-javaslat).

#### 🔍 #3 — A11 lista `Mind`-tabon a Lezajlott-sorok `a11-row--dim` halványítása
- **Hol.** A11 lista `StateAll` `<DataTable rowClassName={dimPast}>` + `dimPast = row => row.when === 'past' ? 'a11-row--dim' : ''`.
- **Spec.** Spec §4.3.1 sehol nem ír halványítási konvenciót.
- **D-X precedens.** A D-13 DataTable contract-bővítés **`rowClassName` generikus prop**ot ad (a D-13 motiváció része: T-7 "dim Lezárt/Elutasítva pattern" cross-screen — a Bejelentés-listán `dimResolved`). A halványítási elv **cross-screen pattern** (A1-list — `Lezárt/Elutasítva`), itt az A11-Programokra-fork ekvivalens szándékkal (`Lezajlott`). **Részben dokumentált**, részben UI-találmány — a halványítás mintáját a D-13 felszabadítja, de a tartalom-ágra-fork nem rögzíti.
- **Döntés.** **D-X precedens-szelídítés-jelölt** (a halványítási elv **D-13 generikus rowClassName-szerződéssel** elvileg fedett). SPEC-FEEDBACK **SF-85** (átadási megjegyzés: `rowClassName=dimPast` cross-screen pattern A1↔A11 ekvivalens). |
| **#4 A11 lista State 1 + 2 thumbnail-emoji `🎉` + State 3 empty-state-icon `🎉`** | A11 lista | 🔍 — DS-emoji-tiltás-violáció (Batch 1 🔍 #4 cross-screen). SF-73 cluster-be olvasztva. |
| **#5 A11 szerkesztő StateValidationError 3-mezős hiba-kombináció** (`title="Gyer"` + `dateRange` + `location`) | A11 szerkesztő State 4 | 🔍 — host-szintű mock-narratív, ekvivalens A10 🔍 #6 mintájával. SF-75 mintájára. |

---

## Batch 2 összefoglaló

| Kategória | Tételszám |
|---|---|
| ✅ | **8** (4 mező/végpont + 4 UI-cell-formázás) |
| ⚠ | **4** (1 KRITIKUS `latitude/longitude+map-link`, 3 közepes) |
| 🟡 | **4** (D-15 + D-13 cluster) |
| 🔍 | **3-5** (TimeCell színkód, 4-tab Lezajlott-derived, halványítás-fork, emoji-cluster, validation-narratív) |
| **Összesen** | **~20 mező/végpont/UI-elem** |

**SPEC-FEEDBACK Batch 2 tervezet:** SF-79 (lat/lng+map-link), SF-80 (locationText maxLength 120 ≠ 300 + label * jelölés), SF-81 (pastDate confirm dialog), SF-82 (cellType-bővítés titleWithLocation+dateRange), SF-83 (TimeCell színkód), SF-84 (4-tab Lezajlott-derived).

---

# Batch 3 — A12 Városi információk (`CityInfo`)

**Spec-fedés.** `60_tartalom` §2.5 (SD-71 `groupLabel` szabad-szöveg) + §2.6 (HTTPS-only URL) + §2.7 (közös `iconRef`) + §3.4 (`CityInfoController` 9 végpont T-19..T-27 + reorder + `/v1/city-info-groups` distinct-lookup) + §4.4 (UI-szerződés — News/Event-eltéréssel) + `00_domain_model` §4.4 (9 mező).

**Screen-mockok.**
- `a12-cityinfo-lista.html` — 3 állapot (1 `Default` 8 cityinfo · 2 Drag-közben · 3 First-time empty).
- `a12-cityinfo-szerkeszto.html` — 4 állapot (1 Új info · 2 Valid URL · 3 Unreachable URL · 4 Validation error).

**Organism-szerződés.**
- **Lista.** `AppShell` + `PageHeader` + `FilterPillBar` + host-inline `InfoRow` komponens (drag-handle + title+desc + url-host + **per-row LinkValidator-state badge** + `updatedAt`). **A lista NEM fogyaszt `DataTable`-t**, hanem saját CSS-grid `a12-list`-tel rendereli a sorokat. **A lista NEM rendereli a `PublishStateChip`-et per-row.**
- **Szerkesztő.** `AppShell` + `PageHeader` + `ContentEditor kind="cityinfo" showCover={false}` + `CityinfoExtraFields` host-komponens via `extraFields`-slot (`LinkValidator` URL-mezőhöz).

---

## Forward pass — `CityInfo` 9 mező + §3.4 9 végpont + §4.4 UI-szerződés

### ✅ Spec-ben + screen-en is megvan

| Spec-mező / végpont / UI-blokk | Spec-forrás | Screen-evidence |
|---|---|---|
| `CityInfo.id`, `title` (max 200), `contentStatus`, `publishedAt`, `createdAt`, `updatedAt` (audit) | `00_domain_model` §4.4 | A12 lista `CITY_INFOS[*]` mock-rekordok `{id, title, updatedAt}`; A12 szerkesztő `ContentEditor.value.title` mező + `publishState` ✅ a value-on, **de a `PublishStateChip` per-row a listán hiányzik** — lásd ⚠ #4. |
| `CityInfo.url` (kötelező, `https://` előtag, max 2000, `must_be_https` validáció) | `00_domain_model` §4.4 + `60_tartalom` §2.6 + §3.4.2 | A12 szerkesztő `CityinfoExtraFields.LinkValidator` URL-mező + StateUrlValid mock `url: 'https://korhaz.balatonalmadi.hu'` + StateValidationError mock `url: 'nem-egy-url'` + `fieldErrors.url = "Érvénytelen URL — kezdje http:// vagy https:// résszel."` ekvivalens a spec `must_be_https` i18n-kulcsával. A `LinkValidator.state='invalid'` az AC-C1 érvénytelen-URL-státuszt fedi ✅. |
| **T-21 `POST /v1/city-infos`** — create-szerződés (`Draft` hard-coded, `sortOrder` server-set `max+1`) | `60_tartalom` §3.4.2 | A12 szerkesztő StateNew `value={publishState: 'draft', title: '', body: '', url: '', urlState: 'idle'}` ✅. **A `sortOrder` mező a value-on nincs (nem szerkeszthető) ✅** — spec-konform. |
| **T-22 `PUT /v1/city-infos/{id}`** — szerkeszthető: `title`, `description`, `url`, `iconRef`, `groupLabel` | `60_tartalom` §3.4.3 | A12 szerkesztő `ContentEditor` + `CityinfoExtraFields` `title` + `body` (description-helyett, lásd ⚠ #1) + `url` mezőket renderel. **`iconRef` + `groupLabel` szerkesztő-mezők TELJESEN hiányoznak** — lásd ⚠ #2 + ⚠ #3. |
| **T-26 `POST /v1/city-infos/reorder`** drag-and-drop sorrendezés | `60_tartalom` §3.4.5 + §4.4.3 | A12 lista State 1 `mgr-cat__grip "⋮⋮" "Húzd a sorrend változtatásához"` minden soron + State 2 `StateDragging` mock-state a `a12-row--dragging` árnyékkal + `a12-drop-zone` kék vízszintes vonalláal ✅. Vizuálisan demonstrálva. *(Az on-drop callback no-op, az Angular-port a `POST /v1/city-infos/reorder`-ra kötné — kanonikus.)* |
| **§4.4.3 Drag handle "≡"** | `60_tartalom` §4.4.3 | `a12-row__grip` `<span>⋮⋮</span>` literál — **`⋮⋮` ≠ spec `≡`** literal-eltérés, ekvivalens-szándék — alacsony hatás (mindkettő drag-handle-szerű glyph), 🔍-kategóriába sem kerül. |

### ⚠ Spec-ben van, screen-en nincs — hiányosság

#### ⚠ #1 — **`CityInfo.description` mező TÍPUS-konfliktus: spec `plain text max 500`, screen `RichTextEditor` HTML-formátum** *(KRITIKUS)*
- **Spec.** `00_domain_model` §4.4: *"`description`: string, opcionális, max 500 karakter. Plain text"*; `60_tartalom` §3.4.2: *"`description`: opcionális, plain text, max 500"* — FluentValidation: `RuleFor(x => x.description).MaximumLength(500).When(x => x.description != null)`. §4.4.2 mezősablon: *"`description` — Rövid leírás: opcionális, max 500, plain text textarea."*
- **Screen.** A12 szerkesztő `ContentEditor kind="cityinfo"` a `Tartalom *` mezőre `RichTextEditor`-t renderel (HTML-tárolású, SD-69 whitelist, max 10 000 karakter) — **NEM** plain-text textarea max 500-zal. A `value` szerződésen `body` (a News/Event HTML-bodyjával ekvivalens mezőnév) szerepel, **NEM** `description`. A StateUrlValid mock-on `body: '<p>24 órás sürgősségi szolgálat...</p>'` HTML-tartalommal. A `LinkValidator.error` literal "kötelező mező" benyomást ad (`Tartalom *` a `mgr-ce-field__label-req` `*`-gal).
- **Hatás.** **KETTŐS spec-eltérés:**
  - (a) **mezőnév** `body` ≠ spec `description` (DTO-szerződés-konfliktus az Angular-porton);
  - (b) **mezőtípus** rich-text HTML + max 10 000 ≠ spec plain-text textarea + max 500 (FluentValidation-konfliktus, AC-C1 mezőszintű validáció).
  - (c) A `Tartalom *` `*` kötelezőként jelöli, **≠ spec opcionális**.
  - (d) A spec `description` mező nincs SD-69 HTML-szanitizációval — a `<p>24 órás sürgősségi szolgálat...</p>` HTML-tartalom a szerver-oldalon **plain-text-ként** mentődne (a `<p>` tag-ek karakterekként számolnának), **vagy** a backend-szanitizáció kivetné őket (`field_not_editable`).
- **Döntés.** **JAVÍTANDÓ** (kanonikus organism-bővítés + mock-korrekció). (a) `ContentEditor.kind="cityinfo"` **NE rendereljen `RichTextEditor`-t** a body-mezőre, hanem `<textarea>` plain-text (`mgr-ce-field__textarea`); a mezőnév `value.description` (NEM `body`); a label `Rövid leírás` (NEM `Tartalom *`); `*` jelölés eltávolítása (opcionális); `maxLength={500}` + char-counter (a Batch 1 ⚠ #6 char-counter-ekvivalensen). (b) A mock-on `description: 'A városi képviselő-testület jegyzőkönyvei...'` plain-text formátum (nem `<p>...</p>`). SPEC-FEEDBACK **SF-86** (kettős kritikus: organism kind-szerinti renderelés-elágazás + mock-data-típus-korrekció).

#### ⚠ #2 — **`CityInfo.iconRef` mező SZERKESZTŐ-on TELJESEN hiányzik**
- **Spec.** `00_domain_model` §4.4 + `60_tartalom` §2.7 (közös ikonkészlet kulcs) + §3.4.2 (`iconRef` whitelist-validáció max 50) + §4.4.2 mezősablon: *"`iconRef` — Ikon: opcionális, ikon-választó a közös ikonkészletből."* Az `IconPicker` organism (`60_tartalom` §4.4 implicit + A6 D-8 C-2A azonos közös ikon-katalógussal).
- **Screen.** A12 szerkesztő `CityinfoExtraFields` csak `LinkValidator` URL-mezőt renderel; **`iconRef` IconPicker-affordancia teljesen hiányzik**. A `value` szerződés `iconRef` mezőt sem hordoz.
- **Hatás.** A polgári app `screen_varosi_informaciok_lista` **ikonos listát** vár (spec §5.1) — a tartalomkezelő nem tud ikont rendelni a tételhez. AC-C1 `iconRef` whitelist-validáció UI-tükre teljesen hiányzik. A `60_tartalom` §2.7 **közös ikonkészlet** elve sérül (`Category` ↔ `CityInfo`).
- **Döntés.** **JAVÍTANDÓ** (kanonikus organism-bővítés). `CityinfoExtraFields`-be `iconRef` mező IconPicker-szerű button-popoverrel (A6 D-8 C-2A mintán) — a közös `iconCatalog`-glyph-szettből. SPEC-FEEDBACK **SF-87** (host-komponens bővítés + új mock-state).

#### ⚠ #3 — **`CityInfo.groupLabel` mező + `/v1/city-info-groups` autocomplete SZERKESZTŐ-on TELJESEN hiányzik**
- **Spec.** `00_domain_model` §4.4 + `60_tartalom` §2.5 (SD-71 szabad-szöveg max 100) + §3.4.6 (`GET /v1/city-info-groups` distinct-lookup) + §4.4.2 mezősablon: *"`groupLabel` — Csoport: opcionális, max 100, **autocomplete** a meglévő distinct értékekről (`GET /v1/city-info-groups`); szabad szöveges új érték megengedett."* + §4.5.4 i18n `content.cityInfo.field.groupLabel.placeholder = "Pl. Strandok, Hivatalok"`. A polgári app `screen_varosi_informaciok_lista` a `groupLabel`-szerint **szekcionál** (spec §5.3.3).
- **Screen.** A12 szerkesztő `CityinfoExtraFields` csak `LinkValidator`-t renderel; **`groupLabel` autocomplete-input TELJESEN hiányzik**. A `value` szerződés `groupLabel` mezőt sem hordoz.
- **Hatás.** A polgári lista-szekcionálás (`Strandok`, `Hivatalok`, `Egészségügy`...) tartalomkezelő-oldali input-kontraktja teljesen elveszik. AC-C2 (`groupLabel` autocomplete 3-criterion) UI-tesztelhetősége eltűnik. A `60_tartalom` §3.4.6 distinct-lookup-végpont fogyasztó-oldalának nincs felülete.
- **Döntés.** **JAVÍTANDÓ** (host-komponens bővítés). `CityinfoExtraFields`-be `groupLabel` autocomplete-input (PrimeNG `p-autocomplete`-ekvivalens; host-felelős a `GET /v1/city-info-groups`-hívásért) + placeholder a spec-konform `content.cityInfo.field.groupLabel.placeholder`. SPEC-FEEDBACK **SF-88** (host-komponens bővítés + új mock-state autocomplete-suggestion-list nyitva).

#### ⚠ #4 — **A12 lista `PublishStateChip` per-row TELJESEN hiányzik + lista-szintű `contentStatus`-szűrő nincs** *(KRITIKUS)*
- **Spec.** `00_domain_model` §4.1 + §4.4 — `CityInfo` ugyanazt a `ContentStatus`-enumot örökli (Draft/Published/Archived). §4.4.1 oszlop-szerződés a `60_tartalom` §4.2.1 News-konfigurációt cross-referenz-eli (Status-multiselect-szűrő + Archive-toggle). A spec implicitje: a CityInfo is fedi a 3-állapotos életciklust.
- **Screen.** A12 lista **NEM rendereli a `PublishStateChip`-et per-row**; nincs `Állapot` oszlop sem; a screen-header literal-szöveg explicit: *"nincs publish-state-chip (minden info él)"* — **ez a screen-en kódolt UX-pozíció, hogy a CityInfo tételek mind élnek (Published)**, ami a spec-ellen. A mock-data `CITY_INFOS[*]` rekordjain nincs `state` mező, **csak** `state: 'valid' | 'unreachable'` — ami a LinkValidator-state (ortogonális dimenzió a contentStatus-tól!).
- **Hatás.** **DUPLA KONFLIKT:**
  - (a) A vezető **nem tudja vázlatba helyezni** vagy **archiválni** egy cityinfo-t (a spec szerinti T1-T4 átmenetek mind elérhetetlenek).
  - (b) A `PublishStateChip` cross-organism-kontraktja A10+A11+A12 mindhárom listán renderelt kellene — itt teljesen hiányzik. A `60_tartalom` §4.5.1 common-i18n `content.common.status.Draft|Published|Archived` UI-tükre A12-en teljesen elveszik.
  - (c) A T-25 `POST /v1/city-infos/{id}/transition` végpont elérhetetlen — a kebab-menü ⚠ #3 Batch 1 cross-cutting alá esik.
- **Döntés.** **JAVÍTANDÓ** (kanonikus organism-bővítés). A12 lista `InfoRow`-on `PublishStateChip` per-row + a `FilterPillBar`-ba státusz-szűrő (vagy `TabFilter` az A10/A11-mintán). A "minden info él" screen-pozíció **téves spec-értelmezés**: a `CityInfo` is megőrzi a teljes ContentStatus-életciklust. SPEC-FEEDBACK **SF-89** (kritikus, cross-cutting az SF-63 Archived-cluster + SF-64 kebab+dropdown összevont javaslattal).

#### ⚠ #5 — A12 lista `iconRef` oszlop + `groupLabel` oszlop + `groupLabel`-szűrő mind hiányzik
- **Spec.** `60_tartalom` §4.4.1 *"Új oszlopok: `iconRef` (ikon-cell), `groupLabel` (szűrő: `loadOptionsFrom: '/v1/city-info-groups'`), `url` (rejtett), `sortOrder` (rejtett). Default rendezés: `sortOrder asc`."*
- **Screen.** A12 lista `InfoRow` 6 cellát rendereli (`grip / title+desc / url+host / linkValidator-state / updatedAt / chev`) — **`iconRef` ikon-cella + `groupLabel` cella mindkettő teljesen hiányzik**. A `FilterPillBar.filters` csak `[{Állapot: 'Bármi'}]`-t hordoz — `groupLabel` (csoport-szűrő) hiányzik.
- **Hatás.** A polgári-oldali ikonos lista + szekcionált lista alaptulajdonsága a tartalomkezelőnek vizuálisan nem reprezentált. A `loadOptionsFrom`-szerű dynamic-filter pattern (Tier-2 FilterPillBar bővítés-jelölt) elérhetetlen.
- **Döntés.** **JAVÍTANDÓ** (mock-bővítés + organism-bővítés). `InfoRow.cellLayout`-ba `iconRef` (24px ikon-cella) + `groupLabel` (12px-es text-cella vagy chip-cella). `FilterPillBar.filters` bővítés `{key: 'group', label: 'Csoport', loadOptionsFrom: '/v1/city-info-groups'}`. SPEC-FEEDBACK **SF-90** (mock-bővítés + cell-layout-redesign + organism filter-pill `loadOptionsFrom` bővítés).

#### ⚠ #6 — A12 szerkesztő `url` mező után "Megnyitás új lapon" link nincs
- **Spec.** `60_tartalom` §4.4.2 mezősablon `url`: *"az érték érvényessége után 'Megnyitás új lapon' link"* + §4.5.4 i18n `content.cityInfo.field.url.openInNewTab = "Megnyitás új lapon"`.
- **Screen.** A `LinkValidator` organism (`link-validator.jsx:55`) `state === 'valid'` esetén `<button title="Újra-ellenőrzés">↻</button>` retry-button-t renderel — **NEM** "Megnyitás új lapon" link. A `CitizenPreview` jobb-oszlopban ugyan van egy "→"-mintás link-renderelés, de az a **polgári app preview**, NEM a szerkesztő-oldali tartalomkezelői "Megnyitás új lapon" affordance.
- **Hatás.** A tartalomkezelő nem tudja gyorsan ellenőrizni a megadott URL-t az `target="_blank"` új-lapon-megnyitással.
- **Döntés.** **JAVÍTANDÓ** (organism-bővítés). `LinkValidator.state='valid'` esetén `<a target="_blank" rel="noopener noreferrer">Megnyitás új lapon ↗</a>` link a retry-button mellett. SPEC-FEEDBACK **SF-91** (organism-bővítés, alacsony prioritás).

### 🟡 Screen-en van, spec-ben nincs, DE D-X rögzíti

| Screen-elem | Hol jelenik meg | D-X hivatkozás |
|---|---|---|
| **#1 `LinkValidator` organism** szerkesztő-on (on-blur valid/invalid/unreachable state-szett) | A12 szerkesztő `CityinfoExtraFields.LinkValidator` | **D-13 Tier-3 organism-kiemelés rögzíti** (`ORGANISMS.md:542`) — *"új — A12 specifikus. URL-mező a polgári app cityinfo-elemeihez. On-blur validáció indikátor-state-tel (loading / valid / invalid / unreachable) + favicon-grab a valid URL-hez."* A 4 state-elem ORGANISMS.md prop-táblázatában explicit. **NEM** UI-találmány. (Az induló-prompt "S15 explorer" nincs külön fájlon, de a D-13 ORGANISMS-eligible organism-tier-besorolása a state-szettet rögzíti.) |
| **#2 `ContentEditor kind="cityinfo" showCover={false}`** (nincs cover) | A12 szerkesztő | **D-13 explicit rögzíti** (`ORGANISMS.md:356` *"showCover: boolean — Default true (A10/A11), false A12-höz"*). |
| **#3 `ContentEditor split-view + previewSlot`** (CityinfoPreview cityinfo-card formátummal) | A12 szerkesztő mind a 4 artboardon | **D-13 C-4** (lásd Batch 1 🟡 #3 + Batch 2 🟡 #2 cross-screen). |
| **#4 D-17 publish-bar gomb-sorrend** | A12 szerkesztő | **D-17** (Batch 1 🟡 #2 cross-screen). |
| **#5 Drag-handle + drop-zone vizuális mintázat** (`a12-row--dragging` shadow + `a12-drop-zone` 4px-os kék vonal) | A12 lista State 2 `StateDragging` | **Részben D-X rögzíti** — A6 D-8 C-1A "drag-and-drop fogantyúval" cross-screen pattern; az A12-en `ReorderableList` organism **explicit kihagyva** (ORGANISMS.md Tier-4 *"Explicit kihagyva: ... az A12 cityinfo-listán külön drag-organism szükségtelen"*). A drop-zone vízszintes-kék-vonal visual-cue specifikus mintáját D-X nem rögzíti — host-szintű impl. choice. |

### 🔍 Screen-en van, spec-ben nincs, NEM dokumentált — UI-találmány

#### 🔍 #1 — **A12 lista per-row LinkValidator-state badge (`valid`/`unreachable`/`invalid`/`loading`) mint lista-cella** *(KRITIKUS UI-TALÁLMÁNY)*
- **Hol.** A12 lista `InfoRow.STATE_BADGE` dot+label (`'elérhető'` / `'nem elérhető'` / `'érvénytelen URL'` / `'ellenőrzés…'`) minden soron, a `url` cella és `updatedAt` cella között. Mock-data `CITY_INFOS[*].state` mező hordozza (`'valid'` 7×, `'unreachable'` 1× — "Önkormányzati jegyzőkönyvek").
- **Spec.** `60_tartalom` §4.4.1 oszlop-szerződés `iconRef`/`groupLabel`/`url`(hidden)/`sortOrder`(hidden) — **a LinkValidator-state mint per-row cella sehol nem említve**. A `LinkValidator` organism (ORGANISMS.md) **szerkesztő-on-blur-hez** rögzítve — NEM lista-on-render-hez.
- **D-X precedens.** Sehol nem található — sem D-13 (organism-kiemelés), sem ORGANISMS.md, sem `60_tartalom` §3.4 ír *háttér-job, ami időnként újra-validálja a `CityInfo.url`-eket és lista-szintű badge-en mutatja*. **Az induló-prompt kérdezte:** *"A LinkValidator on-blur valid/invalid/unreachable state-szett D-15-előtti spec-iter alatt — ha S15 explorer-jegyzettel dokumentált → 🟡, ha sehol → 🔍"* — **a `s15-*-explorer.html` fájl NEM létezik** (a `preview/screens/`-en csak `s13-datetimerangepicker-explorer.html` és `s6_5-beallitas-nav-explorer.html` van). A per-row LinkValidator-state **mint lista-cella** sehol nem rögzített.
- **Hatás.** **Önálló UI-találmány** (NEM trivi-extension a meglévő organism-fogyasztásból):
  - (a) A per-row state-badge **háttér-job-feltevés**t implikál (a lista-rendereléskor a URL-eknek érvényes state-jük van — ami csak akkor lehet, ha periodikus URL-érvényesség-ellenőrző job fut). Spec ezt **nem** specifikálja.
  - (b) A "Önkormányzati jegyzőkönyvek" 'unreachable' (4xx/5xx) mock-illusztrációja **operatív értéket** ad (a vezető láthatja, mely linkek elhalottak) — funkcionális pilot-extension-jelölt.
  - (c) A `STATE_BADGE` ortogonális a `contentStatus`-szal (a Published + Unreachable rekord létezhet, sőt a State 1 mock-on pont ilyen van) — a UI-on a kétdimenziós állapot összemosódhat.
- **Döntés.** **SPEC-SZELÍDÍTÉS-JELÖLT (új SD-X)** vagy **TÖRLÉS**. Két javaslat:
  - **(a) Megerősítés.** Új SD-X *"A12 lista per-row LinkValidator-state badge"* — feltételezve egy óránkénti vagy napi háttér-job-ot, ami a `CityInfo.url`-ek elérhetőségét frissíti egy `lastCheckedAt`+`lastCheckedState` mezőn. A `60_tartalom` §3.4.* új végpontot + új mező-párt + új AC-X-eket bocsát ki. **NY-T (új átadott szál):** *"A12 URL-érvényesség-háttér-job — kelletik-e a pilotra?"*.
  - **(b) Törlés.** A per-row badge mock-szinten törlendő (vagy csak vizuális demoként marad, de nem fejlesztői átadás-prioritás). A `LinkValidator`-organism szerkesztő-on-blur-fogyasztása megmarad.
- SPEC-FEEDBACK **SF-92** (KRITIKUS spec-szelídítés-vs-törlés; spec-csapat döntsön).

#### 🔍 #2 — A12 lista State 1 first-time-empty `🔗` emoji + State 2 thumbnail-helyett `🌐` favicon-glyph minden soron
- **Hol.** State 3 `.a12-empty__icon` `<div>🔗</div>` + InfoRow `a12-row__url-favicon "🌐"` minden soron a `url`-cella elején.
- **DS guide.** "No emoji in product UI" — Batch 1 🔍 #4 cross-screen. SF-73 alá olvasztva.
- **Döntés.** Lásd SF-73 cluster. SPEC-FEEDBACK **SF-73 bővítés** (Batch 1 + Batch 2 + Batch 3 közös emoji-cluster A10 📰🖼️ + A11 🎉 + A12 🔗🌐).

#### 🔍 #3 — A12 lista host-derived `row.host` cella (`'korhaz.balatonalmadi.hu'`) + `row.updatedAt` mint host-felelős mock-mező
- **Hol.** A12 lista `InfoRow.a12-row__url-host {item.host}` + `a12-row__date {item.updatedAt}` — a `host` derived a `url`-ból mock-szintű (`hostFromUrl(url)`-ekvivalens), az `updatedAt` formális audit-mező.
- **Spec.** `60_tartalom` §4.4.1 oszlop-szerződésen `url` (`visible: false` alapból) — **a `host`-derived külön cella mint kanonikus oszlop sehol nem említve**; a host-megjelenítés a `cellType: 'url'` formázás része lehet, de explicit nem dokumentált.
- **Döntés.** **MOCK-KORREKCIÓ** vagy **SPEC-SZELÍDÍTÉS-JELÖLT** (a host-derived cell `cellType: 'urlHost'` mint `60_tartalom` §4.4.1 oszlop-bővítés). SPEC-FEEDBACK **SF-93** (alacsony prioritás).

#### 🔍 #4 — A12 lista **NEM** fogyaszt `DataTable` Tier-2 organism-et — host-szintű inline `InfoRow` CSS-grid
- **Hol.** A12 lista `<div className="a12-list">{CITY_INFOS.map(item => <InfoRow ...>)}</div>` — host-szintű inline lista-renderer (CSS-grid `a12-row` saját stylesheet-tel), **NEM** a kanonikus `DataTable` organism.
- **D-X precedens.** A spec §4.4.1 implicit DataTable-szerződést ír (a §4.2.1-cross-reference), de a drag-and-drop reorder + per-row LinkValidator-badge a kanonikus `DataTable` API-jával **nem fedhető le** (a `DataTable` Tier-2 nem hordoz `onReorder` propot). Az A6 `CategoryTreeEditor` (Tier-4, drag-aware) precedens: ott is **saját komponens** a `DataTable` helyett.
- **Hatás.** A12 lista a **kanonikus list-screen-konvenció**ból (Tier-2 DataTable) kilóg — D-X precedens-alapú (A6 mintán), de explicit nem rögzített.
- **Döntés.** **HANDOFF.md átadási megjegyzés**: a drag-aware lista-screenek (A6, A12) `DataTable`-helyett saját inline-rendererrel élnek, **mert** a Tier-2 DataTable nem rendelkezik `onReorder` API-val. A `DataTable` Tier-2 organism bővítés-jelölt (`onReorder`-prop + reorder-mode), ha 2+ host-screen ezt fogyasztja — **SF-94** (alacsony prioritás organism-bővítés).

#### 🔍 #5 — A12 lista State 3 empty-state literal-szöveg "Még nincs egyetlen hasznos link sem." ≠ spec `content.empty.cityInfo.title = "Még nincs városi információ."`
- **Hol.** A12 lista `.a12-empty__title "Még nincs egyetlen hasznos link sem."` + `.a12-empty__desc "...Kezdj a városi kórház, polgármesteri hivatal és háziorvos elérhetőségével."`
- **Spec.** `60_tartalom` §4.5.6 `content.empty.cityInfo.title = "Még nincs városi információ."` + `description = "Adj hozzá hasznos linkeket a polgárok számára."` + `action = "Új városi információ"`.
- **Hatás.** Ekvivalens-szándék (host-szintű copy-finomítás), tone-of-voice-konzisztens. Mock-narratív.
- **Döntés.** **MOCK-KORREKCIÓ-JELÖLT** (low priority) vagy spec-szelídítés (a "hasznos linkek" megfogalmazás jobban tükrözi a tartalomkezelő-szándékot). SPEC-FEEDBACK **SF-95** (alacsony prioritás).

---

## Batch 3 összefoglaló

| Kategória | Tételszám |
|---|---|
| ✅ | **6** (5 mező/végpont + 1 UI-blokk drag) |
| ⚠ | **6** (3 KRITIKUS: description-típus, iconRef hiány, groupLabel hiány; 1 KRITIKUS PublishStateChip hiány; 2 közepes: iconRef+groupLabel-oszlopok, Megnyitás-link) |
| 🟡 | **5** (D-13 organism-cluster + D-17 + A6 drag-precedens) |
| 🔍 | **5** (1 KRITIKUS per-row LinkValidator-badge, 4 mock-korrekció/HANDOFF) |
| **Összesen** | **~22 mező/végpont/UI-elem** |

**SPEC-FEEDBACK Batch 3 tervezet:** SF-86 (description-típus kettős-konfliktus), SF-87 (iconRef hiány szerkesztőn), SF-88 (groupLabel hiány szerkesztőn + autocomplete), SF-89 (PublishStateChip + contentStatus-szűrő hiány — cross-cutting SF-63+SF-64 összevont), SF-90 (iconRef+groupLabel oszlopok + group-szűrő), SF-91 (Megnyitás új lapon link), SF-92 (per-row LinkValidator-badge kritikus spec-szelídítés-vs-törlés), SF-93 (host-derived cell), SF-94 (DataTable reorder-bővítés), SF-95 (empty-state copy).

**A Batch 3 KRITIKUS-4 hatás összegzése:**
- ⚠ #1 (description-típus) — `RichTextEditor` HTML 10 000 ≠ spec plain-text textarea 500; mezőnév `body` ≠ `description`; opcionális vs kötelező; a polgári-oldali DTO-szerződés (§5.3.3) megsérül.
- ⚠ #2-3 (iconRef + groupLabel mind hiányzik a szerkesztőn) — a polgári app ikonos+szekcionált listájának input-kontraktja nem létezik.
- ⚠ #4 (PublishStateChip hiány a listán + state-szűrő) — a vezető nem tudja vázlatba helyezni / archiválni a cityinfo-t; cross-cutting az SF-63 Archived-clusterrel.
- 🔍 #1 (per-row LinkValidator-badge) — **funkcionálisan értékes** UI-találmány, de **háttér-job-feltevést implikál** — spec-szelídítés vagy törlés szükséges.

---

# Cross-cutting — Közös tartalmi váz §4.1 + `ContentStatus` állapotgép (SD-70) + HTML-szanitizáció (SD-69) + delete-guard cluster

A 3 entitás közös vázának spec-fedés-státusza, a `ContentStatus` 4-átmenetes állapotgépe (T1-T4), a SD-69 HTML-szanitizáció, és a delete-guard 409-konfirm-cluster mind cross-screen-pattern — itt egyben mappelve. A per-batch ⚠ tételeket NEM ismétli, csak a cross-batch hatás-összegzést adja.

### Közös váz §4.1 — `contentStatus` + `publishedAt` + audit (`createdAt`/`createdBy`/`updatedAt`/`updatedBy`)

| Mező | Spec-forrás | Cross-batch evidence + státusz |
|---|---|---|
| `contentStatus` (enum: Draft / Published / Archived) | `00_domain_model` §4.1 + `60_tartalom` §2.9 | A10 lista `PublishStateChip` `draft+published` ✅; A11 lista ua. ✅; A12 lista **ÖSSZESEN HIÁNYZIK PER-ROW** (Batch 3 ⚠ #4); **Archived UI-tükre mind a 6 screenen hiányzik** (Batch 1 ⚠ #2 cross-cutting). |
| `publishedAt` | `00_domain_model` §4.1 | A10/A11 lista `Publikálva` oszlop `mono`-formátum ✅; A12 lista nem renderel publishedAt-oszlopot (mert nincs status-chip sem). A szerkesztők CitizenPreview-ja megjeleníti ✅ (host-szintű). |
| Audit (`createdAt`/`createdBy` = SD-23 `TenantUser`-join) | `00_domain_model` §4.1 SD-23 + `60_tartalom` §3.2.1 NewsDto | Lista-on `createdByName` mock-szinten szerepel (A10 `Szerző` oszlop, lásd 🔍 Batch 1 #2). **A szerkesztő-screenen az §4.2.4 Audit szekció minden tartalom-típuson hiányzik** — Batch 1 ⚠ #7 cross-batch. |

### `ContentStatus` állapotgép (SD-70) — T1-T4 átmenet UI-tükre

| Átmenet | Spec | UI-megvalósítás (cross-batch) |
|---|---|---|
| **T1** `Draft → Published` | §2.9 + §4.2.6 *"Publikálás"* gomb-feliraton + `publishedAt = now()` | A10/A11/A12 szerkesztő `ContentEditor.publish-bar` `Publikálás →` button ✅. **Bulk-publikálás UI nem implementált** (Batch 1 ⚠ #5). |
| **T2** `Published → Draft` | §2.9 + §4.2.6 *"Visszavonás vázlatba"* sub-action + `publishedAt = null` | **TELJESEN ELÉRHETETLEN UI-szinten** (Batch 1 ⚠ #3 — kebab + publish-dropdown teljes hiánya). |
| **T3** `Published → Archived` | §2.9 + §4.2.6 *"Archiválás"* (elsődleges levételi akció, D-T3) | **TELJESEN ELÉRHETETLEN** (Batch 1 ⚠ #2 + ⚠ #3). |
| **T4** `Archived → Published` | §2.9 + §4.2.6 *"Újrapublikálás"* + új `publishedAt = now()` | **TELJESEN ELÉRHETETLEN** (Batch 1 ⚠ #2 + ⚠ #3). |
| **Tiltott** Draft → Archived; Archived → Draft → `409 invalid_transition` | §2.9 + AC-T5 | UI-szinten nem releváns (a `Publikálás ▾` dropdown spec-szerinti megépítése ezeket eleve nem ajánlja fel; az AC-T5 backend-validáció marad). ✅ implicit-fedés. |
| **DELETE state-érzékeny** | §2.9 + AC-D1 (Draft + Archived törölhető, Published `409 cannot_delete_published`) | **DELETE UI-szinten egyik tartalom-típuson sem renderelt** (sem sor-akció, sem kebab-item, sem bulk-delete) — lásd ⚠ Batch 1 #3 + #5. |

**Cross-batch következtetés.** A `ContentStatus` állapotgép 4 átmenetéből UI-szinten **csak T1 (Draft → Published) működik**; T2/T3/T4 mind elérhetetlen. **Az AC-T1-T6 hat acceptance criterion közül 4 (T2/T3/T4 + Tiltott T5 vizuális visszajelzés) UI-tesztelhetetlenné válik.** Pilot-blokkoló deficiencia.

### HTML-szanitizáció (SD-69)

A `News.body` és `Event.body` HTML-tárolás + szerver-oldali szanitizáció (whitelist: `<p>`, `<br>`, `<strong>`, `<em>`, `<ul>`, `<ol>`, `<li>`, `<a href="https://...">`) max 10 000 karakter. A `60_tartalom` §3.1.3 explicit: *"a kliens a szerver válaszát fogadja el"* — a kliens-oldali szanitizáció **nem** az igazság-forrás.

| Aspektus | Spec | Screen-fedés |
|---|---|---|
| HTML-tárolás | SD-69 + §3.1.3 | A10/A11 `RichTextEditor` HTML-tartalmat ad ki (`<strong>`, `<ul>`, `<li>`, `<a>` tag-ek a mock `PRESET_BODY`-n) ✅. |
| Whitelist toolbar (B/I/lista/link) | §4.2.5 + §4.6 PrimeNG Editor | `RichTextEditor` pilot-szintű toolbar (FK-1 lezárás) — implementáció-szerződésen konform. ✅ |
| Char-counter `xxxx / 10000` | §4.2.5 + §4.6 + AC-A6 | **MINDEN szerkesztő-screenen hiányzik** — Batch 1 ⚠ #6. |
| **Üres tartalom `<p></p>` → `400 invalid_html_or_empty_after_sanitization`** | §3.1.3 + AC-V1 | UI-szintű implementáció backend-felelős (a `<RichTextEditor>` nem prevenciózza). ✅ implicit. |
| `<a href>` csak `https://` enged | §3.1.3 | A `RichTextEditor` link-insertion-button host-felelős — a screen-mock-on nincs interaktív demoja. ✅ implicit (Angular-port szerver-validációval). |
| **A12-en spec-konfliktus: `description` plain text, NEM HTML** | §4.4.2 + §3.4.2 | **A12 szerkesztő `RichTextEditor`-t használ a `body` mezőre** — Batch 3 ⚠ #1 KRITIKUS. |

### Delete-guard + bulk-atomicity cluster (§3.2.6-7, §3.3.7, §3.4.5 + AC-D1-D3)

| Aspektus | Spec | Cross-batch UI-fedés |
|---|---|---|
| Single DELETE `Published`-en → `409 cannot_delete_published` | §3.2.6 + AC-D1 | **Sehol nem demonstrálva** — Batch 1 ⚠ #3 (kebab-menü hiánya magában foglalja). |
| Bulk DELETE atomicitás (vegyes batch → `409`, semmi nem törlődik) | §3.2.7 + AC-D2 | **Sehol nem demonstrálva** — Batch 1 ⚠ #5. |
| `details.publishedIds` lista a 409-payload-ban | §3.2.7 | Backend-szerződés; a kliens-UI a vegyes-batch-confirm-dialog-mockját feltételezi (`60_tartalom` §4.5.5 i18n `bulk_published_blocked`). UI-szinten nem renderelt. |

**Cross-batch következtetés.** A delete-guard egyetlen 409-konfirm-dialog mock **mind a 3 tartalom-típuson hiányzik** (analóg a Phase 2C SF-41 A6+A7 delete-guard-clusterrel). HANDOFF.md atomikus-batch-szerződés mock-pótlás-jelölt.

---

## Phase 2D — záró összegzés

### Konszolidált statisztika

| Kategória | Batch 1 (A10) | Batch 2 (A11) | Batch 3 (A12) | Cross-cutting | **Összesen** |
|---|---|---|---|---|---|
| ✅ Spec + screen-en megvan | 22 | 8 | 6 | 7 (váz, T1, SD-69-tartalom-bekötés) | **43** |
| ⚠ Spec-ben van, screen-en nincs | **8** (3 KRITIKUS) | **4** (1 KRITIKUS) | **6** (4 KRITIKUS) | 3 (T2-T4 UI-tükre + char-counter + Audit szekció — cross-batch összevont) | **18 + 3 = 21** *(a cross-batch tételek a per-batch ⚠ tételek bővítései, nem új tételek — duplán-számolás-elkerüléssel a 18 marad)* |
| 🟡 D-X rögzíti | 9 | 4 | 5 | 0 (a D-X-ek per-batch fedik) | **18** |
| 🔍 NEM dokumentált | 7 | 5 | 5 | 1 (per-row LinkValidator-badge → már Batch 3 alá olvasztva) | **17** |
| **Összesen** | **46** | **21** | **22** | — | **~96 mező/végpont/UI-elem** |

### A 8 KRITIKUS ⚠ + 🔍 — pilot-blokkoló deficiencia-lista

| # | Tétel | Hatás | SF |
|---|---|---|---|
| 1 | `News.pushOnPublish` szerkesztő-mező teljes hiánya (A10) | AC-N1.8 UI-tesztelhetetlen + 2 i18n confirm-variant elérhetetlen | SF-62 |
| 2 | `Archived` állapot UI-tükre teljesen abszens mind a 6 screenen (cross-batch) | T3 + T4 + AC-A1 archive-checkbox + 3-állapotos PublishStateChip mind elérhetetlen | SF-63 |
| 3 | Kebab + Publikálás-dropdown UI sehol nem renderelt (cross-batch) | T2/T3/T4 funkcionálisan blokkolt; AC-A2 + AC-T1-T6 6 acceptance UI-tesztelhetetlen | SF-64 |
| 4 | `Event.latitude`/`longitude` + Térkép-megnyitás link hiánya (A11) | AC-E1.5-1.9 5 acceptance UI-tükre megsemmisül; polgári térkép-renderelés input-kontraktja megsérül | SF-79 |
| 5 | `CityInfo.description` típus-quad-konfliktus (RichTextEditor HTML 10 000 ≠ plain-text 500; mezőnév `body` ≠ `description`) | AC-C1 mezőszintű validáció megsemmisül; polgári-oldali DTO §5.3.3 megsérül | SF-86 |
| 6 | `CityInfo.iconRef` szerkesztő-mező teljes hiánya | Polgári ikonos lista (`screen_varosi_informaciok_lista`) input-kontrakt megsemmisül | SF-87 |
| 7 | `CityInfo.groupLabel` autocomplete-mező + `/v1/city-info-groups` lookup fogyasztó-felület teljes hiánya | Polgári lista-szekcionálás (`Strandok`/`Hivatalok`) input-kontrakt megsemmisül; AC-C2 3 acceptance UI-tesztelhetetlen | SF-88 |
| 8 | A12 lista `PublishStateChip` per-row + contentStatus-szűrő teljes hiánya | Cityinfo-tartalomkezelő nem tud vázlatba helyezni / archiválni; cross-cutting #2-vel | SF-89 |
| **+1** | 🔍 A12 lista per-row LinkValidator-state badge — háttér-job-feltevés spec-szelídítés-vagy-törlés | Funkcionálisan értékes (halott linkek detektálás), DE spec sehol nem rögzíti; új NY-T-jelölt | SF-92 |

### Az SF-cluster-térkép (SF-62..SF-95)

| SF-tartomány | Szám | Tartalom |
|---|---|---|
| **SF-62..SF-69** | 8 | Batch 1 A10 ⚠ tételek (pushOnPublish, Archived cross-cutting, kebab+dropdown, default-sort, bulk-actions, char-counter, Audit szekció, cover-disabled) |
| **SF-70..SF-78** | 9 | Batch 1 A10 🔍 tételek (title maxLength, Szerző oszlop, Borítókép→Push filter, emoji-cluster, CitizenPreview literal, cover-kötelező-szabály, Eldobás vs Visszavonás, Szerkesztő-oszlop-cím, device-frame minta) |
| **SF-79..SF-85** | 7 | Batch 2 A11 ⚠+🔍 tételek (lat/lng+map-link KRITIKUS, locationText maxLength+kötelező-jelölés, pastDate-confirm, cellType-bővítés, TimeCell színkód, 4-tab derived, dim-Past-fork) |
| **SF-86..SF-95** | 10 | Batch 3 A12 ⚠+🔍 tételek (description-quad-konfliktus, iconRef hiány, groupLabel hiány, PublishStateChip+state-szűrő hiány, oszlopok+filter-bővítés, Megnyitás új lapon, **per-row LinkValidator-badge KRITIKUS**, host-derived cell, DataTable.onReorder bővítés, empty-state copy) |

**Összesen: 34 SF-tétel** (SF-62..SF-95) a Phase 2D-ből.

### Tartalom-ág-specifikus észrevétel: a `PublishStateChip` 2-állapotos vs 3-állapotos organism-szerződési deficit

A `60_tartalom` SD-70 háromállapotú életciklust ír (`Draft` / `Published` / **`Archived`**); a `PublishStateChip` organism **2-állapotos**-ként implementálva (`ORGANISMS.md:377` + `publish-state-chip.jsx` + `_styles.css:4373-4389` — csak `--draft` és `--published` CSS-modifier-pár). A 3. állapot (`Archived`) bevezetése:
- **CSS-bővítés:** új `.mgr-pub-chip--archived { background: var(--u-slate-100); color: var(--u-slate-700); }` + `.mgr-pub-chip--archived .mgr-pub-chip__dot { background: var(--u-slate-500); }` — slate-tónus, semleges-pasztell.
- **JSX-bővítés:** `state="archived"` prop-érték + label "Archivált" (i18n `content.common.status.Archived`).
- **ORGANISMS.md-frissítés:** *"3-állapotos publikálási státusz-chip (Vázlat / Publikálva / Archivált)"* — `publish-state-chip.jsx` aláírás javítva.

A PublishStateChip 3-állapotos bővítése az **SF-63 + SF-89 kettős javaslat-csomag** része.

### Phase 2D → Phase 3 átadási prioritások

**P0 — Pilot-blokkoló (HANDOFF.md fix-tétel):**
- SF-62 (`pushOnPublish` szerkesztő-mező)
- SF-63 + SF-89 (3-állapotos `PublishStateChip` + Archived cross-cutting + A12-en per-row PublishStateChip-bevezetés)
- SF-64 (kebab + publish-dropdown 4-átmenet UI)
- SF-79 (`Event` koordináta-páros + map-link)
- SF-86 (`CityInfo.description` plain-text textarea + mezőnév-csere)
- SF-87 (`CityInfo.iconRef` IconPicker a szerkesztőn)
- SF-88 (`CityInfo.groupLabel` autocomplete a szerkesztőn)
- SF-92 (per-row LinkValidator-badge — **spec-csapat döntse el**: megerősítés új SD-X-szel + háttér-job-spec, vagy törlés)

**P1 — Közepes prioritás (mock-bővítés + organism-bővítés):**
- SF-65 (default-sort `createdAt`), SF-66 (bulk-actions), SF-67 (char-counter), SF-68 (Audit szekció), SF-69 (cover-disabled-az-első-mentésig)
- SF-80 (`locationText` maxLength + kötelező-jelölés), SF-81 (`pastDate`-confirm dialog)
- SF-90 (A12 lista `iconRef`+`groupLabel` oszlopok + group-szűrő), SF-91 (Megnyitás új lapon link)

**P2 — Alacsony prioritás (HANDOFF átadási megjegyzés vagy spec-szelídítés-jelölt):**
- SF-70 (title maxLength=200), SF-71 (Szerző oszlop default-visible), SF-72 (Borítókép→Push filter-pill), SF-73 (emoji-cluster cross-screen), SF-74 (CitizenPreview literal-szöveg HANDOFF), SF-75 (cover-kötelező + banner-literal), SF-76 ("Eldobás" vs "Visszavonás"), SF-77 (Szerkesztő-oszlop-cím), SF-78 (device-frame starter-projekt-konvenció)
- SF-82 (cellType bővítés: titleWithLocation + dateRange), SF-83 (TimeCell színkód), SF-84 (4-tab Lezajlott-derived), SF-85 (dim-Past D-13 precedens)
- SF-93 (host-derived cell), SF-94 (DataTable.onReorder bővítés), SF-95 (empty-state copy)

### FK-1 (RichTextEditor mibenléte) — lezárás-státusz emlékeztető

Az induló-prompt explicit kérte ezt rögzíteni — itt **emlékeztetőként**:

> **FK-1 a `60_tartalom` v1.0 lezárta.** A funkcionális forrás (`03_implementacios_terkep.md` nyitott-kérdés-tábla FK-1) a hír/program tartalom-mezőjének rich-text-vs-plain-fallback kérdését hagyta nyitva. A `60_tartalom` v1.0 SD-69 (HTML-tárolás + whitelist) és §4.6 (PrimeNG Editor implementációs választás) ezt lezárta. **A `RichTextEditor` jelenlegi pilot-szintű impl. (D-13)** az SD-69 whitelisttel konform; a HANDOFF.md hatáskörében a PrimeNG Editorra-csere (FluentValidation szerver-szanitizációval).

**NEM nyitott kérdés — NEM SF-tétel.** A SPEC-FEEDBACK.md `## A10+A11+A12 spec-szelídítések` fejezet bevezetőjében ennek emlékeztetését rögzíti, hogy a Phase 3-ban a HANDOFF.md fejlesztő-csapathoz fordulás során **ne** újra-nyitott kérdésként kerüljön elő.

---

*Phase 2D Batch 1+2+3 + Cross-cutting lezárva. A `SPEC-FEEDBACK.md` `## A10+A11+A12 spec-szelídítések` ági-fejezete (SF-62..SF-95, 34 tétel) párhuzamosan írva. A Phase 3 mindezt a `HANDOFF.md`-be konszolidálja és a spec-csapathoz visszacsatolja.*
