Back to projects

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-src

Deep 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.

Highlights

Production React 19 / TypeScript / Vite SPA for Hungarian State Treasury policy reviews
Feature-sliced architecture with Zod at the HTTP boundary and ESLint-enforced import seams
Password login + Microsoft Entra ID SSO; JWT claim UI gating; idle timeout and token rotation
Live run progress polling, legislation HTML diffs sanitized with DOMPurify
Multi-stage Docker (nginx + CSP), runtime-injected API URL; GitHub Actions → ACR → Azure Container Apps
A11y: skip link, route focus, aria-live / aria-sort, native progress