diff --git a/backend/app/routers/search.py b/backend/app/routers/search.py
new file mode 100644
index 0000000..a2d3d2b
--- /dev/null
+++ b/backend/app/routers/search.py
@@ -0,0 +1,11 @@
+from fastapi import APIRouter, Depends
+
+from app.dependencies import get_search_client
+from app.search_client import SearchClient
+
+router = APIRouter()
+
+
+@router.get("/api/search")
+def search(q: str = "", client: SearchClient = Depends(get_search_client)):
+ return {"results": client.search(q)}
diff --git a/backend/tests/test_routers_search.py b/backend/tests/test_routers_search.py
new file mode 100644
index 0000000..41bc0c1
--- /dev/null
+++ b/backend/tests/test_routers_search.py
@@ -0,0 +1,52 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from app.main import app
+from app.dependencies import get_search_client
+
+
+class FakeSearchClient:
+ def __init__(self):
+ self.queries = []
+
+ def search(self, query):
+ self.queries.append(query)
+ if query == "检索":
+ return [
+ {
+ "key": "产品文档/架构设计.md",
+ "title": "架构设计.md",
+ "path": "产品文档",
+ "snippet": "支持全文检索功能",
+ }
+ ]
+ return []
+
+
+@pytest.fixture
+def client():
+ fake_client = FakeSearchClient()
+ app.dependency_overrides[get_search_client] = lambda: fake_client
+ with TestClient(app) as test_client:
+ test_client.fake_client = fake_client
+ yield test_client
+ app.dependency_overrides.clear()
+
+
+def test_search_returns_matching_results(client):
+ response = client.get("/api/search", params={"q": "检索"})
+ assert response.status_code == 200
+ body = response.json()
+ assert body["results"][0]["key"] == "产品文档/架构设计.md"
+ assert "检索" in body["results"][0]["snippet"]
+
+
+def test_search_returns_empty_results_for_no_match(client):
+ response = client.get("/api/search", params={"q": "不存在的关键词"})
+ assert response.status_code == 200
+ assert response.json() == {"results": []}
+
+
+def test_search_passes_query_string_to_search_client(client):
+ client.get("/api/search", params={"q": "MinIO"})
+ assert client.fake_client.queries == ["MinIO"]