Compare commits

...

2 Commits

Author SHA1 Message Date
Loretta f70cb237d8 Add quick-filter panel support to MgGridBase
Introduced a FilterPanel slot and supporting components for per-field quick filtering in DevExpress Blazor grids. Added MgGridFilterPanelBase and MgTagBox for declarative, AND-combined field filters. Updated IMgGridBase and base classes to support SetFieldQuickFilter. Documented the extension in ADR 0004 and clarified SearchText handling. Registered DevExpress docs fetch domain and performed minor cleanups.
2026-07-15 15:20:44 +02:00
Loretta 4a16943d3e Centralize environment state in AcEnv framework
Refactored FruitBankConst and FruitBankConstClient to delegate PROD/DEV environment logic to AcEnv.IsProdDb, removing local state and events. Updated MGGRID_TODO.md with ADR reference. Added ADR 0002 documenting the migration of environment infrastructure (BaseUrl, env state, badge) to the framework. Updated settings.local.json with new doc/code read commands and improved build error reporting.
2026-07-15 10:16:26 +02:00
6 changed files with 95 additions and 30 deletions

View File

@ -100,7 +100,15 @@
"PowerShell(\\(Get-Content \"H:\\\\Applications\\\\Aycode\\\\Source\\\\AyCode.Blazor\\\\AyCode.Blazor.Components\\\\docs\\\\MGGRID\\\\MGGRID_TODO.md\" | Measure-Object -Line\\).Lines)",
"PowerShell(\"=== FruitBank.Common ===\")",
"Bash(git check-ignore *)",
"PowerShell(dotnet build \"H:\\\\Applications\\\\Mango\\\\Source\\\\FruitBankHybridApp\\\\FruitBank.Common.Server\\\\FruitBank.Common.Server.csproj\" -v q --nologo 2>&1 | Select-String -Pattern \"error CS\" | Select-Object -First 20; \"--- CS hibak szama: ---\"; \\(dotnet build \"H:\\\\Applications\\\\Mango\\\\Source\\\\FruitBankHybridApp\\\\FruitBank.Common.Server\\\\FruitBank.Common.Server.csproj\" -v q --nologo 2>&1 | Select-String -Pattern \"error CS\" | Measure-Object\\).Count)"
"PowerShell(dotnet build \"H:\\\\Applications\\\\Mango\\\\Source\\\\FruitBankHybridApp\\\\FruitBank.Common.Server\\\\FruitBank.Common.Server.csproj\" -v q --nologo 2>&1 | Select-String -Pattern \"error CS\" | Select-Object -First 20; \"--- CS hibak szama: ---\"; \\(dotnet build \"H:\\\\Applications\\\\Mango\\\\Source\\\\FruitBankHybridApp\\\\FruitBank.Common.Server\\\\FruitBank.Common.Server.csproj\" -v q --nologo 2>&1 | Select-String -Pattern \"error CS\" | Measure-Object\\).Count)",
"PowerShell(git -C \"H:\\\\Applications\\\\Mango\\\\Source\\\\FruitBankHybridApp\" show --stat --name-only dbc7fd3)",
"Read(//h/Applications/Aycode/Source/AyCode.Core/AyCode.Services/docs/**)",
"Read(//h/Applications/Aycode/Source/AyCode.Core/AyCode.Services/docs/SIGNALR_DATASOURCE/**)",
"Read(//h/Applications/Aycode/Source/AyCode.Core/AyCode.Services.Server/docs/**)",
"Read(//h/Applications/Aycode/Source/AyCode.Core/AyCode.Services/SignalRs/**)",
"Read(//h/Applications/Aycode/Source/AyCode.Core/AyCode.Services.Server/SignalRs/**)",
"WebFetch(domain:raw.githubusercontent.com)",
"WebFetch(domain:docs.devexpress.com)"
]
}
}

View File

@ -27,9 +27,10 @@ namespace FruitBank.Common.Server
/// </summary>
public const string PreOrderWindowEnd = "PreOrderWindowEnd";
// ── Environment flag — method-only surface on purpose: no property to bind/serialize/read accidentally ──
private static bool? _isProd;
// ── Environment flag → AcEnv.IsProdDb (AyCode.Core framework, 2026-07) ──
// Egy-forrás keret-állapot (ugyanaz, amit a kliens tükröz). A method-only felület szándékosan megmarad:
// nincs property, amit véletlenül bind-olni/szerializálni lehetne. A set-once őr (a szerver DB-je nem
// változhat futásidőben) itt marad — az AcEnv-írás előtt.
/// <summary>
/// Set once by the plugin startup after DB-catalog classification.
@ -37,19 +38,17 @@ namespace FruitBank.Common.Server
/// </summary>
public static void SetIsProd(bool isProd)
{
if (_isProd.HasValue && _isProd.Value != isProd)
if (AcEnv.IsProdDbHydrated && AcEnv.IsProdDb != isProd)
throw new InvalidOperationException(
$"IsProd is already set to {_isProd.Value}; refusing to change it to {isProd}.");
$"IsProd is already set to {AcEnv.IsProdDb}; refusing to change it to {isProd}.");
_isProd = isProd;
AcEnv.SetIsProdDb(isProd);
}
/// <summary>
/// True = PROD database. Throws until SetIsProd ran — an uninitialized read must never return a default.
/// </summary>
public static bool IsProd()
=> _isProd ?? throw new InvalidOperationException(
"IsProd has not been initialized — SetIsProd must run at startup before any read.");
public static bool IsProd() => AcEnv.IsProdDb;
static FruitBankConst()
{

View File

@ -17,30 +17,19 @@ public static class FruitBankConstClient
set => AcEnv.BaseUrl = value;
}
// A szerver-környezet (PROD/DEV) — az érték KIZÁRÓLAG a szerver IsProdEnvironment() válaszából jöhet
// (a szerver a DB-katalógusból sorolja be magát, fail-closed módon), URL-alakból/configból SOHA.
// Az EGYETLEN értékadási pont: FruitBankSignalRClient (kapcsolat-felépüléskor hidratál, ld. EnsureEnvironmentAsync).
// Hidratálatlan olvasás → exception (fail fast); sikertelen lekérdezés → marad hidratálatlan (fail closed).
private static bool? _isProd;
public static bool IsProd
=> _isProd ?? throw new InvalidOperationException(
"FruitBankConstClient.IsProd nincs hidratálva — a FruitBankSignalRClient a kapcsolat felépülésekor tölti fel a szerver IsProdEnvironment() válaszából (await client.EnsureEnvironmentAsync()).");
// IsProd → AcEnv.IsProdDb (AyCode.Core framework, 2026-07): a szerver ADAT-környezete (a mögöttes DB PROD-e),
// NEM build-konfiguráció. Delegát az egy-forrás keret-állapotra (fail-fast + változás-esemény) — a hívóhelyek
// változatlanok. Az érték forrása: a FruitBankSignalRClient a kapcsolat felépülésekor hidratál (EnsureEnvironmentAsync).
public static bool IsProd => AcEnv.IsProdDb;
public static bool IsProdHydrated => AcEnv.IsProdDbHydrated;
public static void SetIsProd(bool isProd) => AcEnv.SetIsProdDb(isProd);
/// <summary>Az IsProd TÉNYLEGES változásakor tüzel (első hidratálás + announce-detektált env-váltás) —
/// a megjelenítők (title-badge, UI-sáv) feliratkozási pontja. Az értékadás forrása változatlanul EGY hely.</summary>
public static event Action<bool>? IsProdChanged;
public static void SetIsProd(bool isProd)
public static event Action<bool>? IsProdChanged
{
var changed = _isProd != isProd;
_isProd = isProd;
if (changed) IsProdChanged?.Invoke(isProd);
add => AcEnv.IsProdDbChanged += value;
remove => AcEnv.IsProdDbChanged -= value;
}
/// <summary>True, ha az IsProd már hidratált — kapu-logikához (első-connect await) és a push-összevetéshez.</summary>
public static bool IsProdHydrated => _isProd != null;
public static string DefaultHubName = "fbHub";
public static string LoggerHubName = "loggerHub";

View File

@ -3,6 +3,7 @@ using AyCode.Core.Extensions;
using AyCode.Core.Loggers;
using AyCode.Utils.Extensions;
using DevExpress.Blazor;
using DevExpress.Data.Filtering;
using DevExpress.Data.Helpers;
using DevExpress.Utils.Filtering.Internal;
using FruitBank.Common.Models;
@ -57,6 +58,10 @@ public class MgGridBase : DxGrid, IMgGridBase
// Not implemented in this legacy class - will be removed
}
/// <inheritdoc />
public void SetFieldQuickFilter(string fieldName, CriteriaOperator? criteria)
=> SetFieldFilterCriteria(fieldName, criteria); // legacy class - will be removed
[Inject] public required IEnumerable<IAcLogWriterClientBase> LogWriters { get; set; }
[Inject] public required FruitBankSignalRClient FruitBankSignalRClient { get; set; }
[Inject] public required LoggedInModel LoggedInModel { get; set; }

View File

@ -0,0 +1,63 @@
# 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: —

View File

@ -9,3 +9,4 @@ Architektúra-szintű döntések durable rekordjai (Nygard-stílus): egy fájl =
| ADR | Cím | Status |
|---|---|---|
| [0001](0001-non-measurable-item-derived-weight.md) | Nem mérendő tétel súlya — derivált pallet-mérés a termék átlagsúlyából és tárájából | Proposed (2026-07-14) |
| [0002](0002-environment-infrastructure-to-framework.md) | Környezet-infrastruktúra (BaseUrl, szerver-adatkörnyezet, env-badge) keretbe emelése | Accepted (2026-07-15) |