React 19, TypeScript, Vite, Entra ID, Azure
MÁK Kincstár AI — frontend
Senior Frontend Developer · DXS · May 2026 –
At DXS I own the frontend of MÁK Kincstár AI: an internal SPA for the Hungarian State Treasury where specialists start and follow AI-assisted policy reviews. The list filters by date and specialty; filter, pagination, and sort live in the URL. A running review refreshes every 10 seconds (otherwise once a minute) from a header widget that keeps polling across navigation. Detail views show linked legislation, internal rules, and the AI change proposal as an HTML diff. Admins manage users (CRUD, specialty access, soft-delete) and backend settings including cron schedulers. Auth is password login plus Microsoft Entra ID SSO; roles come from JWT claims for UI gating only — the server authorizes every call.
Login (password | Entra ID SSO)
→ JWT session (idle timeout, X-New-Access-Token rotation)
→ policyReviews list (URL filters + poll)
→ detail: legislation · internal rules · AI HTML diff (DOMPurify)
→ admin: users · settings / cron
Deploy: GitHub Actions → ACR → Azure Container Apps
one Docker image (Node 22 → nginx 1.27)
runtime APP_CONFIG.API_URL + CSP connect-srcDeep dive
Feature slices at the HTTP boundary
Modules are policyReviews, users, and settings — each with api.ts, Zod schemas that map DTOs to domain types, components, and a barrel index. Cross-feature imports are blocked by ESLint. Server state uses useAsyncResource (loading / error / ready) with background refresh via refreshKey and a race guard for slow responses. List sort stays client-side so a poll does not wipe the user’s order.
Auth without /me
There is no /me or /logout endpoint. The role is read from the JWT userRole claim for UI-only gates (ADMIN / USER); RequireAdmin wraps /users and /settings. Entra flow: status check on login, 302 to Microsoft, return on /auth/entra?code=…, one-time code exchange. Idle timeout and access-token rotation via X-New-Access-Token keep long treasury sessions safe without rebuilding the client.
One image, every environment
Multi-stage Docker builds Node 22 down to nginx 1.27. The entrypoint writes window.APP_CONFIG.API_URL and injects the backend origin into CSP connect-src, so the same artifact runs in every environment. Vite VITE_API_URL is local-dev only. Optional same-origin nginx reverse proxy (APP_API_PROXY) when CORS should not cross origins. Security headers ship with the container.
Accessibility and untrusted HTML
Skip link, focus management on route change, aria-live / aria-sort, and a native progress element for run status. Backend legislation diffs arrive as full HTML; DOMPurify sanitizes with an html profile, style attributes blocked, colors kept on our CSS classes so XSS cannot ride a suggested edit.