feat: 引入 CloudSync 核心能力并新增 Avalonia 桌面端与发布脚本

- 后端:新增 CloudSync 认证/权限/端点/服务与 DTO
- 数据:新增用户/会话/安全策略实体与 EF Core migrations
- 前端:新增云同步设置 UI、客户端与本地存储;Vite 支持 maui 构建输出到 wwwroot
- 桌面端:新增 Avalonia 项目、内置 WebServer、托盘与 Windows 全局热键
- 发布/构建:新增 Windows/Linux 发布脚本与统一入口;调整 MAUI 资源与安装包配置
- 文档:同步更新 README/docs 与协作规则
This commit is contained in:
ShaoHua
2026-04-07 03:34:34 +08:00
parent 18d37fdd24
commit 7a4c516a20
85 changed files with 5774 additions and 127 deletions
+14 -2
View File
@@ -19,9 +19,10 @@
- **Linux 入口线**`01-*` + `02-*`
- 01:新增 Avalonia 入口、选择 Linux 可用的 WebView 控件、复用现有前后端协议
- 02Linux 打包/交付产物(优先自包含:AppImage/Flatpak 之一;补充 .deb/.tar.gz
- 02Linux 打包/交付产物(已落地:`.tar.gz` 发布脚本 + Flatpak 基础结构;详见 `publish-linux.ps1``pack/linux/`
- **Search 线**`03-*`
- 主要在前端完成;与云同步/平台入口基本无耦合,可并行
- 03:已完成:主界面搜索框(按标题包含匹配;命中即显示含上下文;Esc 清空;英文大小写不敏感)
- **云同步线**`04-*` + `05-*` + `06-*`
- 04:服务端基础能力(登录、任务同步/读取、配置下发、用户隔离)
- 05:客户端配置与同步工作流(手动指定服务端地址、登录后拉取任务)
@@ -29,9 +30,20 @@
- **文档与验收线**`07-*`
- 对齐文档与现实现状/接口;补齐验收步骤与自测清单
## 待验证表
| 子任务 | 实现状态 | 验证状态 | 备注 |
|---|---|---|---|
| 01 - Linux 入口 | 已完成 | 待验证 | 基于 Avalonia + WebView.Avalonia 实现 |
| 02 - Linux 打包/交付 | 已落地 | 待验证 | `.tar.gz` 发布脚本 + Flatpak 基础结构 |
| 03 - Search 关键词检索 | 已完成 | 待验证 | 搜索框 + 树状任务标题包含匹配 |
| 04 - 云同步 服务端基础能力 | 已完成 | 已验证 | API 契约与错误码已固化到 04 文档 |
| 05 - 云同步 客户端配置与同步 | 已完成 | 待验证 | 新增“云同步设置”弹窗:地址校验+保存探测、登录/登出、登录后拉取云端任务并在主界面只读展示 |
| 06 - 安全与落盘策略 | 未标注 | 待验证 | |
| 07 - 文档与验收 | 未标注 | 待验证 | |
## 交付判定(v1.2.0 Done Definition
- Linux:在基线发行版(建议 Ubuntu LTS)上可启动、可渲染前端、可调用本地 API;且有可安装/可运行的交付产物
- Search:可在主界面按标题实时过滤任务(含层级任务的展示策略清晰)
- 云同步(基础可用):可配置服务端地址;登录后可拉取该用户任务;服务端可下发“是否允许落盘”;客户端在禁止落盘时不产生本地持久化
@@ -39,6 +39,36 @@
- 开发态:Avalonia WebView 指向前端 dev server(例如 `http://localhost:5173`)或指向本地 WebServer
- 生产态:加载随应用交付的静态资源(`wwwroot`)并确保 SPA fallback 生效(访问非 `/assets/*` 的路由能回到 `index.html`
## 实现落地(已完成)
### 1) 项目结构
- 新增 Linux 桌面端入口项目:`src/Hua.Todo.Avalonia`
- 入口类型:Avalonia Desktop AppClassicDesktopLifetime
### 2) WebView 方案选型(已落定)
- 采用:`WebView.Avalonia` + `WebView.Avalonia.Desktop`
- Windows:依赖 WebView2 Runtime
- Linux:依赖 GTK + WebKitGTK(运行环境缺失时 WebView 会初始化失败)
### 3) 资源加载策略(与 MAUI 对齐)
- 生产态(默认):内嵌 WebServer 托管 `wwwroot` 静态资源,WebView 指向 `HostUrl`
- 开发态:将 `IsUsingStatic=false`WebView 指向 `ForEndUrl`(例如 Vite dev server
### 4) 前端契约对齐(与 MAUI 一致)
- 在 WebView 导航完成后注入:
- `window.__API_BASE_URL__ = "${HostUrl}/api"`
- `window.mauiInterop`(事件名/字段名与现有前端保持一致)
### 5) 本地 API 与数据库初始化
- 内嵌 WebServer 使用 Kestrel 启动并注册动态 API 与 Controllers
- 启动时执行数据库迁移(Migrate),并设置 SQLite WAL 模式以降低锁冲突风险
- 默认 SQLite 路径使用用户目录(`LocalApplicationData/Hua.Todo/Hua.Todo.db`),避免安装目录无写权限导致启动失败
## 实施步骤(建议)
1. 新建 Avalonia 宿主项目
@@ -61,4 +91,3 @@
- 前端能通过 `window.__API_BASE_URL__` 正确请求本地 `/api/*`(至少任务列表接口可用)
- 页面路由/刷新不会出现 404SPA fallback 生效)
- 开发态可调试(至少能看到控制台/网络错误,或能通过日志定位)
@@ -21,13 +21,102 @@
## 接口契约(需要在实现前先写清楚)
建议输出一份“云同步 API 契约”并固化到 docs(便于客户端对接)。至少包含:
- 登录:`POST /auth/login`(或等效)
- 获取用户任务:`GET /tasks`(或等效,支持增量/版本号是加分项,但 v1.2.0 可先全量)
- 上传/同步:`POST /sync`(或按任务粒度的增删改接口)
- 获取安全配置:`GET /security/policy`
- 返回字段至少包含:`allowPersist`(是否允许落盘)
- 可扩展:`deviceTrust``sessionTtl``requireSecondFactorFor`
v1.2.0 已实现一套最小可用契约(用于 05/06 客户端对接时冻结字段名/错误码)。
### 通用约定
- Base URL:由客户端配置(例如 `https://{host}:{port}`
- 认证:`Authorization: Bearer {accessToken}`
- 错误响应(统一结构):
```json
{ "code": "ERROR_CODE", "message": "Human readable message." }
```
### 错误码
- `UNAUTHORIZED`:未登录或会话失效
- `FORBIDDEN`:权限不足(RBAC / 策略拒绝)
- `SECOND_FACTOR_REQUIRED`:需要二次认证(step-up
- `BAD_REQUEST`:请求参数不合法
- `NOT_FOUND`:资源不存在
### Auth
- 初始化管理员(仅当系统尚无云用户时允许一次):
- `POST /auth/bootstrap`
- Body`{ "userName": "admin", "password": "..." }`
- 200:成功;403:已初始化或不允许
- 登录:
- `POST /auth/login`
- Body`{ "userName": "admin", "password": "..." }`
- 200`{ accessToken, expiresAtUtc, userId, role, permissions[] }`
- 二次认证(step-up,v1.2.0 最小实现为“复用登录口令进行再认证”):
- `POST /auth/step-up`
- Header`Authorization: Bearer ...`
- Body`{ "password": "..." }`
- 200`{ stepUpExpiresAtUtc }`
### Tasks
- 获取当前用户任务全量:
- `GET /tasks`
- Header`Authorization: Bearer ...`
- 权限:`tasks:read`
- 200`CloudTaskItem[]`
### Sync
- 上传/同步(增删改后返回最新全量):
- `POST /sync`
- Header`Authorization: Bearer ...`
- 权限:`sync:write`
- 二次认证:必需(否则返回 `SECOND_FACTOR_REQUIRED`
- Body
```json
{
"upserts": [
{ "id": 1, "title": "A", "priority": 1, "isCompleted": false, "parentTaskId": null },
{ "id": null, "title": "New", "priority": 1, "isCompleted": false, "parentTaskId": null }
],
"deletes": [2, 3]
}
```
- 200
```json
{
"serverTimeUtc": "2026-04-06T17:39:30.0281279Z",
"tasks": [ /* CloudTaskItem[] */ ]
}
```
### Security Policy
- 获取安全策略(服务端下发):
- `GET /security/policy`
- Header`Authorization: Bearer ...`
- 权限:`policy:read`
- 200
```json
{
"allowPersist": true,
"allowSync": true,
"requireSecondFactorFor": ["sync:write", "policy:write"]
}
```
- 更新安全策略(高风险操作):
- `PUT /security/policy`
- Header`Authorization: Bearer ...`
- 权限:`policy:write`
- 二次认证:必需(否则返回 `SECOND_FACTOR_REQUIRED`
- Body`{ "allowPersist": false, "allowSync": false }`
## 关键实现点(建议)
@@ -49,3 +138,8 @@
- 未授权角色/权限访问受限接口会被拒绝(错误响应可被客户端识别)
- 能返回安全策略配置(至少包含 `allowPersist`),并可通过配置切换行为
## 当前实现说明(v1.2.0
- 数据隔离:`Tasks` 表新增 `UserId` 外键,云端 API 的所有读写按当前会话用户隔离;本地模式使用固定的 `local` 用户 ID(不影响既有 Dynamic API)。
- RBAC:内置 `admin / user / readonly / nosync` 角色与权限映射;并叠加 `SecurityPolicies.AllowSync` 作为“是否允许同步写入”的策略开关。
- 二次认证:通过 `POST /auth/step-up` 将会话提升到 step-up 状态;`POST /sync``PUT /security/policy` 会强制要求 step-up。