feat: 完成v1.3.0架构对齐与Web端根路径托管全量开发

- 重构架构:抽离AddCloudSyncServer到扩展类,补全中间层文档对齐
- 修复根路径404与鉴权跳转:新增中间件处理浏览器请求302跳转
- 实现种子数据初始化:添加默认管理员账号自动创建逻辑
- 优化前端代理与构建:新增Vite代理配置与自动构建Target
- 补全测试与文档:新增集成测试,更新开发与部署文档
This commit is contained in:
ShaoHua
2026-08-08 07:33:44 +08:00
parent 4fe0b5a963
commit 3213d4c718
32 changed files with 1937 additions and 86 deletions
+88 -28
View File
@@ -10,45 +10,101 @@
| 项目 | 类型 | 职责 | 平台 |
|---|---|---|---|
| [Hua.Todo.Core](file:///d:/Proj/6.Hua.Todo/src/Hua.Todo.Core) | 类库 | 领域实体、仓储接口(`TaskEntity`、`UserEntity`、`SecurityPolicyEntity`、`AuditLogEntity`、`ITaskRepository` 等) | netstandard / net |
| [Hua.Todo.Application](file:///d:/Proj/6.Hua.Todo/src/Hua.Todo.Application) | 类库(共享层) | EF Core `TodoDbContext`、`TaskService`/`TaskRepository`、动态 API(`DynamicApi/`)、云同步(`CloudSync/`)、迁移 | net |
| [Hua.Todo.Host](file:///d:/Proj/6.Hua.Todo/src/Hua.Todo.Host) | ASP.NET 服务端 | 独立服务端宿主,承载本地动态 API + 云同步端点 + Admin 管理后台静态资源 | Windows/Linux 等服务器 |
| [Hua.Todo.Application](file:///d:/Proj/6.Hua.Todo/src/Hua.Todo.Application) | 类库(共享层) | EF Core `TodoDbContext`、`TaskService`/`TaskRepository`、CloudSync 业务服务(`Application/Services/CloudSync/`)、动态 API 属性层、迁移 | net |
| [Hua.Todo.HttpApi.AspNetCore](file:///d:/Proj/6.Hua.Todo/src/Hua.Todo.HttpApi.AspNetCore) | 类库(ASP.NET Core 专属 HTTP 层) | 承载依赖 ASP.NET Core 的实现:DynamicApiMiddleware、Mcp Server 端点、云同步服务端 DI(SessionAuthenticationHandler、CloudSyncServerService) | net(依赖 `Microsoft.AspNetCore.App` 共享框架) |
| [Hua.Todo.Host](file:///d:/Proj/6.Hua.Todo/src/Hua.Todo.Host) | ASP.NET 服务端 | **Host 双角色统一部署**:(1) Web 端前端/后端同源部署(承载前端静态资源 + Dynamic API + Swagger + MCP);(2) 云同步权威服务端(供 MAUI/Avalonia 的 CloudSyncProxy 转发);不区分模式 | Windows/Linux 等服务器 |
| [Hua.Todo.Maui](file:///d:/Proj/6.Hua.Todo/src/Hua.Todo.Maui) | MAUI 客户端 | Windows / macOS / iOS / Android 入口;内嵌 WebServer + WebView 承载 Vue 前端 | 多端 |
| [Hua.Todo.Avalonia](file:///d:/Proj/6.Hua.Todo/src/Hua.Todo.Avalonia) | Avalonia 客户端 | Linux / Windows 桌面入口;内嵌 WebServer + `WebView.Avalonia` 承载 Vue 前端 | 桌面(含 Linux) |
| [Hua.Todo.Web](file:///d:/Proj/6.Hua.Todo/src/Hua.Todo.Web) | Vite + Vue 3 前端 | 同一份前端构建产物,被多个宿主以静态资源形式承载 | 浏览器/WebView |
## 二、依赖方向(必须保持单向)
> 本图为 2026-08-08 v1.3.0 工单 05 更新版(代码对齐时间戳)。后续修改架构章节时,必须更新本标记并走 Glob/Grep 校验(详见 v1.3.0 00-工单总览 §5「架构文档 ↔ 代码一致性强制策略」)。
```
Hua.Todo.Core
↑
Hua.Todo.Application
↑
├── Hua.Todo.Host (服务端注册 AddCloudSyncServer + 动态 API)
├── Hua.Todo.Maui (客户端,仅注册 AddApplicationServices)
└── Hua.Todo.Avalonia (客户端,仅注册 AddApplicationServices)
Hua.Todo.Core (无依赖)
↑ 单向引用
Hua.Todo.Application (依赖 Core)
↑ 单向引用
Hua.Todo.HttpApi.AspNetCore (依赖 Application;依赖 Microsoft.AspNetCore.App 共享框架)
↑ 单向引用
├── Hua.Todo.Host (注册 AddApplicationServices + AddCloudSyncServer + AddMcpServerServices)
├── Hua.Todo.Maui (仅引用 Application + HttpApi.AspNetCore 的 CloudSyncProxy 子模块;不引用 AddCloudSyncServer)
└── Hua.Todo.Avalonia (同上,仅嵌入式 + CloudSyncProxy)
Hua.Todo.Web (无 .NET 依赖;通过 HTTP/同源调用上述任一宿主)
```
- **禁止反向依赖**:Core 不得引用 Application;Application 不得引用任何宿主项目。
- **客户端不暴露云同步端点**:MAUI / Avalonia 只调用 `AddApplicationServices()`,不调用 `AddCloudSyncServer()`,详见 [docs/project/研发工单-v1.2.0/08-cloud_sync_refactor_plan.md](../../../docs/project/研发工单-v1.2.0/08-cloud_sync_refactor_plan.md)。
- **禁止反向依赖**:Core 不得引用 Application;Application 不得引用 HttpApi.AspNetCore / 任何宿主;HttpApi.AspNetCore 不得引用宿主项目。
- **MAUI / Avalonia 不得注册 AddCloudSyncServer**:只注册 `AddApplicationServices()` + `AddCloudSyncProxy()`,权威云同步端点只在 Host 暴露。
- **MAUI / Avalonia 跨层引用边界**:只引用 HttpApi.AspNetCore 中与嵌入式相关的类型(CloudSyncProxyMiddleware、CloudSyncProxySettings 等),不引用 CloudSyncServerService 等 Host-only DI 扩展(实际通过命名空间自然隔离)。
## 三、两种运行模式
### 模式 A:嵌入式(MAUI / Avalonia + WebView)
- 启动内嵌 Kestrel WebServer(默认端口 5057),托管 Vue 前端的静态产物(`wwwroot/`)+ 本地 `/api/*`
- WebView 加载 `HostUrl`(生产)或 `ForEndUrl`(开发,例如 Vite dev server)
- 注入:`window.__API_BASE_URL__ = "${HostUrl}/api"`、`window.mauiInterop`
- 默认 SQLite 路径:`LocalApplicationData/Hua.Todo/Hua.Todo.db`(避免安装目录无写权限)
- 不暴露云同步端点;登录/同步走外部 Host
### 端口对照表(全局统一,禁止硬编码歧义值)
### 模式 B:独立服务端(Hua.Todo.Host)
- 独立部署的 ASP.NET 应用,端口 `:5173`(Vite proxy 目标)
- 同时注册 `AddApplicationServices()` + `AddCloudSyncServer()`,对外提供:
- `/api/*`:本地任务 API(动态 API)
- `/auth/*`、`/tasks/*`、`/sync`、`/security/policy`、`/cloud-sync/probe`:云同步端点
- `/admin/*`:管理后台前端静态资源
- 数据库:`src/Hua.Todo.Host/Hua.Todo.db`(开发/测试用)
| 端口 | 用途 | 所属模式 | 说明 |
|---|---|---|---|
| `:5057` | 嵌入式 Kestrel WebServer(HTTP) | 嵌入式 | MAUI / Avalonia 内嵌;Vite proxy 默认 target |
| `:5173` | Web 端 ASP.NET(HTTP) | Web 端 | 前端云同步默认填写的服务器地址;Host `Program.cs.UseUrls` 显式绑定 |
| `:7055` | Web 端 ASP.NET(HTTPS) | Web 端 | 开发环境可选;生产由反向代理(Nginx/Caddy)统一 TLS 终止 |
| `:5174` | Vite dev server(开发) | 两者均可 | WebView / 浏览器开发调试入口;`.env.development` 使用 |
### 模式 A:嵌入式(MAUI / Avalonia + WebView)
> 桌面/移动原生客户端,**数据先存本地 SQLite(本地缓存)**,再按需与 Web 端同步。
**请求链路(前端 → 本地 → 远端)**:
```
WebView(Hua.Todo.Web)
├─ 本地 Todo 操作(增删改查) → 同源 /api/task* 等动态 API
│ → EmbeddedWebServerService(:5057)
│ → UseDynamicApi
│ → ITaskService / TaskRepository
│ → 本地 SQLite(Hua.Todo.db)
└─ 云同步操作(探测 / 登录 / 拉取 / 推送 / 策略)
→ 同源 /api/auth、/api/tasks、/api/cloud-sync/*、/api/security/*
→ EmbeddedWebServerService(:5057)
→ UseCloudSyncProxy(CloudSyncProxyMiddleware)
→ 后端 HttpClient 转发到「用户配置的 Web 端地址」(例 http://localhost:5173)
→ Web 端 Hua.Todo.Host 的动态 API 做鉴权与同步
```
**关键规则**:
- 启动内嵌 Kestrel WebServer(端口 `:5057`),生产托管 Vue 前端静态产物(`wwwroot/`),开发加载 Vite dev server(`ForEndUrl=http://localhost:5174`)
- 注入:`window.__API_BASE_URL__ = "${HostUrl}/api"`(HostUrl=`http://localhost:5057`)、`window.mauiInterop`
- DI 只注册 `AddApplicationServices()` + `AddCloudSyncProxy()`,**不注册 `AddCloudSyncServer()`**:嵌入式端不做用户管理、不暴露云同步的权威端点
- 默认 SQLite 路径:`LocalApplicationData/Hua.Todo/Hua.Todo.db`(避免安装目录无写权限)
- 本地用户 ID 固定为 `TodoUserIds.LocalUserId = "local"`,与云端用户隔离
### 模式 B:Web 端(Hua.Todo.Host,部署入口)= **Host 双角色统一部署**
> ⚠️ Host 部署时不区分模式:
> - **对外角色**:用户浏览器直接访问 Host(`http://host-address:5173/`)→ 即"Web 端前端 + 后端同源部署"
> - **对内角色**:同时承担"云同步权威服务端"职责,接受 MAUI/Avalonia 嵌入式客户端通过 CloudSyncProxy 转发 `/api/*` 过来的请求
>
> 因此 `Hua.Todo.Host/Program.cs` 必须同时注册:`AddApplicationServices` + `AddCloudSyncServer` + `AddMcpServerServices`。
>
> 独立部署的 ASP.NET 服务端,既是**后端接口服务**,也是**前端静态站点托管**,部署产物是单个 `Hua.Todo.Host` 进程。
**端点划分(四个逻辑入口,同一进程)**:
| URL 前缀 | 内容 | 来源 |
|---|---|---|
| `/`(根路径及所有 SPA 路由) | **Hua.Todo.Web 用户前端**(登录后 Todo 列表) | `src/Hua.Todo.Web` 的 `dist/` 构建产物复制到 `Hua.Todo.Host/wwwroot/`;若缺失则由 `MinimalBootstrapPageMiddleware` 返回最小引导页(中文错误提示 + 构建命令,不 404) |
| `/api/*` | **动态 API**(本地+云同步共用的一套接口) | `Hua.Todo.Application/DynamicApi` 扫描所有 `IDynamicApiService` 自动暴露(task / auth / tasks / security / cloud-sync / admin / voice)。权限检查时,浏览器 HTML 直访 Accept:text/html → 302 跳 `/`(前端接管登录弹窗);其他 API 请求(JSON)→ 401/403 JSON 错误 |
| `/mcp` | **MCP Server 端点**(Streamable HTTP) | `McpEndpointExtensions.cs` 映射,供 MCP 客户端调用 |
| `/swagger` + `/admin/*` | **Swagger UI** + **管理后台前端**(用户管理、审计、策略) | Swagger:开发环境启用;Admin:`Hua.Todo.Host/wwwroot/admin/`(当前占位,后续 Vue 3 构建产物填入) |
**关键规则**:
- 同时注册 `AddApplicationServices()` + `AddCloudSyncServer()`(后者额外注册 `IPasswordHasher<UserEntity>`、云同步动态 API、安全策略校验器等)
- 中间件顺序必须严格遵守(见 `00-工单总览.md` §5):Swagger → MinimalBootstrapPageMiddleware → UseDefaultFiles/UseStaticFiles → CORS → Authentication → Authorization → UseDynamicApi → MapMcpServer → MapFallbackToFile → Run
- 端口:HTTP `:5173` + HTTPS `:7055`,`Program.cs` 显式 `UseUrls` 绑定
- 开发环境**不启用 `UseHttpsRedirection`**(由反向代理统一做 TLS 终止),避免前端 axios 把 307 当错误
- 数据库:开发/测试使用 `src/Hua.Todo.Host/Hua.Todo.db`(SQLite);生产可切换其他后端
## 四、跨平台原则
@@ -60,11 +116,15 @@ Hua.Todo.Web (无 .NET 依赖;通过 HTTP/同源调用上述任一宿主)
| 扩展点 | 位置 |
|---|---|
| DI 注册总入口 | [Hua.Todo.Application/ServiceCollectionExtensions.cs](file:///d:/Proj/6.Hua.Todo/src/Hua.Todo.Application/ServiceCollectionExtensions.cs) |
| 云同步 DI | `Hua.Todo.Application/CloudSync/CloudSyncServiceCollectionExtensions.cs` |
| 云同步端点 | `Hua.Todo.Application/CloudSync/CloudSyncEndpointExtensions.cs` |
| 动态 API 中间件 | `Hua.Todo.Application/DynamicApi/DynamicApiMiddleware.cs` |
| DI 注册总入口 | `Hua.Todo.Application/Common/ServiceCollectionExtensions.cs`(`AddApplicationServices`) |
| 云同步服务端 DI(Host 专用) | `Hua.Todo.HttpApi.AspNetCore/CloudSync/CloudSyncServiceCollectionExtensions.cs`(`AddCloudSyncServer`) |
| 云同步代理 DI / 中间件(嵌入式) | `Hua.Todo.Application/Services/CloudSync/Services/CloudSyncProxyService.cs`(`AddCloudSyncProxy` / `UseCloudSyncProxy`) |
| 云同步代理设置端点(嵌入式) | `Hua.Todo.Application/Services/CloudSync/Services/ICloudSyncProxySettingsService`(继承 `IDynamicApiService`,由 DynamicApi 自动暴露;仅在 AddCloudSyncProxy 时注册 DI) |
| 云同步接口(auth/tasks/security/admin/cloud-sync probe) | `Hua.Todo.Application/Services/CloudSync/Services/ICloud*Service` 实现 `IDynamicApiService`,由 DynamicApi 自动暴露 |
| 动态 API 中间件 + 路由/权限 | `Hua.Todo.HttpApi.AspNetCore/DynamicApi/DynamicApiMiddleware.cs`(含 `DynamicApiRouteAttribute` / `RequirePermissionAttribute`) |
| MCP Server(工具描述符自动生成 + 端点) | `Hua.Todo.HttpApi.AspNetCore/Mcp/DynamicMcpToolExtensions.cs` + `McpServiceCollectionExtensions.cs`(DI 注册 `AddMcpServerServices`) + `McpEndpointExtensions.cs`(端点 `MapMcpServer`) |
| 嵌入式 WebServer | `Hua.Todo.{Maui,Avalonia}/Services/EmbeddedWebServerService.cs` |
| 种子数据初始化器(Web 端 DB Migrate 后) | `Hua.Todo.Application/Services/DataSeeder/IDataSeeder`(仅在 `AddCloudSyncServer` 时注册) |
| 全局快捷键平台实现 | `Hua.Todo.{Maui,Avalonia}/Services/Platforms/*GlobalHotKeyService.cs` |
## 六、版本统一策略