feat: 增加项目管理功能
引入 SQLite 数据库(Drizzle ORM + bun:sqlite),实现项目 CRUD 与归档/恢复/删除 生命周期管理,新增项目管理前端页面,migration 嵌入单文件构建产物保持部署体验。 - src/server/db: schema、connection、migration 执行器、项目数据访问层 - src/server/routes/projects: 7 个 API 端点(列表/创建/详情/更新/归档/恢复/删除) - src/web: 项目管理页面(TDesign Table/Tabs/Dialog/Form),TanStack Query hooks - scripts: 构建时嵌入 migration SQL,开发期独立 generate-migrations-data 脚本 - tests: 60 个后端测试 + 27 个前端测试,覆盖 DB/migration/API/路由/页面 - docs: 更新架构、后端、发布、配置、部署、使用文档
This commit is contained in:
60
tests/server/bootstrap-db.test.ts
Normal file
60
tests/server/bootstrap-db.test.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
/* eslint-disable @typescript-eslint/no-empty-function, @typescript-eslint/require-await */
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { mkdirSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
|
||||
import type { ResolvedConfig } from "../../src/server/config/types";
|
||||
|
||||
import { bootstrap, type BootstrapDependencies } from "../../src/server/bootstrap";
|
||||
import { createMemoryLogger } from "../../src/server/logger";
|
||||
|
||||
function makeTempConfig(overrides: Partial<ResolvedConfig> = {}): ResolvedConfig {
|
||||
const base = join(tmpdir(), `bootstrap-db-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
||||
mkdirSync(base, { recursive: true });
|
||||
return {
|
||||
configDir: base,
|
||||
dataDir: join(base, "data"),
|
||||
host: "127.0.0.1",
|
||||
logging: {
|
||||
consoleLevel: "info",
|
||||
fileLevel: "info",
|
||||
filePath: join(base, "data", "logs", "test.log"),
|
||||
rotationFrequency: "daily",
|
||||
rotationMaxFiles: 14,
|
||||
rotationSizeBytes: 52428800,
|
||||
rotationSizeRaw: "50MB",
|
||||
},
|
||||
port: 0,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("bootstrap 数据库集成", () => {
|
||||
test("启动时将数据库传递给 startServer", async () => {
|
||||
let started = false;
|
||||
let receivedDb: unknown = undefined;
|
||||
|
||||
const cfg = makeTempConfig();
|
||||
const mockLoadConfig = (async () => cfg) as unknown as BootstrapDependencies["loadConfig"];
|
||||
const mockOnSignal = (_signal: string, _handler: () => void) => {};
|
||||
const mockStartServer = (options: { db: unknown }) => {
|
||||
receivedDb = options.db;
|
||||
started = true;
|
||||
return { close: () => {} };
|
||||
};
|
||||
|
||||
const deps: BootstrapDependencies = {
|
||||
createLogger: async () => createMemoryLogger(),
|
||||
loadConfig: mockLoadConfig,
|
||||
onSignal: mockOnSignal,
|
||||
startServer: mockStartServer,
|
||||
};
|
||||
|
||||
await bootstrap({ configPath: join(cfg.configDir, "config.yaml"), mode: "production" }, deps);
|
||||
|
||||
expect(started).toBe(true);
|
||||
expect(receivedDb).not.toBeUndefined();
|
||||
expect(typeof (receivedDb as { close?: unknown }).close).toBe("function");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user