Two-pane vocab (list/create + terms/add) + kind-tabbed authorities
(list/create); shared sv/en LabelEditor; create+list only (no backend
edit/delete yet); 4 new hooks; enables the nav stubs; Vitest+RTL+MSW.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lazy-load ObjectNewPage and ObjectEditForm routes to bring the initial
JS bundle under the 150 KB gz budget (was 159 KB, now 140 KB).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds `memory-serve` 2.1 as an optional workspace dependency, a `build.rs`
that runs `load_directory` only when `CARGO_FEATURE_EMBED_WEB` is set, a
`web_assets` module serving `web/dist` at `/` with SPA fallback (200 OK)
for unknown client-side routes, and a feature-gated integration test.
The default build (no feature) compiles and tests cleanly without `web/dist`.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add shadcn input/label/card primitives and implement the login page:
email/password form using useLogin, navigates to /objects on success,
shows inline i18n error on 401 (auth.invalid) or network failure.
2 new tests, 9 total green.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Installs @tanstack/react-query and react-router-dom; adds typed query
hooks (useMe, useObjectsPage, useObject, useFieldDefinitions, useLogin,
useLogout), a QueryClient+MemoryRouter test render helper, and
RequireAuth — a layout route that blocks unauthenticated access and
redirects to /login. All 7 tests pass, typecheck/lint/build clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bootstraps the web/ SPA: Vite 6 + React 19 + TypeScript 5.8, Vitest
with jsdom, @testing-library/react, and a green smoke test asserting
the App renders its Collection heading.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Preserves the documented set-to-current idempotent no-op: re-setting an
already-public object's visibility no longer rejects when a required field
was introduced after publish. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
set_visibility now gates the transition to Public: every field definition
with required=true must have a value on the object (typed inventory-minimum
columns are already NOT NULL, so only flexible required fields are checked).
Missing values yield VisibilityError::MissingRequiredFields(keys); the admin
publish endpoint maps it to 422. The gate runs in db so every caller is
protected and the check is atomic with the transition.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire best-effort Meilisearch index sync into the admin write paths
(create/update/delete/set_fields/set_visibility). Adds
SearchClient::sync_object (reindex if the object exists, remove if gone —
one uniform path), an optional AppState.search client, and a reindex
helper that logs failures via tracing without failing the committed
write. Server gains MEILI_URL/MEILI_MASTER_KEY/MEILI_INDEX config;
search stays disabled (no-op) when unset. reindex_all remains the
recovery path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GET/POST /api/admin/vocabularies and GET/POST /api/admin/vocabularies/{id}/terms;
reads gated on ViewInternal, writes on EditCatalogue; labels round-trip verified.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>