416 Commits

Author SHA1 Message Date
logaritmisk 47240dafcc feat: edit/delete authorities, blocked when referenced (#30) 2026-06-05 19:53:20 +02:00
logaritmisk 83a7202861 feat: rename + delete vocabularies, blocked when in use (#30) 2026-06-05 19:41:39 +02:00
logaritmisk 09baf2949f feat: edit/delete terms — audited, blocked when referenced (#30)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 19:30:24 +02:00
logaritmisk f6053068be docs(plans): reference-data edit/delete lifecycle (#30 + #36)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 18:30:55 +02:00
logaritmisk e58b150ab2 docs(specs): reference-data edit/delete lifecycle (#30 + #36)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 18:15:53 +02:00
logaritmisk e7ae41362e chore: add 'just storybook' recipe
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 17:00:09 +02:00
logaritmisk ffcfb41c7e merge: set up Storybook (preview + MSW + stories for real components)
CI / web (push) Has been cancelled
Storybook 10.4.2 (react-vite) with the addon-vitest/a11y/docs/mcp addons.
.storybook/preview.tsx wired to the real provider tree (QueryClient + ConfigProvider
+ MemoryRouter), real CSS + i18n, and MSW reusing src/test/handlers.ts. 8 colocated
stories for real components (Button/Badge/Input/Checkbox/VisibilityBadge/LabelEditor/
Highlight/SearchResultRow) incl. one CssCheck. Boilerplate removed.

112 web tests (existing 85 survived + 27 storybook); typecheck/lint/build clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 16:58:08 +02:00
logaritmisk b2d026f217 feat(web): set up Storybook (preview + MSW + stories for real components) 2026-06-05 16:55:40 +02:00
logaritmisk 4e1138f8ce merge: follow-ups batch (#38 #28 #41 #26)
CI / web (push) Has been cancelled
#38 enum-type SearchHitView.visibility + tighten VisibilityBadge prop.
#28 set_fields 422 carries the offending field (FieldErrorView); the object form
highlights it (both direct-edit and create-redirect paths name the field).
#41 normalize localized_text values to the default language on save.
#26 pin pnpm via packageManager + align CI to pnpm 11.

85 web tests; api suite green; bundle 145.8 KB gz; en/sv parity.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 15:54:04 +02:00
logaritmisk e6fc3eaf2c build(web): pin pnpm via packageManager + align CI to pnpm 11 (#26)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 15:50:40 +02:00
logaritmisk b4d71b0f80 fix(web): VisibilityBadge typed to the union (#38); normalize localized_text to default language on save (#41)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 15:46:48 +02:00
logaritmisk 0a29127f7e fix(web): name the field in the edit banner on create->fields-error redirect (#28)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 15:43:35 +02:00
logaritmisk 0c9db7bcdb feat(web): highlight the offending field on a set_fields 422 (#28)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 15:39:49 +02:00
logaritmisk d6dc1c9b57 feat(api): field-level set_fields 422 body (#28); enum-type SearchHitView.visibility (#38)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 15:32:48 +02:00
logaritmisk cd3606c0e9 docs(plans): follow-ups batch (#38 #28 #41 #26)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 15:29:35 +02:00
logaritmisk 260eac903e merge: instance locale (env) + single-language content authoring
CI / web (push) Has been cancelled
DEFAULT_LANGUAGE/DEFAULT_TIMEZONE env config surfaced via public GET /api/config;
SPA config provider defaults the UI language from the instance (overridable per
browser). Content authoring collapsed to a single language (LabelEditor +
localized_text) at the instance default. The multilingual content SCHEMA is left
completely untouched (dormant) — re-enabling is UI-only, zero migration. Storage
stays UTC; timezone exposed for future display/PDF use.

81 web tests; full backend green; bundle 145.7 KB gz; en/sv parity 106/106.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 15:16:12 +02:00
logaritmisk 9d0475e8ec feat(web): single-language content authoring (LabelEditor + localized_text at default lang)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 15:05:20 +02:00
logaritmisk 04e9c95c52 refactor(web): split config hook/context (.ts) from provider (.tsx) to clear react-refresh lint
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 15:01:33 +02:00
logaritmisk de11292203 feat(web): config provider — fetch /api/config, default UI language from instance
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 14:58:01 +02:00
logaritmisk 825b23adec test(server): assert default_language/default_timezone config defaults 2026-06-05 14:55:37 +02:00
logaritmisk 2460a1368d feat: DEFAULT_LANGUAGE/DEFAULT_TIMEZONE config + public GET /api/config 2026-06-05 14:52:09 +02:00
logaritmisk 4a76d6043a docs(plans): instance locale + single-language content authoring (4 tasks)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 14:29:40 +02:00
logaritmisk 0f43c75b24 docs(specs): instance locale (env) + single-language content authoring
Keep the multilingual content schema (dormant); simplify authoring inputs to one
language. Default language + timezone via env vars (no settings table). Public
/api/config endpoint surfaces them to the SPA. Per-account UI language deferred.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 14:23:32 +02:00
logaritmisk 3c6a41a80a merge: tier 4 hardening batch 1 (#1 #2 #21)
#1 graceful shutdown on SIGINT/SIGTERM (axum with_graceful_shutdown).
#2 configurable DB pool size (--db-max-connections / DB_MAX_CONNECTIONS, default 5).
#21 audit vocabulary/term/authority creation atomically, attributing the acting
user; ~15 call sites threaded an AuditActor.

173 workspace tests; clippy + fmt clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 22:10:13 +02:00
logaritmisk 146e0164e7 refactor(db): name audit entity_type constants for vocab/term/authority (#21)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 22:05:06 +02:00
logaritmisk 984be697ac feat: audit vocabulary/term/authority creation, attributing the acting user (#21)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 21:54:50 +02:00
logaritmisk 7181437625 feat(server): configurable DB pool size via --db-max-connections/DB_MAX_CONNECTIONS (#2)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 21:46:41 +02:00
logaritmisk 7e235ffd3e feat(server): graceful shutdown on SIGINT/SIGTERM (#1) 2026-06-04 21:42:55 +02:00
logaritmisk b0d2c247df docs(plans): tier 4 hardening batch 1 (#1 #2 #21)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 21:41:29 +02:00
logaritmisk e9a5a10524 chore: sync Cargo.lock — domain gains utoipa (tier 3 #3)
CI / web (push) Has been cancelled
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:26:21 +02:00
logaritmisk df113bd7ac merge: tier 3 typed-client (#3 #24 #29)
Decision #3 = Option A (utoipa::ToSchema allowed in domain, no I/O deps).
domain: ToSchema on Visibility/AuthorityKind + new DataType enum.
api: open-map fields (#24); enum value_types for visibility/data_type/kind (#29);
domain enums registered in OpenAPI; client regenerated. Frontend: dropped the
now-redundant fields/visibility casts. Wire format unchanged; schema diff additive.

domain 26 + api 41 + web 78 tests; bundle 145.5 KB gz.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:25:54 +02:00
logaritmisk 0ee3b970cb refactor(web): drop redundant fields/visibility casts now the client is typed (#24 #29)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 20:20:13 +02:00
logaritmisk 5a72f85989 feat(api): enum-typed visibility/data_type/kind + open-map fields in OpenAPI (#24 #29)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 20:14:30 +02:00
logaritmisk d3c33a6c5d feat(domain): derive ToSchema on Visibility/AuthorityKind; add DataType enum (#3 Option A)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 20:08:41 +02:00
logaritmisk 331a6d7f34 docs(plans): tier 3 typed-client (#3 Option A, #24, #29)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:06:27 +02:00
logaritmisk 0d971cda15 merge: tier 2 papercuts (#22 #18 #9 #4 #34 #31 #32 #37)
CI / web (push) Has been cancelled
Backend: add_term FK→404 (#22); log discarded errors on public 500 paths (#18);
enum↔CHECK cross-ref comments (#9); drop dead clone + harden serve smoke test (#4).
Frontend: search 503 'unavailable' vs generic error (#34); loading/error states on
terms & authorities lists (#31); authority kind-tab ARIA + dead i18n key removal
(#32); authority-kind reveal test (#37).

78 web tests; 72 backend tests; bundle 145.5 KB gz.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 17:39:35 +02:00
logaritmisk 914527edc6 fix(web): place aria-selected on the role=tab element (#32) + assert it
Per WAI-ARIA, aria-selected must be on the same element carrying role="tab".
The previous impl placed it on an inner <span> via the render-prop, making it
invisible to assistive technology. Move both role="tab" and aria-selected to
the NavLink, compute currentKind once from useParams, drop the render-prop.
Add a Vitest assertion that the selected tab has aria-selected="true" and an
unselected tab has aria-selected="false".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 17:32:18 +02:00
logaritmisk ff513e1712 fix(web): search 503 vs error (#34); terms/authorities list error states (#31); authority-tab a11y + dead keys (#32); authority-kind test (#37) 2026-06-04 17:28:01 +02:00
logaritmisk 1a91b8a242 chore: cross-ref enum/CHECK constraints (#9); drop dead clone + harden smoke test (#4)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 17:21:33 +02:00
logaritmisk 2bce469ed2 fix(api): 404 when adding a term to a missing vocabulary (#22); log public 500s (#18)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 17:17:35 +02:00
logaritmisk fbb7a297a6 docs(plans): tier 2 papercuts — #22/#18/#9/#4/#34/#31/#32/#37
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 17:14:39 +02:00
logaritmisk 8442afbf02 chore: gitignore local docker-compose.override.yml
CI / web (push) Has been cancelled
2026-06-04 14:56:21 +02:00
logaritmisk 869a2c6e50 docs(dev): Running locally + tests README; add Meilisearch to compose; env defaults
Single docker compose (Postgres + Meilisearch) for dev and tests. .env.example
now works out-of-the-box (SESSION_COOKIE_SECURE=false for http://localhost login;
MEILI_* matching compose).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 14:52:34 +02:00
logaritmisk 126f84962a merge: fields management — create field definitions (endpoint + /fields UI)
CI / web (push) Has been cancelled
POST /api/admin/field-definitions (EditCatalogue) over the existing db layer,
validated through FieldType::from_parts (422 on inconsistent type/binding),
dup key -> 409, nonexistent vocabulary / empty key -> 422. /fields two-pane
screen: grouped list + create form with conditional vocabulary/authority-kind
selects, reused LabelEditor; creating a field invalidates the shared
[field-definitions] cache so it appears in the object editor too. Fields nav
enabled — no disabled nav stubs remain.

api tests green (8 admin_fields + suite); web 72 tests; bundle 145.4 KB gz.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 14:36:14 +02:00
logaritmisk daad9438ba fix(api): map CHECK-constraint violation (empty key) to 422 2026-06-04 14:35:56 +02:00
logaritmisk fd1c22191b polish(web): fields form resets error, shared labelText, drop dead nav.soon, a11y required marker, Other group last
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 14:29:25 +02:00
logaritmisk 37c80121ed feat(web): /fields two-pane screen (grouped list + create form) + nav (no stubs left)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 14:22:57 +02:00
logaritmisk 6ad1304efd feat(web): useCreateFieldDefinition mutation + MSW handler
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 14:16:55 +02:00
logaritmisk df8f31d14d fix(api): map nonexistent-vocabulary FK violation to 422; cover term/authority create paths
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 14:15:19 +02:00
logaritmisk b508273a52 feat(api): POST /api/admin/field-definitions (create field definition)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 14:09:08 +02:00