# Döntésnapló — Urbino Specifikációs projekt

**Dokumentum-típus:** élő döntésnapló
**Státusz:** élő — minden lényeges termék- vagy technikai döntés ide kerül
**Frissítve:** 2026.05.20 (v1.6)
**Cél olvasó:** senior fejlesztő + Claude Code

> **Mire való ez a fájl.** A Specifikációs projekt **döntés-emlékezete**.
> Minden lényeges döntésnél rögzíti: mi a döntés, mi az indok, mi volt a
> mérlegelt alternatíva, ki döntött. A Claude Code és a fejlesztő ebből látja
> egy helyen, mi miért dőlt el.
>
> **Két döntés-réteg, ne keveredjen:**
> - **K-xxx — kanonikus döntés.** A stratégiai / funkcionális projektben
>   születik, a `kanonikus_donek.md`-ben él. A Specifikációs projekt ezeket
>   **nem vitatja újra** — csak hivatkozza.
> - **SD-xxx — specifikációs döntés.** A Specifikációs projektben születik,
>   itt él. Implementációs / platform-szintű döntések.
>
> Ha egy SD-döntésnek kanonikus súlya lenne, azt a Specifikációs projekt
> **visszacsorgatja** a funkcionális projektnek — ott kap K-számot. A
> specifikáció nem oszt ki K-számot magának.
>
> **Az "Ü-" előtagú bejegyzések** a felmérő kör (2026.05.18) tisztázó
> döntései — ezek alapozták meg a projekt indulását.

---

## A felmérő kör döntései (Ü-1 — Ü-6)

> A specifikációs munka megkezdése előtti közös helyzetfelmérés zárta le
> ezeket. Forrás: felmérő kör, 2026.05.18.

### Ü-1 — Multi-tenancy modell

**Döntés:** Kétszintű, fizikailag elkülönített multi-tenancy — egy Core DB és
tenantonként egy-egy Tenant DB. A tenant-azonosítás a `Tenant` HTTP request
headerből. A tenant DB minden működési lekérdezéshez önellátó; a Core-ból csak
szűk, csak-olvasható adatkör replikálódik be (lásd SD-1, SD-2, SD-3).

**Indok:** Az `02_architekturalis_kerdeslista.md` fejlesztői válaszai
egyértelműen a DB-per-tenant modellt erősítik ("sok db"; tenant-szintű backup;
per-request tenant-aware factory). A tenant DB önellátóvá tétele elkerüli a
cross-DB joint a működési útvonalon.

**Mérlegelt alternatíva:** A `project_backend` CLAUDE.md egy-`urbino_core`
adatbázis-modellje — ez a leírás elavultnak bizonyult, felülírva.

**Ki döntötte:** Az alapító, fejlesztői inputtal. A fejlesztői megjegyzés
("a tenant db lesz használva a működéshez, a core-ból syncelünk dolgokat")
az SD-2/SD-3 alapja.

### Ü-2 — A `VarosApp_Projekt_Brief.md` státusza

**Döntés:** A `VarosApp_Projekt_Brief.md` **elavult háttéranyag**. Ahol
ütközik a kanonikus döntésekkel, a kanonikus döntés nyer. A polgári app
adatigényét a Flutter képernyőkből olvassuk vissza, nem a briefből.

**Indok:** A brief 2026.05.11-i, a kanonikus érlelés (05.12—05.14) előtti;
több ponton közvetlenül ütközik a kanonikus döntésekkel (anonim bejelentés,
ML-duplikáció státusza, terméknév, szerepkörök).

**Következmény:** Nincs anonim/vendég bejelentés — a regisztráció kötelező
(`02_kerdeslista` 4. is ezt mondja).

**Ki döntötte:** Az alapító.

### Ü-3 — A "Triage kész — Kiosztás" gomb modellje

**Döntés:** Megerősítve. Az inline-szerkesztés (K-026) a négy triage-mezőt
(kategória, prioritás, határidő, felelős) kitöltés közben menti (optimistic
update); a "Triage kész — Kiosztás" gomb külön aktus, amely az `Új → Kiosztva`
állapotátmenetet véglegesíti és kiváltja az értesítéseket.

**Indok:** A `10_triage_flow` 8.4 jelezte ezt megerősítésre váró pontként. A
szétválasztás indokai: Anna félbehagyhat egy triage-et félkész értesítés
nélkül; van egy mérhető "kész" pillanat (a 30 mp-hez); a gomb validál.

**Mérlegelt alternatíva:** Tiszta inline Linear-minta, ahol a státusz maga is
inline dropdown — elvetve, mert a triage egy *aktus*, aminek van "elvégeztem"
pillanata.

**Ki döntötte:** Az alapító. **Megjegyzés:** ez specifikációs döntés (a
státusz-állapotgép-spec építi be). Ha a funkcionális projekt kanonikussá
emeli, ott kap K-számot — a specifikáció nem osztja ki magának.

### Ü-4 — A téves duplikáció-összevonás korrekciója

**Döntés:** (a) verzió — a téves összevonás a pilotra **kézi újranyitással**
korrigálható. Nem vezetünk be visszafordítható elutasítás-altípust.

**Indok:** A `20_duplikacio` 7.1 két utat vázolt; a téves összevonás ritka
eset, a kézi újranyitás áthidalja. A rendes "összevonás visszavonása" funkció
6-12. hó.

**Következmény:** A státusz-állapotgépben az `Elutasítva` **kivétel nélkül
végállapot** marad.

**Ki döntötte:** Az alapító.

### Ü-5 — A kategória-modell szintezése

**Döntés:** A pilot kategória-modellje **kétszintű** (gyökér + alkategória),
a K-036 szerint. Az `02_architekturalis_kerdeslista.md` 5. pontjának "most
csak lapos" megjegyzése elavult.

**Indok:** A K-036 (2026.05.14) kanonikus, és későbbi, mint a kérdéslista. A
duplikáció-heurisztika (K-032) gyökér-szintű kategória-egyezésre épül — lapos
modellnél ez értelmezhetetlen volna.

**Ki döntötte:** Az alapító.

### Ü-6 — Felhasználó-meghívás és offline bejelentés

**Döntés:** (1) A felhasználó-felvétel **e-mail meghívóval** történik (a
meghívó token/lejárat/sablon a felhasználó-spec része). (2) **Nincs offline
bejelentés-készítés** a pilotra.

**Indok:** Az `02_kerdeslista` 9. pontja az e-mail invite flow-t adja meg. Az
offline bejelentés-készítést a brief MVP-célként jelölte, de a kérdéslista
nyitva hagyta — a pilotra kivesszük.

**Ki döntötte:** Az alapító.

---

## Specifikációs döntések — platform-szintű alapréteg (SD-1 — SD-13)

> Forrás: `01_kozos_mintak.md` v0.2, 2026.05.18. Az SD-1 — SD-13 a
> platform-szintű alapréteg döntései.

### SD-1 — Kétszintű multi-tenancy

**Döntés:** Egy Core DB + tenantonként egy Tenant DB, fizikailag elkülönítve.
A tenant-azonosítás a `Tenant` HTTP request headerből. Ez felülírja a
`project_backend` CLAUDE.md egyetlen-`urbino_core` modelljét.

**Indok:** Az Ü-1 döntés technikai formalizálása; a fejlesztői műhely
válaszai (DB-per-tenant, tenant-szintű backup).

**Mérlegelt alternatíva:** Egy közös DB tenant-oszloppal (a `CLAUDE.md`
korábbi modellje) — elvetve a fejlesztői döntés alapján.

**Teendő:** A `project_backend` CLAUDE.md "Tenant context" és "Key
Configuration" szakasza frissítendő — visszajelzés a kódbázis gazdájának.

**Ki döntötte:** Specifikáció, az Ü-1 alapján.

### SD-2 — `TenantUser`-projekció

**Döntés:** A Core DB-ből a tenant DB-be egy szűk, csak-olvasható `TenantUser`
projekció replikálódik (`coreUserId`, `displayName`, `email`, `roles[]`,
`isActive`). A tenant-oldali entitások (felelős, naplózó stb.) erre a
`TenantUser`-re mutatnak FK-val, nem a Core `User`-re. A működési útvonalon
nincs cross-DB join.

**Indok:** A cross-DB join elkerülése a működési lekérdezésekben (bejelentés-lista,
adatlap, Dashboard); a `BaseController` AutoMapper-projekciói a tenant DB-n
belül maradnak.

**Mérlegelt alternatíva:** Teljes `User`-replikáció (felesleges adat); cross-DB
olvasás (lassú, ellentmond az önellátó-elvnek).

**Ki döntötte:** Specifikáció, a fejlesztői iránymutatás alapján.

### SD-3 — Egyirányú Core→Tenant szinkron

**Döntés:** A szinkron egyirányú, a Core a "source of truth". A
`User`/`UserTenantRole` változás **azonnal**, a Core-oldali mentés
tranzakciójához kötve propagál a `TenantUser`-be. A default kategória-katalógus
csak tenant-provisioning-időben másolódik. Más Core-adat nem replikálódik. A
`TenantUser` a tenant-oldalon soha nem szerkeszthető.

**Indok:** Az egyirányúság kizárja a konfliktus-feloldást (divergencia,
last-write-wins). A "mi azonnal, mi nem" elve: a változás gyakorisága és az
elvárt konzisztencia dönt — a felhasználó/szerepkör azonnal kell (kiosztás,
jogosultság), a katalógus ritka.

**Nyitott technikai részlet:** A tranzakció-határon átnyúló sync konkrét
mintája (event-driven outbox / közvetlen propagálás / reconciliation-job)
fejlesztői műhely-döntés. Elvárás: a sync tranzakcióhoz kötött, de a
Core-művelet sikere ne függjön a tenant DB válaszidejétől.

**Ki döntötte:** Specifikáció, a fejlesztői iránymutatás alapján.

### SD-4 — A `Tenant`-regisztrum pilot-sémája

**Döntés:** A Core `Tenant` tábla mezői: `id`, `code` (a header-érték),
`name`, `dbConnectionRef` (nem nyers connection string — secret-hivatkozás),
`status`, `timeZone`, plusz `AuditableEntity`-mezők.

**Indok:** A pilot-minimum, ami a tenant-resolutionhöz és a megjelenítéshez
kell. A `dbConnectionRef` titok-kezelési elve: jelszó nem a táblában.

**Ki döntötte:** Specifikáció (a kérdéslista ezt "Nem eldöntött"-ként hagyta —
a "dönts te" felhatalmazás alapján).

### SD-5 — A `Tenant.status` értékkészlete

**Döntés:** Négy érték: `Setup` (provisioning alatt, csak Urbino-admin éri el),
`Active` (éles), `Suspended` (felfüggesztve, 403), `Archived` (lezárt, csak
olvasható). A pilotra a `Setup → Active` átmenet él; mind a négy érték az
első naptól létezik.

**Indok:** Hogy a tenant életciklusát ne kelljen később migrálni. A
`Suspended`/`Archived` az Urbino-admin későbbi modulja.

**Ki döntötte:** Specifikáció (a "dönts te" felhatalmazás alapján).

### SD-6 — Tenant-resolution middleware-ben

**Döntés:** A tenant-resolution ASP.NET Core middleware-ben történik. A DI
per-request scope-ban ad ki tenant-specifikus `DbContext`-et tenant-aware
factory-n keresztül. A `BaseController` a tenant-resolutionről nem tud —
transzparens.

**Indok:** A kérdéslista 1. pontjának fejlesztői válaszai (middleware,
per-request scope, transzparens controller).

**Ki döntötte:** Specifikáció, a fejlesztői műhely válaszai alapján.

### SD-7 — A tenant-szerepkörök kódbeli nevei

**Döntés:** `dispatcher`, `manager`, `content_manager`, `field_worker`. A
teljes Zitadel-szerepkör a `tenant_<role>_<code>` mintát követi (pl.
`tenant_dispatcher_almadi`).

**Indok:** A `05_jogosultsagok_v2.md` négy szerepkörének kódbeli leképezése,
a `CLAUDE.md` névkonvenciójával konzisztensen.

**Nyitott pont:** A `manager` név megfelelő-e (a `CLAUDE.md` példája is ezt
használja, de a tenant-admin értelmében) — fejlesztői visszajelzést kér; egy
soros csere, ha mást preferálnak.

**Ki döntötte:** Specifikáció (a "dönts te" felhatalmazás alapján);
megerősítésre vár.

### SD-8 — A kategória-katalógus hibrid modellje

**Döntés:** A default kategória-katalógus a Core DB-ben él
(`DefaultCategoryCatalog`); tenant-provisioning-időben lemásolódik a tenant DB
`Category` táblájába; minden másolt rekord megtartja a `sourceCatalogId`
hivatkozást a Core-forrásra. A tenant-oldali működés kizárólag a tenant DB
`Category` tábláját kérdezi.

**Indok:** A kérdéslista 5. pontjának három opciója közül a hibrid — tiszta
(cross-DB nélküli) lekérdezés, és követhető marad, melyik kategória
termékesített (K-036 termék/tenant tulajdon-határa a `sourceCatalogId`-ra
épül).

**Mérlegelt alternatíva:** Üres tenant-tábla + Core-olvasás (cross-DB minden
olvasásnál); független másolat forrás-hivatkozás nélkül (elveszik a
"rendszer-default" információ).

**Ki döntötte:** Specifikáció.

### SD-9 — UTC tárolás

**Döntés:** Minden időpont-adat UTC-ben tárolódik, PostgreSQL `timestamptz`
oszloptípussal. A szerver minden belső számítást UTC-ben végez.

**Indok:** A kérdéslista 6. pontjának válasza ("with timezone").

**Ki döntötte:** Specifikáció, a fejlesztői műhely válasza alapján.

### SD-10 — Tenant-szintű megjelenítési időzóna

**Döntés:** A megjelenítési időzóna tenant-szintű (`Tenant.timeZone`, alap
`Europe/Budapest`), nem a felhasználó eszközéé. A nap/hét-határt (a Dashboard
"ma"/"ez a hét" definíciója) a szerver számítja tenant-időzónában.

**Indok:** A városgazdálkodás földrajzi helyhez kötött — a tenant-időzóna
konzisztens élményt ad. A `40_riport` megköveteli, hogy a Dashboard és a heti
PDF ugyanazt a hét-definíciót használja — ezért a határ a szerveren.

**Nyitott pont:** Az egyedi időpont-mezők megjelenítés-konverziójának helye
(szerver-oldali DTO vs. admin felület) fejlesztői döntés.

**Ki döntötte:** Specifikáció, a kérdéslista válasza alapján.

### SD-11 — Offset-alapú paginálás

**Döntés:** A lista-végpontok offset-alapú paginálást használnak a meglévő
`ListRequest` mintán. Nincs cursor-paginálás a pilotra.

**Indok:** A kérdéslista 7. pontjának válasza ("Offset based"); a pilot-skálán
(~100 bejelentés/hó) az offset nem okoz lassulást.

**Ki döntötte:** Specifikáció, a fejlesztői műhely válasza alapján.

### SD-12 — Egyedi hibasséma

**Döntés:** A hibaválasz egyedi séma — HTTP státuszkód + JSON hibatest, nem
RFC 7807. A 400-as validációs hiba a meglévő `fieldErrors` szerkezetet adja.
A státuszkód-keret: 400 validáció, 401 auth, 403 jogosultság/rossz tenant
header, 404 nem létező vagy idegen tenant ID, 409 állapot-konfliktus, 422
üzleti szabály.

**Indok:** A kérdéslista 7. pontjának válasza ("egyedi. státuszkód + json
válasz"). A 404 idegen tenant-ID-ra biztonságilag helyes (nem árulja el, hogy
az ID másik tenantnál létezik); a 403 a rossz tenant headerre marad.

**Ki döntötte:** Specifikáció, a fejlesztői műhely válasza alapján.

### SD-13 — Cross-tenant kísérlet naplózása

**Döntés:** A cross-tenant hozzáférési kísérlet (rossz/jogosulatlan `Tenant`
header) naplózott biztonsági esemény: időpont, Core `User.id`, kért tenant
`code`, tényleges jogosultságok. A naplózás nem blokkolja a 403-as választ.

**Indok:** A K-008 multi-tenant fegyelem — a jogosulatlan tenant-hozzáférés
vagy hibás kliens, vagy támadási kísérlet, mindkettő naplózandó.

**Nyitott pont:** Az általános application-logging stratégia (Serilog vs.
built-in, hová gyűlik) üzemeltetési döntés; a specifikáció csak a tenant-id
kötelező jelenlétét írja elő minden naplóeseményben.

**Ki döntötte:** Specifikáció.

---

## Specifikációs döntések — domain-modell, 1–4. blokk (SD-14 — SD-23)

> Forrás: `00_domain_model.md` v0.2–v0.5, 2026.05.18. A `Ticket` és kísérői,
> a referencia-entitások, a Core DB és a tartalmi entitások blokk döntései. A
> TD-1 — TD-13 tervezési pontokat az alapító 2026.05.18-án eldöntötte; az
> alábbi SD-k a naplózott végeredmény.

### SD-14 — Esemény-időpontok denormalizálása a `Ticket`-en

**Döntés:** Az `assignedAt` (`Új → Kiosztva` időpontja) és a `resolvedAt`
(`Folyamatban → Lezárt` időpontja) dedikált mezőként a `Ticket`-en is
megjelenik, az `ActivityLog` mellett — tudatos denormalizáció.

**Indok:** A riport-aggregáció (átlagos lezárási idő = `resolvedAt − createdAt`,
`40` 3.5) gyakori lekérdezés; napló-aggregációból számolni minden riportnál
drága. A két leggyakrabban kérdezett esemény-időpont a `Ticket`-en
denormalizáltan él.

**Mérlegelt alternatíva:** Minden esemény-időpontot csak az `ActivityLog`-ból
számolni — elvetve a riport-teljesítmény miatt. A többi esemény-időpont
(pl. `InProgress`-be lépés) marad az `ActivityLog`-ban.

**Ki döntötte:** Specifikáció (tisztán technikai döntés).

### SD-15 — Általános `Attachment` entitás és S3-tárolás

**Döntés:** A csatolmány-entitás `Attachment` néven (nem `Photo`), `AttachmentKind`
(`ReportPhoto` / `ResolutionPhoto`) + `contentType` mezővel. A fájl bináris
adata nem a DB-ben van: S3-kompatibilis blob storage tárolja, az
`Attachment.fileRef` egy hivatkozás oda.

**Indok:** Az általános `Attachment` (a `Photo` helyett) lehetővé teszi, hogy
egy későbbi nem-fotó csatolmány ne igényeljen új entitást. Az S3-tárolás a
kérdéslista 8. pontjának fejlesztői válasza.

**Mérlegelt alternatíva:** `Photo`-specifikus entitás — elvetve a bővíthetőség
kedvéért.

**Nyitott pont:** A feltöltési flow (presigned URL, tömörítés, méretkorlát) a
bejelentés-feltöltés feature-spec dolga; a blob storage tenant-szegmentációja
fejlesztői döntés.

**Ki döntötte:** Specifikáció (tisztán technikai döntés).

### SD-16 — A `ticketNumber` megjelenítési azonosító

**Döntés:** A `Ticket` egy `ticketNumber` mezőt kap — tenant-szinten
folyamatos, 1-től induló egész sorszám. A belső `id` (auto-increment PK) soha
nem jelenik meg a felhasználónak. A felhasználói felületeken a megjelenő
azonosító a `Tenant.displayPrefix` + `-` + `ticketNumber` (pl. `ALM-234`).

**Indok:** A belső auto-increment `id` kiszivárogtatása rossz gyakorlat (lyukas
lehet, sorszám-becslést tesz lehetővé). A `ticketNumber` tenant-szintű, mert a
`Ticket` a Tenant DB-ben él (SD-1). A `displayPrefix` azért kell, mert a polgár
**több városnál is** bejelenthet, és a polgári app városokon átnyúló
"Bejelentéseim" listájában a két azonos sorszámú ügy így vizuálisan elkülönül.

**Mérlegelt alternatíva:** Az `id` közvetlen megjelenítése (kiszivárogtatja a
belső sorszámot); év-prefixes azonosító, pl. `2026-0234` (a pilotra fölösleges
komplexitás).

**Nyitott technikai pont:** A `ticketNumber` ütközésmentes, tenant-szintű
kiosztásának mintája (külön szekvencia vagy zárolt számláló) fejlesztői döntés,
a `Ticket`-spec rögzíti. Új mező a `Tenant`-on: `displayPrefix` (3. blokk).

**Ki döntötte:** Az alapító, a "fenntartható, többvárosos" szempont
megadásával; a specifikáció dolgozta ki.

### SD-17 — A belső jegyzet külön `TicketNote` entitás

**Döntés:** A belső jegyzet nem a `Ticket` egy szövegmezője, hanem külön
`TicketNote` entitás: egy bejelentéshez több jegyzet fűzhető, mindegyik saját
szerzővel (`authorId → TenantUser`) és időponttal. A `Ticket.internalNote`
mező és a `NoteAdded` `ActivityLog`-esemény elmarad.

**Indok:** A több-bejegyzéses jegyzet-történet hamar igénnyé válik (diszpécser
és vezető is fűzhet megjegyzést, időrendben). Egy felülíródó `Ticket`-mező ezt
nem tudná. Mivel a `TicketNote` maga a jegyzet-történet, nincs szükség külön
`NoteAdded` naplóeseményre — az `ActivityLog` tisztán az életciklus-eseményeké
marad.

**Mérlegelt alternatíva:** Egyetlen `internalNote` szövegmező a `Ticket`-en
(a `10` 3.2 így mutatta) — elvetve, mert a több-jegyzet igény előrelátható.

**Ki döntötte:** Az alapító ("legyen több hozzáadható érték már most").

### SD-18 — A bejelentés-besorolás bármely kategória-szinten teljes

**Döntés:** A `Ticket.categoryId` (és a `citizenSuggestedCategoryId`) **bármely**
`Category`-rekordra mutathat — gyökér-kategóriára vagy alkategóriára egyaránt.
Egy bejelentés besorolása teljes akkor is, ha csak gyökér-kategóriáig megy; az
alkategória pontosít, de nem kötelező.

**Indok:** A polgári `screen_uj_bejelentes_2` képernyő hat gyökér-szintű
csempét mutat, alkategória-választó lépés nélkül — ha a modell kötelező
alkategóriát írna elő, a polgári bejelentés sosem lehetne érvényes triage
előtt. A triage-ben (K-031) az alkategória így *lehetőség*, nem kötelező
ötödik kattintás, ami a gyors triage-t (`10`, 30 mp cél) támogatja. A kötelező
alkategória ráadásul értelmezhetetlen a természetesen alkategória-nélküli
gyökereknél (pl. "Egyéb"). A felhasználóbarát választás a nem-kötelező
alkategória.

**Mérlegelt alternatíva:** Kötelező alkategória minden bejelentésre — elvetve;
mesterséges "alapértelmezett alkategória" minden gyökér alá kellett volna,
ami zaj, és a polgári flow-t megtörné.

**Következmény:** A duplikáció-heurisztika (K-032) gyökér-szintű
kategória-egyezése változatlanul működik — a `Category.parentId` self-FK-n a
heurisztika mindig felmegy a gyökérig. Az 1. blokk `categoryId`-sorai e döntés
szerint javítva (nem "alkategória-szintű" többé).

**Ki döntötte:** Az alapító ("kezeld úgy, ahogy felhasználóbarátabbnak
gondolod"); a specifikáció dolgozta ki.

### SD-19 — A `User` globális, szerepkör-mentes entitás

**Döntés:** A Core `User` entitás **nem** tartalmaz szerepkör-mezőt. A
szerepkör a `UserTenantRole` kötés-entitáson él, és tenantonként eltérhet. A
`User.status` a globális fiók-állapot (`Invited` / `Active` / `Disabled`); a
tenant-szintű aktivitást a `UserTenantRole` és a `TenantUser.isActive` adja.

**Indok:** Egy `User` több tenanthoz is tartozhat (K-025 implicit unió-modell,
`01_kozos_mintak` 1.3), tenantonként más szerepkörrel. A szerepkör ezért
fogalmilag a (felhasználó, tenant) párhoz tartozik, nem a felhasználóhoz.

**Mérlegelt alternatíva:** Szerepkör-mező a `User`-ön — elvetve, mert a
többtenantos modellben értelmezhetetlen (melyik tenant szerepköre?).

**Ki döntötte:** Specifikáció (a többtenantos modell természetes
következménye).

### SD-20 — A `UserTenantRole` explicit kötés-entitás

**Döntés:** A `User` ↔ `Tenant` kapcsolatot egy explicit `UserTenantRole`
entitás modellezi (`userId`, `tenantId`, `role`), nem `[ManyToManyConnection]`
attribútumos join. Egy (felhasználó, tenant, szerepkör) hármas egy sor; több
szerepkör ugyanazon a tenanton több sor.

**Indok:** A kapcsolatnak saját adata van (a `role`), és a `CLAUDE.md`
`[ManyToManyConnection]` mintája tiszta, attribútum nélküli join-táblára való.
Az explicit entitás ráadásul lehet `AuditableEntity` — a szerepkör-hozzárendelés
ki/mikor adata audit-érték.

**Mérlegelt alternatíva:** `[ManyToManyConnection]` a `User` és `Tenant`
között — elvetve, mert a `role` attribútumot nem hordozná tisztán.

**Ki döntötte:** Specifikáció (tisztán technikai döntés).

### SD-21 — A tartalmi típusok külön entitások

**Döntés:** A `News`, `Event`, `CityInfo` három külön entitás a Tenant DB-ben,
nem egyetlen közös `Content` entitás `contentType` diszkriminátorral.

**Indok:** A három típus mezőkészlete érdemben eltér — az `Event`-nek
időpontja (`startsAt`/`endsAt`) és helyszín-koordinátája van, a `CityInfo`-nak
kötelező külső `url`-je, a `News` ezektől mentes. Egy közös entitás sok
típus-feltételes nullable mezőt jelentene, ami a validációt és a
`BaseController`-illesztést zavarossá teszi. Három tiszta entitás külön
`BaseController`-leszármazottal és `TableStateConfig`-gal átláthatóbb; a
`60_tartalom` is három külön nézetcsaládként kezeli őket.

**Mérlegelt alternatíva:** Egy közös `Content` entitás `contentType`
diszkriminátorral — elvetve a típus-feltételes mezők zavarossága miatt.

**Ki döntötte:** Specifikáció (tisztán technikai döntés).

### SD-22 — A tartalmi életciklus háromértékű enum

**Döntés:** A tartalmi entitások publikálási életciklusa `ContentStatus` enum:
`Draft` / `Published` / `Archived`. Nem egyszerű `isPublished` logikai mező.

**Indok:** Az `Archived` állapot — a "volt publikálva, de már nem aktuális" —
egy logikai mezővel nem megkülönböztethető a "még sosem volt publikálva"
`Draft`-tól. A háromértékű enum tisztán elválasztja a sosem-publikált, az élő
és a visszavont tartalmat, ami a tartalomkezelő archívum-nézetéhez kell
(`60_tartalom` 3.5).

**Mérlegelt alternatíva:** `isPublished` bool — elvetve, mert az `Archived`
és a `Draft` nem különböztethető meg vele.

**Ki döntötte:** Specifikáció (tisztán technikai döntés).

### SD-23 — A tartalmi szerző az `AuditableEntity.createdBy`

**Döntés:** A tartalmi entitások (`News`, `Event`, `CityInfo`) szerzője az
`AuditableEntity.createdBy` (a Core `User.id`) — nincs külön `authorId →
TenantUser` mező, eltérően a `TicketNote`-tól (SD-17).

**Indok:** A `TicketNote` azért kapott külön `authorId`-t, mert ott a
szerző-megjelenítés gyakori és cross-DB join nélkül kell. A tartalmi
entitások listái a pilotra nem feltétlenül mutatják a szerző nevét minden
soron hangsúlyosan; ahol mégis kell, a `TenantUser`-feloldás elérhető.

**Mérlegelt alternatíva:** `authorId → TenantUser` mező a tartalmi
entitásokon is — nem elvetve, hanem **a `60_tartalom`-specre halasztva**: ha
a tartalom-listák szerző-oszlopa cross-DB nélküli megjelenítést igényel, a
mező felvehető.

**Ki döntötte:** Specifikáció; **megerősítendő a `60_tartalom` feature-specnél**.

---

## Specifikációs döntések — bejelentés-lista és -adatlap feature (SD-24 — SD-32)

> Forrás: `20_admin_felulet/10_bejelentes_lista_es_adatlap.md` v1.0,
> 2026.05.18. A manager (admin) felület első feature-specének tervezési
> döntései, a 9 lépéses munkamenet 2. és 4. lépésében jóváhagyva.

### SD-24 — Optimistic-update: rekord-szintű konfliktus-detektálás

**Döntés:** Az inline-szerkesztés optimistic-update ütközését **rekord-szinten**
detektáljuk: ütközés akkor van, ha a `Ticket` **bármely** mezeje változott a
betöltés óta. A kliens a betöltött `updatedAt`-ot visszaküldi
(`expectedUpdatedAt`); ha nem egyezik a tárolttal, a mentés `409`-cel elutasul.

**Indok:** A pilot ügyforgalmán (~100 bejelentés/hó, egy kisváros) rendkívül
ritka, hogy két diszpécser ugyanazt az ügyet triage-elje egyszerre — a "Új" tab
épp azt szolgálja, hogy ki-ki más ügyet vesz. A "hamis" ütközés (két különböző
mező) gyakorlatilag nem fordul elő, és ha mégis, a `409` kezelése elfogadható. A
mező-szintű detektálás bonyolultsága nincs arányban a pilot-haszonnal.

**Mérlegelt alternatíva:** Mező-szintű detektálás (ütközés csak ugyanazon mező
egyidejű írásakor) — elvetve a pilotra; a bonyolultsága (mezőnkénti
verzió-követés) aránytalan. 6-12. hó: ha egy nagyobb tenant forgalma indokolja,
lokalizált finomítás.

**Ki döntötte:** Az alapító, a specifikáció javaslatára.

### SD-25 — `409`-feloldás: teljes adatlap-újratöltés

**Döntés:** Ha az inline-mentés `409`-et ad (`reason: "stale"`), az adatlap a
friss szerver-állapottal **teljesen újratöltődik**, és nem-blokkoló jelzés
jelenik meg. A diszpécser épp szerkesztett mezeje a friss értékre áll vissza.

**Indok:** A pilot-scope-hoz (K-016) képest egy konfliktus-feloldó merge-UI túl
nehéz. A teljes újratöltés egyszerű, kiszámítható, és a ritka esetre arányos.

**Mérlegelt alternatíva:** Ütköző mező kiemelése + merge-UI (a diszpécser
eldönti, melyik érték maradjon) — elvetve a pilot-scope miatt.

**Ki döntötte:** Az alapító, a specifikáció javaslatára.

### SD-26 — A triage-sáv csak nem-végállapotban szerkeszthető

**Döntés:** A bejelentés-adatlap triage-sávjának négy inline mezeje (kategória,
prioritás, határidő, felelős) **csak `New`, `Assigned`, `InProgress` állapotban**
szerkeszthető. `Resolved` és `Rejected` ügyön mind a négy mező csak olvasható.

**Indok:** Egy lezárt ügy mezőit "csendben" módosítani megkerüli az
állapotgépet és rontja az audit-tisztaságot. Ha egy `Resolved` ügyön változtatni
kell, a helyes út a korrekciós visszanyitás (`Resolved → InProgress`), és utána a
módosítás. A `Rejected` amúgy is kemény végállapot (Ü-4).

**Mérlegelt alternatíva:** A `Resolved`-on a felelős-mező nyitva marad (mert a
`Resolved` puha végállapot) — elvetve az egyszerű, egységes szabály kedvéért.

**Ki döntötte:** Az alapító, a specifikáció javaslatára.

### SD-27 — Az állapot-csík négy fő-ági állapotot mutat

**Döntés:** Az adatlap állapot-csíkja a négy fő-ági állapotot mutatja
(`Új → Kiosztva → Folyamatban → Lezárt`), az aktuális kiemelve; a "Triage" elem
**kikerül** a csíkról (nem állapot — `10` 2.1). `Rejected` ügyön a csík helyett
önálló "Elutasítva" jelző áll, az elutasítási indok megjelenítésével.

**Indok:** A csík tájékozódási segédlet, nem az állapotgép rajza — a formális
modellt a `02_globalis_allapotgep.md` adja. A "Triage" elem eltávolítása
konzisztens a `10` 2.1-gyel ("a triage művelet, nem állapot"). A `Rejected`
mellékág-jellegét egy külön jelző tisztábban közli, mint egy elágazó csík.

**Mérlegelt alternatíva:** A csík 1:1 tükrözi az állapotgépet, elágazással az
`Elutasítva` mellékágra — elvetve a vizuális összetettség miatt.

**Következmény:** Visszacsorgó jelzés a funkcionális projektnek (VF-1): a
`00_architektura_v4.md` 4.2 állapot-csík vázlata a "Triage"-t állapotként
ábrázolja — az ábra pontosítandó.

**Ki döntötte:** Az alapító, a specifikáció javaslatára.

### SD-28 — A "Triage kész" gomb mindig hív, a szerver validál

**Döntés:** A "Triage kész — Kiosztás" gomb technikailag **mindig kattintható**
és hív; a szerver érvényesíti a triage-előfeltételt (`02_globalis_allapotgep.md`
5.1 — `categoryId` és felelős kitöltve), és hiány esetén `422` + `fieldErrors`-t
ad. A kliens **előjelezheti** a hiányt (halvány gomb + tooltip) — ez kényelmi
réteg, nem a validáció helyettesítője.

**Indok:** A szerver az igazság forrása — egy elavult kliens sem tud félkész
ügyet kiosztani. A kliens-oldali előjelzés a triage-élményt gyorsítja, de nem
megkerülhető védvonal. Konzisztens a `[validationForm]` minta szellemével.

**Mérlegelt alternatíva:** A gomb diszabolt, amíg a kötelező mezők hiányoznak
(tisztán kliens-oldali kapuzás) — elvetve, mert a szerver-oldali validáció így is
kötelező, és a két réteg közül a szerveré az elsődleges.

**Ki döntötte:** Az alapító, a specifikáció javaslatára.

### SD-29 — A duplikátum-adatlap redukált, csak-olvasható nézet

**Döntés:** Egy duplikációként elutasított `Ticket` (kitöltött `originalTicketId`)
adatlapja **redukált, csak-olvasható nézet**: a polgári nyersanyag (cím, leírás,
fotók, helyszín) + hangsúlyos link az eredeti ügyre. A triage-sáv, az
akció-gombsor és a "Hasonló bejelentések" doboz **nem jelenik meg**.

**Indok:** A duplikátum lezárt mellékág-ügy; a teljes triage-apparátust mutatni
rajta zaj. A redukált nézet a lényegre vezet: "ez egy duplikátum, itt az
eredeti". A `20` 4.2 amúgy is csak a kétirányú linket írja elő.

**Mérlegelt alternatíva:** Teljes adatlap, zárolt mezőkkel — elvetve, mert a
triage-apparátus egy duplikátumon értelmetlen.

**Megjegyzés:** A redukált nézet pontos tartalma interakcióban van a duplikáció
feature-spec-kel — az finomíthatja.

**Ki döntötte:** Az alapító, a specifikáció javaslatára.

### SD-30 — A bejelentés-lista és -adatlap szemantikai szabályai

**Döntés:** A 2. lépés II. szekciójában jóváhagyott kilenc szabály egy
döntésként:

1. **"Késésben" tab** — a `dueDate` nélküli ügy soha nem kerül a "Késésben"
   tabba; a "késés" határa a tenant-időzóna szerinti napkezdet (egy ügy akkor
   késésben, ha `dueDate` < a mai nap kezdete). A határidő napján még nincs
   késésben.
2. **"Hozzám rendelt" tab** — `assignedUserId == kérő` **VAGY**
   `assignedGroupId ∈ a kérő csoporttagságai`. Indok: a terepi munka csoportra
   oszlik, a terepi dolgozó landingje ez a tab.
3. **"Mind" tab** — alapból a `Rejected` ügyeket is tartalmazza; a státusz-szűrő
   szűkíthet.
4. **Tab × fejléc-szűrő** — a tab rögzített `AND`-előszűrő; a státusz-fejléc-szűrő
   választéka a tabra szűkül, így az ellentmondás elő sem áll.
5. **Default rendezés** — minden tabon `createdAt DESC`, kivéve a "Késésben"
   tabot, ahol `dueDate ASC`.
6. **Lista kategória-oszlop** — a `categoryId` neve, ha kitöltött; különben a
   `citizenSuggestedCategoryId` neve "(javasolt)" jelöléssel; különben "—".
7. **Tevékenység-napló** — emberi mondatokká formázva jelenik meg; az
   `ActivityLog.fromValue`/`toValue` stabil, nyelvfüggetlen azonosítót tárol,
   nem magyar felületi szöveget — a magyar megjelenítést az admin felület
   i18n-rétege adja.
8. **Felelős-mentés** — egyetlen `/assignee` végpont; az `ActivityLog`-esemény
   típusát az ügy állapotából vezeti le (`New` → mezőírás esemény nélkül;
   `Assigned`/`InProgress` → `Reassigned`).
9. **Terepi adatlap-nézet** — az adatlap egyetlen, szerepkör-érzékeny nézet: a
   `field_worker` a triage-sávot csak olvassa, a belső jegyzetet csak olvassa, a
   "Hasonló bejelentések" dobozt nem látja; a `content_manager` az adatlapot nem
   éri el.

**Indok:** Mind a kilenc a funkcionális dokumentumok és az alapdokumentumok
határát súrolja; a felfedezés-lépésben (1. lépés) edge case-ként merültek fel, és
a 2. lépésben egyenként jóváhagyva.

**Ki döntötte:** Az alapító, a specifikáció javaslatára.

### SD-31 — Inline-mentés mezőnkénti `PUT`-végpontokkal

**Döntés:** A négy triage-mező inline-mentése négy dedikált végponton történik
(`PUT /v1/tickets/{id}/category|priority|due-date|assignee`), nem egy összevont
`PATCH`-csel.

**Indok:** A felelős inline-mentése `Assigned`/`InProgress` állapotban
`Reassigned` `ActivityLog`-eseményt vált, a kategória/prioritás/határidő mentése
**nem** vált eseményt — egy dedikált végpont az esemény-típust tisztán tudja, egy
általános `PATCH`-nek dedukálnia kellene. A mezőnkénti `PUT`-ok a
`02_globalis_allapotgep.md` akció-végpont-stílusába illeszkednek, és az
`authorization.json` mezőnként szabályozható.

**Mérlegelt alternatíva:** (A) egy összevont `PATCH /v1/tickets/{id}` — elvetve
az esemény-naplózás dedukciós nehézsége miatt; (C) hibrid (`PATCH .../triage` a
három egyszerű mezőre + külön `/assignee`) — elvetve, mert a határ önkényes.

**Ki döntötte:** Az alapító, a specifikáció javaslatára.

### SD-32 — Az `updatedAt` mint optimistic-concurrency token

**Döntés:** A `Ticket.updatedAt` (`AuditableEntity`-ből, `timestamptz`, SD-9) az
inline-szerkesztés és az akció-végpontok **optimistic-concurrency tokenjeként**
is szolgál. Nincs külön `rowVersion` mező. A kliens a betöltött `updatedAt`-ot
visszaküldi (`expectedUpdatedAt`); ha nem egyezik a tárolttal, a művelet
`409`-cel (`reason: "stale"`) elutasul.

**Indok:** Az `updatedAt` már létezik (`AuditableEntity`), `timestamptz`, és az
`AppDbContext` automatikusan frissíti. Egy dedikált `rowVersion`/xmin külön
EF-konfigot kívánna — fölösleges a pilotra, a rekord-szintű detektáláshoz
(SD-24) az `updatedAt` elegendő.

**Eltérés a `BaseController` mintától:** a standard `BaseController` update nem
ellenőriz verziót — az inline-mentő és az akció-végpontok igen (a kliens által
küldött `updatedAt`-ot összevetik a tárolttal a mentés előtt). A feature-spec
"Eltérés a mintától:" jelöléssel rögzíti. A `00_domain_model.md` 1.2.8 egy
megjegyzés-sorral bővül a kettős szerepről — **nem új mező**.

**Mérlegelt alternatíva:** Dedikált `rowVersion` mező — elvetve, fölösleges
EF-konfig a pilotra.

**Ki döntötte:** Specifikáció (a 3. lépésben SD-súlyúnak ítélve a
`00_domain_model.md`-érintettség miatt).

### SD-33 — A specifikációs dokumentumok külön `urbino-docs` repóban

**Döntés:** A specifikációs dokumentumok (alapdokumentumok és feature-specek)
egy önálló `urbino-docs` Git-repóban élnek **kanonikusan**. Egy CI-szinkronizáló
script a releváns részeket a kódrepók (`project_backend`,
`project_backend_client_angular`) `docs/` mappáiba másolja; a Claude Code a
kódrepó `docs/` mappájából olvassa a kontextust.

**Indok:** A specifikáció és a kód külön életciklusú — a spec a kód előtt jár,
és több kódrepót szolgál ki. A kanonikus különtartás megakadályozza, hogy a
spec szétdivergáljon a két kódrepó között; a CI-másolás biztosítja, hogy a
Claude Code mindig a friss, kanonikus változatot lássa.

**Következmény — fájlnév-konvenció:** Repó-kontextusban a verziót a Git
commit-history hordozza. A fájlnevek ezért **stabilak és timestamp-mentesek**
(`00_domain_model.md`, `20_admin_felulet/10_bejelentes_lista_es_adatlap.md`); a
tartalmi verziószám a fájl fejlécében (`Verzió:`) és a verziónaplóban él. A
2026.05.18-i kézi átadáshoz használt timestamp-es elnevezés
(`__v1.1__20260518`) átmeneti — az `urbino-docs` repó felállásával megszűnik.

**Következmény — a szinkronizáló script hatóköre:** definiálandó, melyik
kódrepó `docs/`-jába mi kerül. Irányelv: a feature-spec szerver-fejezete a
`project_backend`-be, az admin-fejezete a `project_backend_client_angular`-be
releváns; a `00_domain_model`, `02_globalis_allapotgep`, `01_kozos_mintak`,
`00_terminologia`, `kanonikus_donek` **mindkét** kódrepóba. A pontos
script-konfiguráció CI/DevOps-hatáskör — nem a specifikációé —, de karbantartandó,
ahogy új feature-spec születik.

**Mérlegelt alternatíva:** A specifikáció a kódrepók `docs/` mappájában él
közvetlenül (külön repó nélkül) — elvetve, mert két kódrepó van, és a spec
közöttük szétdivergálna; nincs egyetlen kanonikus forrás.

**Ki döntötte:** Az alapító.

---

## Specifikációs döntések — felhasználókezelés feature (SD-34 — SD-39)

> Forrás: `20_admin_felulet/20_felhasznalokezeles.md` v1.0, 2026.05.19. Az
> SD-34 — SD-39 a felhasználókezelés és a jogosultság-modell érvényesítésének
> döntései.

### SD-34 — A meghívó-token külön `UserInvitation` entitásban él

**Döntés:** A felhasználó-meghívó tokenje egy önálló `UserInvitation`
Core-entitásban él (`userId`, `tenantId`, `tokenHash`, `expiresAt`, `status`,
`consumedAt`), nem a `User` mezőiként. Egy `User`-höz időben több
`UserInvitation` is tartozhat; a tábla `AuditableEntity`.

**Indok:** A meghívásnak saját, ismételhető életciklusa van — kiküldik, lejár,
újraküldik (új token, régi érvénytelen), beváltják. Ha ezt a `User`-en
tárolnánk, az újraküldés felülírná az előzményt, és nem maradna nyoma, hányszor
és mikor hívták meg a felhasználót. Külön entitásként a meghívási kísérletek
sora megmarad, és a `createdBy` rögzíti, ki (melyik vezető) küldte a meghívót.

**Mérlegelt alternatíva:** Meghívó-mezők a `User`-en (`inviteToken`,
`inviteExpiresAt`) — elvetve, mert az újraküldés felülírná az előzményt, és a
meghívási történet elveszne.

**Ki döntötte:** Specifikáció (tisztán technikai döntés).

### SD-35 — A meghívó-token lejárata 7 nap; az újraküldés érvényteleníti a régit

**Döntés:** A meghívó-token érvényessége 7 nap (`expiresAt = createdAt + 7
nap`). A meghívó újraküldése új tokent generál, és a korábbi `Pending`
`UserInvitation`-t ugyanarra a `User`-re ezen a tenanton `Revoked`-ra állítja —
így egy `User`-höz egy tenanton legfeljebb egy `Pending` meghívó tartozik. A
`Pending → Expired` átmenet a pilotra lazy ellenőrzéssel (a beváltási
kísérletkor), nem időzített háttér-jobbal.

**Indok:** A 7 nap átível egy hétvégét és igazodik az önkormányzati tempóhoz,
de nem hagy hetekig nyitva egy aktiválatlan tokent. Az „új token érvényteleníti
a régit" elv kizárja, hogy egyszerre több érvényes meghívó-link létezzen.

**Mérlegelt alternatíva:** 24 vagy 72 órás lejárat — elvetve, az önkormányzati
ügymenethez a 7 nap kényelmesebb. Időzített lejárat-job — iterációba halasztva.

**Ki döntötte:** Az alapító (a lejárati idő); a specifikáció (az újraküldési és
lazy-lejárati mechanika, technikai döntésként).

### SD-36 — Tenant-szűrt Core-lekérdezés a felhasználó-kezelő végpontokon

**Döntés:** A felhasználó-kezelő végpontok (`GET /v1/users`, `invite`, `PUT`,
`deactivate`, `reactivate`, `resend`) a Core DB `User`/`UserTenantRole`
adatait kezelik, de minden lekérdezést a `Tenant` HTTP headerből kiolvasott
tenantra szűrnek: csak az a `User` látható/kezelhető, akinek van
`UserTenantRole`-ja az aktív tenanton. Idegen tenant `User`-ének `id`-jára a
végpont `404`. A szűrést egy dedikált controller (munkanév:
`UserManagementController`) végzi, nem a tenant-resolution middleware.

**Indok:** A vezető csak a saját tenantja felhasználóit kezelheti; cross-tenant
`User` nem szivároghat a listába. A Core DbContext a `BaseController`-mintában
transzparens (SD-6) — de a felhasználó-kezelés tenant-kontextusú felület, ezért
ezen a szűk végpont-körön a Core-lekérdezés tenant-tudatossá válik.

**Eltérés a „Core transzparens" elvtől:** szűk és explicit — csak a
felhasználó-kezelő végpontok szűrnek a `Tenant` headerre; a `User`-t
referenciaként használó más kód (pl. a `CreatedBy`-feloldás) nem.

**Mérlegelt alternatíva:** A felhasználó-lista a tenant DB `TenantUser`-
projekciójából jön, az írás a Core-ra megy — elvetve, mert az olvasás és írás
külön DB-n megtörné a standard `TableStateConfig` CRUD-mintát.

**Ki döntötte:** Specifikáció (tervezési döntés, alapítói jóváhagyással).

### SD-37 — A `TenantUser` `status` enum mezeje az `isActive` bool helyett

**Döntés:** A `TenantUser`-projekció (SD-2) `isActive` (bool) mezeje `status`
enumra változik, amely a Core `UserStatus`-t tükrözi (`Invited` / `Active` /
`Disabled`). A `TenantUser` a meghívott (`Invited`) felhasználót is
projektálja, nem csak az aktívakat.

**Indok:** Egy `Invited` felhasználó se nem „aktív", se nem „letiltott" — a
bináris mező nem tudja megkülönböztetni. Mivel a felhasználókezelés az
`Invited` felhasználót is projektálja (hogy a tenant-oldali felhasználó-lista
és a Dashboard csapat-nézete lássa a még nem aktivált kollégát), a
tenant-oldali kódnak látnia kell a háromértékű állapotot anélkül, hogy a
Core-hoz fordulna.

**Mérlegelt alternatíva:** Marad az `isActive` bool, az `Invited` felhasználó
`isActive = false` — elvetve, mert nem különböztetné meg az `Invited`-et a
`Disabled`-tól.

**Következmény:** Az SD-2 `TenantUser`-sémájának és a `00_domain_model.md` 2.3
szakaszának pontosítása.

**Ki döntötte:** Specifikáció (tervezési döntés).

### SD-38 — Felhasználó-invariánsok: kötelező szerepkör, vezető-védelem, ön-kizárás tilalma

**Döntés:** A felhasználókezelés három üzleti invariánst kényszerít ki: (1)
minden felhasználónak legalább egy `UserTenantRole`-ja van az aktív tenanton —
a felvétel és a szerkesztés is kikényszeríti; (2) a tenant sosem marad vezető
nélkül — az utolsó aktív `manager` szerepkör nem vonható vissza, az utolsó
aktív vezető nem deaktiválható; (3) a vezető nem zárhatja ki önmagát — sem a
saját `manager` szerepkörének visszavonásával (ha ő az utolsó), sem a saját
fiókja deaktiválásával. A sértést a szerver `422` + `reason`-kóddal jelzi.

**Indok:** Pilotkörnyezetben egy elgépelés ne okozzon tenant-leállást: ha egy
tenant vezető nélkül marad, a Beállítások senkinek nem elérhető, és csak
Urbino-admin beavatkozással állítható helyre. A kötelező szerepkör kizárja a
„belép, de semmit nem lát" zavaró állapotot.

**Mérlegelt alternatíva:** Figyelmeztetés, de engedi a műveletet — elvetve,
pilotkörnyezetben a kemény korlát a helyes. Nincs védelem — elvetve.

**Ki döntötte:** Az alapító (a specifikáció által felmutatott alternatívák
közül).

### SD-39 — A `User` nem törölhető, csak deaktiválható

**Döntés:** A `User` entitásnak nincs `delete` művelete; a `BaseController`
`delete` és `bulk delete` műveletei a felhasználó-kezelő controlleren nem
elérhetők. A felhasználó „eltávolítása" mindig deaktiválás (`status =
Disabled`).

**Indok:** A `User.id`-ra a `Ticket.createdBy`/`updatedBy`, az
`ActivityLog.actorId` és a `TicketNote.authorId` hivatkozik. Egy `User`
törlése elárvult hivatkozásokat csinálna. A deaktiválás megőrzi az adatokat és
a hivatkozásokat.

**Mérlegelt alternatíva:** Hard delete kaszkád-anonimizálással — elvetve,
fölösleges bonyolultság a pilotra; a deaktiválás üzletileg elegendő.

**Konzisztencia:** A `Category` „törölni nem, csak deaktiválni" elvével
(`50_konfig` 2.4) azonos megfontolás.

**Ki döntötte:** Specifikáció (tisztán technikai döntés).

---

## Scope-döntés — bejelentés-lista és -adatlap feature

> Nem SD-szintű platform- vagy implementációs döntés, hanem pilot-scope-döntés —
> a követhetőség kedvéért itt rögzítve.

### A pilot-bejelentés-lista bulk-művelet nélkül indul

**Döntés:** A pilot bejelentés-listája **nem kap bulk-műveletet** — sem
tömeges elutasítást, sem batch-triage-t. A `TableStateConfig`-vázlat kijelölő-
oszlop nélkül készül.

**Indok:** Konzisztens a K-016 MVP-fegyelemmel és a `10` 6.2-vel (a batch-triage
explicit elhalasztott). A `02_globalis_allapotgep.md` NY-Á3 formálisan nyitva
hagyta a tömeges státuszváltás kérdését — a pilotra nemleges a válasz. A
`BaseController` bulk-delete-je amúgy sem releváns, mert a `Ticket` nem törölhető
(az elutasítás a "lágy lezárás").

**Visszafordíthatóság:** scope-döntés — a bulk-művelet a 6-12. hónapra
hozzáadható; az állapotgép logikája nem változik, csak a kiváltás lesz csoportos.

**Ki döntötte:** Az alapító, a specifikáció javaslatára (2. lépés).

---

## Jelölt döntések — teljes szöveggel

> Ezek a `01_kozos_mintak.md`-ben jelölve, de nem kaptak SD-számot, mert
> inkább elhatárolások / továbbutalások, mint önálló platform-döntések. A
> követhetőség kedvéért itt teljes szöveggel.

### J-1 — A finomszemcsés permission-réteg elhalasztva

**Döntés:** A pilotra nincs külön permission-kulcs réteg — a szerepkör maga a
jogosultság, az `authorization.json` közvetlenül szerepkörre szabályoz.
Finomszemcsés (mezőnkénti, csoportonkénti) jogosultság a 6-12. hónap dolga.

**Indok:** K-016 (szigorú pilot-scope); a route-alapú `authorization.json`
szerepkör-szinten is teljesen működik. Új szerepkör enélkül is csak egy új
sor a mátrixban.

**Forrás:** `01_kozos_mintak.md` 3.4.

### J-2 — A `Ticket` tevékenység-naplója külön entitás

**Döntés:** A `Ticket` tevékenység-naplója (`ActivityLog`) nem az
`AuditableEntity`-re épül, hanem önálló, append-only entitás a tenant DB-ben:
minden státuszváltás, felelős-váltás, elutasítás, visszanyitás, összevonás
egy-egy rekord. A pontos szerkezetet a `Ticket`-spec / a státusz-állapotgép-spec
fejti ki.

**Indok:** Az `AuditableEntity` csak az utolsó módosítást tudja; a
`10_triage_flow` (4.x, 6.1) változás-történetet követel. Rendszerszintű
audit-modul a pilotra nincs (K-016, `00_architektura` 6.2) — a `Ticket`-szintű
napló elég.

**Forrás:** `01_kozos_mintak.md` 7.2.

---

## Specifikációs döntések — triage- és státusz-kezelés feldolgozó kör (SD-40 — SD-41)

> Forrás: a triage-folyamat és státusz-kezelés admin-felületi feldolgozó köre,
> 2026.05.19. A kör megállapította, hogy a triage- és státusz-akciók
> API-szerződését (3.3–3.4), a jogosultság-route-leképezést (3.8) és az
> i18n-réteget (4.6) a `10_bejelentes_lista_es_adatlap.md` v1.1 **már lefedi** —
> önálló feature-spec nem indokolt. A kör két döntést hozott: egy
> domain-modell-pontosítást (SD-40) és egy reszponzivitás-döntést (SD-41), és a
> `10_bejelentes_lista_es_adatlap.md` v1.2 célzott pontosítását (a 4.7 mobil-
> reszponzív szakasz).

### SD-40 — A `Duplicate` elutasítási indok szövege kliens-oldalról áll össze

**Döntés:** Ha egy `Ticket` `rejectionReasonCode`-ja `Duplicate`, a
`rejectionReasonText` mező **üres marad** (`null`) — a szerver **nem** ír bele
generált szöveget. A duplikáció-hivatkozást strukturáltan az `originalTicketId`
és az `originalTicketDisplayId` mező hordozza. A felhasználónak megjelenő
"Duplikátuma a(z) ALM-X-nek" szöveget a kliens állítja össze egy i18n
sablon-kulcsból (`ticket.rejection.duplicate`, paraméter: `originalDisplayId`).

**Indok:** A platform i18n-elve (`01_kozos_mintak.md` 5.3) szerint a szerver
kulcsot/kódot ad, nem kész szöveget — egy szerver-oldalon generált magyar mondat
nem fordítható, és "befagy" a mezőbe (ha a szövegezés változik, a régi rekordok
régi szöveget hordoznak). A kliens-oldali sablon az SD-30 szellemébe illeszkedik
(a tevékenység-naplónál is a stabil azonosító a szerveré, a szöveg a kliensé), és
a `displayId` megjelenítéskori friss feloldását adja. Az `originalTicketId`/
`originalTicketDisplayId` a hivatkozást **már** hordozza — nincs szükség
redundáns referencia-mezőre.

**A K-034 nem sérül.** A kanonikus döntés azt írja elő, hogy a duplikátum
"Duplikáció" indoklással és **eredeti-ügy hivatkozással** kerül `Elutasítva`-ba.
Ezt a strukturált mezőpár (`originalTicketId`/`originalTicketDisplayId`) + a
belőle rajzolt szöveg teljesíti — a döntés csak azt pontosítja, hogy a
"hivatkozás" strukturált mező (és abból rajzolt szöveg), nem beégetett mondat.

**Mérlegelt alternatívák:** (a) Szerver-oldali generált szöveg a
`rejectionReasonText`-be — elvetve, mert sérti az i18n-elvet és befagyasztja a
szöveget. (b) A `rejectionReasonText` egy nyelvfüggetlen referenciát hordoz (pl.
`ref:ticket:original:5`) — elvetve, mert az `originalTicketId` ezt az
információt már hordozza; redundáns mező.

**Következmény:** A `00_domain_model.md` 1.2.3 `rejectionReasonText` mezősora és
a TD-5 lezáró sora pontosítva (v1.4).

**Ki döntötte:** Az alapító, a specifikáció javaslatára.

---

### SD-41 — A bejelentés-adatlap akció-gombsora keskeny nézetben sticky alsó sáv

**Döntés:** A bejelentés-adatlap (`/bejelentesek/details/<id>`) a Tailwind v4
`lg`-töréspont alatt egyoszlopos elrendezésre vált; ebben a keskeny nézetben az
akció-gombsor a viewport aljára rögzített (sticky) sávban marad, **nem** folyik
a tartalom végére.

**Indok:** A `10_triage_flow_v1.md` 3.6 (Wow #6 — a szombat délutáni baleseti
delegálás) szerint a diszpécser a telefonján, reszponzív nézetben oszt ki egy
sürgős ügyet, 5 percen belül. A "Triage kész — Kiosztás" gomb görgetés nélküli
elérése ehhez kell — hosszú adatlapon (sok fotó, hosszú tevékenység-napló) a
tartalom végén folyó gombsor a görgetés aljára kerülne, ami a triage-keretet
feszíti.

**Mérlegelt alternatíva:** A gombsor a tartalom végén folyik (a tartalmi
folyamot követve) — elvetve, mert hosszú adatlapon a gomb elérhetetlenné válna
görgetés nélkül, és a Wow #6 mérhető ígéretét (5 perc) feszítené.

**Következmény:** A `10_bejelentes_lista_es_adatlap.md` v1.2 új 4.7 szakasza ezt
és a teljes adatlap-reszponzív átrendeződést rögzíti (egyetlen `lg`-töréspont, a
triage-sáv egyoszlopos viselkedése). Egy nyitott finom-mechanika: a sticky sáv és
a virtuális billentyűzet együttműködése — visszacsorgó jelzés a
`01_kozos_mintak.md` reszponzív-rétegéhez (VF-4).

**Ki döntötte:** A specifikáció (technikai/UX-döntés, az alapító jóváhagyásával a
feldolgozó kör menetében).

---

## Specifikációs döntések — duplikáció-szűrés és összevonás feature-spec (SD-42 — SD-48)

> Forrás: a duplikáció-szűrés és bejelentés-összevonás feature-spec
> (`20_admin_felulet/20_duplikacio_es_osszevonas.md` v1.0), 2026.05.19. A
> feature-spec a `20_duplikacio_v1.md` funkcionális tervét és a
> `02_globalis_allapotgep.md` 3.7 kész átmenetét fejlesztői mélységgel tölti
> ki. Hét döntés; a feature **nem vezet be új entitást, enumot vagy tárolt
> mezőt** — a duplikáció adatmodellje (`originalTicketId` self-FK, `Duplicate`,
> `Merged`) a `00_domain_model.md`-ben már kész. A feature-spec a TD-D1 —
> TD-D7 belső jelölést használja; a döntésnaplóban ezek SD-42 — SD-48.

### SD-42 — A bejelentő-átkötés hordozója: nincs külön entitás (TD-D1)

**Döntés:** K-034 előírja, hogy összevonáskor a duplikátum bejelentője az
eredeti ügy értesítendői közé kerül. Ezt **nem külön entitás vagy mező**
hordozza: az eredeti ügy értesítendőinek halmaza lekérdezésből áll elő —
`{eredeti.reporterId} ∪ {d.reporterId | d.originalTicketId = eredeti.id}`. Az
`originalTicketId` self-FK beírása az összevonáskor **önmagában** átköti a
duplikátum bejelentőjét; nincs `TicketSubscriber`-féle kapcsoló-entitás.

**Indok:** A pilotra a duplikáció az **egyetlen** forrása több értesítendőnek
— egy egész entitás egyetlen use-case-ért aránytalan, és feszítené a
pilot-scope-ot (K-016). A lekérdezés-modell illeszkedik a `20_duplikacio_v1.md`
4.2 "fordított navigáció" gondolatához (a self-FK fordított oldala). A megoldás
**nem függ** a nyitott `NY-2`-től (a `reporterId` cél-típusa): csak a
`reporterId` azonosító-szerepét használja, a célentitás modellezését nem.

**Mérlegelt alternatíva:** Új `TicketSubscriber` kapcsoló-entitás
(`[ManyToManyConnection]`, `Ticket` ↔ polgári-felhasználó) — elvetve, mert új
entitás/migráció/EF-config egyetlen pilot-use-case-ért, és a célentitása maga
is nyitott (`NY-2`) volna. Ha jövőben *nem-duplikáció* eredetű feliratkozó is
kell, akkor érdemes erre váltani — addig a lekérdezés arányos.

**Következmény:** A `00_domain_model.md` 1.2.6 egy magyarázó megjegyzés-sort
kap az értesítendő-halmaz lekérdezés-modelljéről. Új tárolt mező nincs. Az
értesítés tényleges **kézbesítése** (csatorna, időzítés) nem ennek a
feature-nek a tárgya — megtartott hiány, a polgári adatigény-spec / `Ticket`-spec
hatásköre (lásd a feature-spec NY-D1).

**Ki döntötte:** Az alapító, a specifikáció javaslatára.

---

### SD-43 — A heurisztika kategória-jele forrás-fallbackkel oldódik fel (TD-D2)

**Döntés:** A duplikáció-heurisztika kategória-jele (K-032) ügyenként
`categoryId` → `citizenSuggestedCategoryId` sorrendben oldja fel a gyökér-
kategóriát. Ha egy ügynek **egyik** kategória-mezeje sincs kitöltve, a
kategória-jel **nem értékelhető**, és — a GPS nélküli eset (`20_duplikacio_v1.md`
2.4) analógiájára — a rendszer nem ad duplikáció-gyanút.

**Indok:** A duplikáció-doboz a triage **közben** jelenik meg, amikor a most
vizsgált ügynek (és a `New` állapotú kandidátusoknak) még nincs megerősített
`categoryId`-ja (`00_domain_model.md` 1.2.2 — a `categoryId` `New`-ban üres
lehet). Fallback nélkül a wow-pillanat pont a triage kezdetén nem szólna. A
polgári app gyökér-csempéket mutat, így a `citizenSuggestedCategoryId`
tipikusan eleve gyökér-szintű — pont az, amit a heurisztika néz.

**A döntés K-032 alkalmazási részlete, nem felülírása.** K-032 a "mindhárom
jel együtt" szabályt írja elő — ezt a döntés **megtartja**: a három jelből egy
sem hagyható el. Csak a kategória-jel *forrása* oldódik fel rugalmasan
(`categoryId` → `citizenSuggestedCategoryId`). Az alapítóval megerősítve, hogy
ez a kanonikus döntés alkalmazási részlete.

**Mérlegelt alternatíva:** Kategória-jel elhagyása, ha a kategória hiányzik
(csak a térbeli és az idő-jel dönt) — elvetve, mert **közvetlenül ütközne**
K-032 "mindhárom feltétel" szövegével (kanonikus felülírás, megállás-köteles),
és a kategória-jel a hamis riasztás fő szűrője (`20_duplikacio_v1.md` 2.3).

**Ki döntötte:** Az alapító, a specifikáció javaslatára.

---

### SD-44 — A `similar`-végpont nem-standard read-only heurisztika-végpont (TD-D3)

**Döntés:** A `GET /v1/tickets/{id}/similar` **nem `BaseController`-művelet** —
read-only, mellékhatás nélküli heurisztika-számítás egy `Ticket`-hez relatív
halmazon. A feature-spec teljes szerződéssel adja meg (request, `SimilarTicketDto`
response, sorrend, limit, hibakódok), "Eltérés a mintától" jelöléssel.

**Indok:** A `BaseController` `ListAsync` mintája `ListRequest`-szűrésű listát
ad — a `similar` nem ilyen: egy konkrét `{id}`-hez relatív, számított halmaz,
három jellel. A `10_bejelentes_lista_es_adatlap.md` 3.2.2 ezt előrevetítette
("külön hívás, heurisztika-számítás, nem a detail-DTO-ban"), és az `NY-bej-6`
ide delegálta a tartalmi szerződést — amelyet ez a feature-spec lezár.

**Technikai részletek (a feature-spec 3.1.5 / lásd SD-48 alatt):** távolság-
számítás bounding-box előszűrés + Haversine; gyökér-feloldás egylépéses
`Category.parentId`-felmenet; `Ticket(status, createdAt)` index; a heurisztika-
küszöbök kódba égetve. A tenant-határ automatikus a befecskendezett
`DbContext` révén — nem eltérés a mintától.

**Ki döntötte:** A specifikáció (tisztán technikai döntés).

---

### SD-45 — Az összevonás nem-standard write-végpont, tranzakciós kétoldali mellékhatással (TD-D4)

**Döntés:** A `POST /v1/tickets/{id}/merge` workflow-akció a
`10_bejelentes_lista_es_adatlap.md` 3.4 akció-végpont-mintája szerint (a
`TicketWorkflowService`-ben, a `reject` szomszédjaként), nem `BaseController`
update. A `02_globalis_allapotgep.md` 3.7 kétoldali mellékhatását **egyetlen
adatbázis-tranzakcióban** hajtja végre: a duplikátumon `status := Rejected`,
`rejectionReasonCode := Duplicate`, `rejectionReasonText := null`,
`originalTicketId := <eredeti id>`, egy `Merged` `ActivityLog`-sor; az
eredetin a `status` változatlan, egy `Merged` `ActivityLog`-sor. A duplikátum
triage-adatai (`categoryId`, `priority`, `dueDate`, felelős, `assignedAt`)
**változatlanok** — a `Rejected`-be lépés nem nullázza őket.

**Indok:** A művelet két `Ticket`-et és két `ActivityLog`-sort érint —
részleges siker (a duplikátum lezárul, de az eredeti logja nem íródik be)
aszimmetrikus, inkonzisztens állapotot hagyna. A tranzakció-kötöttség a
`01_kozos_mintak.md` `User`-sync-mintájának szellemét követi. A `{id}` route-
paraméter **a duplikátum** — konzisztens a `10` 3.4 akció-végpontjaival, ahol
a `{id}` mindig az átmenetet elszenvedő ügy; az eredeti ügyet a request body
`originalTicketId`-ja adja.

**Ki döntötte:** A specifikáció (technikai döntés, az alapító jóváhagyásával).

---

### SD-46 — A `merge` hét formalizált előfeltétele (TD-D5)

**Döntés:** A `merge`-végpont hét előfeltételt ellenőriz, és sértésükkor a
besorolt hibakódot adja: (1) a duplikátum létezik → `404`; (2) az eredeti
létezik → `404`; (3) `originalTicketId ≠ {id}` → `422 self_merge`; (4) a
duplikátum nem-végállapotú → `409 invalid_transition`; (5) az eredeti
nem-végállapotú → `422 original_not_open`; (6) az eredeti nem maga is
duplikátum (`originalTicketId` üres rajta) → `422 original_is_duplicate`; (7)
a `expectedUpdatedAt` egyezik a duplikátum `updatedAt`-jával → `409 stale`.

**Indok:** A `02_globalis_allapotgep.md` 3.7 csak az 1–2-t és a 4-et mondta ki
explicit ("az eredeti létezik és nem maga a duplikátum"; "bármely
nem-végállapotból"). A versenyhelyzet-elemzés három továbbit tárt fel: az 5.
(az eredeti időközben lezárulhatott — a `20` 3.3 a *doboz* találatait szűri
nyitott ügyekre, de a végpont API-first közvetlenül is hívható), a 6.
(lánc-tiltás — az eredeti időközben maga is duplikátummá válhatott), és a 7.
(kétszeres/kölcsönös összevonás — a SD-32 concurrency-token a duplikátumra
alkalmazva). A `409`/`422`-határ a `01_kozos_mintak.md` 6.3 szerint: a `{id}`
ügy állapot-/verzió-konfliktusa `409`, a megnevezett eredeti ügy
alkalmatlansága `422`.

**Következmény:** A 6. előfeltétel (lánc-tiltás) szigorúbb, mint amit a
`02_globalis_allapotgep.md` 3.7 kimondott — nem ütközés (a 3.7 nem engedte meg
explicit a láncot), de a 3.7 egy mondatot érdemel erről: visszacsorgó jelzés
(a feature-spec VF-D1).

**Ki döntötte:** A specifikáció (az állapotgép és az SD-32 alkalmazása).

---

### SD-47 — A `Merged` `ActivityLog` két sora; az i18n-kulcs kettébontva (TD-D6)

**Döntés:** Az összevonás **két** `Merged` `ActivityLog`-sort ír — egyet a
duplikátumra (`fromValue` = a duplikátum korábbi `status`-a, `toValue` =
`"ticket:<eredeti id>"`), egyet az eredetire (`fromValue` = `null`, `toValue` =
`"ticket:<duplikátum id>"`). A `toValue` az SD-30 szerint stabil, nyelvfüggetlen
`ticket:<id>` referencia (a `Reassigned` `"group:3"` mintája). A
`10_bejelentes_lista_es_adatlap.md` 4.6 egyetlen `ticket.activity.merged`
kulcsa **kettébontva**: `ticket.activity.merged.asDuplicate` és
`ticket.activity.merged.asOriginal` — a kliens az oldalt a `Merged` log
`fromValue`-jából tudja (duplikátum-oldal: `TicketStatus`; eredeti-oldal:
`null`).

**Indok:** A két ügy adatlapján a `Merged` esemény külön jelenik meg, és a két
irány eltérő magyar mondatot kíván ("ezt a bejelentést összevontad ide" vs.
"ide összevonva egy bejelentés") — egyetlen kulcs nem fejezi ki mindkettőt. A
kétsoros napló a kétirányú link (`20_duplikacio_v1.md` 4.2) napló-vetülete.

**Következmény:** Visszacsorgó jelzés a `10_bejelentes_lista_es_adatlap.md`
4.6 i18n-szakaszának (a feature-spec VF-D2) — a `ticket.activity.merged` kulcs
kettébontandó.

**Ki döntötte:** A specifikáció (az SD-30 elv és a `10` 4.6 sablon alkalmazása).

---

### SD-48 — Az `originalTicketDisplayId` származtatott DTO-mező, nem tárolt domain-mező (TD-D7)

**Döntés:** Az `originalTicketDisplayId` — amely a detail-DTO-ban (`10` 3.2.2),
a `similar`- és a merge-válaszban megjelenik — a DTO-réteg **származtatott**
értéke: az eredeti `Ticket` `displayId`-ja (`Tenant.displayPrefix` + `-` + az
eredeti `ticketNumber`, SD-16 szerint feloldva). A `Ticket` egyetlen tárolt
duplikáció-mezeje az `originalTicketId` self-FK; az `originalTicketDisplayId`
mindig feloldással keletkezik, sosem tárolódik.

**Indok:** A `displayId` maga is származtatott (SD-16); az
`originalTicketDisplayId` ennek az eredeti ügyre alkalmazott vetülete. Tárolni
redundáns és inkonzisztencia-kockázat (ha az eredeti `ticketNumber`/prefix
változna). A `00_domain_model.md` 1.2.6 mezőtáblája egyetlen tárolt
duplikáció-mezőt definiál — az `originalTicketId`-t.

**Viszony az SD-40-hez — pontosítás, nem ütközés.** Az SD-40 szövege az
`originalTicketId` **és** az `originalTicketDisplayId` "mezőpárt" említi a
duplikáció-hivatkozás strukturált hordozójaként. Az SD-40 nem mondta ki, hogy
a `displayId`-vetület *tárolt* mező — az SD-48 ezt pontosítja: a hivatkozást
strukturáltan az `originalTicketId` tárolja, az `originalTicketDisplayId` a
belőle rajzolt származtatott DTO-érték. Az SD-40 kliens-oldali
`ticket.rejection.duplicate` sablonja (paraméter: `originalDisplayId`) ezzel
**konzisztens** — a paramétert a DTO származtatott mezeje tölti.

**Következmény:** A `00_domain_model.md` 1.2.6 egy magyarázó megjegyzés-sort
kap; új tárolt mező nincs.

**Ki döntötte:** A specifikáció (domain-modell-tisztázás).

---

## Konszolidációs kör — jogosultság-modell és `authorization.json`

> Nem SD-szintű platform-döntés-blokk, hanem egy **konszolidációs kör**
> módszertani döntései és megtartott hiányai — a triage v1.2 körhöz hasonlóan
> (lásd a v1.1 verziónapló-tételt). A kör terméke a
> `30_szerver/05_jogosultsag_es_authorization.md` v1.0 referencia. A
> követhetőség kedvéért itt rögzítve. Új SD-számot nem hoz: a
> jogosultság-érvényesítés mechanikáját az `01_kozos_mintak.md` 3.5 (SD-7,
> J-1) már lefedte.

### A kör megállapítása — nem önálló feature-spec

**Döntés:** A `manager_felulet_atadas.md` javasolt sorrendjének 3. pontja (a
jogosultság-modell) **nem önálló feature-spec**, hanem egy célzott
konszolidációs kör. A felfedezés szerint a jogosultság-érvényesítés
mechanikáját — a kétrétegű érvényesítés, a `tenant_`-prefix-konvenció, a
`vezető`-reláció felsorolásos leképezésének elve, a `TenantRole` enum, a
token-érvényesség kezelése — az `01_kozos_mintak.md` 3.5 már teljesen
rögzítette; egy feature-spec ezt csak ismételné. A kör valódi hézaga az volt,
hogy nincs *egyetlen, teljes* route→szerepkör nézet.

**Indok:** Konzisztens az instrukció "a specifikáció nem írja le újra, amit egy
másik dokumentum már megold" elvével. A `manager_felulet_atadas.md` 3. pontja
"permission-kulcsokat" említett — ezt a megfogalmazást az `01_kozos_mintak.md`
3.4 (J-1) már felülbírálta: a pilotra route-alapú, szerepkör-szintű a modell.

**Ki döntötte:** A specifikáció (0.–1. lépés), az alapító jóváhagyásával.

### TD-J1 — A referencia helye és neve

**Döntés:** A kör terméke a `30_szerver/05_jogosultsag_es_authorization.md`
fájlban él — a `30_szerver/` modul-mappában, mert a route-alapú jogosultság a
szerveren érvényesül; a `05` számelőtag a funkcionális forrással
(`05_jogosultsagok_v2.md`) párba állítja.

**Mérlegelt alternatíva:** `20_admin_felulet/` — elvetve, mert a kliens-oldali
route-guard csak UX-réteg (`10` 4.4). Másik alternatíva: az `01_kozos_mintak.md`
3. szakaszának bővítése — elvetve, mert a `01` a platform-mintát adja (a
*hogyan*), a teljes route-lista pedig egy konszolidált *referencia* (a *mit*); a
`01` 3.5 maga is elhatárolta magát ("a konkrét permission-mátrixot a
feature-specek adják").

**Ki döntötte:** A specifikáció (2. lépés), az alapító jóváhagyásával.

### TD-J2 — A referencia formája: hivatkozás, nem újraközlés

**Döntés:** A referencia a meglévő 23 route-ot **hivatkozza, nem közli újra** —
a route-ok kanonikus helye a forrás-feature-specekben marad (`10` 3.8,
`20_dup` 3.5, `20_felhasznalokezeles` 3.8). A teljes route→szerepkör képet egy
**traceability-mátrix** hordozza (a referencia 3.2), amely a `05` minden
akció-sorát egy táblába vonja, de minden sor a forrásra mutat. A
traceability-mátrix a referencia *része*, nem külön fájl.

**Indok:** Ez feloldja a "konszolidált, de nem duplikált" feszültséget: a
Claude Code megkapja az egy helyen álló teljes képet (a mátrix), és minden
route-nak megmarad az egyetlen kanonikus forrása. A mátrix *leszármaztatott
nézet*, nem párhuzamos igazság — ha egy feature-spec route-blokkja változik, a
mátrix sora frissül, a route-definíció nem duplikálódik.

**Mérlegelt alternatíva:** Generált, tényleges `authorization.json`-fájl mint
melléklet — elvetve a pilotra: a `40_riport`/`50_konfig`/`60_tartalom`
route-jai még nincsenek meg (MH-J1), a fájl eleve hiányos lenne. A CI-generált
teljes `authorization.json` iterációs elem (a referencia 8.1).

**Ki döntötte:** A specifikáció (2. lépés), az alapító jóváhagyásával.

### TD-J3 — A hézagos modulok kezelése: szabály igen, route-string nem

**Döntés:** A három le nem fedett modulnál (riport, kategória/csoport/
tenant-alapadat, tartalom) a referencia a **szerepkör-szabályt** rögzíti
(Szabály-R1/R2/R3, a referencia 3.3) — ez a `05` mátrixból determinisztikus —,
a **pontos API-route-stringet** viszont nem találja ki, hanem megtartott
hiányként (MH-J1) a forrás-feature-spec hatáskörébe utalja.

**Indok:** A szerepkör-hozzárendelés a `05`-ből determinisztikus, a route-név
nem (`BaseController`-minta route-alkalmazási döntés, a feature-spec hozza). Egy
kitalált route-string csendes tervezés lenne — amit az instrukció tilt. A
megtartott-hiány-jelölés a tisztességes forma: a szabály megvan, a string a
feature-spec dolga. Ez a v2.1 instrukció (d) pontjának alkalmazása: a hiány nem
blokkolja a feature gerincét.

**Ki döntötte:** A specifikáció (1.–2. lépés), az alapító jóváhagyásával.

### Megtartott hiányok — a konszolidációs körből

> A v2.1 instrukció (d) szerint: a hiány nem blokkolja a feature gerincét,
> ezért a feature halad; a hiány nyomon követhető marad.

- **MH-J1 — A hézagos modulok pontos API-route-nevei.** A `40_riport` (`05`
  2.7), a `50_konfig` nem-felhasználó-rész (`05` 2.8), a `60_tartalom` (`05`
  2.9) route-stringjei. A szerepkör-szabály (R1/R2/R3) determinisztikus és kész;
  csak a route-string hiányzik. **Hatáskör:** `40_riport`, `50_konfig`,
  `60_tartalom` feature-specek. **Nem blokkol:** a `vezető`-reláció, a
  szerepkör-hozzárendelés és az AC-D előírások enélkül is teljesek.
- **MH-J2 — Mely hézagos-modul-entitások engednek `DELETE`-et.** A törölhető
  vs. csak archiválható kérdés a feature-spec dolga. **Hatáskör:** ua. **Nem
  blokkol:** a default konzervatív — a route hiánya az `authorization.json`-ban
  `403`-at ad ("fail closed").
- **MH-J3 — A manuális bejelentés-nyitás (`POST /v1/tickets`)
  route-leképezése.** A `10` 3.10 már külön feature-re utalta. **Hatáskör:**
  manuális-nyitás feature-spec. **Nem blokkol:** a szerepkör
  (`dispatcher`/`manager`) ismert.

### Elhatárolás — a polgári oldal

**NY-J1:** A polgári mobilapp jogosultság-/auth-modellje **nem** a
konszolidációs kör hatóköre, és nem is megtartott hiánya: a polgár nem
tenant-szerepkörrel lép be, és a polgári auth maga is nyitott (`01` 3.1,
`10` NY-bej-1). Külön kérdés, a polgári adatigény-spec dolga.

### Visszacsorgó jelzés a funkcionális/specifikációs projektnek

**VF-J1:** A `20_duplikacio_es_osszevonas.md` 3.5 a `roles` tömbben csupasz
`dispatcher`/`manager` formát használ, szemben az `01_kozos_mintak.md` 3.3
`tenant_`-prefixes mintájával és a `10` 3.8 / `20_felhasznalokezeles` 3.8
gyakorlatával. Vélhetően elírás (nincs "Eltérés a mintától:" jelölés, ami
tudatos eltérést jelezne) — javítandó `tenant_dispatcher`/`tenant_manager`-re.
A `05_jogosultsag_es_authorization.md` referencia mindenképp a helyes
prefix-formát használja; a `20_dup` 3.5 javítása konzisztenssé teszi a forrást.
**Cél-dokumentum:** `20_duplikacio_es_osszevonas.md`.

---

## A Dashboard és heti PDF-riport feature-spec döntései (SD-49 — SD-57)

> Forrás: `20_admin_felulet/40_riport.md` v1.0, 2026.05.20. A vezetői
> riport-modul feature-spec kilenc döntése. **Az MH-J1 megtartott hiány a
> `40_riport`-modul pontos API-route-neveire ezzel lezárva** — a
> feature-spec 3.1 szakasza hat route-ot nevez meg, mindegyik
> `["tenant_manager"]` (Szabály-R1).

### SD-49 — `WeeklyReport` új entitás (Tenant DB)

**Döntés:** Új entitás a Tenant DB-ben, `WeeklyReport` néven,
`AuditableEntity` származással. A heti PDF-et el kell tárolni (bináris
S3-hivatkozás + strukturált pillanatkép), mert három dolog épül rá: a
`/riportok` archívum (`90_sitemap_v3.md` 2.5), a Dashboard "Heti riport
letöltése" gombja (`40` 4.4), és az e-mail-melléklet. A `snapshotData`
(`jsonb`) a riport számszerű tartalmát tárolja strukturáltan — a "múlt
héthez képest" szakasz és az archívum-adatlap PDF-visszafejtés nélkül
olvashatja. A `WeeklyReport` **nem** `ContentStatus`-életciklust követ
(nincs `Draft`/`Published`); a `generationStatus` a háttér-job futás-
állapota, nem publikálási életciklus.

**Indok:** A funkcionális réteg az entitást nem modellezte — a
`00_domain_model.md` 5.2 entitás-indexében nincs `WeeklyReport`. A `40` 4.4
viszont kimondja az archívumot és a "legutóbbi letöltése" gombot, ami
perzisztenciát igényel.

**Mérlegelt alternatíva:** A PDF-et nem perzisztálni, hanem minden
letöltéskor újragenerálni. Elvetve: (a) a `40` 4.4 archívumot ír elő — egy
korábbi hét riportja akkor is elérhető kell legyen, ha az adat közben
változott (egy visszanyitott ügy nem írhatja át visszamenőleg a 28. hét
riportját); (b) az újragenerálás nem-determinisztikus a múltbeli adatra.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-50 — `GET /v1/dashboard` aggregációs végpont (eltérés a `BaseController`-mintától)

**Döntés:** A Dashboard adatát egy dedikált, számolt végpont adja:
`GET /v1/dashboard`. Ez nem `BaseController`-CRUD — nincs mögötte entitás,
nincs lista/get/create. A válasz egyetlen összeállított DTO: a négy KPI +
a csapat-tábla sorai + a `latestReport` blokk. Nincs paginálás, nincs
`ListRequest`, nincs szűrő-paraméter.

**Indok:** A Dashboard egyetlen GET-tel betölt — egy kérés kevesebb
hálózati kör, és a négy KPI ugyanabból a `Ticket`-halmazból számolható egy
lekérdezés-csoportban. A `40` 3.4 / K-016 fix nézőpontja ("ez a hét") a
szűrő-paraméter ellen szól.

**Mérlegelt alternatíva:** Külön végpont minden KPI-nak (`GET
/v1/dashboard/kpi/open`, stb.). Elvetve: több hálózati kör, és a
megfontolt aggregációs csoportosítást szétdarabolja.

**Ki döntötte:** Specifikáció (tisztán technikai).

### SD-51 — "Nyitott ügyek" KPI = `New` + `Assigned` + `InProgress`

**Döntés:** A `kpi.openCount` predikátuma: `status ∈ {New, Assigned,
InProgress}`. A `Resolved` és `Rejected` végállapot kizárva
(`02_globalis_allapotgep.md` 1.). A "Nyitott ügyek" kártya lefúrása a
`/bejelentesek` "Mind" tabjára visz, a státusz-fejléc-szűrőt a három
nyitott állapotra állítva (query-paraméter a `TableStateConfig` URL-mintán
belül).

**Indok:** A vezető a "nyitott ügyek" kártyán a *teljes függő munkaterhet*
akarja látni — a triage-eletlen `New` ügy is függő munka. Ez konzisztens a
PDF "hét végén nyitott ügyek" sorával (`40` 4.2), és a "Mind" tab +
státusz-szűrő a `10` érintése nélkül megoldja a lefúrást (a `40` 3.3
"olcsó fejlesztés" elvét tartva).

**Mérlegelt alternatíva:** A `New`-t kihagyni (mert az "Aznapi új" kártya
már mutatja az aznap érkezetteket). Elvetve: a két KPI nem fedi át egymást
— az "Aznapi új" naphoz kötött, a "Nyitott" állapothoz; egy tegnapelőtt
érkezett `New` ügy függő munka. Egy új "Nyitott" tab a `10` listán szintén
elvetve, mert érintené a `10` feature-specet ott, ahol nem szükséges.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-52 — "Aznapi új" és "Aznap lezárt" lefúrás (TD-R4-A irány)

**Döntés:** A négy KPI-kártya mind kattintható, a `/bejelentesek` listára
fúr le. Az "Aznapi új" a Beérkezett oszlop dátum-tartomány-szűrőjét
állítja a mai napra (a `10` listán már létező szűrő, `10` 4.2). Az "Aznap
lezárt" egy új `resolvedAt` ("lezárás dátuma") szűrőt kíván a `10`
listán — ez a **VF-R1 visszacsorgó jelzés**. Amíg a VF-R1 nincs
átvezetve, az "Aznap lezárt" átmenetileg a `/bejelentesek?tab=lezart`-ra
fúr le dátum-szűrő nélkül (működik, csak nem szűkített).

**Indok:** A `40` 3.2 explicit kattinthatónak mondja a számokat. A vegyes
viselkedés (két kártya kattintható, kettő nem) UX-szempontból zavaró, és a
"Késésben" kártya biztosan kattintható (a `10` "Késésben" tabra). Egy
Dashboard-saját, előszűrt listanézet új képernyőt hozna — pont a `40` 3.3
"nem új képernyő" elve ellen.

**Mérlegelt alternatívák:** (a) az "Aznapi új" és "Aznap lezárt" kártyák
ne legyenek kattinthatók — elvetve a vegyes UX miatt; (b) Dashboard saját,
előszűrt lista — elvetve az "olcsó fejlesztés" elv ellen.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-53 — A csapat-tábla sorai: `field_worker` + `Active` `TenantUser`

**Döntés:** A Dashboard csapat-tábla sorai a `TenantUser`-ek, ahol
`roles ∋ field_worker` ÉS `status = Active` (SD-37). Az `Invited` és
`Disabled` `TenantUser` nem sor. Akinek nincs heti ügye, az is sor
(0/0/null értékekkel) — a Wow #2 összehasonlítási alapja (`40` 3.3). A
predikátum `roles ∋ field_worker`, nem "kizárólag field_worker": a K-025
implicit unió-modell szerint egy `dispatcher + field_worker` kombinációjú
felhasználó is megjelenik (ő terepen is dolgozik).

**Indok:** A `40` 3.3 Wow #2 lényege a *rácsodálkozás* — Béla a teljes
csapatot egymás mellett látja, és ettől tűnik fel a kiemelkedő. Az
`Invited` (még be nem lépett) felhasználó 0/0/— sora félrevezető lenne
("miért nem dolgozik?") — a felhasználó-listán látszik, a teljesítmény-
táblán nem. A `Disabled` szintén kizárt.

**Mérlegelt alternatíva:** Csak az aznap/héten aktív munkatársak. Elvetve:
az összehasonlítási alap csorbulna.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-54 — A csapat-tábla személy-szintű (`assignedUserId`); a csoportos kiosztás kimarad; a PDF összesít

**Döntés:** A Dashboard csapat-tábla `resolvedThisWeek` és
`inProgressCount` oszlopai csak a személyre (`assignedUserId`) kiosztott
ügyet számolják egyénhez. A csoportra (`assignedGroupId`) kiosztott
(és `assignedUserId = null`) ügy egyetlen sorhoz sem rendelődik. A heti
PDF `snapshotData.weekNumbers.resolvedCount` ezzel szemben **minden**
lezárt ügyet számol, a kiosztás módjától függetlenül (a PDF összesít, nem
személyez — K-035).

**Következmény, kimondva:** a `team[].resolvedThisWeek` értékek összege
eltérhet a PDF `resolvedCount`-jától. A két szám két különböző kérdésre
felel; az eltérés helyes — a fejlesztő ne "javítsa el" egyformára.

**Indok:** A `40` 3.3 lefúrása explicit "Felelős = Zoltán Kovács"
személy-szűrőt mond — a funkcionális terv maga is személy-szintű
teljesítményt ért a táblán. A `Group` a pilotra "egy címke + taglista", a
csoporton belüli munkamegosztás nincs modellezve (`00_domain_model.md`
2.2) — nincs alapja csoportos ügyet taghoz rendelni.

**Mérlegelt alternatíva:** Egy csoportos ügyet minden tagnak beszámítani.
Elvetve: torzítaná a számokat (egy ügy ötször számítódna).

**Megtartott hiány (MH-R1):** A csoport-szintű teljesítmény-aggregáció a
pilotra tudatosan kimarad; a terepi mobilapp későbbi kérdése.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-55 — Három pont: kiemelés-küszöb, első hét, idempotencia

**SD-55/a — A csapat-tábla kiemelés-küszöbe relatív.** `isTopPerformer ==
true` annál az **egy** sornál, amelynek `resolvedThisWeek` értéke
szigorúan nagyobb minden más soré-nál ÉS `> 0`. Holtverseny esetén vagy
ha mindenki `0`: minden sor `false`. **Indok:** A `40` 3.3 Wow #2 lényege
a *relatív* rácsodálkozás ("Zoltán 40%-kal több ügyet zár"). Abszolút
küszöb önkényes számot vagy konfigurációt kívánna (K-016 ellen hat);
"nincs kiemelés" elveszi a Wow #2 vizuális csúcspontját.

**SD-55/b — A pilot első hete semleges sort kap.** Az első heti PDF "A
múlt héthez képest" szakasza semleges sort tartalmaz ("Ez az első heti
összegző — összehasonlítási alap a következő héttől."), nem hagyja ki a
szakaszt. **Indok:** A szakasz elhagyása csonka PDF-et adna, ami
Péternek magyarázatra szorulna — a `40` 4.1 "magyarázat nélkül
megmutatható" elve ellen.

**SD-55/c — Idempotencia: `(tenantId, year, isoWeek)` egyedi.** A
`WeeklyReport` tenantonként egy hétre pontosan egy rekord; a generáló
job újrafutáskor a meglévő sort frissíti. Az `isoWeek` az ISO-8601
hét-számozást követi (1–53). **Indok:** A `40` 4.4 hétfő reggeli
automatikus generálást ír elő; a job-retry (`Failed → Generating`) és a
manuális trigger duplikátum nélkül kell működjön.

**Ki döntötte:** SD-55/a és /b: Alapító, a specifikáció javaslatára.
SD-55/c: Specifikáció (tisztán technikai).

### SD-56 — Összesített `deliveryStatus` (három érték) + manuális `resend` akció

**Döntés:** A `WeeklyReport.deliveryStatus` négy értékű enum:
`Pending` / `AllSent` / `PartialFailure` / `AllFailed`. Címzettenkénti
követés a pilotra nincs — a `recipientCount` mező adja az utolsó
kézbesítési kísérlet címzett-számát a kontextushoz. A riport-adatlap egy
**"Riport újraküldése"** akciót kínál (R-6, `POST
/v1/weekly-reports/{id}/resend`): a PDF újra kimegy az **aktuális**
címzett-listának, a PDF-tartalom nem generálódik újra (a múltbeli
pillanatkép stabil, SD-49).

**Indok:** A pilotra 1–3 címzett (`40` 4.5); a vezető számára releváns
információ az, hogy *kiment-e mindenkinek*. A címzettenkénti
`Sent`/`Failed` napló a hibakereséshez hasznos, de a felületen a pilotra
elég az összesített jelzés (a részletek a szerver-logban). A `resend`
önkiszolgáló utat ad a vezetőnek a kézbesítési hiba javítására.

**Mérlegelt alternatíva:** Címzettenkénti státusz-tábla (egy
`WeeklyReportDelivery` aldetail-entitás). Elvetve a pilotra mint
túltervezés; iterációs elem, ha a pilot kívánja.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-57 — A riport-adatlap olvasásra mutatja a címzett-listát; a `resend` konkrét címzetteket sorol (NY-R1 lezárása)

**Döntés:** A `/riportok/details/<id>` adatlap egy **"Címzettek"** szekciót
kap (a "Kézbesítés állapota" után, az "Audit" elé): a `50_konfig`
aktuális címzett-listájának olvasásra való megjelenítése, a
szerkesztésre a Beállítások / Általános oldalra mutató szöveggel. A
`resend` megerősítő párbeszéd a konkrét címzetteket felsorolja:
"Újraküldöd a riportot a következő címzetteknek: <címzett-lista>?".

A megjelenített címzettek az **aktuális** `50_konfig` lista (nem a
generálás pillanatában rögzített pillanatkép) — konzisztens a `resend`
viselkedésével (R-6, SD-56).

**Indok:** (1) konzisztencia a `deliveryStatus` megjelenítésével — ha
`PartialFailure` állapotot jelzünk, a vezetőnek látnia kell, **kiknek**
ment; (2) a `resend` rejtett szerződését feloldja (a "jelenlegi
címzetteknek" rejtett szövegét konkrét listára cseréli); (3) a címzett-
lista nem érzékeny adat (hivatali levelezőlista); (4) konzisztens a `40`
4.1 elvével ("a riport kommunikálható, nem nyers").

**Mérlegelt alternatíva:** Csak a Beállításokra utaló szöveg, címzettek
nélkül. Elvetve, mert a `PartialFailure` és a `resend` ekkor kontextus
nélküli.

**Következmény (a feature-spec 8.2 feltételezés-listájában):** A
`50_konfig` ad egy olvasó-végpontot a tenant aktuális címzett-listájához
(`tenant_manager` jogosultsággal). Ez nem új tervezési döntés a riport-
feature-spec részéről — a `50_konfig` adta a címzett-listát; az olvasó-
végpont igénye a `50_konfig` feature-spec rendes része.

**Ki döntötte:** Specifikáció, az alapító felhatalmazása alapján (NY-R1
nyitott kérdés a feature-spec 8.5-ből, az alapító a 8.5 kezelését a
specifikációra bízta).

### Megtartott hiányok — a riport-feature köréből

> A v2.1 instrukció (d) szerint: a megtartott hiány nem blokkolja a
> feature gerincét, ezért a feature halad; a hiány nyomon követhető marad.

- **MH-R1 — A csoport-szintű teljesítmény-aggregáció a Dashboard csapat-
  tábláján a pilotra kimarad.** A tábla csak a személyre osztott ügyet
  számolja (SD-54); a csoportos kiosztás nem jelenik meg személy-soron.
  **Hatáskör:** terepi mobilapp későbbi tervezése — a csoporton belüli
  munkamegosztás ott modellezett. **Nem blokkol:** a személy-szintű tábla
  és a PDF összesítése enélkül is teljes.
- **MH-R2 — Az `openAtWeekEnd` a generálás pillanatának `Ticket.status`-át
  használja**, nem a pontos vasárnap 24:00-i állapot `ActivityLog`-
  rekonstrukcióját. **Hatáskör:** riport-feature iteráció — ha a pilot-
  tapasztalat pontos hét-végi pillanatképet kíván, az `ActivityLog`-
  alapú rekonstrukció iterációs elem. **Nem blokkol:** a job hétfő reggel,
  néhány órával a hét vége után fut; pilot-volumenen (`~100
  bejelentés/hó`, SD-11) az ablakban történő állapotváltás elhanyagolható.
- **MH-R3 — A Dashboard csapat-lefúrása a pilotra a felelős-szűrt teljes
  `/bejelentesek` listát adja**, nem a heti+lezárt szűkítést, amit a `40`
  3.3 megfogalmazása sugall. **Hatáskör:** riport-feature iteráció.
  **Nem blokkol:** a `40` 3.3 maga is kimondja — a lefúrás a meglévő
  lista előszűrve, "olcsó fejlesztés"; a Wow #2 a felelős-szűrt listával
  teljesül.

### Visszacsorgó jelzés — a riport-feature köréből

**VF-R1 — A `10_bejelentes_lista_es_adatlap.md` listája egy "lezárás
dátuma" (`resolvedAt`) dátum-tartomány-szűrővel bővítendő.** Az SD-52
Dashboard-kártya-lefúrás ("Aznap lezárt") ezt kívánja. A `createdAt`-
szűrő a `10` listán már létezik (a Beérkezett oszlop dátum-tartomány-
szűrhető — `10` 4.2); csak a `resolvedAt`-szűrő hézag. Kis, célzott
kiegészítés; egyeztetendő a Dashboard→lista query-param-szerződés
(`resolvedFrom`/`resolvedTo`) a `10` `TableStateConfig` URL-
kódolásával. **Cél-dokumentum:** `10_bejelentes_lista_es_adatlap.md`.

### Elhatárolás — a riport-feature köréből

**NY-R2 — A polgári elégedettség-mérés** nem ennek a kör hatóköre. A
`40` 7.3 szerint Péter pályája "polgári elégedettséget" várna a
riportban, de a pilot-MVP-ben nincs mérési mód (`10` NY-bej-5: a "Te is
segíthetsz" blokk írás-jellegű polgári akciói nincsenek a domain-
modellben). A riport a pilotra elégedettségi mutató nélkül készül.
**Béla felé jelezni kell:** Péternek ne ígérjen olyat, ami a pilotra
nincs (`40` 7.3). **Hatáskör:** polgári mobilapp funkcionális
tervezése + adatigény-spec — ha a riportba valaha elégedettségi szám
kell, a polgári appnak mérnie kell.

---

## A Beállítások feature-spec döntései (SD-58 — SD-67)

> Forrás: `20_admin_felulet/30_beallitasok.md` v1.0, 2026.05.20. A
> Beállítások modul három aloldalának (`/beallitasok/kategoriak`,
> `/beallitasok/csoportok`, `/beallitasok/altalanos`) feature-specje;
> a `/beallitasok/felhasznalok` aloldalt a `20_felhasznalokezeles.md`
> fedi. Tíz specifikációs döntés: a `Tenant` mezőbővítése, egy új
> entitás (`WeeklyReportRecipient`), két új mintázat (egyedi-fájl-mező;
> Core-mezőkre korlátozott tenant-írás), a kategória-CRUD négy
> eltérése, a csoport-CRUD megerősítése, a jogosultság-csomópont, és
> az "Általános" aloldal szerkezete.
>
> **A `40_riport.md` SD-57 fogyasztói várakozása ezzel formálisan
> teljesül**, új végpont nélkül: a `GET /v1/weekly-report-recipients?isActive=true`
> standard CRUD lista ugyanaz a forrás, amit a riport-adatlap és a
> `resend`-megerősítő-dialógus fogyaszt.

### SD-58 — A `Tenant` entitás kibővül logó- és kontakt-mezőkkel

**Döntés:** A Core DB `Tenant` entitása négy új mezőt kap a meglévő hét
(`id`, `code`, `name`, `displayPrefix`, `dbConnectionRef`, `status`,
`timeZone`) mellé: `logoFileRef` (a tenant logójának S3-objektum-
hivatkozása, az `Attachment.fileRef`-mintával konzisztens, SD-15; max 500
karakter); `contactAddress` (max 300); `contactPhone` (max 50);
`contactEmail` (max 200, e-mail formátum-validációval). Mind a négy
**opcionális** — a tenant pilot-indítását nem blokkolja a kontakt-adat
üressége. A `Tenant.name` változatlan kötelező.

**Indok:** A `50_konfig_v2.md` 5.1 előírja a "tenant-név, logó,
kontakt-adatok" hármasát. A `00_domain_model.md` 3.2 `Tenant`-táblája
ezeket még nem tartalmazta — a feature-spec ide vezeti vissza. A négy
mező mind **tartalom-paraméter** (K-037), nem brand-paraméter; nincs
köztük "téma", "szín", "app-név".

**Mérlegelt alternatíva:** Külön `TenantContact` entitás a kontakt-
adatoknak, 1:1-ben a `Tenant`-hoz. Elvetve — három-négy egyszerű mező
nem indokol külön entitást; a `Tenant` rekord-szintű audit
(`AuditableEntity`) elég. Ha később "több hivatkozási pont" (pl. külön
ügyfélszolgálati cím vs. levelezési cím) kell, az iterációs elem.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-59 — Új entitás: `WeeklyReportRecipient` (Tenant DB)

**Döntés:** A heti riport címzett-listája egy új entitás a **Tenant
DB-ben**, `WeeklyReportRecipient` néven, az alábbi mezőkkel: `id` (PK),
`name` (opcionális megjelenő név, max 200), `email` (kötelező, max 200,
e-mail formátum, egyedi a tenanton belül), `isActive` (default: `true`).
`AuditableEntity` — címzettenkénti audit. **Nincs FK-kapcsolat a
`WeeklyReport`-tal** — logikai fogyasztás.

A `Tenant.contactEmail` (SD-58) és a `WeeklyReportRecipient.email`
**nem ugyanaz**: a `contactEmail` a város *nyilvános* kapcsolattartási
címe (polgári app "Ügyfélszolgálat" szekciójának), a
`WeeklyReportRecipient` a heti riport *belső* kézbesítési listája
(polgármester, alpolgármester, hivatali titkárság). A kettő céljában
különbözik — keverni hiba volna.

**Indok:**
- Konzisztens a domain-modell entitás-orientációjával (a `Group.members`,
  az `UserTenantRole` is külön entitás-soros modell, nem JSON-tömb).
- A `BaseController` CRUD-ot ingyen adja — lista, get, create, update,
  delete, mind standard mintával.
- Egyenként auditált: ki vette fel a polgármester e-mailjét — fontos
  hivatali nyomvonalat ad.
- A `40_riport.md` 4.4 "konkrét címzett-lista a `resend` megerősítő-
  dialógusban" (SD-57) egyszerű query-vel olvasható.
- Tenant DB-ben él, nem Core-ban: a címzett-lista **tenant-specifikus**
  működési adat, nem a tenant-regisztráció része.

**Mérlegelt alternatíva 1:** JSON-tömb-mező a `Tenant`-on
(`reportRecipients jsonb`). Egyszerűbb tárolás, de (a) mezőnkénti audit
nincs, (b) duplikátum-érvényesítés nehézkesebb, (c) a `BaseController`
nem kezeli, egyedi végpontok kellenek, (d) a Core DB-ben lenne, miközben
a riport maga (`WeeklyReport`) Tenant DB-ben — keveredő DB-szint.

**Mérlegelt alternatíva 2:** `User`-entitást alapul vevő modell ("a
polgármester is egy `User`, csak nem lép be"). Elvetve: a
`50_konfig_v2.md` 5.2 explicit kimondja: "a címzett **nem szerepkör** —
a polgármester nem lép be a manager felületre". A polgármester nem
`User`, csak címzett.

**Az induló állapot — UI-szinten, nem seed.** A pilot-tenant
felvételekor a vezető (Béla) **nem kerül be automatikusan**
`WeeklyReportRecipient`-ként. A funkcionális réteg ("a vezető alapból
rajta van", `50_konfig_v2.md` 5.2) ezt UI-megfogalmazásban oldja meg: az
első megnyitáskor informatív kártya jelzi, hogy a lista üres, a vezető
egy kattintással felveheti magát. A `User.email`-jét **nem** ajánlja
fel automatikusan a kliens — az nem feltétlenül a kívánt riport-cím.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-60 — A logó-feltöltés dedikált végponttal, nem `Attachment`-tel ("egyedi-fájl-mező" minta)

**Döntés:** A tenant logója **nem** `Attachment`-rekord (az
`Attachment` `ticketId`-hez kötött, `00_domain_model.md` 1.4). A logó az
S3-tárolóban él, és a `Tenant.logoFileRef` (SD-58) tárolja az objektum-
hivatkozást.

A feltöltés dedikált végponton megy: `POST /v1/tenant-settings/logo`
(multipart/form-data, egyetlen `file` mező a binárissal). MIME-szűrés
(`image/png`, `image/jpeg`, `image/svg+xml`), méret-limit 2 MB, magic
bytes ellenőrzés a header-hazudás ellen. A korábbi logó S3-objektuma
törlésre kerül (`AfterSaveAsync`); ha a törlés meghiúsul, csak naplózódik
(árva objektum, NY-K3). Külön `DELETE /v1/tenant-settings/logo`
visszaállítja a `logoFileRef`-et `null`-ra.

Olvasás: a `logoFileRef` a `TenantSettingsDto`-ban szerepel; a kliens
egy presigned URL-en éri el (a `Attachment` minta szerint, SD-15
konzisztens — de **nem** `Attachment`-entitás).

**Új mintázat — "egyedi-fájl-mező".** Amikor egy entitásnak van egy
szakosított képmezeje, ami nem általános fájl-rendszer (nem
`Attachment`), és nem hivatkozott más entitások által: dedikált
`POST`/`DELETE` multipart-végpont az entitás-erőforrás alá, a
binárist S3-objektum-kulcsra fordítja, és csak a hivatkozást írja az
entitás-mezőbe. **Ez nem általánosított Attachment-modell** — célzottan
egy mezőhöz tartozik. A `CLAUDE.md` v1.2 3. szakasza rögzíti a mintát.

**Indok:** A logó egyetlen objektum, nem több, nem listázott, nem
polgári-API-tárgya. A dedikált végpont egyszerűbb, mint az `Attachment`
általánosított rendszer; a méret-limit és MIME-szűkítés szigorúbb.

**Mérlegelt alternatíva 1:** A logó egy `Attachment`-rekord, és a
`Tenant.logoAttachmentId` mutat rá. Túltervezés — az `Attachment`
`ticketId`-vel egyoldalúan kötött; ezt általánosítani egy globális
fájl-modellt nyitna, amit a pilotra nem igazolt igény.

**Mérlegelt alternatíva 2:** Presigned URL-feltöltés (a kliens
közvetlenül S3-ba tölt, a backend csak a `logoFileRef`-et frissíti).
Stabilabb skálán, de bonyolultabb mechanika a piloton. **Megnyitva
fejlesztői döntésnek** — a végpont-szerződés (`POST /v1/tenant-settings/logo`)
ugyanaz; a backend belső implementációja választható.

**Visszacsorgó jelzés (VF-K1):** Ha más entitásnál (pl. `News.coverImage`)
ugyanez merül fel, ez a minta — vagy az `Attachment` általánosítása —
választható. A `60_tartalom` feature-spec dönt. Lásd VF-K1 lent.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-61 — `Tenant`-PUT korlátozott mezőkészletre, `TenantSettingsController` ("Core-mezőkre korlátozott tenant-szintű írás" minta)

**Döntés:** A `PUT /v1/tenant-settings` végpont (új) a vezető
(`tenant_manager`) számára engedett, de **csak** az alábbi mezők
szerkeszthetők: `name`, `contactAddress`, `contactPhone`, `contactEmail`
(SD-58). A többi `Tenant`-mező (`code`, `displayPrefix`,
`dbConnectionRef`, `status`, `timeZone`) **nem szerkeszthető a vezető
által** — ezek `urbino_admin` hatáskörűek (K-024). A `logoFileRef`
szintén nem ezen a végponton változik, hanem a logó-feltöltőn (SD-60).

A `TenantSettingsController` **dedikált controller**, **nem** a
standard `Tenant`-CRUD-ra ráhúzott. A Core `DbContext`-et használja, de
a `Tenant` headerből kiolvasott `code`-ra **explicit szűr** — kizárólag
az aktív tenant `Tenant`-rekordját olvassa/írja. **Hasonló minta a
`UserManagementController`-hez** (`20_felhasznalokezeles.md` 3.1,
SD-36).

A controller-elnevezés szándékos: `TenantSettingsController` — a
vezető a *saját tenantja beállításait* szerkeszti, nem a globális
`Tenant`-regisztrumot.

**Új mintázat — "Core-mezőkre korlátozott tenant-szintű írás".** A
`tenant_manager` szerepkör általában **nem ír** Core DB-be — de néhány
Core-entitás-mező szűk halmazára kivételt teszünk. Az ilyen végpont
dedikált controllerrel dolgozik, Core `DbContext`-tel, **explicit
`Tenant`-header-szűréssel**. A szerkeszthető mezők listája szűkített; a
tiltott mezők szerepeltetése `400 field_not_editable`-lel zár. Ez
**célzott kivétel**, nem általános felhatalmazás. A `CLAUDE.md` v1.2 3.
szakasza rögzíti a mintát.

**Indok:** A `Tenant` Core DB-ben él (`01_kozos_mintak.md` 1.6), a
`tenant_manager` normálisan nem ír Core-adatot. Ez egy **célzott
kivétel** — a `name` és kontakt-mezők *az adott tenant operatív
tulajdonai*, miközben a regisztrum-mezők (`code`, DB-kapcsolat,
státusz, prefix) **platformszintűek**. A kettő szétválasztása a
végpont-szinten történik: a `TenantSettingsController` csak a
"tenant-tulajdon" mezőket fogadja.

**Mérlegelt alternatíva:** A vezető a teljes `Tenant`-PUT-ot kapja, és
a tiltott mezőket "olvasásra-zár" annotációval védjük. Elvetve — a
kérés-szintű szűkítés robusztusabb és olvashatóbb az
`authorization.json`-on és az API-doksin keresztül.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-62 — A gyökér-kategória dedikált végponton jön létre, a default-katalógusból

**Döntés:** A `Category` `BaseController` `POST` végpontja a standard
`POST /v1/categories` **csak alkategória létrehozására engedett**
(`parentId` kitöltött, és a hivatkozott `Category` gyökér). Új gyökér-
kategória létrehozása **egy dedikált végpontra** korlátozódik:
`POST /v1/categories/from-default` (body: `{ defaultCategoryId }`). A
végpont a Core DB `DefaultCategoryCatalog` táblájából előveszi a
hivatkozott rekordot (és alkategóriáit), és a tenant DB `Category`
táblájába másolja a hibrid modell szerint (SD-8): új `Category`
rekord(ok) jönnek létre, `sourceCatalogId` kitöltve a Core-forrásra.

A standard `POST /v1/categories` viselkedése (eltérés a mintától):
- `parentId == null` → `409 root_must_come_from_default`. K-008 érvényesítése.
- `parentId` egy alkategória → `409 category_depth_exceeded`. Fa-mélység
  invariáns.
- `parentId` egy gyökér → új alkategória létrejön (standard eset).

A `from-default`-választható forrás olvasó-végpontja:
`GET /v1/categories/available-default-roots` — a `DefaultCategoryCatalog`
gyökerei, amelyekhez a tenant DB-ben még nincs `Category` rekord
(`sourceCatalogId` ezt jelzi). Ez **cross-DB olvasás a működési
útvonalon kívül**: az SD-2 elv ("cross-DB join a működési útvonalon
nincs") a *működési* útvonalra szól (lista, adatlap, Dashboard), nem a
ritka konfig-műveletekre. Két szekvenciális `SELECT`, join nélkül; a
pilot-volumenen elhanyagolható. A feature-spec ezt **lokálisan**
dokumentálja, nem a `01_kozos_mintak.md` általános szabályának
módosítása. A `CLAUDE.md` v1.2 5. szakasza rögzíti az elv-enyhítés
mintáját.

**Indok:** A K-008 multi-tenant fegyelem szerint a gyökér-kategória
terméktulajdon (K-036). A "csak default-katalógusból" elv API-szinten
csak akkor érvényesíthető megkerülhetetlenül, ha a standard `POST` nem
fogad gyökeret — alternatívaként a `name`-szabály törékeny lenne
(`Category.name` szerkeszthető a tenant által, `50_konfig_v2.md` 2.2). A
`sourceCatalogId` mint forrás-hivatkozás (SD-8) erősebb invariáns.

**Mérlegelt alternatíva:** A `name`-szabály alapján szűrni (a
`Category.name` csak akkor lehet érvényes, ha szerepel a
`DefaultCategoryCatalog`-ban gyökérként). Elvetve — a `name`
szerkeszthető, így nem stabil kulcs.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-63 — A `Category` delete-guard, deaktiválás mint elsődleges UI-út

**Döntés:** A `BaseController` standard `DELETE /v1/categories/{id}`
végpontja **`BeforeDeleteAsync`-guard**-dal védett:
- Ha a `Category`-ra (vagy bármely leszármazottjára) van `Ticket`
  hivatkozás (`Ticket.categoryId` vagy
  `Ticket.citizenSuggestedCategoryId`) → `409 category_referenced` +
  `details: { directTicketCount: N, descendantsWithTickets: [...] }`.
- Ha a `Category`-nak van leszármazottja (alkategóriája), és bármelyikre
  van hivatkozás → szintén `409 category_referenced`, a részletekben az
  érintett alkategória(k) megjelölve.
- Ha minden tiszta → standard delete (gyökérnél a leszármazottakkal együtt
  kaszkádol).

A **deaktiválás mint UI-elsődleges út**: a `/beallitasok/kategoriak`
aloldalon a sor-szintű akció "Deaktiválás" (az `isActive`-mező
átállítása PUT-tal), a "Törlés" csak másodlagos opció (kebab-menüben),
és a UI figyelmezteti a vezetőt: "A törlés végleges. Ha vannak (vagy
lehetnek) bejelentések ebben a kategóriában, érdemes inkább deaktiválni."

**A `Group` delete-guard-ja ennek a mintának kiterjesztése (nem önálló
SD).** A `Group` entitásra ugyanez érvényes: ha van `Ticket`-rekord
`assignedGroupId == {id}`-val → `409 group_referenced`. A
`30_beallitasok.md` 3.2.4 részletezi; a domain-szabály azonos az
SD-63-mintával.

**Eltérés a mintától:** A `BaseController` `DELETE` nem ellenőriz
hivatkozásokat. A `Category`-spec `BeforeDeleteAsync`-ja igen — ez
explicit eltérés-jelölést kap a feature-spec 3. szakaszában.

**Indok:** A `50_konfig_v2.md` 2.4 kimondja: "Kategóriát törölni a
pilotra nem lehet, csak deaktiválni — ez az adatintegritást védi." A
`00_domain_model.md` 2.1 ezt megerősíti. A funkcionális réteg "nem lehet
törölni" annyit ad, hogy a UI ne kínálja prominensen; a fejlesztői
mélységnél a szerver-oldali guard a megkerülhetetlen biztosíték:
API-first valaki közvetlenül hív, ne tudjon elárvult
`Ticket.categoryId`-t csinálni.

**Mérlegelt alternatíva:** A delete-végpontot egyáltalán nem teszik
közzé — `405 Method Not Allowed`. Elvetve, mert "soha nem törölhető"
túl szigorú: egy frissen importált, hivatkozás-nélküli rosszul
választott gyökeret a vezető visszavonhat. A guard mint feltételes
engedély a jó középút.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-64 — A `Category`-reorder szülő-hatókörben (`parentId` paraméter)

**Döntés:** A `BaseController` reorder-mintája standard, de a
`Category`-nál a hatókör **szülő-kontextusban értelmes**. Két reorder-
művelet egy végponton: `POST /v1/categories/reorder` body
`{ parentId: null|long, ids: [...] }`. A `parentId == null` a gyökereket
rendezi; a `parentId == <gyökér-id>` a gyökér alatti alkategóriákat
rendezi. A végpont validálja, hogy az `ids`-tömb minden eleme a megadott
`parentId`-jű szülőhöz tartozik; ha valamelyik más szülőhöz → `400
fieldErrors.ids[i] = "wrong_scope"`.

A UI-megfelelő: a kategória-lista **csoportosított struktúrával**
jelenik meg (gyökér mint csoport-fejléc, alkategóriák alatta) — a
sortolás csoport-fejlécen drag-and-drop a gyökerek között, csoporton
belül drag-and-drop az alkategóriák között.

**Eltérés a mintától:** A standard `BaseController.Reorder` egy lapos
lista sorrendjét rendezi. A `Category`-nál a `parentId` mint hatókör-
paraméter szükséges, mert a `sortOrder` szülő-szinten belül értelmes
(`00_domain_model.md` 2.1: "A megjelenítési sorrend a szülőn belül").

**Indok:** A polgári app a hat gyökér-csempét mutatja
(`screen_uj_bejelentes_2`) — a sorrend ezen a szinten számít. Az
alkategóriák szülőn belül láthatók a triage-dropdown-on és a polgári
alkategória-választón — a sorrend ott szülőn belül értelmes. A
globális sorrend értelmetlen.

**Mérlegelt alternatíva:** A reorder két különálló végpont
(`/categories/reorder-roots` és `/categories/reorder-children`).
Elvetve — egyetlen végpont a `parentId`-val egyértelmű és könnyebben
karbantartható.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-65 — A `Group` standard CRUD, taglista `[ManyToManyConnection]`-nel — megerősítés

**Döntés:** A `Group` entitás CRUD-ja **standard a `BaseController`
szerint**, eltérés-jelölés nélkül. A `members` mező a `GroupDto`-ban egy
`tenantUserIds: long[]` tömb; a `[ManyToManyConnection]`-attribútum a
`Group.Members` navigációs kollekción auto-mappeli a join-tábla-sorokat
(`CLAUDE.md` "Many-to-Many Relations" minta).

Az "egy helyről szerkeszthető" döntés (`50_konfig_v2.md` 6.2)
**UI-szintű, nem API-szintű**. A szerver elfogadja a `members`-változást
a `PUT /v1/groups/{id}`-n; a felhasználó-aloldal
(`20_felhasznalokezeles.md` 4.3) csoporttagság-szekciója *csak
olvasásra* jeleníti meg — ez a kliens döntése, nem a szerver kényszere.

**A `GroupDto.members` denormalizált megjelenítő-mező** — eltérés a
mintától. A standard `[ManyToManyConnection]` csak ID-tömböt ad; a
feature-spec a megjelenítő-DTO-t (`[{id, displayName, status, roles}]`
a `TenantUser`-ből) is hozzáfűzi, hogy a csoport-adatlap egyetlen
hívással rajzolható legyen. Konzisztens a `20_felhasznalokezeles.md` 4.
mintájával.

**Indok:** A `50_konfig_v2.md` 3.2 a csoportot "egy címke + egy
taglista" formában rögzítette; a `00_domain_model.md` 2.2 már leírta a
`[ManyToManyConnection]` mintát. A feature-spec nem ad hozzá újat —
csak rögzíti, hogy a standard mintát követjük, és a UI-konvenciót
(a felhasználó-adatlapon olvasásra) szerver-oldalon nem kényszerítjük.

**Mérlegelt alternatíva:** Külön végpontok a tagság-műveletre (`POST
/v1/groups/{id}/members`, `DELETE /v1/groups/{id}/members/{userId}`).
Elvetve — a `[ManyToManyConnection]` auto-mapping kényelmesebb, a UI
ugyanaz a "checkbox-lista a csoport-adatlapon" minta, mint a
felhasználó szerepkör-jelölőnégyzeteinél.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-66 — `authorization.json` 22 új route, mind `tenant_manager`-only; a riport-fogyasztás új végpont nélkül teljesül

**Döntés:** A négy aloldal API-jának teljes route-listája az
`authorization.json`-ban, mind `tenant_manager` szerepkörrel (a
tenant-prefix futásidőben kiegészül a `Tenant` header kódjával). A 22
új route: 8 a `Category`-családra (`/v1/categories`,
`/v1/categories/{id}`, `/v1/categories/from-default`, `/v1/categories/reorder`,
`/v1/categories/available-default-roots`); 5 a `Group`-családra
(`/v1/groups`, `/v1/groups/{id}`); 4 a `tenant-settings`-családra
(`/v1/tenant-settings`, `/v1/tenant-settings/logo`); 5 a
`weekly-report-recipients`-családra. Részletes lista:
`30_beallitasok.md` 3.5.

**A `40_riport.md` SD-57 fogyasztói várakozás új végpont nélkül
teljesül.** A `GET /v1/weekly-report-recipients` (lista) **ugyanaz az
URL**, amit a `40_riport.md` SD-57 "olvasó-végpont a tenant aktuális
címzett-listájához" alatt feltételezett. A riport-adatlap és a
`resend`-megerősítő-dialógus ugyanazt a `GET /v1/weekly-report-recipients?isActive=true`-t
hívja, mint a Beállítások / Általános aloldal címzett-szekciója. Ezzel
a `40_riport.md` 8.2 (3) feltételezés formálisan teljesül, **új végpont
nélkül**. AC-szinten az AC-R1.3 (`30_beallitasok.md` 6.) gépiesen
ellenőrzi.

**Indok:** A `05_jogosultsagok_v2.md` 2.8 a teljes Beállítások-blokkot
`tenant_manager`-only-nak deklarálja. A finomított akciók (SD-62
`from-default`, SD-63 delete-guard, SD-64 reorder, SD-60 logó) mind
ugyanennek a szerepkörnek a hatókörében maradnak — egyik sem nyit új
jogosultsági síkot. A `tenant_dispatcher`, `tenant_content_manager`,
`tenant_field_worker` egyik végponthoz sem fér.

**Mérlegelt alternatíva:** A "gyökér-kategória importálása" külön
(szigorúbb) szerepkört kapjon (pl. `tenant_admin_strict`). Elvetve —
K-024 szerint a tenant-tulajdon a vezető hatáskörében van; a
"termékesített készletből választás" UI-kényszere a K-008-at
érvényesíti, nem külön jogkört igényel.

**Az MH-J1 megtartott hiány tovább szűkül.** A `40_riport` (v1.0) és a
`30_beallitasok` (v1.0) feature-spec lezárta a riport- és konfiguráció-
modul route-jait — már csak a `60_tartalom` modul route-stringei
nyitottak (`CLAUDE.md` v1.2 6. szakasz).

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### SD-67 — Az "Általános" aloldal egyetlen képernyő három mentési-modellel

**Döntés:** A `/beallitasok/altalanos` aloldal **nem** lista-oldal,
hanem **egyetlen szerkesztő-űrlap**, négy logikai szekcióval:
(1) tenant-alapadatok (`name` szerkeszthető; `code`, `displayPrefix`,
`timeZone` olvasásra); (2) logó (kép-előnézet, "Feltöltés"/"Csere"/
"Eltávolítás"); (3) kontakt-adatok (`contactAddress`, `contactPhone`,
`contactEmail`); (4) heti riport címzettjei (`WeeklyReportRecipient`
beágyazott mini-lista).

**Három mentési-modell egy képernyőn:**
- Az (1) + (3) szekció egyetlen `PUT /v1/tenant-settings` mentéssel megy
  (`[validationForm]`-minta, egyszer kattint a "Mentés"-re).
- A (2) logó-szekció külön végpontokon (SD-60); feltöltéskor azonnal
  kimegy, nem várja meg a fő mentést.
- A (4) címzett-lista soronként mentődik (külön `POST`/`PUT`/`DELETE` a
  `WeeklyReportRecipient`-en).

**Eltérés a mintától:** Az admin-felület szokványos mintája "lista +
adatlap + szerkesztés" (`01_kozos_mintak.md` 6.4); az "Általános"
ehelyett egyetlen rekord szerkesztő-űrlapja. Ez nem új komponens-igény
(`50_konfig_v2.md` 7.3), csak a meglévő `[validationForm]` és
`<form-field>` használata "lista nélkül". A beágyazott címzett-lista a
`[ManyToManyConnection]`-mintával rokon, de itt **különálló entitás**
(`WeeklyReportRecipient`), nem n-n kapcsolat — egy egyszerű in-place
CRUD-tábla a szekción belül.

**Indok:** A `Tenant`-ból csak **egy** sor van (a saját). Listázni nem
értelmes. A `WeeklyReportRecipient` lista rövid (1–3 elem tipikusan), nem
indokol külön aloldalt. Az egész tenant-konfigurációt egy képernyőn
látni Béla számára átláthatóbb, mint öt különböző oldalt kattintgatni.

**Mérlegelt alternatíva:** Külön aloldalak —
`/beallitasok/altalanos/alapadatok`, `/beallitasok/altalanos/logo`,
`/beallitasok/altalanos/kontakt`, `/beallitasok/altalanos/riport-cimzettek`.
Túltervezés — a `50_konfig_v2.md` 7.3 explicit kimondja, hogy a
Beállítások a pilot legkevesebb komponens-igényű része; az egységes
"Általános" oldal ezt tartja.

**Következmény:** A `90_sitemap_v3.md` 2.6 nézet-leltár "Általános"
sora egyetlen URL (`/beallitasok/altalanos`); nincs `/details/<id>`
aloldala (a `GET /v1/tenant-settings` paraméter nélküli — a `Tenant`
headerből oldódik). A `40_riport.md` SD-57 "Beállítások / Általános
oldalra mutató link" konkrétan ide mutat.

**Ki döntötte:** Alapító, a specifikáció javaslatára.

### Megtartott hiányok — a Beállítások feature-spec köréből

A v2.1 instrukció (d) szerint: a megtartott hiány nem blokkolja a
feature gerincét, ezért a feature halad; a hiány nyomon követhető marad.

**NY-K1 — A `DefaultCategoryCatalog` formális mezőtáblája.** A
`00_domain_model.md` 4. blokkja a default-katalógust megemlíti, de
formális mezőtáblát nem ad hozzá (a 4. blokk a `News`/`Event`/`CityInfo`
tartalom-entitásokra fókuszál). Az SD-62 `from-default`-importja és az
`available-default-roots` olvasó-végpont igényli a `DefaultCategoryCatalog`
mezőit (`id`, `name`, `iconRef`, `parentId`). **Nem blokkol:** az
API-szerződések egyértelműek, a Beállítások feature-spec kódolható; a
`00_domain_model.md` 3.4 egy későbbi pontosítása (a `60_tartalom`-spec
mellett vagy után) rögzíti a teljes mezőtáblát. **Cél-dokumentum:**
`00_domain_model.md` 3.4. *(A `00_domain_model.md` v1.7 nyitott
kérdés-táblázatába is bekerült.)*

**NY-K2 — A polgári mobilapp olvasói szerződése a tenant-kontakt-
adatokra.** A `50_konfig_v2.md` 6.3 "egy adat, egy hely" döntésével
konzisztensen a `Tenant.contactAddress`/`contactPhone`/`contactEmail`
mezőket egy publikus vagy citizen-auth-os olvasó-végpontnak el kell
érhetővé tennie (a polgári app "Ügyfélszolgálat" szekciójához,
`screen_tovabbi_menu.PNG`). Potenciálisan a logó is része (a polgári
fejléc-ikon). **Nem blokkol:** a mezők rendelkezésre állnak a `Tenant`
entitáson (SD-58); a polgári-oldali route, auth-modell, és a kiküldött
szűkített DTO formája a polgári adatigény-spec hatásköre. **Cél-
dokumentum:** polgári adatigény-spec.

**NY-K3 — S3-objektum-clean-up az árva logókhoz.** A `Tenant.logoFileRef`
cseréjekor az `AfterSaveAsync` törli a régi S3-objektumot; meghiúsulás
esetén árva marad. Egy időszakos clean-up job a megoldás. **Nem
blokkol:** árva S3-objektumok nem zavarják a működést, csak helyet
foglalnak; egy negyedévente futó takarítás bőven elég. **Hatáskör:**
üzemeltetési / iterációs.

**NY-K4 — Konfigurációs esemény-napló (`ConfigurationAuditLog`).** A
négy érintett entitás (`Category`, `Group`, `WeeklyReportRecipient`,
`Tenant`) `AuditableEntity` "ki/mikor utoljára"-szinten audit-olt;
mezőnkénti változás-történet nincs. **Nem blokkol:** a pilot-igényre az
`AuditableEntity` elég (a `20_felhasznalokezeles.md` 3.9 ugyanezt
rögzítette a felhasználó-oldalon). Ha a hivatali nyomvonal-igény ezt
kívánja, iterációs elem. **Hatáskör:** iteráció (6-12. hó), ha a
pilot-tapasztalat kívánja.

### Visszacsorgó jelzés — a Beállítások feature-spec köréből

**VF-K1 — A `News.coverImage` (és más, jövőbeli egyedi-kép-mezők) az
SD-60 mintáját követhetik.** Az SD-60 "egyedi-fájl-mező" mintája
(dedikált multipart-feltöltés, S3-objektum-hivatkozás-mező, nem
`Attachment`) általánosítható a `60_tartalom`-feature-spec borítókép-
kezelésére is. **Nem ennek a feature-specnek a dolga eldönteni** — a
`60_tartalom`-spec dönt, az SD-60-at modellként használhatja, vagy az
`Attachment`-általánosítást választhatja (ami egy globális
fájl-rendszert nyitna). **Cél-dokumentum:** `60_tartalom`-feature-spec.

### Elhatárolás — a Beállítások feature-spec köréből

**A felhasználó-aloldal (`/beallitasok/felhasznalok`)** nem ennek a
körnek a hatóköre. A `20_felhasznalokezeles.md` v1.0 már önálló
feature-specként lefedi, beleértve a meghívó-modellt, a fiók-állapot-
életciklust, a vezető-védelmet és a csoporttagság-olvasási nézetet a
felhasználó-adatlapon. **Hatáskör:** `20_felhasznalokezeles.md`.

**A polgári-oldali olvasói felület** (tenant-info, kategória-fa) nem
ennek a körnek a hatóköre. A `30_beallitasok.md` 5. szakasz
megerősíti, hogy a polgári app a `Category`-lookup standard
fogyasztója, és az NY-K2 nyitott kérdést hagyja a polgári adatigény-
spec hatáskörében. **Hatáskör:** polgári adatigény-spec.

**A `Tenant.status` állapotgép-átmenetei** (`Setup → Active →
Suspended ⇄ Active`, `Active/Suspended → Archived`) nem ennek a
körnek a hatóköre — `urbino_admin`-hatáskör (K-024, SD-5). A
Beállítások feature-spec a `Tenant.status` mezőt nem érinti
szerkeszthető módon (SD-61: a tiltott mezők között szerepel).
**Hatáskör:** Urbino-admin spec.

---

### SD-68 — A tartalmi entitások borítóképe az SD-60 "egyedi-fájl-mező" mintát követi

**Döntés:** A `News.coverImageRef` és `Event.coverImageRef` mezők
kezelése az SD-60 mintáját általánosítja a tartalmi entitásokra. A
mezők dedikált multipart-végpontokon szerkeszthetők (`POST/DELETE
/v1/news/{id}/cover-image`, `POST/DELETE /v1/events/{id}/cover-image`);
a standard `PUT /v1/news/{id}` / `PUT /v1/events/{id}` `400
fieldErrors.coverImageRef = "field_not_editable"`-lel zár, ha a kérés
tartalmazza a mezőt.

**Validáció a feltöltőn:** MIME-típus `image/jpeg`, `image/png`,
`image/webp` (`400 invalid_mime_type`); max 5 MB (`400 file_too_large`);
min 1 KB (`400 file_too_small`).

**Csere-szemantika:** új feltöltés esetén az új fájl S3-ba kerül, a
`coverImageRef` átáll az új kulcsra, a régi S3-objektum törlése az
`AfterSaveAsync`-ben. S3-törlés meghiúsulása WARNING-szintű
logbejegyzéssel rögzítendő (NY-K3 árva-takarítás mintája).

**Idempotens DELETE:** `coverImageRef = null` állapotban a `DELETE
.../cover-image` `204`-gyel zár, semmi nem változik.

**Indok:** Az SD-60 a Beállítások feature-spec által bevezetett
"egyedi-fájl-mező" minta — a `Tenant.logoFileRef`-re alkalmazva. A
`30_beallitasok.md` VF-K1 visszacsorgó jelzése explicit felvetette, hogy
a `News.coverImage` (és más jövőbeli egyedi-kép-mezők) ugyanezt a
mintát követhetik. Az SD-68 ezt a felvetést **elfogadja**: az
"egyedi-fájl-mező" minta általánosítható; a `News`/`Event` borítóképe
**nem** `Attachment`-rekord (az `Attachment` `ticketId`-hez kötött), és
nem általános fájl-rendszer, csak egy entitás-mező S3-objektum-
hivatkozással. A standard `PUT`-on való tiltás megakadályozza a véletlen
felülírást.

**Mérlegelt alternatíva:** Az `Attachment`-modell általánosítása —
ekkor a `News`/`Event` borítóképei `Attachment`-rekordok lennének
`AttachmentKind.NewsCover`/`EventCover` értékkel, a `ticketId` mezőt
általánosított `parentId`-vé (vagy poliformikus FK-vá) téve. **Elvetve:**
ez egy nagy ívű refactoring lett volna (`Attachment.ticketId` minden
hivatkozás-átírása, polimorf FK PostgreSQL-szintű kezelése, query-szint
újraírása), aránytalanul nagy mértékben a kis pilot-igényhez képest. A
"egyedi-fájl-mező" minta könnyen alkalmazható, és ha később (6-12. hó)
általános fájl-rendszer-igény jelentkezik, az `Attachment`-általánosítás
külön iterációs lépésként megtehető.

**Következmény:** A `00_domain_model.md` v1.7 → v1.8 — a 4.2 `News` és
4.3 `Event` mezőtáblákon új lábjegyzet a `coverImageRef`-ről (SD-68); a
mezők tárolása változatlan. A `CLAUDE.md` v1.2 → v1.3 — a 3. szakasz
"egyedi-fájl-mező" minta-magyarázatának frissítése, az SD-68
alkalmazási példájával.

**Ki döntötte:** A specifikációs kör, a `60_tartalom`-spec 2. lépésében
(D-T1). A VF-K1 ezzel **lezárva**.

### SD-69 — A `News.body` és `Event.body` HTML-tárolás szigorú szerver-oldali szanitizációval

**Döntés:** A `News.body` és `Event.body` mezők HTML-tartalmat tárolnak,
de **szigorú szerver-oldali szanitizációval**: a megengedett
HTML-elemek és attribútumok zárt whitelistje:

| Tag | Megengedett attribútum |
|---|---|
| `<p>` | — |
| `<br>` | — |
| `<strong>` | — |
| `<em>` | — |
| `<ul>`, `<ol>`, `<li>` | — |
| `<a>` | `href` (csak `https://`); `target="_blank"` és `rel="noopener noreferrer"` automatikusan hozzáadva |

**Tiltott elemek:** `<script>`, `<iframe>`, `<img>`, `<video>`, `<style>`,
`<form>`, `<input>`, `<button>`, `<table>` és minden más nem-whitelist
tag — szerver-oldali szanitizáció eltávolítja, a tartalom (text content)
plain szövegként megmarad.

**Tiltott attribútumok:** `style`, `onclick`, `onerror`, és minden `on*`
event-handler.

**URL-szigorítás:** az `<a href>`-en csak `https://`-előtagú URL
megengedett; `javascript:`, `data:`, `file:`, `http://` — kiszűrve, a
`<a>` tag tartalma plain szövegként megmarad.

**Méret-korlát:** max 10 000 karakter a teljes HTML-tartalomra
(tag-ekkel együtt). FluentValidation `MaximumLength(10000)`.

**Üresség-ellenőrzés:** szanitizáció után a text content trim után nem
lehet üres. `<p></p>` egyedüli tartalomként, vagy csak whitespace →
`400 fieldErrors.body = "invalid_html_or_empty_after_sanitization"`.

**Indok:** A funkcionális dokumentum (`60_tartalom_v2.md` 3.6) "korlátozott
rich text" formátumot ír (cím, félkövér, dőlt, lista, link). A pilot
tartalmi igénye nem indokol teljes WYSIWYG-et (táblázat, beágyazott
média), de a plain text túl szegényes a hivatalos közlemény műfajához.
A HTML-tárolás szanitizáció-whitelisttel a "korlátozott rich text"
formális megvalósítása: a backend tárolja a strukturált tartalmat
(mindenki egyezően tudja olvasni), a szanitizáció kiszűri az XSS-rést
(`<script>`, `on*` event-handlerek). Az SD-69 explicit listát ad a
megengedett tagekről — a Claude Code-nak nincs kétértelműsége.

**Mérlegelt alternatíva:** **(1) Plain text + Markdown szubset.** Egy
korlátozott Markdown-konverter (csak `**bold**`, `*italic*`, listák,
`[link](url)`). Elvetve, mert (a) a Markdown polgári-oldali renderelése
a Flutter-oldalon új komponensigény (a Flutter app nem natívan
Markdown-renderelő); (b) a Markdown szubsetjének definíciója és a
szerver-validációja ugyanolyan munka, mint a HTML-szanitizáció — nem
egyszerűbb; (c) az admin oldali szerkesztő-felület (rich-text-szerkesztő)
HTML-t ad ki, nem Markdown-t; egy HTML → Markdown → HTML round-trip a
kliens-szerver közt felesleges bonyolítás. **(2) Plain text + szöveg-
formázás-jelölés.** A `[B]szöveg[/B]` BBCode-szerű mintával. Elvetve
ugyanazon okok miatt, és mert a BBCode már nem korszerű.

**A PrimeNG Editor implementációs választás:** a rich-text-szerkesztő
komponens (a `60_tartalom`-spec 4.6) HTML-t ad ki és fogad — illeszkedik
az SD-69 tárolási formátumához.

**Következmény:** A `00_domain_model.md` v1.7 → v1.8 — a 4.2/4.3
`body`-mező lábjegyzettel pontosított (SD-69). A `60_tartalom`-spec
3.1.3 a teljes whitelist-szabályrendszert formálisan rögzíti. **A
domain-modell NY-6 nyitott kérdése lezárva** (a tartalmi `body`
formátuma).

**Ki döntötte:** A specifikációs kör, a `60_tartalom`-spec 2. lépésében
(D-T2).

### SD-70 — `ContentStatus` állapotgép három állapottal és négy átmenettel; T3 és T2 külön akció publikált tartalmon

**Döntés:** A három tartalmi entitás (`News`, `Event`, `CityInfo`)
azonos állapotgépet használ a `ContentStatus` enumon. **Három állapot
és négy megengedett átmenet:**

| # | Átmenet | Kiváltó akció | Mellékhatás |
|---|---|---|---|
| T1 | `Draft → Published` | "Publikálás" | `publishedAt := now()` |
| T2 | `Published → Draft` | "Visszavonás vázlatba" | `publishedAt := null` |
| T3 | `Published → Archived` | "Archiválás" | `publishedAt` változatlan |
| T4 | `Archived → Published` | "Újrapublikálás" | `publishedAt := now()` (új) |

**Tiltott átmenetek:** `Draft → Archived`, `Archived → Draft`, és minden
"önmagába"-átmenet — `409 invalid_transition`, `details.from`,
`details.to`.

**Két külön akció publikált tartalmon:** A `Published` állapotú
tartalomra a "Visszavonás vázlatba" (T2) és az "Archiválás" (T3)
**két különböző akció** — nem egyetlen "levétel" akció. Indok: a két
átmenet szemantikája eltér; a T2 (`Published → Draft`) a "munka újra
nyitva" — szerkesztésre szánjuk, és a `publishedAt` törlődik. A T3
(`Published → Archived`) a "munka kész, de nem aktuális" — megőrizzük
a publikálási emléket (`publishedAt` változatlan), de a polgár már nem
látja. Egyetlen "levétel" gomb két célt kompromittálna; a kebab-menü
külön mutatja a két akciót.

**`DELETE` állapot-érzékeny:** `Draft` és `Archived` törölhető;
`Published` → `409 cannot_delete_published`,
`details.currentStatus = "Published"`. Bulk DELETE atomi — egyetlen
`Published` is `409`-szel zárja a teljes batchet.

**`publishedAt` szemantikája:**
- A jelenleg publikált tartalom `publishedAt`-je a "jelenlegi publikálási
  idő".
- Az archív tartalom `publishedAt`-je a "legutóbbi publikálás emléke"
  (T3 nem törli — szándékos).
- T4 esetén a `publishedAt` újra `now()` — új publikálási időpont,
  nem a régi visszahozása. A polgári app a `publishedAt desc`-rendezés
  miatt a frissek között mutatja az újrapublikáltakat.

**Indok:** Az SD-22 már rögzítette a három `ContentStatus` enum-értéket;
a `02_globalis_allapotgep.md` korábbi verziója (v0.1) ezt nem
részletezte (a tartalmi életciklust a `60_tartalom`-spec hatáskörébe
utalta). Az SD-70 a feature-spec **mind a három tartalmi entitásra
közös**, formális átmenet-tábláját rögzíti. A három entitás
**szerkezetileg rokon** (SD-21), de **életciklusilag azonos** — egy
közös `ContentStatus` állapotgép azonos szabályokkal mindhárom helyen
indokolt (egyszerű, gépiesen ellenőrizhető, a Claude Code-nak
kétértelműség nélkül implementálható).

**Mérlegelt alternatíva — háromállapotú UX vs. kétállapotú:** A
funkcionális dokumentum (`60_tartalom_v2.md` 3.5) "kétállapotú" UX-et
ír (vázlat / publikált), de a `00_domain_model.md` (SD-22) háromállapotú
enumot rögzít — az archív állapot a tartalomkezelő archívum-nézetéhez
kell. A specifikációs kör a domain-modell háromállapotú változatát
támogatja; a feature-spec UX-szintű döntése, hogy a kebab-menüben két
külön akció van (T2, T3), és a lista alapból `Draft + Published`
szűréssel megy (az `Archived` checkbox-szal kapcsolható be).

**Egy "levétel" akció lett volna az alternatíva**, de elvetve: a
"munka újranyitása" és a "lerakás archívba" két különböző üzleti
döntés. Ha a tartalomkezelő félreérthető akciót kap, a `publishedAt`
sorsa (törölni vagy megőrizni?) konfliktusba kerül.

**Következmény:** A `02_globalis_allapotgep.md` v0.1 → v0.2 — új 9.
szakasz a `ContentStatus` állapotgépről, a fenti táblával, Mermaid-
diagrammal, `transition`-végpont szerződésével, `DELETE`-guard
összefoglalójával. A `60_tartalom`-spec 2.9-ben a tábla átírható
formában szerepel. A `00_domain_model.md` v1.8 SD-70-re hivatkozó
lábjegyzettel.

**Ki döntötte:** A specifikációs kör, a `60_tartalom`-spec 2. lépésében
(D-T3).

### SD-71 — `CityInfo.groupLabel` szabad szöveges címke (max 100), autocomplete distinct-végpontról

**Döntés:** A `CityInfo.groupLabel` **szabad szöveges címke**, max 100
karakter; **nem lookup-entitás**. Nincs `CityInfoGroup` entitás. Az
admin-űrlap a meglévő distinct értékeket egy `GET /v1/city-info-groups`
végpontról kínálja autocomplete-tel, de a tartalomkezelő bármilyen új
értéket beírhat.

**Az autocomplete-végpont szerződése:**
- Request: opcionális `query` query-paraméter (case-insensitive
  contains-szűrés).
- Response: `200 + string[]` — distinct `groupLabel` értékek a `CityInfo`-n,
  `null` és üres kihagyva, alphabet-sort. Üres tenant DB-ben üres tömb.
- Implementáció: `SELECT DISTINCT groupLabel FROM CityInfo WHERE
  groupLabel IS NOT NULL AND groupLabel ILIKE '%...%' ORDER BY
  groupLabel`. Cache nélkül a pilotra (volumen alacsony).

**Polgári oldali szekcionálás:** A polgári app a `groupLabel`-szerint
szekcionálja a városi-információ-listát (`screen_varosi_informaciok_lista`
csoportosított nézet). `null`/üres `groupLabel`-tételek kezelése a
polgári adatigény-spec dolga (NY-T3).

**Indok:** A funkcionális dokumentum (`60_tartalom_v2.md` 3.4) explicit
"szabad szöveges címke"-modellt ír — a tartalomkezelő (`content_manager`)
hatáskörben dönt a csoport-elnevezésekről. A `00_domain_model.md` 4.4
NY-7 nyitott kérdést hagyott ("szabad szöveg marad, vagy kontrollált
lista?"). Az SD-71 a szabad szöveges modell mellett dönt, három okból:

1. **Egyszerűbb.** Nincs új lookup-entitás (`CityInfoGroup`), nincs
   második admin-aloldal a csoportok kezelésére. Egy szöveges mező +
   autocomplete-segéd elegendő.
2. **Rugalmasabb.** A tartalomkezelő tetszőleges új csoportot vehet fel
   bármikor — nincs külön "csoport felvétele" kerülő-művelet.
3. **Az autocomplete teszi natúrlisztá.** A meglévő distinct értékek
   ajánlása megakadályozza a tipikus elgépeléseket ("Strandok" /
   "strandok" / "Strand"); a tartalomkezelő látja, mi van már a
   rendszerben.

**Mérlegelt alternatíva — kontrollált lista:** `CityInfoGroup` entitás
+ admin-oldal a csoport-CRUD-hoz. Elvetve: aránytalan munka a kis
pilot-igényhez képest. Egy tipikus pilot-tenantnál néhány csoport van
(`Strandok`, `Hivatalok`, `Egészségügy`, `Közmű`), és ezek ritkán
módosulnak — a szabad szöveg autocomplete-tel elég.

**Iterációs lehetőség:** Ha a pilot-tapasztalat azt mutatja, hogy a
csoport-elnevezések tényleg tipikus listát alkotnak, és/vagy
átnevezésük gyakori (8.1.6 edge case), egy `CityInfoGroup` entitás
egyetlen lookup-entitásként, alacsony költségen később bevezethető.

**Következmény:** A `00_domain_model.md` v1.7 → v1.8 — a 4.4 `CityInfo`
mezőtáblán a `groupLabel` lábjegyzete újraírva (szabad szöveges,
autocomplete). Az **NY-7 ezzel lezárva**.

**Ki döntötte:** A specifikációs kör, a `60_tartalom`-spec 2. lépésében
(D-T4).

### SD-23 megerősítése — a tartalmi entitások szerzője a `createdBy`

**Megerősítő bejegyzés** (nem új SD-szám). Az SD-23 (`00_domain_model.md`
v0.5, 2026.05.18) a tartalmi entitások szerző-megjelenítését a
`createdBy`-ra joinolt `TenantUser`-ből oldotta meg — explicit
"megerősítendő a `60_tartalom`-specnél" zárszóval. A `60_tartalom`-spec
v1.0 a kérdést újra megfontolta, és **az SD-23-at megerősítette**: a
három tartalmi entitás (`News`, `Event`, `CityInfo`) listái sehol nem
nevesítenek szerző-oszlopot (a `60_tartalom.md` 3.2, 3.3, 3.4
oszlopkészlete); az adatlap-szintű szerző-megjelenítés egy +1 LEFT
JOIN ugyanazon a Tenant DB-n belül (nem cross-DB) — `createdBy` (Core
`User.id`) → `TenantUser.userId` join, ugyanazon tenant DB-jén belül.

**A `60_tartalom`-spec által megerősített:** dedikált `authorId →
TenantUser` mező a `News`/`Event`/`CityInfo` entitásokon **nem kell**.
A `createdBy`-alapú megjelenítés elég a pilotra. Ha a 6-12. hó
tapasztalata mást mutat (pl. a polgári lista hangsúlyosan szerző-
névvel megy), egy iterációs lépés bevezetheti a dedikált mezőt — de
ez nem T0-igény.

**Következmény:** A `00_domain_model.md` v1.8 SD-23-lábjegyzete
átírva — a "megerősítendő" zárszó helyett "megerősítve a
`60_tartalom`-spec által". Az SD-tábla SD-23 sora is megerősítő
megjegyzéssel.

### Megtartott hiányok — a `60_tartalom` feature-spec köréből

Hat új átadott szál a polgári adatigény-spec felé (NY-T1 — NY-T6); egy
iterációs UX-igény; egy visszacsorgó jelzés a funkcionális projekt
felé (VF-T1); egy megtartott hiány Urbino-admin-hatáskörre (NY-K1
hatókörének pontosítása); egy örökölt megtartott hiány (NY-K3).

**NY-T1 — A `News.pushOnPublish` átvitele a polgári oldalra.** A
`News.pushOnPublish = true`-val publikált hír átvitelének mintája a
polgári oldal felé (minta A — Pull-feed, vagy minta B — Server-push
FCM/APNs-szel). Az admin-oldal a mezőt tárolja, a publikálási tényt és
a `pushOnPublish` jelzést elérhetővé teszi (feed vagy event-rendszer);
a tényleges push (FCM/APNs) implementációja a polgári mobilapp
értesítési rendszerének dolga. **Nem blokkol:** az admin-oldali
mentés-publikálás-flow teljes nélküle. **Hatáskör:** polgári
adatigény-spec.

**NY-T2 — Beágyazott térkép-szelektor a programok koordinátáihoz.** Az
`Event.latitude`/`longitude` admin-oldali megadása a pilotra két
szám-input + "Térkép megnyitása" Google Maps-link. Egy beágyazott
térkép-szelektor (Leaflet/OpenStreetMap) iterációs UX-igény. **Nem
blokkol:** a két szám-input működik. **Hatáskör:** iteráció.

**NY-T3 — A `CityInfo.groupLabel` szerinti szekcionálás a polgári
listán.** A `screen_varosi_informaciok_lista` csoportosított nézete a
`groupLabel`-mező alapján szekcionál. `null`/üres `groupLabel`-tételek
kezelése: "Egyéb" szekció, vagy a többi szekció alá, vagy elrejtés —
polgári oldali UX-döntés. **Nem blokkol:** az admin oldali tárolás
teljes. **Hatáskör:** polgári adatigény-spec.

**NY-T4 — A programok megjelenítési modellje a polgári oldalon.** A
feltöltött Flutter-képernyőképek (`screen_kezdooldal_*`, `screen_hirek_lista`,
`screen_varosi_informaciok_lista`) **nem mutatják explicit** a programok
polgári szekcióját. A program egy közös hír+program-feedbe kerül, vagy
külön program-listát kap — polgári oldali UX-döntés. **Nem blokkol:** az
admin oldali tárolás és API teljes. **Hatáskör:** polgári adatigény-spec.

**NY-T5 — A `News.body` és `Event.body` HTML-tartalmának renderelése a
Flutter polgári oldalon.** Az SD-69 whitelistje a backend tárolási
formátumát adja; a Flutter polgári app a HTML-tartalmat renderelni
köteles a saját komponensével (pl. `flutter_html`). A whitelist
tagek konkrét megjelenítése (`<a>`-hivatkozás megnyitása new tabban,
`<ul>`/`<ol>` stílusa, stb.) polgári-oldali tervezési kérdés. **Nem
blokkol:** a backend formátuma világos. **Hatáskör:** polgári
adatigény-spec.

**NY-T6 — A polgári end-to-end auth (`/v1/citizen/...` végpontok).** A
polgári mobilapp dedikált polgári-auth mögötti végpontokat hív, nem a
manager-route-okat. A polgári auth-modell (token-alapú, OAuth, Zitadel
citizen-realm, stb.) maga is nyitott (`01_kozos_mintak.md` 3.1, NY-bej-1).
A `/v1/citizen/news`, `/v1/citizen/events`, `/v1/citizen/city-infos`
végpontok és a polgári `News`/`Event`/`CityInfo`-DTO-k formája a
polgári adatigény-spec dolga. **Nem blokkor:** a manager-oldali tárolás
és API teljes. **Hatáskör:** polgári adatigény-spec.

**NY-K1 (hatóköri pontosítás) — A `DefaultCategoryCatalog` formális
mezőtáblája.** A `00_domain_model.md` v1.7 nyitott kérdéseiben az
NY-K1 "Cél-dokumentum"-ja "a `00_domain_model.md` 3.4 a `60_tartalom`-
spec köréhez" volt. **A `60_tartalom`-spec v1.0 NEM érintette a
`DefaultCategoryCatalog`-ot** — a 4. blokk a tartalmi entitásokra (`News`,
`Event`, `CityInfo`) fókuszál, a 3.4 default-katalógusra nem. Az NY-K1
ezért **továbbra is nyitott**, de hatókörét pontosítjuk: az
**Urbino-admin spec** (vagy a következő, kategória-fát érintő
specifikációs lépés) hatásköre. **Nem blokkol** semmilyen aktuális
feature-specet. **Hatáskör:** Urbino-admin spec / következő
kategória-fa-érintő lépés.

**NY-K3 (örökölt) — S3-objektum-clean-up árvák.** A
`Tenant.logoFileRef`, `News.coverImageRef` és `Event.coverImageRef`
cseréjekor / törlésekor az `AfterSaveAsync` törli a régi S3-objektumot;
meghiúsulás esetén árva marad. Időszakos clean-up job a megoldás.
**Nem blokkol:** árva S3-objektumok nem zavarják a működést, csak
helyet foglalnak. **Hatáskör:** üzemeltetési / iterációs.

### Visszacsorgó jelzés — a `60_tartalom` feature-spec köréből

**VF-T1 — Admin-route mintázat egységesítése (`varosi_programok` vs.
`programok`).** A `60_tartalom_v2.md` 3.1 a programok admin-route-ját
`/tartalom/programok`-ként, a városi információkat
`/tartalom/varosi-informaciok`-ként rögzítette. A specifikációs kör az
aláhúzás-mintázatot teszi kanonikussá (`/tartalom/varosi_programok`,
`/tartalom/varosi_informaciok`) — a funkcionális dokumentumokkal való
összhang miatt javaslat: a manager-funkcionális dokumentum frissítse
ezt a két route-stringet egységesre. **Nem ennek a feature-specnek a
dolga eldönteni** — a funkcionális projekt választhat: vagy a
specifikáció mintázatát fogadja el (preferált, mert a backend
route-stringje kanonikusan rögzített), vagy másik egységesítést kér.
**Cél-dokumentum:** `60_tartalom_v2.md` 3.1.

### Elhatárolás — a `60_tartalom` feature-spec köréből

**A polgári mobilapp UX-tervezése** nem ennek a körnek a hatóköre. A
spec az admin oldali tartalom-előállítást fedi és a polgári adatigény
**adatszintű** vetületét; a polgári oldali UX (kezdőlap-szekciók,
részletes nézetek, animációk) a Flutter app fejlesztésének hatásköre.
**Hatáskör:** polgári mobilapp fejlesztés.

**A GYIK-szerkesztő** nem ennek a körnek a hatóköre. A K-039 szerint
a GYIK Urbino-hatáskör; az Urbino-admin modul kezeli, nem a
tenant-tartalomkezelő. **Hatáskör:** Urbino-admin spec.

**Ötletláda manager-oldali kezelése, közvélemény-kutatás kérdés-
szerkesztő** nem ennek a körnek a hatóköre — a koncepció-roadmap
6-12. és 12-18. hónapjára szánt elemek (`00_architektura_v4.md` 1.2,
K-039). **Hatáskör:** későbbi feature-specek.

**A polgári mobilapp értesítési rendszere (FCM/APNs)** nem ennek a
körnek a hatóköre — a `News.pushOnPublish` jelzés átvitele a polgári
oldalra az NY-T1 átadott szál. **Hatáskör:** polgári adatigény-spec.

---

## Verziónapló

- **v0.1 (2026.05.18)** — A döntésnapló létrehozása. A felmérő kör hat
  tisztázó döntése (Ü-1 — Ü-6); a platform-szintű alapréteg tizenhárom
  specifikációs döntése (SD-1 — SD-13); két jelölt döntés teljes szöveggel
  (J-1, J-2). Forrás: felmérő kör és `01_kozos_mintak.md` v0.2.
- **v0.2 (2026.05.18)** — A domain-modell 1. blokkjának négy döntése
  (SD-14 — SD-17): esemény-időpont denormalizáció, általános `Attachment` +
  S3-tárolás, `ticketNumber` megjelenítési azonosító, `TicketNote` külön
  entitás. Forrás: `00_domain_model.md` v0.2 és a TD-1 — TD-13 alapítói
  döntések.
- **v0.3 (2026.05.18)** — A domain-modell 2. blokkjának döntése (SD-18): a
  bejelentés-besorolás bármely kategória-szinten teljes. Forrás:
  `00_domain_model.md` v0.3.
- **v0.4 (2026.05.18)** — A domain-modell 3. blokkjának két döntése
  (SD-19 — a `User` szerepkör-mentes globális entitás; SD-20 — a
  `UserTenantRole` explicit kötés-entitás). Forrás: `00_domain_model.md` v0.4.
- **v0.5 (2026.05.18)** — A domain-modell 4. blokkjának három döntése
  (SD-21 — a tartalmi típusok külön entitások; SD-22 — `ContentStatus` enum;
  SD-23 — a tartalmi szerző a `createdBy`). Forrás: `00_domain_model.md` v0.5.
- **v0.6 (2026.05.18)** — A `00_domain_model.md` 5. blokkja (entitás-térkép,
  összegzés) lezárult; a domain-modell adatszerkezeti szinten **teljes**
  (v1.0). Az 5. blokk **nem hozott új döntést** — összegző jellegű. A
  döntésnapló SD-készlete változatlan (SD-1 — SD-23); ez a bejegyzés a
  domain-modell lezárását rögzíti.
- **v0.7 (2026.05.18)** — A `02_globalis_allapotgep.md` elkészült: a `Ticket`
  életciklusának formális állapotgépe. **Nem hozott új SD-t** — az állapotgép
  a meglévő döntésekre épül (Ü-3 — a "Triage kész" gomb mint a `New → Assigned`
  átmenet kiváltója; Ü-4 — a `Rejected` kemény végállapot; TD-5/6/7 — az
  elutasítás, visszanyitás és lezárás-feltételek). Három állapotgép-szintű
  nyitott kérdés keletkezett (NY-Á1 — NY-Á3), ezek a `02_globalis_allapotgep.md`
  8. szakaszában. Ezzel mind a négy alapdokumentum kész.
- **v0.8 (2026.05.18)** — Az első feature-spec
  (`20_admin_felulet/10_bejelentes_lista_es_adatlap.md` v1.0) kilenc
  specifikációs döntése (SD-24 — SD-32): rekord-szintű optimistic-konfliktus,
  `409`-feloldás teljes újratöltéssel, a triage-sáv végállapot-zárolása, a
  négy fő-ági állapot-csík, a "Triage kész" gomb szerver-validációs modellje, a
  duplikátum redukált adatlapja, a lista/adatlap kilenc szemantikai szabálya
  (SD-30), a mezőnkénti inline-mentő végpontok, és az `updatedAt` mint
  optimistic-concurrency token. Plusz egy pilot-scope-döntés: a
  bejelentés-lista bulk-művelet nélkül indul. A feature-spec a domain-modellt
  egyetlen megjegyzés-sorral érinti (SD-32, `00_domain_model.md` 1.2.8) — új
  entitást/mezőt nem hoz.
- **v0.9 (2026.05.18)** — Két új bejegyzés. **SD-33** — a specifikációs
  dokumentumok külön `urbino-docs` repóban élnek, CI-szinkronizálással a
  kódrepók `docs/` mappáiba; a fájlnevek a repó-konvenció szerint stabilak,
  timestamp-mentesek. A bejelentés-lista feature-spec **validációs köre**
  (v1.0 → v1.1): hiányzó hosszkorlátok átvezetve a `00_domain_model.md`
  v1.2-be, a `dueDate` tartomány-megkötés tisztázva (nincs megkötés), a hét
  `ActivityLog` i18n-sablon és a hibakulcs-lista a feature-specbe. A validációs
  kör nem hozott önálló SD-t — a hosszkorlátok adatszerkezeti pótlások, a
  tegezés és a "szerver kulcsot ad" elv a `01_kozos_mintak.md` v0.3 i18n-elvének
  kiterjesztése.
- **v1.0 (2026.05.19)** — A felhasználókezelés feature-spec
  (`20_admin_felulet/20_felhasznalokezeles.md` v1.0) hat specifikációs döntése
  (SD-34 — SD-39): a `UserInvitation` külön entitás, a 7 napos meghívó-lejárat
  és az újraküldési mechanika, a tenant-szűrt Core-lekérdezés, a `TenantUser`
  `status` enum mezeje, a felhasználó-invariánsok (kötelező szerepkör,
  vezető-védelem, ön-kizárás tilalma), és a `User` törölhetetlensége. A
  feature-spec az `NY-5` nyitott kérdést lezárja, és a domain-modellbe egy új
  entitást (`UserInvitation`), egy új enumot (`InvitationStatus`) és egy
  `TenantUser`-mezőmódosítást vezet be — a `00_domain_model.md` v1.3 ezt
  átvezeti.
- **v1.1 (2026.05.19)** — A triage- és státusz-kezelés admin-felületi
  feldolgozó kör két döntése (SD-40 — SD-41). A kör megállapította, hogy a
  triage- és státusz-akciók API-szerződését, a jogosultság-route-leképezést és
  az i18n-réteget a `10_bejelentes_lista_es_adatlap.md` v1.1 **már lefedi** —
  önálló feature-spec nem indokolt; a kör eredménye a v1.2 célzott pontosítása.
  **SD-40** — a `Duplicate` elutasítási indok szövege kliens-oldali i18n
  sablonból áll össze, a `rejectionReasonText` `Duplicate`-nél üres
  (`00_domain_model.md` v1.4 átvezeti). **SD-41** — a bejelentés-adatlap
  akció-gombsora keskeny nézetben sticky alsó sáv (a `10_bejelentes_lista_es_adatlap.md`
  v1.2 új 4.7 szakasza). A kör során elvetett egy harmadik, eredetileg
  tervezett döntést (a `field_worker` "saját ügy" megszorítása mint külön
  `403` business-szabály a `start`/`resolve` végponton): a v1.1 láthatóság-
  modellje — a 3.8 sor-szintű szűrés + az AC-C6 `404` — ezt **már megoldja**,
  külön szabály felesleges lett volna.
- **v1.2 (2026.05.19)** — A duplikáció-szűrés és bejelentés-összevonás
  feature-spec (`20_admin_felulet/20_duplikacio_es_osszevonas.md` v1.0) hét
  specifikációs döntése (SD-42 — SD-48): a bejelentő-átkötés hordozója
  (`originalTicketId`-ból származó halmaz, nincs `TicketSubscriber`); a
  heurisztika kategória-jelének forrás-fallbackje (`categoryId` →
  `citizenSuggestedCategoryId`, K-032 alkalmazási részlete); a `similar`-
  és a `merge`-végpont mint nem-standard végpont; a `merge` hét formalizált
  előfeltétele `409`/`422`-besorolással; a `Merged` `ActivityLog` két sora és
  az i18n-kulcs kettébontása; az `originalTicketDisplayId` mint származtatott
  DTO-mező. A feature **nem vezet be új entitást, enumot vagy tárolt mezőt** —
  a duplikáció adatmodellje már kész; a `00_domain_model.md` v1.5 két magyarázó
  megjegyzés-sort kap az 1.2.6-ba (SD-42, SD-48). A feature-spec lezárja a
  `10_bejelentes_lista_es_adatlap.md` `NY-bej-6` nyitott kérdését, és három
  visszacsorgó jelzést hagy (VF-D1 — a `02_globalis_allapotgep.md` 3.7
  előfeltétel-bővítése; VF-D2 — a `10` 4.6 `Merged`-kulcs kettébontása; VF-D3
  — az `NY-bej-6` lezárásának átvezetése).
- **v1.3 (2026.05.19)** — A jogosultság-modell konszolidációs köre. A kör
  megállapította, hogy a `manager_felulet_atadas.md` 3. pontja nem önálló
  feature-spec — a jogosultság-érvényesítés mechanikáját az
  `01_kozos_mintak.md` 3.5 (SD-7, J-1) már lefedi —, hanem egy konszolidált
  referencia: a `30_szerver/05_jogosultsag_es_authorization.md` v1.0. A kör
  három módszertani döntést hoz (TD-J1 a referencia helye; TD-J2 a hivatkozás-
  nem-újraközlés elve és a traceability-mátrix; TD-J3 a hézagos modulok
  szabály-igen-route-nem kezelése), három megtartott hiányt (MH-J1
  route-nevek, MH-J2 `DELETE`-engedélyek, MH-J3 manuális nyitás), egy
  elhatárolást (NY-J1 polgári oldal) és egy visszacsorgó jelzést (VF-J1 —
  prefix-hiba a duplikáció-specben). Új SD-számot nem hoz; a
  `00_domain_model.md` és a `00_terminologia.md` nem módosul.
- **v1.4 (2026.05.20)** — A Dashboard és heti PDF-riport feature-spec
  (`20_admin_felulet/40_riport.md` v1.0) kilenc specifikációs döntése
  (SD-49 — SD-57). Egy új entitás (`WeeklyReport`, Tenant DB,
  `AuditableEntity`), két új enum (`ReportGenerationStatus`,
  `ReportDeliveryStatus`); hat `40_riport`-route mind `tenant_manager`-only.
  **Az MH-J1 megtartott hiány lezárva** — a `40_riport` modul pontos
  API-route-neveit a feature-spec 3.1 szakasza nevezi meg, a Szabály-R1
  érvényesítése az AC-F1-ben gépiesen ellenőrizhető. Az NY-R1 nyitott
  kérdés (a riport-adatlap mutassa-e a címzett-listát) lezárva SD-57-ben:
  igen, a Címzettek szekció olvasásra. Három új megtartott hiány (MH-R1
  csoport-aggregáció, MH-R2 `openAtWeekEnd` közelítés, MH-R3 csapat-
  lefúrás szűkítése), egy visszacsorgó jelzés (VF-R1 — a `10` lista
  `resolvedAt`-szűrője), egy elhatárolás (NY-R2 polgári elégedettség-
  mérés). A `00_domain_model.md` v1.6 átveszi az új entitást és a két új
  enumot; a `00_terminologia.md` v0.4 egy új sorral bővül (`WeeklyReport`
  mint kódbeli entitás).
- **v1.5 (2026.05.20)** — A Beállítások feature-spec
  (`20_admin_felulet/30_beallitasok.md` v1.0) tíz specifikációs döntése
  (SD-58 — SD-67). A `Tenant` entitás négy új mezővel bővül (SD-58:
  `logoFileRef`, `contactAddress`, `contactPhone`, `contactEmail`); egy új
  entitás keletkezik a Tenant DB-ben (SD-59: `WeeklyReportRecipient`,
  `AuditableEntity`); két új mintázat (SD-60 "egyedi-fájl-mező" a dedikált
  multipart-feltöltéshez; SD-61 "Core-mezőkre korlátozott tenant-szintű
  írás" a `TenantSettingsController` dedikált controllerrel és
  korlátozott mezőkészlettel). A kategória-CRUD négy eltérése: SD-62
  (gyökér csak `from-default`-végpontból, `available-default-roots`
  cross-DB konfig-olvasó), SD-63 (delete-guard + UI-szintű deaktiválás-
  elsődlegesség, ennek a mintájának kiterjesztése a `Group`-ra is
  ugyanezen az SD-számon), SD-64 (reorder szülő-hatókörben), SD-65 (a
  `Group` standard CRUD megerősítése `[ManyToManyConnection]`-nel). SD-66
  rögzíti az `authorization.json` 22 új route-ját — mind `tenant_manager`-
  only —, és formálisan teljesíti a `40_riport.md` SD-57 fogyasztói
  várakozását új végpont nélkül: a `GET /v1/weekly-report-recipients`
  ugyanaz a forrás a `50_konfig` Címzettek szekciójának és a
  riport-adatlapnak. SD-67 az "Általános" aloldal egyetlen képernyő
  három mentési-modellel. Négy új megtartott hiány / nyitott kérdés
  (NY-K1 — a `DefaultCategoryCatalog` formális mezőtáblája; NY-K2 — a
  polgári-oldali tenant-info olvasó; NY-K3 — S3 árva-logó-takarítás;
  NY-K4 — konfigurációs esemény-napló). Egy visszacsorgó jelzés (VF-K1)
  a `60_tartalom`-spec felé az SD-60 minta felhasználhatóságáról a
  `News.coverImage`-en. **Az MH-J1 megtartott hiány tovább szűkül** — a
  `40_riport` (v1.0) és a `30_beallitasok` (v1.0) lezárta a riport- és
  konfiguráció-modul route-jait; már csak a `60_tartalom` modul
  route-stringei nyitottak (`CLAUDE.md` v1.2 6. szakasz). A
  `00_domain_model.md` v1.7 átveszi a `Tenant`-bővítést és az új
  entitást; a `00_terminologia.md` v0.5 két meglévő sort pontosít
  kódbeli megnevezéssel; a `CLAUDE.md` v1.2 két új mintázattal bővül a
  3. szakaszában (egyedi-fájl-mező, Core-mezőkre korlátozott
  tenant-írás), és az 5. szakasza (Multi-tenancy) két új ponttal a
  szűk Core-DB-írási kivételről és a ritka konfig-végpontok cross-DB
  olvasásáról.
- **v1.6 (2026.05.20)** — A `60_tartalom` feature-spec
  (`20_admin_felulet/60_tartalom.md` v1.0) négy új specifikációs döntése
  (SD-68 — SD-71) és egy korábbi döntés (SD-23) megerősítése. **SD-68**
  — a tartalmi entitások borítóképe (`News.coverImageRef`,
  `Event.coverImageRef`) az SD-60 "egyedi-fájl-mező" mintáját követi
  (dedikált `POST/DELETE /v1/{entity}/{id}/cover-image` végpontok,
  standard `PUT`-on `field_not_editable`); a Beállítások-feature **VF-K1
  visszacsorgó jelzése ezzel lezárva**. **SD-69** — a `News.body` és
  `Event.body` HTML-tárolású, szigorú szerver-oldali szanitizációval;
  whitelist nyolc tagre és az `<a href>`-en csak `https://`-előtag; max
  10 000 karakter; a domain-modell **NY-6 nyitott kérdése lezárva**.
  **SD-70** — `ContentStatus` állapotgép három állapot + négy átmenet
  (T1-T4); T2 (Visszavonás vázlatba) és T3 (Archiválás) két külön akció
  publikált tartalmon; `DELETE` állapot-érzékeny (`Published`-re guard).
  Részletek a `02_globalis_allapotgep.md` új 9. szakaszában (v0.2). **SD-71**
  — a `CityInfo.groupLabel` szabad szöveges címke (max 100 karakter),
  nem lookup-entitás; admin-űrlap autocomplete a meglévő distinct
  értékekről egy `GET /v1/city-info-groups`-végpontról; a domain-modell
  **NY-7 nyitott kérdése lezárva**. **SD-23 megerősítve** — a tartalmi
  entitások szerzője a `createdBy`-ra joinolt `TenantUser`; dedikált
  `authorId` mezőre nincs igény. **27 új API-route** az
  `authorization.json`-höz (mind `tenant_content_manager` +
  `tenant_manager` szerepkörrel, Szabály-R3 érvényesítve). **Az MH-J1
  megtartott hiány teljesen lezárva** — a `60_tartalom` modul az utolsó
  hézagos modul volt; már nincs hézagos modul (`CLAUDE.md` v1.3 6.
  szakasz). **Az MH-2 megtartott hiány erre a modulra lezárva** — a
  `News`/`Event`/`CityInfo` `DELETE` engedélyezett `Draft`/`Archived`
  állapotban, `Published`-re guard (`05_jogosultsag_es_authorization.md`
  v1.1 8.3). Hat új átadott szál a polgári adatigény-spec felé (NY-T1 —
  NY-T6, az `News.pushOnPublish` átvitele, a térkép-szelektor, a
  `groupLabel`-szekcionálás, a programok megjelenítési modellje, a HTML-
  renderelés, a polgári auth), egy iterációs UX-igény (NY-T2 — beágyazott
  térkép-szelektor), egy visszacsorgó jelzés (VF-T1 — admin-route
  mintázat egységesítése). A `00_domain_model.md` v1.7 → v1.8 átveszi az
  új `News.pushOnPublish` mezőt, a tartalmi `body` és `coverImageRef`
  lábjegyzeteket, és a `CityInfo` méret-korlátokat. A
  `02_globalis_allapotgep.md` v0.1 → v0.2 új 9. szakaszt kap a
  `ContentStatus` állapotgépről. A `CLAUDE.md` v1.2 → v1.3 frissül: a 3.
  szakasz "egyedi-fájl-mező" minta-magyarázatának frissítése (az SD-68
  alkalmazásával), a 6. szakaszban az MH-J1 teljes lezárása. Az
  `05_jogosultsag_es_authorization.md` v1.0 → v1.1 a 3.2 G-blokk
  hézag-sorait kitölti a 27 konkrét route-tal, az MH-1 és MH-2 lezárásával.
  Implementációs választás: PrimeNG Editor a rich-text-szerkesztőhöz.
