1
0

refactor: 全面优化后端代码质量与架构

- app.ts 单体路由拆分为 routes/ + helpers + middleware + static 独立模块
- 类型去重:CheckFailure/CheckResult 以 shared/api.ts 为唯一源头,收紧 phase 联合类型
- es-toolkit 替换:isPlainObject/isNil/isEmptyObject/isEqual/isError/Semaphore/groupBy
- Bun 内置 API:Object.fromEntries 替代手写 headersToRecord
- bun:sqlite 规范:prepare() → query() 利用内置缓存,避免 N+1 查询
- 新增 getLatestChecksMap/allGetTargetStats 批量查询方法
- 新增 backend-code-quality/api-route-separation/batch-data-queries 规范
- 补充 openspec/config.yaml 后端开发规范与 DEVELOPMENT.md 后端开发指引
This commit is contained in:
2026-05-12 15:15:36 +08:00
parent 696db6ffb5
commit f7facb7232
24 changed files with 868 additions and 368 deletions

View File

@@ -297,4 +297,75 @@ describe("ProbeStore", () => {
cascadeStore.close();
});
test("getLatestChecksMap 返回所有 target 的最新 check", () => {
const targets = store.getTargets();
const map = store.getLatestChecksMap();
expect(map).toBeInstanceOf(Map);
for (const target of targets) {
const latest = map.get(target.id);
if (latest) {
expect(latest.target_id).toBe(target.id);
}
}
});
test("getLatestChecksMap 对无记录的 target 不包含 key", () => {
const freshStore = new ProbeStore(join(tempDir, "fresh-map.db"));
freshStore.syncTargets([
{
type: "http",
name: "no-records",
group: "default",
http: { url: "http://no.records", method: "GET", headers: {}, maxBodyBytes: 104857600 },
intervalMs: 30000,
timeoutMs: 10000,
},
]);
const map = freshStore.getLatestChecksMap();
expect(map.size).toBe(0);
freshStore.close();
});
test("getAllTargetStats 返回所有 target 的聚合统计", () => {
const targets = store.getTargets();
const t1Id = targets[0]!.id;
const t2Id = targets[1]!.id;
const stats = store.getAllTargetStats();
expect(stats).toBeInstanceOf(Map);
const stats1 = stats.get(t1Id);
expect(stats1).toBeDefined();
expect(stats1!.totalChecks).toBeGreaterThan(0);
expect(stats1!.availability).toBeGreaterThanOrEqual(0);
const stats2 = stats.get(t2Id);
if (stats2) {
expect(stats2!.totalChecks).toBe(0);
expect(stats2!.availability).toBe(0);
}
});
test("getAllTargetStats 对无记录的 target 不包含 key", () => {
const freshStore = new ProbeStore(join(tempDir, "fresh-stats.db"));
freshStore.syncTargets([
{
type: "http",
name: "no-stats",
group: "default",
http: { url: "http://no.stats", method: "GET", headers: {}, maxBodyBytes: 104857600 },
intervalMs: 30000,
timeoutMs: 10000,
},
]);
const stats = freshStore.getAllTargetStats();
expect(stats.size).toBe(0);
freshStore.close();
});
});