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á
BackgroundServicejako hosted service; spouští digest každý pracovní den (Po–Pá) v 7:00;PeriodicTimers 1minutovým intervalem; interní stav_lastSentPerTenantzabraň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
DailyDigestServicejakoAddHostedService; testovací endpointGET /dev/digest/test?tenantId=<id>dostupný pouze vDevelopmentprostř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í callbackOnUsersSelected - 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 vInventoryNotificationEmailServiceiInventoryEmailService - appsettings.json — přidána sekce
EvaLinkss klíčemManagerUrl - 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 —
LicenseLimitsrozšířen obool 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íQrGuidpro artikly bez GUID; vrací{ Generated, Total }; nový artikl přespwa-requestdostaneQrGuidautomaticky - 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 chybaArticleID→ArticleOID; přidánoinventory.IsSecuredo response objektu - InventoryItemsController.cs —
pwa-confirm: server-side guard proIsSecure— 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
IsSecureinventury - 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_PersonalInventoryAddona 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 sDeleted = true; záznamy bez vlastnostiDeletedzů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 modelyArticleCategory,ArticleType,CurrencyTypezEva.Data.Models - NewAsset.razor — přidáno pole „Sériové číslo" (
_serialNo); odesíláno vPwaArticleRequest - 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 NULLv 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ý sArticleCategoriesController - ServiceCollectionExtensions.cs — přidána DI registrace
IBaseDataService<CurrencyType>, BaseDataService<CurrencyType> - ArticlesController.cs —
PwaArticleRequestrozšířen ostring? SerialNo; hodnota uložena doarticle.SerialNo - ArticlesController.cs — endpoint
POST api/articles/pwa-requestnastavujeArticleStateIDna 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řídukpi-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.jssCache-Control: no-store;blazor.webassembly.jsnemá 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šechnyITenantAwareentity; 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ěřitMultitenancy.Enabled = truepřed nasazením
Docker — build scripty pro PWA image¶
- EvaAll_DockerBuildAndPush.ps1 — přidán
Invoke-SingleImagePublishprobartech-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-PublishFlowzCommon-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énoumeva.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-pwana192.168.4.25:8083— přidán docompose-EVA-xtdocker-deploy.yaml, závislý narestapi - Reverzní proxy
meva.xtrace.czna192.168.4.67:443— nový nginx vhost proxující na192.168.4.25:8083; SSL certifikáteva_bundle.pemrozšířen o SANmeva.xtrace.cz(stejný privátní klíč jakoeva.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í knihovnyZXing 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áScannerInteropa 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áExchangeDeviceTokenAsyncse stored tokenem; při401maže token z localStorage a skrývá tlačítko - AuthService.cs — přidána metoda
HasStoredDeviceTokenAsync— čtedevice_tokenz localStorage; přidána metodaExchangeDeviceTokenAsync— POST/api/device-auth/exchange→ JWT uložen přesTokenStore
Eva.Manager — Security stránka: přehled všech tokenů tenantu¶
- DeviceTokenView.cs — nový read-only record v
Eva.Data.Models.Security; obohacujeDeviceTokenoUserEmailaUserDisplayName(First + Last name); používán v admin UI pro zobrazení tokenů - DeviceTokenDataService.cs — přidána metoda
GetAllActiveTokensWithUserAsync(long? tenantId)— LINQ joinDeviceToken+ApplicationUser+User; vracíIEnumerable<DeviceTokenView>filtrovaný dle tenantu; přidána metodaAdminRevokeTokenAsync(long tokenId, long? tenantId)— revokuje token přesExecuteUpdateAsync(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 (DxButtonvDataItemTemplate); toolbar tlačítko „Odvolat token" pracuje s vybraným řádkem; voláAdminRevokeTokenAsync;NewButtonVisible="false"naDxGridCommandColumn
Opraveno¶
PWA — Layout fix: mobile-content min-height a scroll¶
- mobile.css —
.mobile-contentopravenmin-height: 0(flex item byl bez omezení, čímžoverflow-y: scrollnefungoval na iOS Safari); přidán-webkit-overflow-scrolling: touchaoverscroll-behavior-y: containpro 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 zGET 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 zGET 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 prefixuEVA-DEV:), POST/api/device-auth/activate→ POST/api/device-auth/exchange→ JWT uložen do localStorage; přidána metodaRefreshAsync()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-fillatd.) místo emoji - NavItem.razor — CSS třída
bottom-nav-item→topbar-nav-item; odstraněny textové popisky (jen ikony stitleatributem 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-nava.topbar-nav-item; Bootstrap Icons CDN přidán doindex.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
AuthorizationHandlerpři souběžných JSInterop voláníchlocalStorage.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.VisibleChangedse nespouštělo při programatickémVisible=truez rodiče; oprava: přidánOnParametersSetAsync, který detekuje přechodfalse→truea zavoláGenerateCodeAsync(); přidán@implements IDisposable; odstraněn debug kód - Security.razor — odstraněny debug logy z
OpenQrPopup; přidánusing Eva.Manager.Components.shared;NewButtonVisible="false"naDxGridCommandColumn; 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éhoapi/...odkazu (oprava CORS/autentizace)
PWA — AssetDetail — formátování ceny¶
- AssetDetail.razor — zobrazení měny:
Symbol ?? Code ?? Namemísto pouzeName— 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:autonatopbar-inner(dříve zabíralo celou výšku viewportu) - MyInventories.razor — oprava
height:autonatopbar-inner
Eva.Manager — EditAccount.razor¶
- EditAccount.razor — přejmenování proměnné
roleCtx→rolevItemTemplatekontextuDxListBox(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 zIConfiguration["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+AddPasswordAsyncnahrazena jednofázovýmGeneratePasswordResetTokenAsync+ResetPasswordAsync; přidáno opětovné načtení uživatele z DB před změnou hesla (zabráníConcurrencyFailurepři opakovaném volání na cachovany objekt z gridu); chybové hlášení přesunuto přímo doDxPopupjako inlinealert
Přidáno¶
Konfigurace monitoring URL¶
- appsettings.json — přidána sekce
Monitorings klíčiGrafanaUrlaPrometheusUrl - .docker/compose-EVA-v141-deploy.yaml — přidány env proměnné
Monitoring__GrafanaUrlaMonitoring__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 /_blazorblok 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()zOnInitializedAsync; přidánprivate long? _previousIda overrideOnParametersSetAsyncs guard_previousId != Id— Blazor reusoval komponentu při navigaci/transfers/new→/transfers/{id}a nevolalOnInitializedAsyncznovu, 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;
DxPopupse dvěma poli (nové heslo + potvrzení); handlerSavePasswordAsyncvoláUserManager.RemovePasswordAsync+UserManager.AddPasswordAsync; přidánSuperAdmindo[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 sTenantID = 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 ICurrentTenantAccessora tenant filter při načítání comboboxů uživatelů (Bug 1) - Transfer.razor —
async void UpdateTransferpřepsáno naasync Task UpdateTransfer; přidánreturn;poNavigationManager.NavigateTo()— zabraňujeObjectDisposedExceptionpo 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/newa/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á implementaceICurrentTenantAccessorpro WebApi; čtetenant_idz 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(routeapi/pwa-auth) — přidányPOST /login-pin(UserName + PIN),POST /refresh(stateless refresh);/mepřesunuto do novéhoMeControllerJwtTokenService.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),SecureStoragepro tokeny, stateless refresh, kontrola expirace JWT;LoginWithDeviceTokenAsyncpro QR/DeviceToken přihlášení AuthDelegatingHandler— automaticky vkládá Bearer token do HTTP požadavků, retry po 401,SessionExpiredMsgpři neúspěšném refreshLoginPageViewModel— přihlášení zkouší nejdřív heslo, poté PIN jako fallback (terminály);OnLoginWithQr— sken QR kódu (prefixEVA-DEV:) a přihlášení přesLoginWithDeviceTokenAsyncMauiProgram— dva pojmenovanéHttpClient:eva-auth-bare(bez auth handleru, pro login/refresh) aeva-api(sAuthDelegatingHandler)
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.DisplayAlertAsynczRestService— service layer přestává záviset na UI vrstvě - AppShell.xaml.cs — implementuje
IRecipient<ApiErrorMsg>; chybové dialogy zobrazuje centrálně přesDisplayAlertna 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 _jsonOptionsnahrazuje inlinenew JsonSerializerOptions()v každém volání; opraveno 43× memory leakHttpResponseMessagepřidánímusing var;pSetBaseAddress()nyní používáUri.TryCreatemísto prázdnéhocatch {} - AppShell.xaml.cs —
WaitIndicatorzměněna naasync Task; odstraněn neawaitovanýTask.Delay(350);ClosePopupAsyncawaited - InventoryListViewModel.cs / PropertyViewModel.cs — odstraněno duplicitní MainThread wrapping;
PropertyViewModelimplementujeIDisposablesWeakReferenceMessenger.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?>naConcurrentDictionary<int, long?>keyovanýSynchronizationContext.Current.GetHashCode(); opravujeWHERE TenantID IS NULLv DxGrid dotazech —AsyncLocalnepropaguje hodnoty do sibling async kontextů (DevExtreme data source callbacky), zatímcoRendererSynchronizationContextje sdílený napříč celým Blazor circuit - doc/developer-guide.md — sekce Multitenancy kompletně přepsána: architektura
ITenantAccessor, diagram toku, vysvětlení mechanismuConcurrentDictionary, záchranná síť vEvaDataContext, 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 (
AsyncLocalsé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,ArticlePhotosSaveFirstve 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
TenantIdz URL; validace přesTenantDataService.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řesIgnoreQueryFilters+AsNoTracking - Messages.resx × 5 — nové klíče
MSG_JOINCODE_REQUIRED,MSG_JOINCODE_INVALIDve všech 5 jazykových souborech - Resource.resx × 5 — nové klíče
CaptionJoinCode,CaptionJoinCodeNullTextve 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řestestconfig.json(URL, credentials, Headless, SlowMo) - PlaywrightFixture.cs — fixture pro správu životního cyklu Playwright/Chromium instance;
TestConfig.csaPageExtensions.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.Playwright1.50.0
Nové integrační testy (Eva.Mobile.WebApi.Tests)¶
- ArticleTransferServiceTests.cs — integrační testy pro
ArticleTransferDataService.ExecuteTransferWithAuditAsync - EvaTestFactory.cs — sdílená
WebApplicationFactorypro 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
ParentLocationzměněna navirtual(umožňuje lazy loading a lepší testovatelnost) - Printer.cs — property
Destinationoznačena[Required, MaxLength(250)]a inicializována nastring.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í sforcepř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
downloadFileFromStreamrefaktorována: přidánodocument.body.removeChild(a)asetTimeout(() => URL.revokeObjectURL(url), 1000)pro správné uvolnění zdrojů po stažení souboru - .gitignore — přidány vzory
testconfig.local.jsona*.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
SaveChangesAsyncaSaveChangesvolají privátníApplyTenantIdToAddedEntities(); automaticky nastavujeTenantIDna všech přidanýchITenantAwareentitách kde jenull— pokrývá volánícontext.Add()mimoBaseDataService - 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 sTenantID=NULLk 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íchTenantID: 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áznamyArticleAuditLogaArticleDisposalnyní 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, metodaCloseInventoryAsyncoznač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 entitCsvImportService— 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 zAdmin, SuperAdminnaAdmin, TenantAdminUsers.razor— TenantAdmin vidí pouze uživatele svého tenanta (filtr dleTenantID)- 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 NULLviolation — inventury s null stavem jsou přeskočeny - Tenant registrace: překlep „Základit" → „Záložit", auto-generace slugu, chybějící
@formnamena ForgotPassword - DB seed: role
TenantAdminchybě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,CreatedDTITenantAware— interface; 27 doménových entit implementujelong? TenantIDICurrentTenantAccessor/ClaimsPrincipalTenantAccessor— čteTenantIDaktuá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: tabulkaTenant, 26×ALTER TABLE ADD TenantID, indexy, migrace existujících dat na výchozí tenantTenantRegistration.razor— veřejná stránka/account/tenant-registrationpro registraci nové firmy (Název, e-mail, heslo)Tenants.razor— Super Admin stránka/admin/tenantspro přehled a správu tenantů (aktivace/deaktivace)MultitenancyOptions— konfiguraceMultitenancy:Enabledvappsettings.json
Změněno¶
- EF Core Global Query Filters —
EvaDataContextautomaticky přidáWHERE TenantID = @currentpro všechnyITenantAwareentity přiMultitenancy:Enabled = true BaseDataService.CreateAsync— automaticky injectujeTenantIDpři vytváření entityJwtTokenService— JWT token nově obsahuje claimtenant_id- 27 EF Core entit — implementují
ITenantAware(long? TenantID) ApplicationUser— přidánTenantID, navigační propertyTenant?Settings.razor— přidána sekce Multitenancy s přepínačemEnabled- NavMenu — odkaz
/admin/tenantszobrazen pro roliSuperAdmin - 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ý: implementaceIChatClientsloužící jako placeholder při chybějícím API klíči. Místonullreference 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ántry/catchdoGetResponseAsynca nová metodaStreamSafe()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ě) neboAI__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ástrojeva_aggregate_assets(COUNT + SUM(Price) nad artikly, bez LIMIT, agregace dle parametrů).EvaAiFunctions.cs— nový nástrojeva_query_users(filtr dle jméno/aktivní, volitelně s počty majetku přiřazeného uživateli).EvaAiFunctions.cs— nový nástrojeva_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í tabulkydbo.AiChatSessionadbo.AiChatMessage.EvaDataContext.cs— přidányDbSet<AiChatSession>aDbSet<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-chatsDxAIChat(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 zAI: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—DelegatingChatClientmiddleware; injectuje nástroje do každého OpenAI volání.- menu.json — přidána položka „AI Asistent" (
/ai-chat, ikonadx-icon-comment). Program.cs—AddDevExpressAI(), registraceIChatClientsUseFunctionInvocation().appsettings.json— přidána sekceAI(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ánDbSet<ArticleDisposal>; navigační kolekceArticleDisposalsv entitěArticle.IArticleDisposalDataService+ArticleDisposalDataService— nová datová vrstva (metodaGetByArticleIdAsync); registrována vAddEvaDataServices().
Logika uzavření inventury (TASK 17)¶
InventoryDataService.CloseInventoryWithAuditAsync— rozšířeno o:- Vytvoření záznamu
ArticleDisposalpro každou položku sIsApprovedDisposal = true(disposedQty = OriginalQuantity − InventoryQuantity, Varianta A). - Přepočet
Article.Quantity = SUM(ArticleLocation.Quantity)po uzavření. - Automatické označení artiklu jako vyřazeného (
IsDisposal = true) pokudArticle.Quantity <= 0.
- Vytvoření záznamu
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".
- 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 (
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 proceduresg_CreateInventoryItemspro 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 slovaDELETEdoDxPopup.DeleteWithItemsAsync— transakční smazání: kaskádově odstraníInventoryItem+Inventory.
Refaktorizace (TASK 15)¶
InventoryEditForm.razor— odebrán@page "/inventories/new", odebrána větevIsNew(nové inventury se zakládají výhradně přes průvodce).
Opraveno¶
Fix UserID v inventuře (TASK 16 FIX)¶
InventoryItemsGrid.razor— opravena chyba:UserIDnebyl 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á nahttps://meva.inventura-majetku.cz.- JWT autentizace (
EvaAuthStateProvider,AuthorizationHandlers 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
nulllokaci 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
InventoryKpiPanelaInventoryValidationPanel.
[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/monitorings 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íčkyprometheus-net.AspNetCoreaDotNetRuntime) - 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
/healthendpoint - 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&CancellationTokenv komponentách — prevenceObjectDisposedExceptionpři asynchronních operacích po zavření stránky - EF Core Concurrency — důsledné používání
IDbContextFactoryausing var dbv asynchronních metodách
DxCheckBox (2026-04-20)¶
- Oprava
InvalidOperationExceptionuDxCheckBoxpřidánímValidationEnabled="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ů doEva.slnx/Eva.Manager.slnx - Docker soubory aktualizovány po přesunu adresářové struktury
.claude/settings.local.jsonpř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.razorpřepracován z toggle (CS/EN) na dropdown se 4 jazyky: 🇨🇿 Česky / 🇸🇰 Slovensky / 🇬🇧 English / 🇩🇪 Deutsch- Nové
.resxsoubory: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}.jsons fallback namenu.jsonProgram.cs— rozšířenísupportedCulturesosk-SKade-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 zappsettings.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(), uptimeEva.Data/Services/dto/DatabaseInfo— record s výsledky dotazuEva.Manager/Services/SystemInfoService— kombinuje verzi aplikace, connection string (host, database) a live DB infoComponents/Pages/SystemInfo.razor— nová stránka/system-info(pouze Admin), sekce: Aplikace / Databáze / ServerComponents/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/IReadOnlyListdle velikosti datasetu - Přidány
DxLoadingPanelpro 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 = nullpo 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ý
DbContextpřístup nahrazen service vrstvou (IReadOnlyList) - Lokalizace všech hardcoded textů — 31 nových klíčů v
Resource.resx+ 2 vMessages.resx - Oprava akumulace výběru —
SelectedDataItems = nullpo 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
DxToastProviderkomponent - Přejmenování proměnných pro konzistentní formát
- Refaktorizace lokalizačních volání
EF Core — oprava concurrency (2026-04-16)¶
UserManagerqueries nahrazenyIDbContextFactory<ApplicationUsers>napříč komponentami (Articles, Transfers, Inventory, Layout) — řešíInvalidOperationException: A second operation was startedappsettings.jsonaappsettings.Development.template.json— aktualizace konfigurace emailu
Docker compose (2026-04-16)¶
- Odstraněny zastaralé compose soubory (
_web-only,_with_Printvarianty) - 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ý
IDbContextFactoryaIConfigurationodstraněny; nahrazenySystemInfoService - 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 contextv komponentách sUserManager— 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řesIHttpContextAccessor(SSR), zápis přes JSsetCookie- Pozadí draweru dle tématu — CSS proměnná
--eva-drawer-panel-bg, každé téma má vlastní gradient vwwwroot/css/themes/theme-*.css ThemeSwitcher/komponenty —ThemeSwitcher.razor,ThemeSwitcherContainer.razor,ThemeSwitcherItem.razorwwwroot/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-bgNuGet.Config— konfigurace zdrojů a source mapping (devexpress, baget.xtrace.cz, nuget.org)Directory.Build.props— sdílené MSBuild vlastnosti pro všechny projektyDirectory.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 zEva.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>ssetCookie;<link>protheme-switcher.cssMainLayout.razor— odstraněnDxThemeProviderwrapper, přidán<ThemeSwitcher />v nav lištěDxThemes.cs—DxThemesServicepřepsán: konstruktor injektujeCookiesService+IThemeChangeService+IHttpContextAccessor; nováSetActiveThemeAsync(); explicitníNamepro FluentLight/FluentDark v Clone; každé téma načítá per-theme CSS souborServiceCollectionExtensions.cs— přidána registraceAddTransient<CookiesService>()Program.cs— přidánoAddHttpContextAccessor()Components/_Imports.razor— přidány@using Eva.Manager.Components.Layout.ThemeSwitchera@using Eva.Manager.ServicesDrawer.razor.css— gradient nahrazenvar(--eva-drawer-panel-bg, <fallback>)wwwroot/css/site.css— opravena chybaopen.iconic→open-iconic(404 fix)Eva.Manager.csproj— CPM: odstraněnyVersionatributy, přidána sdílená vlastnosti z Directory.Build.propsComponents/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
Versionatributy z<PackageReference>— verze spravujeDirectory.Packages.props - Odstraněny duplicitní vlastnosti (
TargetFramework,Nullable,ImplicitUsings) — přesunuty doDirectory.Build.props
Odstraněno¶
Eva.sln,Eva.Manager.sln— nahrazeny.slnxsouboryEva.Manager/docs/DEV/— dokumentace přesunuta dodoc/howto.md(kořen) — přesunuto dodoc/howto.mdqodana.yaml— odstraněnoThemeLoader.razor— nahrazen cookie přístupem (soubor existuje ale je prázdný)ThemePicker.razor— nahrazenThemeSwitcherkomponentou (soubor existuje ale je prázdný)
Opraveno¶
- SSR/Interactive render mode —
<Routes/>bez@rendermodezpůsoboval SSR pro celou app; opraveno přidáním@rendermode="@RenderModeForPage"(InteractiveServerRenderMode(prerender: false)) - setCookie JSException —
window.setCookienebylo dostupné z externího .js souboru; přesunuto jako inline script do App.razor - open-iconic 404 — překlep
open.iconic→open-iconicv 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