chore: 收口 review 执行清单与 runtime 验证

- 补齐 design/10-review 执行清单、验收标准与相关设计治理记录

- 迁移已完成的 tree、mindmap、runtime fallback、AI kernel 等设计和缺陷条目

- 推进 Rust Web runtime、tree/sidebar、page aggregate、mindmap 与 OnlyOffice 路由侧验证支撑

- 增加 task177-task180 smoke/audit 脚本及前端相关测试覆盖
This commit is contained in:
lix-2026
2026-05-14 05:52:08 +08:00
parent b4a452a8b7
commit 96e03645f7
69 changed files with 4780 additions and 979 deletions
+65 -1
View File
@@ -175,6 +175,8 @@ pub async fn documents(
"owner": "mnote-web",
"projectionOwner": result.get("projectionOwner").cloned().unwrap_or_else(|| json!("rust-kernel")),
"queryName": "search.documents.query",
"degraded": result.get("degraded").cloned().unwrap_or_else(|| json!(false)),
"degradedReason": result.get("degradedReason").cloned().unwrap_or(Value::Null),
"requestId": context.trace.request_id,
"traceId": context.trace.trace_id,
},
@@ -239,12 +241,13 @@ async fn load_search_results_with_filters(
.await
{
Ok(value) => Ok(value),
Err(_) => execute_runtime_query_against_data(
Err(_) if config.allow_dev_fixtures => execute_runtime_query_against_data(
context,
Some(workspace_id),
runtime_query,
fallback_search_dataset(workspace_id),
),
Err(error) => Ok(degraded_empty_search_projection(error.message())),
}
}
@@ -256,6 +259,16 @@ fn empty_search_projection() -> Value {
})
}
fn degraded_empty_search_projection(reason: &str) -> Value {
json!({
"enqueueAssetIds": [],
"projectionOwner": "rust-kernel",
"results": [],
"degraded": true,
"degradedReason": reason,
})
}
fn fallback_search_dataset(workspace_id: &str) -> Value {
json!({
"documents": [
@@ -413,6 +426,8 @@ mod tests {
assert!(html.contains("search.documents.query"));
assert!(html.contains("search-result"));
assert!(html.contains("Rust Web 搜索结果"));
assert!(html.contains("data-mnote-dev-fixture=\"true\""));
assert!(html.contains("data-mnote-dev-fixture-kind=\"sidebar-tree\""));
}
#[tokio::test]
@@ -467,4 +482,53 @@ mod tests {
assert_eq!(payload["meta"]["projectionOwner"], "rust-kernel");
assert_eq!(payload["projectionOwner"], "rust-kernel");
}
#[tokio::test]
async fn search_documents_does_not_return_builtin_fixture_when_convex_unavailable() {
let app = build_app(AppState::new(AppConfig {
service_name: "mnote-web".into(),
service_version: "0.1.0".into(),
bind_addr: "127.0.0.1:0".into(),
public_bind_addr: "127.0.0.1:3000".into(),
legacy_next_base_url: Some("http://127.0.0.1:3100".into()),
enable_legacy_next_compat: true,
enable_debug_shell_routes: false,
hermes_base_path: "/api/hermes".into(),
compat_next_base_path: "/api/compat/next".into(),
convex_url: None,
convex_admin_key: None,
allow_dev_fixtures: false,
query_fixtures_json: None,
mutation_fixtures_json: None,
dev_user_id: "dev-user".into(),
dev_user_name: "开发用户".into(),
dev_user_email: "dev@mnote.local".into(),
}));
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/api/search/documents")
.header("content-type", "application/json")
.body(Body::from(
json!({
"workspaceId": "ws_demo",
"query": "Hermes"
})
.to_string(),
))
.expect("request"),
)
.await
.expect("response");
assert_eq!(response.status(), StatusCode::OK);
let body = to_bytes(response.into_body(), usize::MAX)
.await
.expect("body");
let payload: Value = serde_json::from_slice(&body).expect("json");
assert_eq!(payload["results"], json!([]));
assert_eq!(payload["meta"]["degraded"], true);
assert!(!payload.to_string().contains("Hermes 技能知识图谱开发"));
}
}