3213d4c718
- 重构架构:抽离AddCloudSyncServer到扩展类,补全中间层文档对齐 - 修复根路径404与鉴权跳转:新增中间件处理浏览器请求302跳转 - 实现种子数据初始化:添加默认管理员账号自动创建逻辑 - 优化前端代理与构建:新增Vite代理配置与自动构建Target - 补全测试与文档:新增集成测试,更新开发与部署文档
12 KiB
12 KiB
项目架构(Hua.Todo 专属)
适用范围:本规则属于 项目规则(仅 Hua.Todo 项目生效)。
描述当前仓库的项目划分、依赖方向、运行模式与跨平台策略,供智能体在做改动时快速对齐架构边界。 完整设计参见 docs/manual/05-技术栈与项目结构.md 与 docs/manual/07-技术架构设计.md。
一、项目清单(src/)
| 项目 | 类型 | 职责 | 平台 |
|---|---|---|---|
| Hua.Todo.Core | 类库 | 领域实体、仓储接口(TaskEntity、UserEntity、SecurityPolicyEntity、AuditLogEntity、ITaskRepository 等) |
netstandard / net |
| Hua.Todo.Application | 类库(共享层) | EF Core TodoDbContext、TaskService/TaskRepository、CloudSync 业务服务(Application/Services/CloudSync/)、动态 API 属性层、迁移 |
net |
| Hua.Todo.HttpApi.AspNetCore | 类库(ASP.NET Core 专属 HTTP 层) | 承载依赖 ASP.NET Core 的实现:DynamicApiMiddleware、Mcp Server 端点、云同步服务端 DI(SessionAuthenticationHandler、CloudSyncServerService) | net(依赖 Microsoft.AspNetCore.App 共享框架) |
| Hua.Todo.Host | ASP.NET 服务端 | Host 双角色统一部署:(1) Web 端前端/后端同源部署(承载前端静态资源 + Dynamic API + Swagger + MCP);(2) 云同步权威服务端(供 MAUI/Avalonia 的 CloudSyncProxy 转发);不区分模式 | Windows/Linux 等服务器 |
| Hua.Todo.Maui | MAUI 客户端 | Windows / macOS / iOS / Android 入口;内嵌 WebServer + WebView 承载 Vue 前端 | 多端 |
| Hua.Todo.Avalonia | Avalonia 客户端 | Linux / Windows 桌面入口;内嵌 WebServer + WebView.Avalonia 承载 Vue 前端 |
桌面(含 Linux) |
| 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
七、测试项目架构
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.{模块名} - 文件组织:每个模块新建子目录,模块级共用测试放根目录