# Changelog — `ui`

All notable changes to the **ui** container are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and the container adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

The `api` and `ui` containers are versioned independently. The UI is
deliberately replaceable; bumping the **major** here implies a breaking
change to UI-internal surfaces (route paths under `/app/*`, Twig
templates, internal class names). The HTTP wire contract it speaks to
the api is owned by the `api` container's changelog.

Tags use the `ui-v<MAJOR>.<MINOR>.<PATCH>` form so they don't collide
with the api's tags in this monorepo.

## [Unreleased]

### Added
- Settings page now shows two **Audit toggles** for switching off the public-endpoint audit emissions (reporter `POST /report` and consumer `GET /blocklist`) without restarting the api. Posts to a new `/app/settings/audit-toggles` BFF route that PATCHes `/api/v1/admin/app-settings`.
- Per-entity audit-log toggle on the reporter and consumer edit pages. Combined with the global Settings toggle via AND so either side is sufficient to silence the audit row.
- Tokens page now shows a **Remove** action on revoked rows that hard-deletes the row via `POST /app/tokens/{id}/purge`.

### Changed
- Dashboard "Bans (7 days)" line chart replaced by a stacked bar chart of distinct blocked IPs per day broken down by category (last 7 days). Empty categories still render as zero series so the legend doesn't churn between renders.
- Reporter detail page's "Recent reports" table and consumer detail page's "Last activity" table now include the `report.received` / `blocklist.requested` audit rows the entity itself emitted, alongside the existing admin-action rows. The "View all in audit log" link points at `/app/audit?subject_kind=…&subject_id=…`, and the audit page shows a banner explaining the subject filter when active.

## [1.0.0] — 2026-05-01

First stable release. Implements every milestone of `SPEC.md` from the
UI side (M8–M10, M12–M14) plus shared concerns from M13.

### Added
- Slim 4 + FrankenPHP BFF on `:8080`. Twig 3 templates, Tailwind CSS 3 (build-time, no CDN), Alpine.js for interactions, htmx for forms, no client-side framework heavier than that.
- OIDC redirect/callback flow against Microsoft Entra ID (authorization code + PKCE, ID-token validation, `groups` claim mapping); local admin login form with Argon2id password validation against `LOCAL_ADMIN_PASSWORD_HASH`.
- PHP-native session manager, file-backed inside the container; CSRF middleware on every state-changing form.
- `ApiClient` (Guzzle) plus `ImpersonationHeaderMiddleware` adding `Authorization: Bearer <UI_SERVICE_TOKEN>` and `X-Acting-User-Id: <user_id>` to every outgoing api call.
- **Pages**:
  - **Dashboard** with Chart.js summaries.
  - **IPs** search/filter table and per-IP detail page with timeline, scores per category, manual/allowlist status, and enrichment.
  - **Subnets / Allowlist** CRUD with confirmation modals on every destructive action.
  - **Policies** editor (category × threshold matrix), live preview of resulting blocklist count, score-distribution chart with threshold-region shading.
  - **Reporters / Consumers** CRUD with last-activity tables; **Tokens** CRUD with raw-token-shown-once modal and copy-to-clipboard.
  - **Categories** editor with linear/exponential decay-curve preview.
  - **Audit log** view, filterable, locale-aware date inputs.
  - **Settings** page: effective config (secrets masked), per-job status with overdue badges, admin-only manual-trigger buttons.
- Light/dark mode toggle persisted in `localStorage`, defaults to system preference.
- Locale-aware date/time rendering: templates emit ISO 8601 UTC inside `<time class="irdb-dt" datetime="…">…</time>` and a small client pass replaces the text after every page load and htmx swap, with `UI_LOCALE` BCP 47 fallback.
- Mobile-responsive sidebar (drawer below `md`).
- Friendly degraded states when the api is briefly unreachable; api-side validation errors surfaced as inline messages rather than raw JSON; toasts for success/failure feedback.
- Login throttling and brute-force lockout on the local admin form.
- Health endpoint (`GET /healthz`) returns 200 even when the api is briefly unreachable, reporting `{status, api_reachable, last_api_check_at}`.
- **Hardening**: security headers (CSP, HSTS, X-Frame-Options, Referrer-Policy), session cookie flagged `SameSite=Lax`/`Secure` in production.

[1.0.0]: https://github.com/your-org/irdb/releases/tag/ui-v1.0.0
