64 lines
7.6 KiB
Markdown
64 lines
7.6 KiB
Markdown
# ADR 0002: Környezet-infrastruktúra (BaseUrl, szerver-adatkörnyezet, env-badge) keretbe emelése
|
|
|
|
## Status
|
|
|
|
Accepted (2026-07-15) — végrehajtás lépésenként, per-lépés review-val; 1. lépés (BaseUrl → AcEnv) kész.
|
|
|
|
## Context
|
|
|
|
- **Kiváltó incidens:** a fbHub és a loggerHub URL-je két külön forrásból élt (`AcHubConnection:Url` appsettings vs. `FruitBankConstClient.BaseUrl` kód-konstans) → a kliens a helyi nop helyett a PROD `shop.fruitbank.hu`-ra töltötte fel a logokat, órákig félrevitt nyomozással. A gyökér: az URL-infrastruktúra a fogyasztói const-osztályon, több igazságforrással.
|
|
- **Frissen épült env-lánc (2026-07):** szerver-adatkörnyezet (PROD/DEV) kliens-oldali ismerete — first-connect kapu (await, fail-closed), szerver push-on-connect announce (env-váltás riasztással), `[PROD]/[DEV]` title-badge, MSTest prod-guard. Élesben igazolva (DEV→PROD DB-váltás restarttal: announce + riasztás + title-váltás működött). **Mindez FruitBank-oldalon született, pedig app-agnosztikus.**
|
|
- **Redundancia:** ugyanaz a fogalom kétszer — szerver `FruitBankConst.SetIsProd` + kliens `FruitBankConstClient.IsProd`; a teszt-guard, badge, jövőbeli destruktív-védelem mind külön-külön kötné be.
|
|
- **„IsProd" tengely-probléma:** három független „prod"-tengely létezik — (1) build-konfiguráció (Debug/Release), (2) adat-környezet (melyik DB-katalógus), (3) hosting env (ASPNETCORE_ENVIRONMENT). A Debug-build + PROD-DB + Development-hosting kombináció élő teszttel bizonyított — egyetlen `IsProd` név ezeket összemosná.
|
|
- **Időzítés:** a közös nagyker-réteg terv (VeggieVoyage) előtt; a ház-mintában van közvetlen precedens: **GridLayout-roaming** (framework-fenntartott tagek `AcSignalRTags` 9001x + framework-kliens-logika + fogyasztói endpoint-implementáció).
|
|
- **Scope IN:** AcEnv állapotok (BaseUrl, IsProdDb); framework-tagek; kliens-base env-gépezet; hub-base announce; Blazor title-réteg; FruitBank-vékonyítás delegátokkal. **Scope OUT:** hosting-env tengely (később, read-only diagnosztika); `IsProdBuild` (független bónusz); `AcEnv.SetConfiguration` config-egységesítés (ACCORE-LOG-T-N2D8 — szinergia, nem feltétel).
|
|
|
|
## Decision
|
|
|
|
**A környezet-infrastruktúra a keretbe kerül** — a fogyasztó csak opt-inel, endpointot implementál és domain-konstansokat tart:
|
|
|
|
1. **Egy-forrás állapotok az `AcEnv`-en** (AyCode.Core): `BaseUrl` ✅ (kész) és `IsProdDb` (+`Set`/`Hydrated`/`Changed` esemény) — a szervernél a DB-katalógus-besorolás tölti (fail-closed), a kliens tükrözi (kapu + announce). A megosztás legitim: a kliensnek nincs saját DB-je, az ő adatkörnyezete a szerveré.
|
|
2. **Tengelyenkénti nevezés:** `IsProdDb` (adat-tengely, wire-en szinkronizált) ≠ `IsProdBuild` (build-tengely, processenkénti, SOHA nem megy wire-ra) ≠ hosting env. Nincs csupasz `IsProd` a kereten.
|
|
3. **Framework-fenntartott SignalR-tagek** (`AcSignalRTags`, a GridLayout 9001x mintájára): query 90020, announce 90021 — a fogyasztói 210/211 kivezetve (wire-váltás: kliens+szerver együtt-deploy).
|
|
4. **Kliens-gépezet az `AcSignalRClientBase`-be:** first-connect kapu (await + dedup: pontosan 1 wire-hívás), `EnsureEnvironmentAsync`, fail-closed nyers query (timeout ≠ `default(bool)`!), announce-elfogás a dispatch-ben (a fogyasztói `MessageReceived` nem is látja). **Opt-in**: `EnvironmentFeatureEnabled => false` default — más fogyasztók (pl. TourIAm) szervere nem ismeri az endpointot, default-on fail-closed törést okozna.
|
|
5. **Hub-base announce:** push-on-connect az `AcEnv.IsProdDb`-ből (best-effort, a kapcsolatot nem dönti).
|
|
6. **Blazor title-réteg** (AyCode.Blazor.Components): `IAcAppTitleService` + browser-implementáció + `<AcEnvironmentTitleBadge AppName="..."/>`; MAUI-implementáció fogyasztói marad (a keretnek nincs MAUI-assemblyje).
|
|
7. **Delegát-minta a fogyasztón:** a `FruitBankConstClient` érintett tagjai átlátszó delegátként maradnak (`BaseUrl` ✅) — nulla törés, a hívóhelyek változatlanok, a felfedezhetőség megmarad (static class nem örökölhet → tag-migráció + delegát, nem literál öröklés).
|
|
8. **Fogyasztónál marad:** domain-konstansok (táblanevek, DomainDescription, email-sablonok), a katalógus-besorolás hívási helye, a query-endpoint implementáció (framework-taggel, GridLayout-minta), MAUI title-impl, AppName.
|
|
|
|
## Consequences
|
|
|
|
**Positive:**
|
|
- Minden jövőbeli app (VeggieVoyage, közös nagyker-réteg) **ingyen** kapja a teljes env-láncot: kapu, announce+riasztás, badge, teszt-guard.
|
|
- A szerver/kliens redundancia megszűnik (egy állapot, egy esemény, sok olvasó); a BaseUrl-divergencia osztálya strukturálisan kizárt.
|
|
- Egységes fail-fast (hidratálatlan olvasás dob) + fail-closed (nem igazolható env = tiltás) szemantika keret-szinten.
|
|
|
|
**Negative:**
|
|
- Wire-tag átszámozás (210/211 → 9002x): kliens + szerver **együtt-deploy** kötelező a váltáskor.
|
|
- `AcEnv` statikus állapot: process-szintű — párhuzamos teszt-kollekciók osztoznak rajta (a jelen MSTest-felállásban nem gond, de tudni kell róla).
|
|
- Az opt-in flag elfelejtése = a feature **némán off** — a keret-doksiban kiemelten dokumentálandó.
|
|
- A delegát-réteg fegyelmet kér: új infra-tag a KERETRE kerüljön, ne a fogyasztói const-ra.
|
|
|
|
**Follow-ups required:**
|
|
- 2. lépés: `IsProdDb` → `AcEnv` (FruitBank-oldali `IsProd`-tagok delegátként).
|
|
- 3. lépés: `AcSignalRTags` 90020/90021 + kliens-base gépezet + opt-in flag + teszt-guard helper a keretbe.
|
|
- 4. lépés: hub-base announce.
|
|
- 5. lépés: Blazor title-réteg + FruitBank-átkötés (MainLayout → `<AcEnvironmentTitleBadge>`).
|
|
- Bónusz/később: `IsProdBuild` (+ opcionális build↔DB keresztellenőrzés, opt-in); `AcEnv.SetConfiguration` (N2D8); SignalR-intervallum konstansok configba (a `SignarlR` typóval együtt kivezetve); MAUI-Android `10.0.2.2` BaseUrl-kérdés.
|
|
|
|
## Alternatives considered
|
|
|
|
- **Fogyasztói szinten hagyni** (rejected): minden app újraimplementálná; a redundancia már most élő bugot szült (BaseUrl-divergencia).
|
|
- **Teljes átnevezés homlokzat nélkül** (a fogyasztói kód mindenhol `AcEnv.*`-ot hív) (rejected): ~12 hívóhely churn, és a csapat a megszokott helyen (`FruitBankConstClient`) keresi az értéket — a delegát ugyanazt az egy-forrást adja nulla töréssel.
|
|
- *Reversibility:* a delegát később bármikor kivezethető, ha a csapat átszokott.
|
|
- **Egyetlen `AcEnv.IsProd` név tengely-bontás nélkül** (rejected): a build/adat/hosting tengelyek összemosása — a Debug-build + PROD-DB élő eset bizonyítja, hogy függetlenek; a névnek a forrást kell mondania (`IsProdDb`).
|
|
- **Reconnect-enkénti újra-lekérdezés a push-on-connect helyett** (rejected mint végállapot): működik, de ellentmond a „csak az elején 1x" elvnek; a push-on-CHANGE pedig konstrukciósan halott (az env-váltás csak restarttal jöhet, ami bontja a csatornát, amin a push utazna) — ezért query-once + announce-on-connect a végleges alak.
|
|
- **Külön köztes osztály (`AcEnvironmentAwareSignalRClientBase`)** (rejected): felesleges hierarchia-szint; az opt-in flag az `AcSignalRClientBase`-en ugyanazt adja ceremónia nélkül.
|
|
|
|
## Related
|
|
|
|
- Related ADRs: —
|
|
- Related TODOs/Issues: `ACCORE-LOG-T-N2D8` (AcEnv.SetConfiguration — szinergia), `ACCORE-LOG-T-D7S3` (protokoll-diagnosztikai logger, átgondolandó), `ACCORE-SBP-T-T5R2` (protokoll-trace Trace-szintre), `ACBLAZOR-GRID-T-E3B6` (template-ErrorBoundary).
|
|
- Precedens: GridLayout-roaming (framework-tag `AcSignalRTags` 9001x + fogyasztói endpoint) — `Nop.Plugin.Misc.AIPlugin/docs/SIGNALR/README.md` „Grid Layout Roaming".
|
|
- External references: —
|