Files
Hua.Todo/.trae/rules/项目/01-项目架构.md
T
ShaoHua 3213d4c718 feat: 完成v1.3.0架构对齐与Web端根路径托管全量开发
- 重构架构:抽离AddCloudSyncServer到扩展类,补全中间层文档对齐
- 修复根路径404与鉴权跳转:新增中间件处理浏览器请求302跳转
- 实现种子数据初始化:添加默认管理员账号自动创建逻辑
- 优化前端代理与构建:新增Vite代理配置与自动构建Target
- 补全测试与文档:新增集成测试,更新开发与部署文档
2026-08-08 07:33:44 +08:00

165 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 项目架构(Hua.Todo 专属)
> 适用范围:本规则属于 **项目规则**(仅 Hua.Todo 项目生效)。
>
> 描述当前仓库的项目划分、依赖方向、运行模式与跨平台策略,供智能体在做改动时快速对齐架构边界。
> 完整设计参见 [docs/manual/05-技术栈与项目结构.md](../../../docs/manual/05-技术栈与项目结构.md) 与 [docs/manual/07-技术架构设计.md](../../../docs/manual/07-技术架构设计.md)。
## 一、项目清单(src/)
| 项目 | 类型 | 职责 | 平台 |
|---|---|---|---|
| [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`、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 (依赖 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 不得引用 HttpApi.AspNetCore / 任何宿主;HttpApi.AspNetCore 不得引用宿主项目。
- **MAUI / Avalonia 不得注册 AddCloudSyncServer**:只注册 `AddApplicationServices()` + `AddCloudSyncProxy()`,权威云同步端点只在 Host 暴露。
- **MAUI / Avalonia 跨层引用边界**:只引用 HttpApi.AspNetCore 中与嵌入式相关的类型(CloudSyncProxyMiddleware、CloudSyncProxySettings 等),不引用 CloudSyncServerService 等 Host-only DI 扩展(实际通过命名空间自然隔离)。
## 三、两种运行模式
### 端口对照表(全局统一,禁止硬编码歧义值)
| 端口 | 用途 | 所属模式 | 说明 |
|---|---|---|---|
| `: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);生产可切换其他后端
## 四、跨平台原则
- **业务逻辑统一在 Application 层**,宿主项目只做 DI 装配与平台桥接
- **平台差异通过接口 + 平台目录**实现(例:`IGlobalHotKeyService` 在 MAUI 与 Avalonia 各有自己的 `Platforms/` 子目录实现)
- **前端只有一份**:Vue 项目通过不同的 `.env.*` 文件区分模式(`.env.development` / `.env.maui` / `.env.production`)
## 五、关键扩展点
| 扩展点 | 位置 |
|---|---|
| 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` |
## 六、版本统一策略
- 全局版本号通过根目录 `Directory.Build.props` 集中管理(当前 `1.2.3`)
- Inno Setup 安装包:`src/Hua.Todo.Maui/setup.iss`、`src/Hua.Todo.Avalonia/setup.iss`
- Linux:`publish-linux.ps1` 产出 `.tar.gz`;`pack/linux/` 含 Flatpak 基础结构
- 详见 [docs/project/研发工单-v1.2.0/02.1-版本统一与打包方案.md](../../../docs/project/研发工单-v1.2.0/02.1-版本统一与打包方案.md)
## 七、测试项目架构
### 7.1 目录结构
```
test/ ← 项目根目录下的顶层测试目录
├── Hua.Todo.Host.Tests/ ← 服务端/Application 层集成测试
│ ├── CloudSync/ ← 云同步模块
│ ├── Meeting/ ← 会议模块
│ └── Attachments/ ← 附件模块
├── Hua.Todo.Maui.Tests/ ← MAUI 平台测试(骨架)
└── Hua.Todo.Avalonia.Tests/ ← Avalonia 平台测试(骨架)
```
### 7.2 分层规则(严禁跨层)
| 测试项目 | 可引用的被测项目 | 不得引用 |
|---|---|---|
| `Hua.Todo.Host.Tests` | `Hua.Todo.Host` / `Application` / `Core` | MAUI / Avalonia 宿主 |
| `Hua.Todo.Maui.Tests` | `Hua.Todo.Maui` / `Application` / `Core` | Avalonia 宿主 |
| `Hua.Todo.Avalonia.Tests` | `Hua.Todo.Avalonia` / `Application` / `Core` | MAUI 宿主 |
### 7.3 技术栈与规范
- 框架:xUnit 2.9+,SQLite In-Memory 模拟 DB
- 测试层次:直接测 Application 服务层(DI 测试),必要时用 `WebApplicationFactory`
- 命名:类 `{被测类}Tests`、方法 `{方法名}_{场景}_{预期结果}`、命名空间 `Hua.Todo.Host.Tests.{模块名}`
- 文件组织:每个模块新建子目录,模块级共用测试放根目录