The sha256Hex helper used window.crypto.subtle.digest(), which is only
available in a secure context (HTTPS / localhost). In the HTTP Docker
environment crypto.subtle is undefined, causing a TypeError before any
request is sent — the setup and login forms both silently failed with
'An unexpected error occurred'.
Fix: pass raw passwords directly to the API. The backend already applies
bcrypt, which is sufficient. No stored hashes need migration because
setup never completed successfully in the HTTP environment.
* frontend/src/pages/SetupPage.tsx — remove sha256Hex call
* frontend/src/api/auth.ts — remove sha256Hex call
* frontend/src/pages/__tests__/SetupPage.test.tsx — drop crypto mock
* frontend/src/utils/crypto.ts — deleted (no remaining callers)
The pie and bar charts were rendering with transparent/missing colors because
resolveFluentToken queried document.documentElement for CSS custom properties.
Fluent UI v9 injects these on its own wrapper div (.fui-FluentProvider), not
on :root. Changed to query that element with a fallback to document.html.
This fixes the fill colors for all four chart components.
- Install Recharts v3 as the project charting library
- Add chartTheme utility with Fluent UI v9 token resolution helper
and a 5-colour categorical palette (resolves CSS vars at runtime)
- Add TopCountriesPieChart: top-4 + Other slice, Tooltip, Legend
- Add TopCountriesBarChart: horizontal top-20 bar chart
- Add useDashboardCountryData hook (wraps /api/dashboard/bans/by-country)
- Integrate both charts into DashboardPage in a responsive chartsRow
(side-by-side on wide screens, stacked on narrow)
- All tsc --noEmit and eslint checks pass with zero warnings
- Task 1: Mark imported blocklist IP addresses
- Add BanOrigin type and _derive_origin() to ban.py model
- Populate origin field in ban_service list_bans() and bans_by_country()
- BanTable and MapPage companion table show origin badge column
- Tests: origin derivation in test_ban_service.py and test_dashboard.py
- Task 2: Add origin filter to dashboard and world map
- ban_service: _origin_sql_filter() helper; origin param on list_bans()
and bans_by_country()
- dashboard router: optional origin query param forwarded to service
- Frontend: BanOriginFilter type + BAN_ORIGIN_FILTER_LABELS in ban.ts
- fetchBans / fetchBansByCountry forward origin to API
- useBans / useMapData accept and pass origin; page resets on change
- BanTable accepts origin prop; DashboardPage adds segmented filter
- MapPage adds origin Select next to time-range picker
- Tests: origin filter assertions in test_ban_service and test_dashboard
- Add SetupGuard component: redirects to /setup if setup not complete,
shown as spinner while loading. All routes except /setup now wrapped.
- SetupPage redirects to /login on mount when setup already done.
- Fix async blocking: offload bcrypt.hashpw and bcrypt.checkpw to
run_in_executor so they never stall the asyncio event loop.
- Hash password with SHA-256 (SubtleCrypto) before transmission; added
src/utils/crypto.ts with sha256Hex(). Backend stores bcrypt(sha256).
- Add Makefile with make up/down/restart/logs/clean targets.
- Add tests: _check_password async, concurrent bcrypt, expired session,
login-without-setup, run_setup event-loop interleaving.
- Update Architekture.md and Features.md to reflect all changes.