Přeskočit obsah

Changelog — Bartech.Mobile.Eva

[Unreleased] — větev AM/v145

Přidáno

TASK5 — EVA branded email wrapper a lokalizace emailů

  • EmailService.cs — přidána metoda WrapEmailBody: obaluje tělo emailů EVA HTML šablonou (header s logem, footer s rokem a odkazem na help); všechny odchozí emaily (notifikace, reset hesla) používají konzistentní brandované rozvržení; opraveno zobrazované jméno odesílatele
  • InventoryItemNotification.cshtml — redesign šablony emailu pro upozornění na položku inventury; přizpůsoben branded wrapperu
  • InventoryEmailService.cs — odstraněn hardcoded URL manažera; URL čtena z EvaLinksOptions.ManagerUrl
  • Messages.resx (5 jazyků) — nové lokalizační klíče pro reset hesla emailem (EMAIL_MSG_RESET_PASSWORD_LINK, EMAIL_MSG_RESET_PASSWORD_CODE, TitleResetPassword)

TASK6 — Denní digest emailů (DailyDigestService)

  • DailyDigestService.cs — nová BackgroundService jako hosted service; spouští digest každý pracovní den (Po–Pá) v 7:00; PeriodicTimer s 1minutovým intervalem; interní stav _lastSentPerTenant zabraňuje duplicitnímu odeslání
  • DailyDigestEmailBuilder.cs — builder pro HTML tělo denního digestu; přehled otevřených inventur, čekajících transferů a akcí vyžadujících pozornost
  • Program.cs — registrován DailyDigestService jako AddHostedService; testovací endpoint GET /dev/digest/test?tenantId=<id> dostupný pouze v Development prostředí

TASK7 — UserPickerPopup a emailové notifikace inventury

  • UserPickerPopup.razor — nová znovupoužitelná komponenta pro výběr uživatelů před odesláním emailové notifikace; DxPopup 700px s DxTextBox vyhledáváním a DxGrid výběrem; tenant-scoped načítání uživatelů přes UserManager; výsledek vrací callback OnUsersSelected
  • InventoryNotificationEmail.cshtml — nová Razor Light šablona emailu pro upozornění na spuštění inventury; obsahuje název inventury, URL odkaz do Eva Manager a pokyny pro uživatele
  • InventoryNotificationEmailService.cs — nová service pro odesílání individuálních emailů uživatelům před zahájením inventury; přeskakuje uživatele bez emailu; vrací (int Sent, int Skipped) tuple
  • InventoryEditForm.razor — integrace UserPickerPopup: tlačítko "Upozornit uživatele" v toolbaru; ikona zámku u titulku pro vizuální indikaci stavu uzamčení
  • EvaLinksOptions.cs — přidána property ManagerUrl (výchozí https://eva.inventura-majetku.cz); použita v InventoryNotificationEmailService i InventoryEmailService
  • appsettings.json — přidána sekce EvaLinks s klíčem ManagerUrl
  • Resource.resx (5 jazyků) — nové klíče: UserPickerSearchPlaceholder, InventoryNotifyUsersTitle, InventoryNotifyUsersButton, InventoryNotifyUsersTooltip, InventoryNotifySuccessMsg, InventoryNotifyPartialMsg, InventoryNotifyNoEmailMsg

Feature: Osobní inventura — zabezpečené skenování QR GUID

  • Inventory.cs — přidáno pole IsSecure (bool): příznak zabezpečené inventury vyžadující skenování QR GUID z etikety majetku
  • TenantLicense.cs — přidáno pole PersonalInventoryEnabled (bool): add-on příznak licence
  • LicenseEnforcementService.cs — LicenseLimits rozšířen o bool PersonalInventoryEnabled; DEMO licence má PersonalInventoryEnabled = false
  • personal_inventory_model.sql — nový SQL update skript: ALTER TABLE dbo."Inventory" ADD COLUMN IF NOT EXISTS "IsSecure" + ALTER TABLE dbo."TenantLicense" ADD COLUMN IF NOT EXISTS "PersonalInventoryEnabled"
  • ArticlesController.cs — nový endpoint POST /api/articles/generate-qr-bulk: hromadné generování QrGuid pro artikly bez GUID; vrací { Generated, Total }; nový artikl přes pwa-request dostane QrGuid automaticky
  • ArticleQrAdmin.razor — nová admin stránka /admin/articles-qr: DxGrid se seznamem majetku s filtrem "Pouze bez QR kódu"; toolbar akce "Generovat QR kódy pro vybrané"
  • menu.json (4 jazyky) — přidána položka 8.5 "QR kódy artiklů" (/admin/articles-qr) do sekce Správa systému
  • InventoriesController.cs — GetPwaInventoryItems: opravena chyba ArticleID → ArticleOID; přidáno inventory.IsSecure do response objektu
  • InventoryItemsController.cs — pwa-confirm: server-side guard pro IsSecure — vrací HTTP 403 pokud inventura vyžaduje QR skenování (defense-in-depth)
  • InventoryScanner.razor (PWA) — žlutý banner "Zabezpečený režim"; pokud IsSecure && !_uuidRegex.IsMatch(code) → sken ignorován s červenou hláškou
  • InventoryDetail.razor (PWA) — badge "Zabezpečená" u názvu inventury; tlačítko "Potvrdit" (ruční potvrzení bez skenování) skryto pro IsSecure inventury
  • InventoryNewWizard.razor — přepínač "Zabezpečená inventura"; pokud PersonalInventoryEnabled, zobrazí DxCheckBox; jinak badge "Není v licenci"
  • Messages.resx (5 jazyků) — nové klíče pro wizard: InventoryWizard_CaptionSecureInventory, InventoryWizard_NotLicensed, InventoryWizard_PersonalInventoryAddon a další

Opraveno

ERR2 — Race condition v QR login PWA

  • Login.razor — přidán guard if (_loadingDevice) return; zabraňující dvojímu odeslání activate requestu; error message zpřesněna
  • DeviceTokenDataService.cs — zpřesněno diagnostické logování v ActivateDeviceAsync (failure case: nenalezen / již použit / expirován)

ERR1 — SimpleCodebookGrid nezobrazuje smazané záznamy

  • SimpleCodebookGrid.razor — LoadGridDataAsync() filtruje záznamy s Deleted = true; záznamy bez vlastnosti Deleted zůstávají zobrazeny (zpětná kompatibilita)
  • Articles.razor, ArticleEditForm.razor, ArticlesLocations.razor, InventoryNewWizard.razor, Transfer.razor — výběrové comboboxy filtrují záznamy s Deleted = true

[1.0.43] — větev AM/v143 — 2026-08-05

Přidáno

PWA — NewAsset formulář — kompletní přepis

  • NewAsset.razor — odstraněna privátní třída AppNamedItem (selhávala v WASM trimmed build); nahrazena přímými modely ArticleCategory, ArticleType, CurrencyType z Eva.Data.Models
  • NewAsset.razor — přidáno pole „Sériové číslo" (_serialNo); odesíláno v PwaArticleRequest
  • NewAsset.razor — klientský tenant filtr pro kategorie a typy: !c.Deleted && (c.TenantID == null || c.TenantID == _tenantId); tenant_id čteno z JWT claimu
  • NewAsset.razor — výchozí měna: lookup Code == "CZK", fallback první v seznamu
  • NewAsset.razor — validace: Typ je povinné pole (ArticleTypeID NOT NULL v DB); chybové hlášení zobrazeno inline
  • NewAsset.razor — catch { } → catch (Exception ex) { _error = "Chyba při načítání dat: " + ex.Message; } (diagnostika chyb v WASM)

WebApi — nový endpoint a rozšíření entit

  • CurrencyTypesController.cs — nový controller GET api/currencyTypes; vzor shodný s ArticleCategoriesController
  • ServiceCollectionExtensions.cs — přidána DI registrace IBaseDataService<CurrencyType>, BaseDataService<CurrencyType>
  • ArticlesController.cs — PwaArticleRequest rozšířen o string? SerialNo; hodnota uložena do article.SerialNo
  • ArticlesController.cs — endpoint POST api/articles/pwa-request nastavuje ArticleStateID na stav „Navrženo" (globální stav, TenantID == null) — nově vytvořený majetek je automaticky zařazen do workflow schvalování

Eva.Manager — Dashboard KPI dlaždice a rychlý filtr

  • Index.razor — přidány tři nové KPI dlaždice: „Návrhy na vyřazení" (link na /articles?quickFilter=disposalProposals), „Neschválené převody", „Návrhy nového majetku" (link na /articles?quickFilter=newAssetProposals); dlaždice s nenulovým počtem mají CSS třídu kpi-card-warning
  • Articles.razor — přidán rychlý filtr (DxComboBox) v toolbaru; čte ?quickFilter= z URL query parametru ([SupplyParameterFromQuery]); filtry: disposalProposals (ArticleDisposal kde !IsDisposal), newAssetProposals (artikly se stavem „Navrženo")
  • Resource.resx × 5 — přidány lokalizační klíče: DashboardDisposalProposals, DashboardPendingTransfersKpi, DashboardNewAssetProposals, ArticleQuickFilter, ArticleQuickFilterAll, ArticleQuickFilterDisposalProposals, ArticleQuickFilterNewAssetProposals

Opraveno

Nginx — cache fix pro PWA boot loader

  • nginx-pwa.conf — přidána location = /_framework/blazor.webassembly.js s Cache-Control: no-store; blazor.webassembly.js nemá hash v názvu a při cache způsoboval načítání starých WASM souborů (stale PWA)

Změněno

Multitenancy — aktivace produkčního nastavení

  • appsettings.json (WebApi) — "Multitenancy": { "Enabled": false } → { "Enabled": true }; aktivuje EF Core globální query filter pro všechny ITenantAware entity; bez této změny byla data všech tenantů viditelná všem uživatelům

CLAUDE.md — pravidlo Tenant sandbox

  • CLAUDE.md — přidána sekce „Bezpečnost dat — Tenant sandbox" s checklistem pro každou práci s daty; přehled entit s/bez ITenantAware; povinnost ověřit Multitenancy.Enabled = true před nasazením

Docker — build scripty pro PWA image

  • EvaAll_DockerBuildAndPush.ps1 — přidán Invoke-SingleImagePublish pro bartech-pwa-eva; PWA image je nyní součástí all-in-one build skriptu spolu s WEB, API, DB a Print
  • EvaPwa_DockerBuildAndPushNewVersion.ps1 — nový individuální build skript pro PWA image; používá Invoke-PublishFlow z Common-PublishHelpers.ps1; volitelný pro rychlé vydání pouze PWA bez ostatních images

Odstraněno

  • doc/task/v143/extended_fce.md — odstraněn soubor s nápady pro budoucí verzi (nepatří do doc/task)

[Infra] — produkční nasazení PWA na meva.xtrace.cz — 2026-08-05

Zdroj: doc/publikace_pwa.md. První produkční nasazení Eva.Mobile.Pwa na infrastruktuře 192.168.4.25 / 192.168.4.67. Dřívější EvaLinksOptions.PwaUrl (https://meva.inventura-majetku.cz) odkazoval na plánovanou/jinou instanci — toto je první ostré nasazení pod doménou meva.xtrace.cz.

Přidáno — infrastruktura

  • .docker/nginx-pwa-prod.conf — nový produkční nginx konfig pro PWA kontejner (HTTP bez SSL — SSL terminuje reverzní proxy, Blazor-Environment: Production, /api/ proxy na interní eva-api:8080)
  • .docker/Dockerfile_PWA — aktualizován, ve finální fázi používá nginx-pwa-prod.conf
  • Kontejner eva-pwa na 192.168.4.25:8083 — přidán do compose-EVA-xtdocker-deploy.yaml, závislý na restapi
  • Reverzní proxy meva.xtrace.cz na 192.168.4.67:443 — nový nginx vhost proxující na 192.168.4.25:8083; SSL certifikát eva_bundle.pem rozšířen o SAN meva.xtrace.cz (stejný privátní klíč jako eva.xtrace.cz)

Tok požadavku: Prohlížeč → meva.xtrace.cz → nginx 4.67:443 → 192.168.4.25:8083 (eva-pwa) → /api/* proxied na 192.168.4.25:8082 (eva-api)


[1.0.43] — větev AM/v143 — 2026-08-05

Přidáno

PWA — QR přihlášení přes kameru (ZXing scanner)

  • scanner.js — přidána funkce ScannerInterop._decodeFromFile: dekóduje QR kód z fotografie pořízené kamerou mobilního prohlížeče pomocí knihovny ZXing Browser; škáluje canvas na max 1024 px před dekódováním (spolehlivost na 12MP snímcích)
  • zxing-browser.min.js — přidána lokální kopie ZXing Browser knihovny (offline podpora, bez závislosti na CDN)
  • Login.razor — přidán QR skenovací mód (tlačítko „Přihlásit přes QR kód"); <input type="file" accept="image/*" capture="environment"> spouští nativní kameru na mobilu; po naskenování se kód předá ScannerInterop a spustí LoginWithDeviceCodeAsync

PWA — Auto-login ze stored DeviceToken

  • Login.razor — při načtení stránky se volá AuthService.HasStoredDeviceTokenAsync(); pokud token existuje v localStorage, zobrazí se tlačítko „Přihlásit se tímto zařízením" (auto-login bez zadání hesla)
  • Login.razor — metoda AutoLoginAsync — volá ExchangeDeviceTokenAsync se stored tokenem; při 401 maže token z localStorage a skrývá tlačítko
  • AuthService.cs — přidána metoda HasStoredDeviceTokenAsync — čte device_token z localStorage; přidána metoda ExchangeDeviceTokenAsync — POST /api/device-auth/exchange → JWT uložen přes TokenStore

Eva.Manager — Security stránka: přehled všech tokenů tenantu

  • DeviceTokenView.cs — nový read-only record v Eva.Data.Models.Security; obohacuje DeviceToken o UserEmail a UserDisplayName (First + Last name); používán v admin UI pro zobrazení tokenů
  • DeviceTokenDataService.cs — přidána metoda GetAllActiveTokensWithUserAsync(long? tenantId) — LINQ join DeviceToken + ApplicationUser + User; vrací IEnumerable<DeviceTokenView> filtrovaný dle tenantu; přidána metoda AdminRevokeTokenAsync(long tokenId, long? tenantId) — revokuje token přes ExecuteUpdateAsync (nastaví RevokedAt = UtcNow) bez načtení entity do paměti; tenant guard brání cross-tenant odvolání
  • Security.razor — grid rozšířen o sloupce UserEmail, UserDisplayName, DeviceName; inline tlačítko „Odvolat" v každém řádku gridu (DxButton v DataItemTemplate); toolbar tlačítko „Odvolat token" pracuje s vybraným řádkem; volá AdminRevokeTokenAsync; NewButtonVisible="false" na DxGridCommandColumn

Opraveno

PWA — Layout fix: mobile-content min-height a scroll

  • mobile.css — .mobile-content opraven min-height: 0 (flex item byl bez omezení, čímž overflow-y: scroll nefungoval na iOS Safari); přidán -webkit-overflow-scrolling: touch a overscroll-behavior-y: contain pro spolehlivý scroll a zamezení pull-to-refresh

Změněno

  • .gitignore — přidán vzor .docker/certs/key.pem (privátní klíč mkcert lokálního certifikátu nesmí do repozitáře)

[1.0.43] — větev AM/v143 — 2026-08-04

Přidáno

PWA — Nové stránky Převodky a Vyřazení

  • Transfers.razor — nová stránka /transfers; seznam otevřených převodek přihlášeného uživatele; barevné badges stavu (Čeká/Připraveno/Schváleno); prázdný stav s ikonou; data z GET api/articles/my-transfers/{userId}
  • Disposals.razor — nová stránka /disposals; seznam návrhů na vyřazení čekajících na schválení; zobrazuje název, kód, důvod a datum návrhu, badge "Čeká na schválení"; data z GET api/articles/my-disposals/{userId}

WebApi — Nové API endpointy pro PWA

  • ArticlesController.cs — přidán GET api/articles/my-stats/{userId} — statistiky pro Home (AssignedCount, AssignedTotal, OpenTransfers, PendingDisposals) v jednom DB dotazu
  • ArticlesController.cs — přidán GET api/articles/my-transfers/{userId} — otevřené převodky uživatele (filtr !IsConfirmed && !IsRejected && !Deleted), vrací název, datum, cílové umístění
  • ArticlesController.cs — přidán GET api/articles/my-disposals/{userId} — návrhy na vyřazení čekající na schválení (!IsDisposal), vrací název artiklu, kód, důvod, datum

PWA — QR / DeviceToken přihlášení

  • AuthService.cs — přidána metoda LoginWithDeviceCodeAsync(string code, string deviceName) — přijme kód (s/bez prefixu EVA-DEV:), POST /api/device-auth/activate → POST /api/device-auth/exchange → JWT uložen do localStorage; přidána metoda RefreshAsync() pro manuální nebo automatický refresh tokenu
  • Login.razor — přidáno viditelné vstupní pole "Kód zařízení (QR sken)" s tlačítkem "Přihlásit přes kód"; Enter v poli spustí přihlášení; HID scanner terminál pole vyplní automaticky

PWA — Navigace přesunuta do topbaru

  • NavMenu.razor — lišta přesunuta z dolního rámce do horního topbaru; CSS třída bottom-nav → topbar-nav; ikony Bootstrap Icons (bi-house-fill atd.) místo emoji
  • NavItem.razor — CSS třída bottom-nav-item → topbar-nav-item; odstraněny textové popisky (jen ikony s title atributem pro přístupnost)
  • MainLayout.razor — <NavMenu /> přesunut do <header>; odstraněn ze spodní části; přihlášený uživatel vidí navigaci, nepřihlášený brand "Eva Mobile"
  • mobile.css — odstraněn --bottomnav-height; .bottom-nav* nahrazeny .topbar-nav a .topbar-nav-item; Bootstrap Icons CDN přidán do index.html

PWA — Home stránka — klikatelné dlaždice + statistiky

  • Home.razor — kompletně přepsán; dlaždice jsou <a href> s Bootstrap Icons, nadpisem a statistikami; "Můj majetek" zobrazuje počet ks a celkovou hodnotu Kč; přidány dlaždice "Převodky" a "Vyřazení" s počtem čekajících položek

PWA — TokenStore — eliminace race condition

  • TokenStore.cs — nový singleton; drží JWT token v paměti; eliminuje race condition v AuthorizationHandler při souběžných JSInterop voláních localStorage.getItem
  • AuthorizationHandler.cs — token čten z TokenStore (paměť), JSInterop jen jako fallback při page refresh; přidán auto-refresh: zachytí 401 na GET requestu, zavolá POST /api/pwa-auth/refresh, zopakuje původní request
  • Program.cs — registrován AddSingleton<TokenStore>()

Opraveno

Eva.Manager — DeviceQrPopup oprava zobrazení

  • DeviceQrPopup.razor — příčina: DxPopup.VisibleChanged se nespouštělo při programatickém Visible=true z rodiče; oprava: přidán OnParametersSetAsync, který detekuje přechod false→true a zavolá GenerateCodeAsync(); přidán @implements IDisposable; odstraněn debug kód
  • Security.razor — odstraněny debug logy z OpenQrPopup; přidán using Eva.Manager.Components.shared; NewButtonVisible="false" na DxGridCommandColumn; ověřeno Playwrightem (otevření, QR kód, countdown, zavření)

PWA — AssetDetail — smazání fotky s potvrzením

  • AssetDetail.razor — přidán _deleteConfirmPhotoId?, ConfirmDeletePhoto(), ExecuteDeletePhoto(), CancelDeletePhoto() — inline alert místo okamžitého smazání; fotky načítány jako data URI (LoadPhotoDataUrls) místo přímého api/... odkazu (oprava CORS/autentizace)

PWA — AssetDetail — formátování ceny

  • AssetDetail.razor — zobrazení měny: Symbol ?? Code ?? Name místo pouze Name — zobrazí "Kč" místo "Czech koruna"

PWA — MyAssets — vyhledávání + výška topbaru

  • MyAssets.razor — přidáno vstupní pole pro vyhledávání (case-insensitive filtr podle názvu/kódu); oprava height:auto na topbar-inner (dříve zabíralo celou výšku viewportu)
  • MyInventories.razor — oprava height:auto na topbar-inner

Eva.Manager — EditAccount.razor

  • EditAccount.razor — přejmenování proměnné roleCtx → role v ItemTemplate kontextu DxListBox (Blazor CS8602 varování)

[1.0.43] — větev AM/v143 — 2026-08-01

Opraveno

Monitoring.razor — odstraněny hardcoded IP adresy

  • Monitoring.razor — nahrazeny hardcoded adresy dynamickými hodnotami; metrics/health URL odvozeny z NavigationManager.BaseUri; Grafana a Prometheus URL čteny z IConfiguration["Monitoring:GrafanaUrl/PrometheusUrl"]; pokud URL nejsou nastaveny, příslušné linky a tlačítka se skryjí — stránka funguje správně na libovolném serveru bez přestavby

Users.razor — oprava reset hesla (concurrency bug)

  • Users.razor — opravena dvoufázová sekvence RemovePasswordAsync + AddPasswordAsync nahrazena jednofázovým GeneratePasswordResetTokenAsync + ResetPasswordAsync; přidáno opětovné načtení uživatele z DB před změnou hesla (zabrání ConcurrencyFailure při opakovaném volání na cachovany objekt z gridu); chybové hlášení přesunuto přímo do DxPopup jako inline alert

Přidáno

Konfigurace monitoring URL

  • appsettings.json — přidána sekce Monitoring s klíči GrafanaUrl a PrometheusUrl
  • .docker/compose-EVA-v141-deploy.yaml — přidány env proměnné Monitoring__GrafanaUrl a Monitoring__PrometheusUrl

Agenti a dokumentace

  • .claude/agents/check-server.md — nový specializovaný agent pro audit produkčních serverů (SSH diagnostika, docker ps, disk, logy)
  • doc/task/monitoring-separation-20260801.md, doc/task/check-server-20260731-20.5.md, doc/task/check-server-20260731-4.25.md, doc/task/fix/nginx-blazor-websocket.md — dokumentace auditu a oprav serverů 4.25 a 20.5

[Infra] — bthodweb produkce — 2026-07-31

Opraveno — infrastruktura

  • Nginx / eva.inventura-majetku.cz — přidán location /_blazor blok s WebSocket hlavičkami (Upgrade, Connection: upgrade, proxy_http_version 1.1, proxy_read_timeout 3600); Blazor Server SignalR nyní používá WebSocket místo long-polling — odstraněn zdroj odpojování uživatelů
  • OS root disk (bthodweb) — uvolněno 106 MB (journal vacuum) + LVM online extend z 10G na 18G (lvextend + resize2fs); využití kleslo z 83 % na 44 %

[1.0.43] — větev AM/v143 — 2026-07-30

Opraveno

Bug 4 — Transfer.razor: refresh při navigaci mezi převodkami

  • Transfer.razor — extrahována metoda InitializeComponentAsync() z OnInitializedAsync; přidán private long? _previousId a override OnParametersSetAsync s guard _previousId != Id — Blazor reusoval komponentu při navigaci /transfers/new → /transfers/{id} a nevolal OnInitializedAsync znovu, detail se zobrazoval prázdný bez F5

Přidáno

Feature — Reset hesla uživatele (Users.razor)

  • Users.razor — přidáno tlačítko "Nastavit heslo" do toolbaru; DxPopup se dvěma poli (nové heslo + potvrzení); handler SavePasswordAsync volá UserManager.RemovePasswordAsync + UserManager.AddPasswordAsync; přidán SuperAdmin do [Authorize] atributu
  • NavMenu.razor — SuperAdmin nově vidí v menu skupinu "Číselníky" filtrovanou jen na položku "Uživatelé" — umožňuje navigaci na /users
  • Resource.resx × 5 — 9 nových lokalizačních klíčů: MenuSetPassword, NewPassword, ConfirmPassword, SelectUserFirst, SetPasswordForUser, PasswordCannotBeEmpty, PasswordsDoNotMatch, SetPasswordFailed, SetPasswordSuccess

[1.0.43] — větev AM/v143 — 2026-07-30

Opraveno

Task3 — Oprava tenant filtrů v comboboxech a DetailTransferu (Bug 1, Bug 2, Bug 3)

  • EvaDataContext.cs — SetTenantFilter: přidáno || e.TenantID == null — pre-v143 záznamy s TenantID = null (legacy data) nyní procházejí global query filtrem a nejsou skryty (Bug 2)
  • Articles.razor, ArticleEditForm.razor, ArticlesLocations.razor, Transfer.razor, Transfers.razor, MyAssets.razor, InventoryEditForm.razor, InventoryList.razor, InventoryItemsGrid.razor, InventoryNewWizard.razor — přidán @inject ICurrentTenantAccessor a tenant filter při načítání comboboxů uživatelů (Bug 1)
  • Transfer.razor — async void UpdateTransfer přepsáno na async Task UpdateTransfer; přidán return; po NavigationManager.NavigateTo() — zabraňuje ObjectDisposedException po navigaci (Bug 3)

Přidáno

Task3 — E2E testy převodek (Eva.Manager.PlaywrightTests)

  • TransferTests.cs — 9 nových Playwright E2E testů pro /transfers, /transfers/new a /transfers/{id}

[1.0.43] — větev AM/v143 — 2026-07-29

Přidáno

Task1 — JWT autentizace a multitenant podpora pro MAUI a WebApi

  • WebApiTenantAccessor — nová implementace ICurrentTenantAccessor pro WebApi; čte tenant_id z JWT claims, takže EF Core global query filtry fungují i mimo Blazor circuit
  • FallbackPolicy (Program.cs) — všechny endpointy WebApi nyní vyžadují autentizaci bez nutnosti [Authorize] na každém controlleru zvlášť
  • AuthController (route api/pwa-auth) — přidány POST /login-pin (UserName + PIN), POST /refresh (stateless refresh); /me přesunuto do nového MeController
  • JwtTokenService.GetUserIdFromExpiredToken — umožňuje stateless refresh tokenu i po vypršení access tokenu (grace period 24 h)
  • Eva.Mobile (MAUI) — MauiAuthService — JWT login (heslo i PIN), SecureStorage pro tokeny, stateless refresh, kontrola expirace JWT; LoginWithDeviceTokenAsync pro QR/DeviceToken přihlášení
  • AuthDelegatingHandler — automaticky vkládá Bearer token do HTTP požadavků, retry po 401, SessionExpiredMsg při neúspěšném refresh
  • LoginPageViewModel — přihlášení zkouší nejdřív heslo, poté PIN jako fallback (terminály); OnLoginWithQr — sken QR kódu (prefix EVA-DEV:) a přihlášení přes LoginWithDeviceTokenAsync
  • MauiProgram — dva pojmenované HttpClient: eva-auth-bare (bez auth handleru, pro login/refresh) a eva-api (s AuthDelegatingHandler)

Task2 — MAUI optimalizace: decoupling chybových hlášení (S1)

  • ApiErrorMsg.cs — nová zpráva ApiErrorMsg(Title, Message) pro WeakReferenceMessenger; odstraňuje přímé volání Shell.Current.DisplayAlertAsync z RestService — service layer přestává záviset na UI vrstvě
  • AppShell.xaml.cs — implementuje IRecipient<ApiErrorMsg>; chybové dialogy zobrazuje centrálně přes DisplayAlert na hlavním vlákně

Změněno

Task2 — MAUI optimalizace: opravy memory leaků, async a dead code (K2, N1, N2, N3, N4, S2, S3)

  • RestService.cs — static readonly _jsonOptions nahrazuje inline new JsonSerializerOptions() v každém volání; opraveno 43× memory leak HttpResponseMessage přidáním using var; pSetBaseAddress() nyní používá Uri.TryCreate místo prázdného catch {}
  • AppShell.xaml.cs — WaitIndicator změněna na async Task; odstraněn neawaitovaný Task.Delay(350); ClosePopupAsync awaited
  • InventoryListViewModel.cs / PropertyViewModel.cs — odstraněno duplicitní MainThread wrapping; PropertyViewModel implementuje IDisposable s WeakReferenceMessenger.Default.UnregisterAll(this)

[1.0.42] — větev AM/v142 — 2026-07-29

Opraveno

Multitenancy — TenantID null v Blazor circuit (Eva.Manager)

  • ClaimsPrincipalTenantAccessor.cs — změna z AsyncLocal<long?> na ConcurrentDictionary<int, long?> keyovaný SynchronizationContext.Current.GetHashCode(); opravuje WHERE TenantID IS NULL v DxGrid dotazech — AsyncLocal nepropaguje hodnoty do sibling async kontextů (DevExtreme data source callbacky), zatímco RendererSynchronizationContext je sdílený napříč celým Blazor circuit
  • doc/developer-guide.md — sekce Multitenancy kompletně přepsána: architektura ITenantAccessor, diagram toku, vysvětlení mechanismu ConcurrentDictionary, záchranná síť v EvaDataContext, diagnostický postup
  • doc/task/v142/tenant_context_fix.md — nový incident report: symptom (prázdné gridy na produkci), diagnostika (SQL log analýza), příčina (AsyncLocal sémantika), oprava a poznámky k Docker deploy

[1.0.42] — větev AM/v142 — 2026-07-28

Přidáno

Fotodokumentace majetku v Eva.Manager

  • ArticleEditForm.razor — přidána záložka „Fotky" v editaci majetku; galerie existujících fotek s lazy-load binárních dat, upload nové fotky (JPEG/PNG, max 10 MB), mazání fotek; fotky se zobrazují pouze po uložení záznamu (Id > 0)
  • Resource.resx × 5 — nové lokalizační klíče ArticlePhotosCard, ArticlePhotosUpload, ArticlePhotosEmpty, ArticlePhotosDeleteConfirm, ArticlePhotosSaveFirst ve všech 5 jazykových souborech (cs-CZ, en-US, de-DE, sk-SK, neutral)

JoinCode ověření při vytváření uživatele (Eva.Manager)

  • CreateUser.razor — přidáno pole „Kód organizace" (JoinCode); zobrazuje se pouze pokud není přednastaven TenantId z URL; validace přes TenantDataService.GetByJoinCodeAsync; při neplatném kódu toast chyba; rozlišuje cestu Admin (TenantId z URL) vs. přímá registrace (JoinCode)
  • TenantDataService — nová metoda GetByJoinCodeAsync(joinCode): case-insensitive vyhledání aktivního tenanta dle JoinCode přes IgnoreQueryFilters + AsNoTracking
  • Messages.resx × 5 — nové klíče MSG_JOINCODE_REQUIRED, MSG_JOINCODE_INVALID ve všech 5 jazykových souborech
  • Resource.resx × 5 — nové klíče CaptionJoinCode, CaptionJoinCodeNullText ve všech 5 jazykových souborech

E2E Playwright testy — nový testovací projekt (Eva.Manager)

  • Eva.Manager.PlaywrightTests — nový xUnit testovací projekt s Playwright; přidán do Eva.slnx; konfigurace přes testconfig.json (URL, credentials, Headless, SlowMo)
  • PlaywrightFixture.cs — fixture pro správu životního cyklu Playwright/Chromium instance; TestConfig.cs a PageExtensions.cs — infrastrukturní helpery
  • LoginTests.cs — E2E testy přihlašování (správné/špatné přihlašovací údaje, zachování session)
  • RegistrationTests.cs — E2E testy registrace nového tenanta a JoinCode flow
  • UserManagementTests.cs — E2E testy správy uživatelů (vytvoření, licence limit, mazání)
  • DataManagementTests.cs — E2E testy správy dat (export JSON/CSV, import)
  • ReportTests.cs — E2E testy report designeru (vytvoření, zobrazení)
  • Directory.Packages.props — přidán Microsoft.Playwright 1.50.0

Nové integrační testy (Eva.Mobile.WebApi.Tests)

  • ArticleTransferServiceTests.cs — integrační testy pro ArticleTransferDataService.ExecuteTransferWithAuditAsync
  • EvaTestFactory.cs — sdílená WebApplicationFactory pro integrační testy WebApi
  • InventoryServiceTests.cs — integrační testy pro InventoryDataService.CreateInventoryItemsFromLocationAsync
  • LocationsControllerTests.cs — integrační testy endpointů /api/locations
  • TenantIsolationTests.cs — integrační testy tenant izolace napříč datovou vrstvou

Změněno

Opravy modelů a služeb (Eva.Data)

  • Location.cs — navigační property ParentLocation změněna na virtual (umožňuje lazy loading a lepší testovatelnost)
  • Printer.cs — property Destination označena [Required, MaxLength(250)] a inicializována na string.Empty (oprava potenciální null reference při serializaci)
  • InventoryDataService.CreateInventoryItemsFromLocationAsync — přidáno mazání stávajících položek před regenerací (RemoveRange + SaveChangesAsync); brání duplicitám při opakovaném volání s force přepsáním

Opravy oprávnění (Eva.Manager)

  • Monitoring.razor — přidán [Authorize(Roles = "Admin, SuperAdmin")] (stránka dříve bez autorizace)
  • SystemInfo.razor — přidán [Authorize(Roles = "Admin, SuperAdmin")] (stránka dříve bez autorizace)

Opravy konfigurace

  • App.razor — JS funkce downloadFileFromStream refaktorována: přidáno document.body.removeChild(a) a setTimeout(() => URL.revokeObjectURL(url), 1000) pro správné uvolnění zdrojů po stažení souboru
  • .gitignore — přidány vzory testconfig.local.json a *.local.json (lokální konfigurace Playwright testů s citlivými credentials)

Verze

  • Directory.Build.props — navýšena verze 1.0.41 → 1.0.42

Multitenancy — záchranná síť TenantID (Eva.Data)

  • EvaDataContext.cs — overridy SaveChangesAsync a SaveChanges volají privátní ApplyTenantIdToAddedEntities(); automaticky nastavuje TenantID na všech přidaných ITenantAware entitách kde je null — pokrývá volání context.Add() mimo BaseDataService
  • 001_bartech_tenant_always.sql — nový idempotentní DB skript Eva.Database/updates/v1.4.2/: zajistí existenci Bartech tenanta (OID=1), přiřadí Max licenci bez expirace a přiřadí všechny uživatele s TenantID=NULL k Bartech (TenantID=1)

[1.0.42] — větev AM/v142 — 2026-07-28 (dřívější commity)

Bezpečnost

  • Tenant audit — kompletní kontrola izolace dat: 28 entit pokrytých ITenantAware + EF Core global query filter (ApplyTenantFilters)
  • DB migrace 006_fix_unique_indexes_tenant.sql — opraveny unique indexy na 5 tabulkách chybějících TenantID:
  • Article_Accessory.UIX_Article_Accessory_Name → (Name, TenantID)
  • Constants.UIX_Constants_ParamCD → (ParamCD, TenantID)
  • Printer.UK_Printer_PrinterCD → (PrinterCD, TenantID) (konsolidace duplikátních indexů)
  • PrinterLabel.UK_PrinterLabel_PrinterLabelCD → (PrinterLabelCD, TenantID)
  • Print_Request.IX_Print_Request_DT → (DT, TenantID)
  • InventoryDataService.CloseInventoryWithAuditAsync — záznamy ArticleAuditLog a ArticleDisposal nyní správně nastavují TenantID

Funkce

  • Správa dat (/tools/data-management) — nová stránka pro správce tenanta:
  • Import vzorových dat (demo-data.json: 10 artiklů, 3 kategorie, 7 typů, 3 stavy, 2 lokality, 3 reporty, tiskárna, 2 štítky)
  • JSON backup (export všech dat tenanta) a restore (import ze zálohy)
  • CSV export artiklů (Excel-compatible, BOM prefix)
  • Report soft-delete — opraveno filtrování smazaných reportů v gridu

Architektura

  • Stored procedures → C# náhrada (tenant-safe, s audit logem):
  • sg_CreateInventoryItems → InventoryDataService.CreateInventoryItemsFromLocationAsync(inventoryId, locationId, force=false) — BFS přes Location hierarchii, Result<int>
  • sg_ExecuteArticleTransfer → ArticleTransferDataService.ExecuteTransferWithAuditAsync(transfer) — aktualizace lokace/stavu/uživatele + ArticleAuditLog, Result<TransferExecuteResult>
  • sg_UpdateArticlesAfterInventory → CloseInventoryWithAuditAsync (od v1.4.1, metoda CloseInventoryAsync označena [Obsolete])
  • TransferExecuteResult — nová result třída (LocationChanges, StateChanges, UserChanges)
  • IInventoryDataService.ConfirmOverwriteError — konstanta pro UI rozlišení "potřeba potvrzení" vs. chyba

[1.0.41] — větev AM/v141 — 2026-07-26

Přidáno

  • /admin/tenant-users — nová stránka pro SuperAdmin: výběr tenanta, DxGrid uživatelů, CRUD (přidat/editovat/smazat), export do CSV (uzivatele_{TenantName}_{datum}.csv)
  • /admin/tenant-export — export celých dat tenanta do JSON + restore (záloha/přenos mezi DB nebo tenanty)
  • /tools/import-articles — kompletní import majetku z CSV šablony (13 sloupců, lazy-create číselníků, volitelné smazání před importem)
  • /tools/import-users — kompletní import uživatelů z CSV šablony (skip duplicitních e-mailů, add-only)
  • TenantExportService — service pro export/restore s INSERT bez OID + RETURNING "OID" + remapování FK referencí napříč všemi vrstvami entit
  • CsvImportService — service pro CSV import majetku a uživatelů (shared template, parse CSV, lazy-create číselníků)
  • 004_codebook_unique_index_per_tenant.sql — migrační skript: unique indexy na číselníkových tabulkách změněny z globálního ("Name") na per-tenant ("Name", "TenantID")
  • Moje organizace (/settings/my-organization) — TenantAdmin může editovat název a kontaktní e-mail své organizace
  • Seed číselníků při registraci — nový tenant dostane automaticky výchozí kategorie, typy a stavy majetku

Změněno

  • Bezpečnost — blokace eskalace role SuperAdmin: UI filtr + server-side guard v EditAccount.razor
  • Filtrování menu dle role: SuperAdmin vidí pouze Správu systému; ostatní role nevidí systémové sekce
  • UploadImport.razor — přístup změněn z Admin, SuperAdmin na Admin, TenantAdmin
  • Users.razor — TenantAdmin vidí pouze uživatele svého tenanta (filtr dle TenantID)
  • Menu JSON (cs/en/de/sk) — přidány položky Správa uživatelů (8.3) a Export/Import dat (8.4) do sekce Správa systému

Opraveno

  • Restore tenanta: chybějící DELETE závislých tabulek před DELETE Article (Transfer_Item, Transfer, Photo_Article_Inventory, Photo_Article, ArticleAuditLog, ArticleDisposal, Article_Assembly, Article_Accessory)
  • Restore tenanta: PK kolize při cross-tenant importu — přepsáno na INSERT bez OID s remapováním FK
  • Restore tenanta: InventoryStateID NOT NULL violation — inventury s null stavem jsou přeskočeny
  • Tenant registrace: překlep „Základit" → „Záložit", auto-generace slugu, chybějící @formname na ForgotPassword
  • DB seed: role TenantAdmin chyběla v install skriptech

[1.0.40] — větev AM/v140 — 2026-05-26

Přidáno

Multitenancy — podpora více organizací (Task24)

  • Tenant.cs — nová EF Core entita; Name, Slug (URL identifikátor), Email, IsActive, CreatedDT
  • ITenantAware — interface; 27 doménových entit implementuje long? TenantID
  • ICurrentTenantAccessor / ClaimsPrincipalTenantAccessor — čte TenantID aktuálního uživatele z JWT claims (WebApi) nebo ASP.NET Identity (Manager)
  • TenantDataService — CRUD pro správu tenantů + RegisterTenantAsync (vytvoří tenant + admin uživatele + výchozí číselníky)
  • 004_005_tenant.sql — PostgreSQL migrace: tabulka Tenant, 26× ALTER TABLE ADD TenantID, indexy, migrace existujících dat na výchozí tenant
  • TenantRegistration.razor — veřejná stránka /account/tenant-registration pro registraci nové firmy (Název, e-mail, heslo)
  • Tenants.razor — Super Admin stránka /admin/tenants pro přehled a správu tenantů (aktivace/deaktivace)
  • MultitenancyOptions — konfigurace Multitenancy:Enabled v appsettings.json

Změněno

  • EF Core Global Query Filters — EvaDataContext automaticky přidá WHERE TenantID = @current pro všechny ITenantAware entity při Multitenancy:Enabled = true
  • BaseDataService.CreateAsync — automaticky injectuje TenantID při vytváření entity
  • JwtTokenService — JWT token nově obsahuje claim tenant_id
  • 27 EF Core entit — implementují ITenantAware (long? TenantID)
  • ApplicationUser — přidán TenantID, navigační property Tenant?
  • Settings.razor — přidána sekce Multitenancy s přepínačem Enabled
  • NavMenu — odkaz /admin/tenants zobrazen pro roli SuperAdmin
  • Lokalizace — 35 nových klíčů v 5 resx souborech (cs-CZ, en-US, de-DE, sk-SK + neutrální)

On-premise vs. SaaS

Multitenancy:Enabled = false (výchozí) zachovává stávající single-tenant chování — vhodné pro on-premise instalace. Enabled = true aktivuje plnou tenant izolaci pro cloud/SaaS nasazení.


Opravy AI nasazení — 2026-05-25

Větev AM/v138 — změny nezcomittovány nebo comittovány bez verze

Přidáno

  • DisabledChatClient.cs — nový: implementace IChatClient sloužící jako placeholder při chybějícím API klíči. Místo null reference loguje chybu a vrací srozumitelnou odpověď.
  • GET /ai/status — anonymní diagnostický endpoint pro ověření stavu AI konfigurace (provider, model, klíč nastaven/nechybí).
  • doc/docker_env.md — kompletní dokumentace všech Docker env proměnných včetně AI nastavení.

Změněno

  • EvaToolsMiddleware.cs — přidán try/catch do GetResponseAsync a nová metoda StreamSafe() pro zachycení chyb při streamování a jejich zapis do logu bez pádu aplikace.
  • Program.cs — startup log obsahuje AI konfiguraci (API klíč maskován, provider, model); přidáno .Trim() na načtený API klíč.
  • DockerExtensions.cs — ConfigureDockerConfiguration čte env proměnné AI_API_KEY (primárně) nebo AI__ApiKey (fallback), AI_PROVIDER, AI_MODEL.
  • appsettings.Docker.json — přidány placeholdery ${AI_API_KEY}, ${AI_PROVIDER}, ${AI_MODEL}.
  • compose-EVA-xtdocker-deploy.yaml — přidány env proměnné AI_API_KEY, AI_PROVIDER, AI_MODEL.

[1.0.39] — 2026-05-24

Task21 — Lokalizace AiChat + nové AI nástroje

Přidáno

  • AiChat.razor — plná lokalizace stránky přes @localizer[...].
  • EvaAiFunctions.cs — nový nástroj eva_aggregate_assets (COUNT + SUM(Price) nad artikly, bez LIMIT, agregace dle parametrů).
  • EvaAiFunctions.cs — nový nástroj eva_query_users (filtr dle jméno/aktivní, volitelně s počty majetku přiřazeného uživateli).
  • EvaAiFunctions.cs — nový nástroj eva_query_user_assets (seznam majetku přiřazeného konkrétnímu uživateli).
  • EvaSystemPrompt.cs — aktualizována pravidla nástrojů (nové nástroje přidány do systémového promptu).
  • Messages.resx (5 jazyků) — přidány lokalizační klíče pro AiChat suggestion bublinky.

Task22+23 — Historie AI konverzací

Přidáno

  • AiConversationService.cs — nová singleton service pro persistenci AI konverzací do DB; ukládá user zprávy, AI odpovědi, tool_call a tool_result záznamy.
  • AiChatSession.cs — nová EF Core entita; hlavička konverzační relace (uživatel, datum, název).
  • AiChatMessage.cs — nová EF Core entita; jednotlivé zprávy / tool_call / tool_result záznamy patřící k relaci.
  • 004_004_NewTable_AI.sql — SQL skript vytvářející tabulky dbo.AiChatSession a dbo.AiChatMessage.
  • EvaDataContext.cs — přidány DbSet<AiChatSession> a DbSet<AiChatMessage>.
  • EvaToolsMiddleware.cs — middleware loguje do DB průchod konverzace (user zprávy, AI odpovědi, tool_call, tool_result).

Dokumentace

  • doc/ai_guide.md — nový vývojářský průvodce pro rozšiřování AI asistenta (jak přidat nástroj, aktualizovat systémový prompt, přidat zdroj dokumentace).

[1.0.38] — 2026-05-24 — AI Chat asistent (Task20)

Přidáno

  • AiChat.razor — nová stránka /ai-chat s DxAIChat (streaming, suggestion bublinky, [Authorize]).
  • EvaAiFunctions.cs — 4 AI nástroje: eva_query_assets, eva_query_inventories, eva_query_transfers, eva_search_docs.
  • EvaDocumentationService.cs — singleton service načítající Markdown soubory z AI:DocsPath; fulltext search (top 3 výsledky, max 2 000 znaků).
  • EvaSystemPrompt.cs — systémový prompt v češtině definující roli, pravidla a dostupné nástroje.
  • EvaToolsMiddleware.cs — DelegatingChatClient middleware; injectuje nástroje do každého OpenAI volání.
  • menu.json — přidána položka „AI Asistent" (/ai-chat, ikona dx-icon-comment).
  • Program.cs — AddDevExpressAI(), registrace IChatClient s UseFunctionInvocation().
  • appsettings.json — přidána sekce AI (Provider, Model, MaxTokens, Temperature, DocsPath).

NuGet závislosti

Balíček Verze
DevExpress.AIIntegration.Blazor 25.2.6
Microsoft.Extensions.AI 9.7.1
OpenAI 2.8.0

[1.0.38] — 2026-05-22 — CSS cleanup + Lokalizace (Task18+19)

Task18 — CSS cleanup

  • site.css — opraveny CSS selektory DxGrid pro vybrané řádky (dxbl-grid-selected-row, dxbl-grid-focused-row).
  • Smazány lokální soubory: dx.light.css, bootstrap.css, open-iconic/, icons/dxicons.* — nahrazeno CDN DevExpress.

Task19 — Lokalizace Eva.Manager (11 Razor stránek)

Lokalizovány stránky a komponenty

Articles.razor, ArticlesLocations.razor, ArticlesDataAudit.razor, ArticleSelectionGrid.razor, InventoryActionButtons.razor, InventoryItemSelectionGrid.razor, InventoryItemsGrid.razor, MyAssets.razor, Transfer.razor, GridArticleDisposals.razor, GridArticleInventories.razor, GridArticleTransfers.razor, InventoryStatusTable.razor, QuickActions.razor

Resource soubory

  • Resource.resx (5 jazyků) — 70 nových klíčů.
  • Messages.resx (5 jazyků) — 19 nových klíčů.
  • doc/developer-guide.md — přidána sekce „Lokalizace" (Resource.resx, Messages.resx, konvence klíčů).

Nové agenty

  • dx-lang.md — agent pro lokalizaci hardcoded textů v Razor stránkách.

[1.0.29] — 2026-05-xx — ArticleDisposal (TASK 17)

Přidáno

Nová entita a tabulka ArticleDisposal

  • ArticleDisposal.cs — nová EF Core entita se sloupci: OID, ArticleID, DisposalDT, DisposalByUserID, DisposalReasonID, DisposalMethodID, Quantity, IsDisposal.
  • 004_003_NewTable_ArticleDisposal.sql — SQL skript pro vytvoření tabulky.
  • EvaDataContext.cs — přidán DbSet<ArticleDisposal>; navigační kolekce ArticleDisposals v entitě Article.
  • IArticleDisposalDataService + ArticleDisposalDataService — nová datová vrstva (metoda GetByArticleIdAsync); registrována v AddEvaDataServices().

Logika uzavření inventury (TASK 17)

  • InventoryDataService.CloseInventoryWithAuditAsync — rozšířeno o:
    1. Vytvoření záznamu ArticleDisposal pro každou položku s IsApprovedDisposal = true (disposedQty = OriginalQuantity − InventoryQuantity, Varianta A).
    2. Přepočet Article.Quantity = SUM(ArticleLocation.Quantity) po uzavření.
    3. Automatické označení artiklu jako vyřazeného (IsDisposal = true) pokud Article.Quantity <= 0.

UI — záložka Vyřazení v detailu artiklu (TASK 17)

  • ArticleEditForm.razor — nová záložka „Vyřazení" za záložkou „Umístění":
    • Read-only přehled: Vyřazený, Datum vyřazení, Vyřadil, Důvod, Způsob (přesunuto z záložky „Karta Majetku").
    • Nový grid GridArticleDisposals.razor — sloupce: Datum, Množství, Důvod, Způsob, Vyřadil.

[1.0.28] — 2026-04-28/29 — Průvodce inventurou, fix UserID (TASK 15 + 16 FIX)

Přidáno

Průvodce novou inventurou (TASK 15)

  • InventoryNewWizard.razor (@page "/inventories/new") — nový dvoukrokový průvodce zakládáním inventury:
    • Krok 1 — výběr zdroje: Podle majetku (filtry: Lokace rekurzivně, Kategorie, Přiřazená osoba, Odpovědná osoba) nebo Podle stávající inventury (DxDropDownBox).
    • Krok 2 — interaktivní grid výběru položek s SelectAllCheckboxMode="AllPages".
  • ArticleSelectionGrid.razor — sdílená komponenta; sloupce: Selection, ID, Inventární číslo, Název, Kategorie, Přiřazená osoba, Odpovědná osoba, Výchozí umístění.
  • InventoryItemSelectionGrid.razor — sdílená komponenta; sloupce: Selection, ID, Inventární číslo, Název, Přiřazená osoba, Stav, Evidenční lokace, Nalezená lokace, Hotovo.
  • CreateInventoryFromArticlesAsync — nová business metoda nahrazující stored procedure sg_CreateInventoryItems pro zakládání nových inventur.

Smazání inventury (TASK 15)

  • Inventories.razor — nové tlačítko „Smazat" dostupné pro Admin/InventoryManager. Vyžaduje potvrzení vepsáním slova DELETE do DxPopup.
  • DeleteWithItemsAsync — transakční smazání: kaskádově odstraní InventoryItem + Inventory.

Refaktorizace (TASK 15)

  • InventoryEditForm.razor — odebrán @page "/inventories/new", odebrána větev IsNew (nové inventury se zakládají výhradně přes průvodce).

Opraveno

Fix UserID v inventuře (TASK 16 FIX)

  • InventoryItemsGrid.razor — opravena chyba: UserID nebyl nastaven při inventarizaci položky. Opravena 3 místa: QuickInventoryOk, ExecuteNotMine, ApplyPerformInventoryModel.

[1.0.27] — 2026-04-28

Přidáno

Eva Mobile PWA (Task 16)

  • Eva.Mobile.Pwa — Blazor WebAssembly PWA pro běžné uživatele; dostupná na https://meva.inventura-majetku.cz.
  • JWT autentizace (EvaAuthStateProvider, AuthorizationHandler s Bearer tokenem).
  • Nové API endpointy: POST /api/pwa-auth/login-password, GET /api/articles/my-assets/{userId}, GET /api/inventories/my-inventories/{userId}.
  • Stránky: Přihlášení, Domů, Můj majetek (přiděleno/odpovídá), Detail majetku, Moje inventury, Detail inventury.
  • Mobilní layout (TopBar + BottomNavigation).

Správa inventur (TASK 15)

  • Smazání inventury — nová funkce v seznamu inventur (Inventories.razor) pro Admina a Správce. Vyžaduje potvrzení vepsáním slova "DELETE".
  • Průvodce novou inventurou (InventoryNewWizard.razor) — kompletně nový proces zakládání:
    • Výběr zdroje: Podle majetku (lokace rekurzivně, kategorie, osoby) nebo Podle stávající inventury.
    • Interaktivní gridy pro výběr konkrétních položek před vytvořením.
    • Nová business logika pro zakládání na straně serveru (nahrazuje původní uloženou proceduru).
  • Podpora pro null lokaci v modelu inventury.

UI a UX Inventury (TASK 14)

  • KPI Dashboard v detailu — integrace KPI karet přímo do prvního tabu karty inventury.
  • Interaktivní KPI karty — kliknutí na kartu (např. "Zbývá", "Rozdíly") automaticky přepne na seznam položek a aplikuje příslušný filtr.
  • Nový validační panel (InventoryValidationPanel.razor) — inteligentní panel chyb a varování:
    • Automatické sbalení (collapse) při velkém počtu záznamů.
    • Rychlé přepínání zobrazení detailů.
    • Barevné indikátory (badge) se souhrnem stavu.
  • Filtrování "Přidáno navíc" — nový pohled v gridu položek pro artikly nalezené mimo plán.

Změněno

  • Restrukturalizace InventoryEditForm — KPI a akční tlačítka přesunuta do tabů pro získání více vertikálního prostoru pro grid položek.
  • Refaktorizace komponent — vyextrahovány samostatné komponenty InventoryKpiPanel a InventoryValidationPanel.

[1.0.26] — větev AM/monitoring — 2026-04-24

Přidáno

Monitoring & Diagnostika (TASK13 / T17) (2026-04-22 – 2026-04-23)

  • src/Eva.Manager/Components/Pages/Monitoring.razor — nová admin stránka /monitoring s live metrikami (paměť, GC, thread pool, health)
  • AppMetricsService & AppSnapshot — real-time sběr systémových metrik pro UI
  • Integrace Prometheus — export metrik na /metrics (balíčky prometheus-net.AspNetCore a DotNetRuntime)
  • Integrace Health Checks — /health (Docker) a /health/details (JSON pro monitoring); kontrola DB a paměťových limitů
  • Dokumentace a postupy pro nastavení Grafana dashboardů (ID 10427, 23179) a Prometheus scrape jobu

Infrastruktura & Stabilita (2026-04-20)

  • Data Protection perzistence — klíče se nyní ukládají do Docker volume manager_dp_keys (v /app/dataprotection-keys); řeší odhlašování uživatelů po restartu kontejneru
  • Docker Healthcheck — automatické sledování stavu kontejneru přes /health endpoint
  • Memory limits v Dockeru — nastaven limit 768 MB (původně) resp. doporučeno 1 536 MB pro stabilitu při generování reportů

Změněno

Komponenty & Životní cyklus (TASK10) (2026-04-20)

  • Odstranění StreamRendering(true) u klíčových komponent (Transfers, InventoryEditForm) — eliminace race-condition při inicializaci (vícenásobné volání OnInitializedAsync)
  • Implementace IAsyncDisposable & CancellationToken v komponentách — prevence ObjectDisposedException při asynchronních operacích po zavření stránky
  • EF Core Concurrency — důsledné používání IDbContextFactory a using var db v asynchronních metodách

DxCheckBox (2026-04-20)

  • Oprava InvalidOperationException u DxCheckBox přidáním ValidationEnabled="false" u statických/read-only prvků bez @bind-Checked

Opraveno

  • Antiforgery token decryption error — vyřešeno perzistencí Data Protection klíčů
  • InvalidOperationException (DbContext threading) — vyřešeno opravou životního cyklu komponent a factory patternem
  • ObjectDisposedException — vyřešeno korektním rušením asynchronních úloh přes CancellationToken

[1.0.25] — větev AM/v123 — 2026-04-16

Přidáno

Solution & infrastruktura (2026-03-31)

  • Restrukturalizace solution — veškerý zdrojový kód přesunut do src/; integrace všech projektů do Eva.slnx / Eva.Manager.slnx
  • Docker soubory aktualizovány po přesunu adresářové struktury
  • .claude/settings.local.json přidáno do .gitignore

Dashboard (2026-04-01)

  • Zcela přepracovaný Index.razor — KPI dlaždice, tabulka inventur, akční panel, dva grafy (vyřazení v čase, kvalita inventur)
  • DashboardKpiCard, InventoryStatusTable, ActionPanel, DashboardCharts — nové sub-komponenty dashboardu
  • Zobrazení verze aplikace v patičce dashboardu (AppEnv.GetShortVersion())

Jazyková podpora — 4 jazyky (2026-04-01)

  • LanguageSwitcher.razor přepracován z toggle (CS/EN) na dropdown se 4 jazyky: 🇨🇿 Česky / 🇸🇰 Slovensky / 🇬🇧 English / 🇩🇪 Deutsch
  • Nové .resx soubory: Messages.sk-SK, Messages.de-DE, Resource.sk-SK, Resource.de-DE (každý ~58–160 klíčů)
  • Nové menu soubory: menu.en-US.json, menu.sk-SK.json, menu.de-DE.json
  • MenuService — culture-aware načítání menu.{culture}.json s fallback na menu.json
  • Program.cs — rozšíření supportedCultures o sk-SK a de-DE

Publikační infrastruktura (2026-04-02)

  • PowerShell skripty pro publikaci Docker imagí EVA na Docker Hub
  • NuGet skripty pro Libs.Bartech.Printing.Core — vytvoření a publikace balíčků
  • Dokumentace publikačního procesu

Security hardening (2026-04-02 – 2026-04-03)

  • Citlivé proměnné v Docker Compose souborech nahrazeny env proměnnými (hesla, tokeny)
  • Aktualizace dokumentace nasazení

TASK103 — Odstranění markdown dokumentace z aplikace (2026-04-03)

  • Smazána složka Eva.Manager/Docs/ (16 .md souborů + obrázky)
  • Odstraněny: DocsViewer.razor, MarkdownInterop.cs, závislosti Markdig, Prism
  • Odkaz "Manuál k aplikaci" nyní otevírá https://evadoc.xtrace.cz (nový target _blank)

TASK104 — Oprava dev konfigurace Program.cs (2026-04-03)

  • Substituce ${DB_HOST/PORT/PASSWORD} podmíněna na !IsDevelopment() — v Dev režimu se načítají credentials přímo z appsettings.Development.json
  • DataProtection: Development → výchozí user-profile cesta; Docker/Production → /tmp/aspnet/dataprotection

DevExpress lokalizace (2026-04-16)

  • copIt.cmd — robocopy skript pro kopírování lokalizačních DLL DevExpress Blazor komponent
  • Přidány lokalizační DLL pro cs-CZ a sk-SK (DevExpress Blazor)

DevExpress licence (2026-04-16)

  • Refaktorizace načítání DevExpress licence z environment proměnných
  • Přidána kontrola alternativní cesty při nenalezení licence

SystemInfo služba a stránka (2026-04-16)

  • Eva.Data/Services/SystemInfoDataService — PostgreSQL dotaz: current_database, pg_size_pretty, version(), inet_server_addr(), port, pg_postmaster_start_time(), uptime
  • Eva.Data/Services/dto/DatabaseInfo — record s výsledky dotazu
  • Eva.Manager/Services/SystemInfoService — kombinuje verzi aplikace, connection string (host, database) a live DB info
  • Components/Pages/SystemInfo.razor — nová stránka /system-info (pouze Admin), sekce: Aplikace / Databáze / Server
  • Components/shared/SysInfoRow.razor — znovupoužitelná subkomponenta řádku s volitelným zvýrazněním
  • Přidána položka "Systémové informace" (5.3) do menu — všechny 4 jazykové varianty

Změněno

API — optimalizace (2026-03-31)

  • Výkonnostní optimalizace API endpointů

NuGet balíčky (2026-04-13)

  • Hromadná aktualizace na kompatibilní verze s .NET 10

DxGrid komponenty — refaktorizace (2026-04-13)

  • Nahrazen InstantFeedbackSource → GridDevExtremeDataSource / IReadOnlyList dle velikosti datasetu
  • Přidány DxLoadingPanel pro stránky s pomalým načítáním
  • Inventories.razor — optimalizace po analýze dx-expert

ArticlesLocations.razor (2026-04-14)

  • Přidáno ukládání layoutu gridu do localStorage
  • Přepínače zobrazení (filter row, group panel, page size, search box)
  • Hromadná změna odpovědné osoby a přiřazeného uživatele
  • Nové lokalizační klíče v Resource.cs-CZ.resx

Articles.razor (2026-04-14 + 2026-04-16)

  • Persistování layoutu DxGrid
  • Oprava akumulace výběru při hromadných akcích — SelectedDataItems = null po každé akci
  • Přidáno tlačítko "Zruš označení" do toolbaru (dx-icon-clearsquared)
  • Ikony přidány ke všem toolbar položkám; hromadné akce ikonou dx-icon-checklist
  • Nastavení gridu přesunuto do submenu dx-icon-setup

InventoryItemsGrid.razor (2026-04-15 + 2026-04-16)

  • Rozšíření gridu: sloupce Přiřazená osoba a Odpovědná osoba
  • Inline editace přes EditFormTemplate — 3-sloupcový layout
  • Hromadná akce "Proveď inventuru" (popup), "Kopírovat do jiné inventury"
  • Filtrování položek dle role uživatele
  • Refaktorizace: přímý DbContext přístup nahrazen service vrstvou (IReadOnlyList)
  • Lokalizace všech hardcoded textů — 31 nových klíčů v Resource.resx + 2 v Messages.resx
  • Oprava akumulace výběru — SelectedDataItems = null po 7 bulk akcích
  • Ikony ke všem toolbar položkám (TASK13b)
  • Filter skupina a nastavení gridu jako submenu (ručně dle TASK13 vzoru)

Transfers (2026-04-14)

  • TransferEmailService — emailové notifikace při vytvoření/schválení/zamítnutí převodů
  • PIN popup ověřování při potvrzení převodu majetku
  • Přizpůsobitelná nastavení DxGrid (filter row, group panel, page size)
  • Aktualizace sloupce stavu v Transfers gridu

ToastMessageService (2026-04-14)

  • Odstranění duplicitních DxToastProvider komponent
  • Přejmenování proměnných pro konzistentní formát
  • Refaktorizace lokalizačních volání

EF Core — oprava concurrency (2026-04-16)

  • UserManager queries nahrazeny IDbContextFactory<ApplicationUsers> napříč komponentami (Articles, Transfers, Inventory, Layout) — řeší InvalidOperationException: A second operation was started
  • appsettings.json a appsettings.Development.template.json — aktualizace konfigurace emailu

Docker compose (2026-04-16)

  • Odstraněny zastaralé compose soubory (_web-only, _with_Print varianty)
  • Refaktorizace deployment setupu — vylepšené zabezpečení a logování

PowerShell publish skripty (2026-04-16)

  • Odstranění diakritiky z výstupních zpráv (kompatibilita v PowerShell)
  • Lokalizace promptů, zavedení krokových zpráv, nové helper funkce

Index.razor — patička (2026-04-16)

  • Přímý IDbContextFactory a IConfiguration odstraněny; nahrazeny SystemInfoService
  • Patička zobrazuje: verze | DB host | DB name | DB size (flex lišta s ikonami)

dx-expert SKILL.md (2026-04-16)

  • Sekce "Toolbar — standardní vzor" přepracována: povinné pořadí položek, vzory pro "Zruš označení", nastavení gridu jako submenu, kompletní ikonová paleta

Opraveno

  • EF Core concurrency — InvalidOperationException: A second operation was started on this context v komponentách s UserManager — viz EF Core sekce výše
  • DevExpress_License — opravena velikost písmen env proměnné v DockerExtensions.cs
  • DxToastProvider — duplicitní instance způsobovaly problémy s notifikacemi

[Unreleased] — větev AM/Theme — 2026-03-30

Přidáno

Runtime přepínání témat (Eva.Manager)

  • ThemeSwitcher — plovoucí panel s barevnými vzorky v nav liště (vpravo), implementovaný dle DevExpress doporučení T845557
  • 6 témat: Fluent Light, Fluent Dark, Blazing Berry, Blazing Dark, Purple, Office White
  • Perzistence tématu v cookie eva-theme — obnoví se při každém reload bez bliknutí
  • CookiesService (Eva.Manager/Services/CookiesService.cs) — čtení cookie přes IHttpContextAccessor (SSR), zápis přes JS setCookie
  • Pozadí draweru dle tématu — CSS proměnná --eva-drawer-panel-bg, každé téma má vlastní gradient v wwwroot/css/themes/theme-*.css
  • ThemeSwitcher/ komponenty — ThemeSwitcher.razor, ThemeSwitcherContainer.razor, ThemeSwitcherItem.razor
  • wwwroot/css/theme-switcher.css — styly panelu (plovoucí panel, barevné vzorky s hover efektem)
  • wwwroot/css/themes/ — 6 per-theme CSS souborů s definicí --eva-drawer-panel-bg
  • NuGet.Config — konfigurace zdrojů a source mapping (devexpress, baget.xtrace.cz, nuget.org)
  • Directory.Build.props — sdílené MSBuild vlastnosti pro všechny projekty
  • Directory.Packages.props — Central Package Management, 36 verzí balíčků
  • Eva.slnx / Eva.Manager.slnx — nový formát solution souborů (náhrada za .sln)
  • doc/ — adresář dokumentace (přesunuto z Eva.Manager/docs/DEV/ a kořene repozitáře)
  • doc/task/claude_task1.md — detailní záznam všech úkolů TASK1–TASK3 s výsledky

Změněno

Eva.Manager

  • App.razor — RegisterTheme(ThemesService.ActiveTheme) místo hardcoded FluentLight; inline <script> s setCookie; <link> pro theme-switcher.css
  • MainLayout.razor — odstraněn DxThemeProvider wrapper, přidán <ThemeSwitcher /> v nav liště
  • DxThemes.cs — DxThemesService přepsán: konstruktor injektuje CookiesService + IThemeChangeService + IHttpContextAccessor; nová SetActiveThemeAsync(); explicitní Name pro FluentLight/FluentDark v Clone; každé téma načítá per-theme CSS soubor
  • ServiceCollectionExtensions.cs — přidána registrace AddTransient<CookiesService>()
  • Program.cs — přidáno AddHttpContextAccessor()
  • Components/_Imports.razor — přidány @using Eva.Manager.Components.Layout.ThemeSwitcher a @using Eva.Manager.Services
  • Drawer.razor.css — gradient nahrazen var(--eva-drawer-panel-bg, <fallback>)
  • wwwroot/css/site.css — opravena chyba open.iconic → open-iconic (404 fix)
  • Eva.Manager.csproj — CPM: odstraněny Version atributy, přidána sdílená vlastnosti z Directory.Build.props
  • Components/Layout/Routes.razor — (klíčová oprava) přidáno @rendermode="@RenderModeForPage" — bez toho byla celá app SSR a interaktivní komponenty nefungovaly

Všechny projekty (.csproj)

  • Odstraněny Version atributy z <PackageReference> — verze spravuje Directory.Packages.props
  • Odstraněny duplicitní vlastnosti (TargetFramework, Nullable, ImplicitUsings) — přesunuty do Directory.Build.props

Odstraněno

  • Eva.sln, Eva.Manager.sln — nahrazeny .slnx soubory
  • Eva.Manager/docs/DEV/ — dokumentace přesunuta do doc/
  • howto.md (kořen) — přesunuto do doc/howto.md
  • qodana.yaml — odstraněno
  • ThemeLoader.razor — nahrazen cookie přístupem (soubor existuje ale je prázdný)
  • ThemePicker.razor — nahrazen ThemeSwitcher komponentou (soubor existuje ale je prázdný)

Opraveno

  • SSR/Interactive render mode — <Routes/> bez @rendermode způsoboval SSR pro celou app; opraveno přidáním @rendermode="@RenderModeForPage" (InteractiveServerRenderMode(prerender: false))
  • setCookie JSException — window.setCookie nebylo dostupné z externího .js souboru; přesunuto jako inline script do App.razor
  • open-iconic 404 — překlep open.iconic → open-iconic v site.css

Starší změny (z git logu větve master)

2026-03 — db2bb89

  • Merge branch master

2026-03 — effc853

  • Povolení WRITE_EXTERNAL_STORAGE (Android)

2026-03 — b3ee431 / 5ff557c / af557c0

  • Foto část 2 — event network, doplnění

2026-03 — 65dd780

  • Přidán .claude/ do .gitignore

2026-03 — a2446de

  • Azure AD login + zabezpečení konfigurace (OpenID Connect, automatická registrace uživatelů, mapování rolí)

2026-03 — 91101f4

  • Tisk z Docker kontejneru — RAW TCP/IP, default port 9100, Windows WinSpool

2026-03 — 4858f40 / fa83c97 / 04cd6bb / 65ab8be

  • Foto část 1 — implementace, build fix v Dockeru

2026-03 — 578f724

  • Upraven build DB, přidán vlastní updater (entrypoint), přidán volume

2026-02 — 860c781 / b36ef21 / f2b822c / 69e8597

  • Vizuální úpravy, tisk štítku při inventuře, dokumentace