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:
@@ -19,9 +19,10 @@
|
||||
|
||||
- **Linux 入口线**:`01-*` + `02-*`
|
||||
- 01:新增 Avalonia 入口、选择 Linux 可用的 WebView 控件、复用现有前后端协议
|
||||
- 02:Linux 打包/交付产物(优先自包含:AppImage/Flatpak 之一;补充 .deb/.tar.gz)
|
||||
- 02:Linux 打包/交付产物(已落地:`.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 App(ClassicDesktopLifetime)
|
||||
|
||||
### 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/*`(至少任务列表接口可用)
|
||||
- 页面路由/刷新不会出现 404(SPA 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。
|
||||
|
||||
Reference in New Issue
Block a user