FruitBankHybridApp/docs/adr/0002-environment-infrastruc...

7.6 KiB

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:

    1. lépés: IsProdDbAcEnv (FruitBank-oldali IsProd-tagok delegátként).
    1. lépés: AcSignalRTags 90020/90021 + kliens-base gépezet + opt-in flag + teszt-guard helper a keretbe.
    1. lépés: hub-base announce.
    1. 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 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: —