feat(api): on-write search reindex after catalogue writes (#17)

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>
This commit is contained in:
2026-06-02 23:25:43 +02:00
parent c4e0c4c834
commit d15afda9b2
17 changed files with 299 additions and 0 deletions
+8
View File
@@ -234,6 +234,8 @@ pub(crate) async fn create_object(
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
crate::reindex(&state, id).await;
Ok((
StatusCode::CREATED,
Json(CreatedObject { id: id.to_string() }),
@@ -299,6 +301,8 @@ pub(crate) async fn update_object(
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
if existed {
crate::reindex(&state, object_id).await;
Ok(StatusCode::NO_CONTENT)
} else {
Err(StatusCode::NOT_FOUND)
@@ -339,6 +343,8 @@ pub(crate) async fn delete_object(
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
if existed {
crate::reindex(&state, object_id).await;
Ok(StatusCode::NO_CONTENT)
} else {
Err(StatusCode::NOT_FOUND)
@@ -443,6 +449,8 @@ pub(crate) async fn set_fields(
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
crate::reindex(&state, object_id).await;
Ok(StatusCode::NO_CONTENT)
}
Err(db::catalog::FieldError::ObjectNotFound) => Err(StatusCode::NOT_FOUND),