The binary now reads a .env file itself (dotenvy::dotenv() at the top of main),
so 'cargo run -p server' / the release binary pick up config without relying on
just's 'set dotenv-load'. Missing .env is a no-op.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Expose full-text search over catalogue objects via a new admin endpoint
backed by the Meilisearch SearchClient. Validates visibility filter values,
short-circuits on empty queries, clamps pagination, and returns 503 when
search is not configured. Registered in OpenAPI; schema.d.ts regenerated.
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>
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>
- GET /api/admin/field-definitions (ViewInternal) — lists all registered
field definitions with key, data_type, vocabulary_id, authority_kind,
required, group, and localized labels
- PUT /api/admin/objects/{id}/fields (EditCatalogue) — replaces an
object's flexible-field values with replace semantics; validates every
key against the registry (UnknownField → 422, TypeMismatch → 422,
Unresolved → 422, ObjectNotFound → 404, Db → 500)
- FieldDefinitionView DTO added; both handlers registered in OpenAPI
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
POST /api/admin/objects (draft|internal only; public rejected 422),
PUT /api/admin/objects/{id} (preserves visibility; 204/404),
DELETE /api/admin/objects/{id} (204/404). Every write records
AuditActor::User(<session-user-uuid>). Tests: lifecycle, public-rejection,
unauthenticated-rejection.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>