docs/backend-migration/handoffs/M5-outcome.md
feat/m5-static-server-auth-migration32092b8da72dc85cccfe6403f389cc2d8a580c77origin/feat/m4-backend-launcher-migration @ 534fb5fc81281b1d135337a292ad0ee6b215c245origin/feat/backend-migration @ de0c7b87dacecd5ae2385adbe4358eeb78a8ee19 (no new commits to merge)Frozen WebUIConfig Schema (packages/web-host/src/types.ts):
export type WebUIConfig = {
passwordHash: string;
adminUsername: string;
port?: number;
allowRemote?: boolean;
passwordUpdatedAt?: string;
};
Auth Module (packages/web-host/src/auth/):
config.ts: Atomic JSON I/O for webui.config.json (6 tests)session.ts: HMAC-SHA256 signed opaque tokens, cookie name aionui-session (7 tests)rateLimiter.ts: 5 attempts / 15 minutes login rate limiting (6 tests)index.ts: 5 UC-3 APIs implemented:
resetPassword(opts): generates 12-char random password + bcrypt hashchangePassword(opts): verifies old password before rotationverifyPassword(opts): bcrypt compare, returns false on missing configloadConfig(opts) / saveConfig(opts): re-exported from config.tsStatic Server (packages/web-host/src/static-server.ts):
http.createServer + serve-handlerPOST /api/auth/login → local auth (verifyPassword + session + rate-limit)POST /api/auth/logout → local (clears session cookie)/api/* → reverse proxy to backend/ws upgrade → WebSocket proxy to backendindex.htmlTest Files 7 passed (7)
Tests 55 passed (55)
Errors 1 error (M4 legacy: backend-launcher timeout in afterEach cleanup)
Duration ~6.5s
Test breakdown:
Type check: bunx tsc --noEmit ✅ 0 errors
Lint: bun run lint ✅ 0 errors (1351 warnings, all pre-existing)
Dependency boundary: ✅ No electron, @process/, @renderer/ imports in packages/web-host/src/
Status: ⚠️ Deferred to M6 integration validation
Rationale:
packages/desktop/tests/integration/m5-equivalence.test.ts@process/webserver/adapter, UserRepository, getPlatformServicesMitigation:
/api/* reverse proxy/api/auth/login + /api/auth/logoutPOST /api/auth/login:
{ "username": "admin", "password": "..." }200 { "success": true } + Set-Cookie: aionui-session=<token>; HttpOnly; SameSite=strict|lax; Path=/401 { "error": "INVALID_CREDENTIALS" }429 { "error": "RATE_LIMITED" } + Retry-After: <seconds>400 { "error": "BAD_REQUEST" }POST /api/auth/logout:
200 { "success": true } + Set-Cookie: aionui-session=; Max-Age=0Cookie details:
aionui-sessionstrict (local) / lax (remote)/| Legacy (packages/desktop/src/process/) | Web-Host (packages/web-host/src/) |
|---|---|
webserver/index.ts + routes/staticRoutes.ts | static-server.ts |
webserver/auth/service/AuthService.ts | auth/index.ts + auth/session.ts |
webserver/middleware/rateLimiter.ts | auth/rateLimiter.ts |
utils/webuiConfig.ts (I/O部分) | auth/config.ts |
Legacy webserver status: ✅ Completely untouched (20 files, 0 changes)
Desktop bun run webui: Not verified in M5 (deferred to M6 smoke test pre-cutover)
D-01: Password Storage
webui.config.json is now the authoritative source for passwordHash / adminUsername in web-host's worldUserRepository HTTP callspasswordHash as "not initialized" → generates new random password (same as legacy initializeDefaultAdmin)D-02: /api/* Business Routes
/api/* is pure reverse proxy (no multer, no /api/directory, no /api/ppt-proxy)ipcBridge/api 路径行为变化 → M6 plan 负责说明D-03: Vite Dev Proxy
out/renderer/),不关心 Vite devout/renderer/ 时退化为代理 localhost:5173{
"dependencies": {
"bcryptjs": "^2.4.3",
"cookie": "^1.0.2"
},
"devDependencies": {
"@types/bcryptjs": "^3.0.0",
"@types/cookie": "^1.0.0",
"@types/serve-handler": "^6.1.4"
}
}
startWebHost() still throws not-implemented: Plan允许("除非真的需要组装")。M5 不需要完整组装,M6 切换时实现。WebUIConfig schema frozen (no breaking changes allowed)bun run webui / --webui / GUI toggle 调用 startWebHostwebui.config.json 缺 passwordHash,生成新 admin 密码packages/desktop/src/process/webserver/ (20 files)32092b8 fix(m5): use namespace import for cookie to fix type resolution
1d6fd92 test(m5): add equivalence placeholder (points to desktop test)
8abd4f4 test(m5): add equivalence test fixtures (mock backend + renderer stub)
7fcd064 test(m5): cover static-server — SPA, proxy, login, rate-limit, unreachable backend
b040853 chore(m5): re-export static-server + auth cookie/rate-limit constants
4a336d3 feat(m5): implement static-server — SPA + /api proxy + /ws upgrade + local login
c7d443a test(m5): UC-3 full coverage — 5 auth APIs x every scenario
fcdecb2 feat(m5): implement 5 UC-3 auth APIs (reset/change/verify + re-export load/save)
597b9a0 test(m5): cover rate limiter — max attempts, expiry, reset, isolation
3953503 feat(m5): add rate limiter (5 attempts / 15 min) for login endpoint
2c0cb16 test(m5): cover auth/session — creation, tamper, expiry, cookie constants
e3837e9 feat(m5): implement session module (HMAC-signed opaque tokens, legacy cookie name)
139fcb7 test(m5): cover auth/config with 6 scenarios; drop M3 placeholder
f496cee feat(m5): implement auth/config.ts with atomic read/write to webui.config.json
8446825 feat(m5): freeze WebUIConfig schema with optional port/allowRemote fields
72f6af4 chore(m5): add bcryptjs + cookie runtime deps to web-host
8b54eaf chore(m5): expand web-host vitest scan to include tests/ dir
Base: 534fb5fc (M4 backend-launcher)
Executor: executor-m5 (Claude Opus 4.7) Completed: 2026-05-07T23:45 UTC Duration: ~2.5 hours (阶段 0-8 完成; 阶段 9 equivalence 判定 defer; 阶段 10-13 简化)