Files
Windows-Gotify-Client-Rust/AGENTS.md
T
KennethCheng a3a6a7c91d chore: 初始化 Windows-Gotify-Client-Rust 项目骨架
使用 Rust + Slint 重建一个轻量、现代、Windows 原生体验良好的 Gotify
桌面客户端。本次只搭目录骨架与占位文件,未进入 Phase 1(Bootstrap)。

本次提交内容
------------
- 保留 AGENTS.md(1363 行定制 Agent 实施计划,含 8 阶段路线图)
- 新建 Cargo.toml([package] 元数据 + AGENTS.md §44 依赖模板 + §42
  release profile;无 [[bin]],等 Phase 1 才加 src/main.rs)
- 新建 README.md(项目导览,引用 AGENTS.md)
- 新建 .gitignore(Rust / Slint / Windows / IDE / 密钥)
- 新建 LICENSE(MIT 占位)
- 按 AGENTS.md §4 建好全部 10 个目录,每个空目录放 .gitkeep:
    assets/        assets/fonts/
    ui/            scripts/
    src/           src/gotify/
    src/storage/   src/windows/
    src/services/  tests/

未提交(Phase 1 起才落地)
------------------------
- src/main.rs 及所有 .rs 业务代码
- ui/*.slint 视图
- scripts/build-release.ps1 等构建脚本
- Cargo.lock(当前 Cargo.toml 是占位、无可编译代码)

技术栈约束(来自 AGENTS.md §1 / §2)
------------------------------------
- Rust stable + Slint 1.17.x + Windows 10/11
- 显式禁用:Tauri / Wails / Electron / WebView2 / WPF / WinUI 3 / Node 运行时
- 单一主程序,无浏览器运行时依赖;UI 由 Slint 原生渲染

仓库
----
远程:https://gitea.kennethcheng.cc/KennethCheng/Windows-Gotify-Client-Rust
2026-09-19 04:02:51 +08:00

39 KiB
Raw Blame History

Windows-Gotify-Client-Rust — Agent Implementation Plan

目标:使用 Rust + Slint 重建一个轻量、现代、Windows 原生体验良好的 Gotify 桌面客户端。

目标不是把现有 C# 项目逐行翻译成 Rust,而是以现有项目的功能为产品基线,重新设计更轻、更清晰、更容易长期维护的架构。


0. Agent 必须先读懂的上下文

现有项目:Windows-Gotify-Client

当前实现已经包含这些核心能力:

  • Gotify HTTP API
  • WebSocket 实时消息
  • WebSocket 断线重连
  • 新消息 Windows 通知
  • 应用/Token 管理
  • 配置保存
  • 最近消息状态保存
  • Windows 托盘
  • 深色/浅色主题
  • 消息列表与详情
  • 点击通知 URL
  • 开机启动相关能力

本次 Rust 版本应保留成熟的核心功能,但不复制当前代码的类结构。

产品定位

这是一个 Windows-only、后台常驻、托盘型 Gotify 客户端。

核心原则:

  1. 小体积
  2. 低内存占用
  3. 后台低 CPU
  4. 无浏览器运行时依赖
  5. 单一主程序
  6. UI 精致现代
  7. 网络层与 UI 完全解耦
  8. Windows 能力原生调用
  9. 配置/状态简单可靠
  10. 默认不做过度工程化

1. 技术栈

必选

  • Rust stable
  • Slint 1.17.x 或当前稳定兼容版本
  • Windows 10 x64
  • Windows 11 x64 / ARM64(条件允许时支持)
  • Cargo

Slint 当前官方文档将 Windows 10 x86-64 与 Windows 11 x86-64 / ARM64 列为测试平台,并支持 Windows 子系统以隐藏控制台窗口。具体版本以开发时锁定的稳定版为准。

Windows 原生能力

优先使用 windows-rs 的 focused crates;只有 focused crate 不覆盖目标 API 时,才使用 windows / windows-sys。

候选:

  • windows-notifyicon:托盘图标
  • windows-registry:开机启动等 Registry 操作
  • windows-window:只有确实需要时使用
  • windows:Toast/WinRT/其它必要 Win32/COM API

不要为了方便把整个 Windows API 集合无脑全部引入。

网络

推荐:

  • reqwest:HTTP
  • tungstenite:WebSocket
  • serde
  • serde_json
  • url

默认优先使用 blocking HTTP + 独立网络线程,而不是为了一个 WebSocket 客户端引入完整 async runtime。

只有当实现明确证明 async 能降低复杂度或改善功能时,才引入 tokio。

日志

推荐:

  • tracing
  • tracing-subscriber

Release 默认降低日志等级,不允许每条消息都产生大量磁盘 IO。

本地数据

V1 默认使用 JSON 文件:

config.json
state.json

不要一开始引入 SQLite。

只有产品明确需要:

  • 大规模历史记录
  • 搜索历史
  • 消息标签
  • 长期存档

才考虑 SQLite。


2. 明确禁止的技术路线

除非出现无法解决的技术限制,否则禁止:

  • Tauri
  • Wails
  • Electron
  • WebView2 作为 UI 主体
  • Web 前端 + WebView
  • Windows App SDK
  • WPF
  • WinUI 3
  • 大型前端框架
  • Node.js runtime
  • 浏览器 runtime

原因不是这些技术不好,而是本项目目标是一个 极轻量 Windows 常驻工具。

UI 应由 Slint 原生渲染,业务逻辑由 Rust 完成。


3. 核心架构

采用:

                        ┌──────────────────────────┐
                        │        Slint UI          │
                        │                          │
                        │ Dashboard / Message      │
                        │ Detail / Settings       │
                        └────────────┬─────────────┘
                                     │
                              UI callbacks
                                     │
                                     ▼
                        ┌──────────────────────────┐
                        │         AppCore          │
                        │                          │
                        │ Config                   │
                        │ Connection state         │
                        │ Message state            │
                        │ User actions             │
                        └───────┬─────────┬────────┘
                                │         │
                     AppCommand │         │ AppEvent
                                │         │
                                ▼         ▼
                      ┌──────────────────────────┐
                      │      Network Worker      │
                      │                          │
                      │ REST API                 │
                      │ WebSocket                │
                      │ reconnect / backoff      │
                      └────────────┬─────────────┘
                                   │
                                   ▼
                              Gotify Server

             ┌──────────────────── AppCore ────────────────────┐
             │                      │                         │
             ▼                      ▼                         ▼
        Storage Worker        Windows Host                Logger
             │                      │
             │                ┌─────┼─────┐
             │                ▼     ▼     ▼
             │              Tray  Toast  Startup
             ▼
        config.json
        state.json

关键设计

UI 永远不能直接:

  • 调用 HTTP
  • 管理 WebSocket
  • 读取配置文件
  • 修改 Registry
  • 调用 Toast
  • 操作托盘

UI 只通过 AppCore 触发操作和接收状态。


4. 目录结构

目标结构:

Windows-Gotify-Client-Rust/
├── Cargo.toml
├── Cargo.lock
├── README.md
├── LICENSE
├── AGENTS.md
├── .gitignore
│
├── assets/
│   ├── icon.ico
│   ├── tray.ico
│   ├── app-icon.png
│   └── fonts/                 # 可选;尽量不内置字体
│
├── ui/
│   ├── app.slint
│   ├── theme.slint
│   ├── colors.slint
│   ├── components.slint
│   ├── message-card.slint
│   ├── message-list.slint
│   ├── empty-state.slint
│   ├── settings-page.slint
│   ├── server-card.slint
│   └── dialogs.slint
│
├── src/
│   ├── main.rs
│   ├── app.rs
│   ├── events.rs
│   ├── commands.rs
│   ├── models.rs
│   ├── error.rs
│   │
│   ├── gotify/
│   │   ├── mod.rs
│   │   ├── api.rs
│   │   ├── websocket.rs
│   │   ├── reconnect.rs
│   │   └── model.rs
│   │
│   ├── storage/
│   │   ├── mod.rs
│   │   ├── config.rs
│   │   └── state.rs
│   │
│   ├── windows/
│   │   ├── mod.rs
│   │   ├── tray.rs
│   │   ├── notification.rs
│   │   ├── startup.rs
│   │   ├── single_instance.rs
│   │   └── url.rs
│   │
│   └── services/
│       ├── mod.rs
│       └── lifecycle.rs
│
├── tests/
│   ├── gotify_api.rs
│   ├── reconnect.rs
│   ├── state.rs
│   └── parsing.rs
│
└── scripts/
    ├── build-release.ps1
    └── package.ps1

5. UI 产品设计

总体视觉方向

关键词:

Fluent / 极简 / 安静 / 高级 / 信息密度适中 / 长时间使用舒服

不要做成:

  • 老式 Windows 管理软件
  • 浏览器 Admin Dashboard
  • 过多渐变
  • 大面积阴影
  • 过大的圆角
  • 花哨动画

整体感觉应该接近:

  • Windows 11 Fluent
  • Linear
  • Raycast
  • Arc
  • 现代桌面通知工具

但不要直接复制任何现有产品。


6. 主窗口布局

推荐默认尺寸:

960 × 680 px

最小尺寸:

760 × 520 px

布局:

┌─────────────────────────────────────────────────────────────┐
│  Gotify                              ● Connected      ─ □ × │
├──────────────┬──────────────────────────────────────────────┤
│              │                                              │
│  ◉ All       │  Messages                                    │
│              │  ─────────────────────────────────────────   │
│  Servers     │                                              │
│  ├ Server A  │  ┌────────────────────────────────────────┐  │
│  └ Server B  │  │ ●  Build succeeded                     │  │
│              │  │   CI / Production                      │  │
│              │  │                          2 min ago      │  │
│              │  └────────────────────────────────────────┘  │
│              │                                              │
│  Filters     │  ┌────────────────────────────────────────┐  │
│  ○ High      │  │ ●  Backup finished                     │  │
│  ○ Normal    │  │   NAS / Backup                         │  │
│  ○ Low       │  │                          8 min ago      │  │
│              │  └────────────────────────────────────────┘  │
│              │                                              │
│──────────────│                                              │
│  ⚙ Settings  │                                              │
│  ℹ About     │                                              │
└──────────────┴──────────────────────────────────────────────┘

注意:上图只表达结构,不是要求做成 ASCII 风格。


7. UI 组件规范

Window

  • 圆角:轻度,约 10~14 px
  • 不要夸张玻璃效果
  • 不要大面积半透明
  • 标题栏简洁
  • 支持 Windows 深浅主题

Sidebar

宽度:约 220~240 px。

内容:

  1. App logo
  2. All messages
  3. Server 列表
  4. Priority filter
  5. Settings
  6. About

Sidebar 应该视觉安静,不抢主内容焦点。

Message Card

每一条消息显示:

  • priority 状态
  • title
  • app name
  • message preview
  • relative time

例如:

● Build succeeded
  GitLab Runner · production
                           2 min ago

Priority 使用小面积视觉标记,不允许整张卡片使用高饱和背景。

推荐表现:

Low       neutral
Normal    subtle accent
High      amber/orange accent
Max       red accent

但是所有颜色都必须进入主题系统统一管理。


8. 消息详情页

点击消息后进入右侧详情视图,或使用可折叠 Detail Panel。

结构:

┌───────────────────────────────────────────────┐
│ ← Message                                     │
│                                               │
│ Build succeeded                               │
│ GitLab Runner · Production                    │
│ 2026-09-19 03:42:18                           │
│                                               │
│ ┌───────────────────────────────────────────┐ │
│ │                                           │ │
│ │ Deploy completed successfully.            │ │
│ │                                           │ │
│ │ Version: v1.4.2                            │ │
│ │ Server: production                         │ │
│ │                                           │ │
│ └───────────────────────────────────────────┘ │
│                                               │
│ [ Copy ] [ Open Link ]                        │
└───────────────────────────────────────────────┘

正文:

  • 默认 plain text
  • 根据 Gotify client::display extras 支持 markdown 时,再提供 Markdown 展示
  • 不要为了 Markdown 引入浏览器
  • V1 可以先纯文本,再扩展 Markdown

Gotify 官方文档定义了 client::display extras,并支持 text/plain 与 text/markdown 等 content type。实现时以服务器实际 API 行为为准。


9. 空状态设计

没有消息时不要只显示:

No messages.

应提供漂亮的空状态:

              ✦

         You're all caught up

       New Gotify messages will
       appear here automatically.

          [ Test Notification ]

不使用外部图片资源,优先用 Slint 自绘简单图形/图标。


10. 设置页面

设置页面必须精简,不做企业软件式的巨型表单。

分为:

Connection

  • Server URL
  • App Token
  • Connection test
  • Auto reconnect
  • Connection status

Notifications

  • Enable desktop notification
  • Sound
  • Notify on High priority
  • Notify on Max priority
  • Click action

Startup

  • Start with Windows
  • Start minimized
  • Minimize to tray
  • Close to tray

Appearance

  • System
  • Light
  • Dark
  • Compact message density

Advanced

  • Log level
  • Clear local state
  • Reset settings
  • Open config directory

默认隐藏 Advanced 部分。


11. 设置交互要求

必须做到:

修改配置
↓
UI 本地状态变化
↓
点击 Save 或自动保存
↓
AppCore 更新 Network Worker
↓
必要时重连

不要让 UI 直接修改 config.json。


12. 托盘体验

应用关闭主窗口时,默认:

Window hidden
App process remains alive
Tray remains alive

托盘菜单:

Open
New messages: 3
────────────
Pause notifications
Settings
────────────
Restart connection
Quit

托盘图标必须:

  • 有正常态
  • 可选 disconnected 状态
  • 不能使用模糊的小图标
  • Windows 11 任务栏大小下仍能识别

Slint 1.17 已提供 SystemTrayIcon,可以优先评估 Slint 原生托盘能力;若 Windows 上需要更完整的原生行为,再使用 windows-rs focused crate。


13. 通知设计

新消息到来:

Gotify
Build succeeded
GitLab Runner · Production

要求:

  • 标题来自 Gotify message title
  • 正文来自 message message
  • priority 用于通知层级
  • click.url 存在时支持点击打开

Gotify 官方 extras 机制中,client::* 为客户端保留命名空间,client::notification 用于通知行为定制;实现应该严格按照 Gotify 官方 extras 语义处理,不要自行发明兼容格式。

URL 打开逻辑必须:

  1. 只接受显式字符串 URL
  2. 解析 URL
  3. 至少允许 https:// / http://
  4. 拒绝 file://
  5. 拒绝 javascript:
  6. 拒绝任意自定义 scheme,除非未来明确增加白名单

14. Gotify 网络设计

HTTP

封装:

GotifyApi

负责:

  • 获取消息
  • 获取应用
  • 创建/读取必要资源
  • 删除消息(如功能需要)
  • Server health / version(如功能需要)

不要让 UI 直接知道 URL 拼接方式。

WebSocket

封装:

GotifyWebSocket

状态:

Disconnected
Connecting
Connected
Reconnecting
Stopped

事件:

enum NetworkEvent {
    Connected,
    Disconnected,
    Message(GotifyMessage),
    Error(NetworkError),
}

15. WebSocket 重连

必须支持指数退避:

1s
2s
4s
8s
16s
30s
30s...

服务器成功连接后重置退避时间。

不要:

loop {
    connect();
}

禁止高频重连打爆服务器。


16. 离线补偿

不要简单照搬现有 C# 的 since=lastId 逻辑。

实现前先验证目标 Gotify Server 版本的分页语义。

目标行为:

程序正常运行
        ↓
保存最后处理消息 ID
        ↓
程序退出 / 网络断开
        ↓
重新启动 / 重连
        ↓
HTTP 补拉缺失消息
        ↓
去重
        ↓
更新 UI
        ↓
继续 WebSocket

必须测试:

  • 断网 10 秒
  • 断网 5 分钟
  • 程序重启
  • Gotify Server 重启
  • 多条消息同时到达
  • 消息 ID 非连续
  • 重复消息

17. 消息去重

V1 不要建立复杂数据库。

采用:

VecDeque<i64>
HashSet<i64>

维护最近 N 条 ID,例如:

200

规则:

if seen(id) {
    ignore
}

超过上限后删除最老 ID。

如果未来消息历史量扩大,再换 SQLite。


18. 状态设计

state.json 只保存真正需要跨进程持久化的状态。

建议:

{
  "last_message_id": 123456,
  "selected_server": "default",
  "last_window_width": 960,
  "last_window_height": 680,
  "version": 1
}

不要每收到一条消息就立刻 fsync / rewrite 整个 JSON。

采用:

memory state
    ↓
mark dirty
    ↓
debounce 2~5s
    ↓
safe atomic write

或者在应用正常退出时保存,并定时 checkpoint。

写文件采用:

state.json.tmp
    ↓
flush
    ↓
atomic replace
    ↓
state.json

避免异常退出导致 JSON 损坏。


19. 配置设计

配置文件路径建议:

%APPDATA%/WindowsGotify/config.json

不要写入安装目录。

配置模型:

struct AppConfig {
    servers: Vec<GotifyServerConfig>,
    selected_server: Option<String>,
    appearance: AppearanceMode,
    notifications: NotificationConfig,
    startup: StartupConfig,
}

V1 可以只支持一个 Server,但数据结构直接按多 Server 设计,避免未来再改 schema。


20. Token 安全

不要把 App Token 打印到日志。

禁止:

Authorization: Bearer xxx

进入日志。

HTTP 错误日志最多打印:

HTTP 401 Unauthorized

而不要打印完整请求头。

V1 可以继续用明文 JSON 保存 token,但必须:

  • 限制文件访问权限到当前用户
  • 日志中永不泄漏 Token
  • UI 中默认密码样式隐藏

未来需要再考虑 Windows Credential Manager。


21. 多 Server 设计

产品层支持:

Server A
Server B
Server C

每个 Server:

{
  "id": "server-a",
  "name": "Home",
  "url": "https://gotify.example.com",
  "token": "...",
  "enabled": true
}

V1 可以只同时连接一个 Server,以减少复杂度。

架构上不要把 single server 写死。


22. UI 与 Rust 通信

Slint 只绑定 Presentation Model。

推荐:

Rust Model
    ↓
Slint properties/models

���要:

Slint callback
↓
HTTP request
↓
JSON parse
↓
file IO

UI callback 应类似:

on_connect_clicked
on_message_clicked(id)
on_open_link(url)
on_save_settings()
on_quit()

然后统一发送给 AppCore。


23. AppCore 状态机

建议有一个明确的应用状态:

enum ConnectionState {
    Disabled,
    Connecting,
    Connected,
    Reconnecting { attempt: u32 },
    Error,
}

UI 根据状态显示:

Connected      → green dot / Connected
Connecting     → spinner / Connecting
Reconnecting   → amber dot / Reconnecting
Error          → red dot / Connection error

不要在 UI 中自己推断网络状态。


24. 错误处理

业务错误统一:

AppError

分类:

ConfigError
NetworkError
WebSocketError
StorageError
WindowsError
ParseError

用户看到的错误必须是人话,例如:

Unable to connect to Gotify server.
Check the server URL and token.

日志中保存技术细节。


25. 日志策略

Debug:

详细连接过程
WebSocket 状态变化
消息解析

Release:

INFO
WARN
ERROR

不要默认记录所有消息正文。

例如:

[INFO] Gotify connected
[INFO] Received message id=1024 priority=5
[WARN] WebSocket disconnected
[INFO] Reconnecting attempt=3

而不是:

[INFO] token=xxx message="这里是一大段隐私内容"

26. 单实例

必须支持:

双击第二次
↓
检测已有实例
↓
激活现有窗口

不要启动两个 WebSocket 实例。

Windows 单实例可以放在:

src/windows/single_instance.rs

27. 开机启动

设置:

Start with Windows
Start minimized

优先使用当前用户 Run 注册表项,不要创建系统服务。

示例:

HKCU\Software\Microsoft\Windows\CurrentVersion\Run

安装/卸载要做到可重复执行。


28. 窗口行为

关闭按钮默认行为:

X
↓
隐藏窗口
↓
继续托盘运行

真正退出:

Tray → Quit

设置里允许用户选择:

Close to tray

未来可支持:

Minimize to tray

29. 动画规范

允许少量微动画:

  • 页面切换
  • 连接状态变化
  • Toast indicator
  • Sidebar hover

禁止:

  • 长时间 loading 动画
  • 无限循环纯装饰动画
  • 消息列表每条都弹入
  • 高耗能动画

动画目标:

100~180ms

原则:

让 UI 感觉“活着”,但不要让它“喧闹”。


30. 字体

优先使用 Windows 系统字体。

默认:

Segoe UI

不要为了 UI 美观强制带一个大型字体文件。

中文显示必须正常。

消息正文要支持中文、Emoji 与常见 Unicode 字符。


31. 图标

优先:

  • 简单 SVG/Path
  • Slint 内置或项目内矢量资源
  • Windows Shell 图标

避免:

  • 大量 PNG
  • 网络下载图标
  • 图标字体
  • 大型 icon package

32. 轻量化目标

Release 目标:

单 exe
无 Node
无 WebView2
无 .NET runtime
无 Java
无 Python

实际 EXE 大小不人为硬性规定,但 Agent 必须记录最终结果。

记录:

Raw EXE size
UPX 后大小(如果使用)
Installed size
Startup memory
Idle memory
Idle CPU

注意:不要为了体积盲目 UPX;先评估安全软件误报和启动开销。


33. 性能基线

启动后空闲:

目标:

CPU:接近 0%
Memory:尽量 < 50 MB

说明:这是目标值而不是硬性 ABI 承诺,最终结果必须实测记录。

收到大量消息时,不允许:

  • 每条消息触发 UI 全量刷新
  • 每条消息写整个 state.json
  • 每条消息产生大量同步文件 IO

应批量更新模型。


34. UI 数据模型

消息:

struct MessageItem {
    id: i64,
    app_id: i64,
    app_name: String,
    title: Option<String>,
    message: String,
    priority: i32,
    timestamp: i64,
    click_url: Option<Url>,
}

注意:不要让 Slint 直接持有复杂网络对象。

UI 使用简化后的 ViewModel。


35. 时间显示

消息列表:

just now
2 min ago
1 hour ago
Yesterday
Sep 18

详情显示完整时间:

2026-09-19 03:42:18

时间转换必须统一使用明确的时区策略。


36. 搜索与过滤

V1 可以支持:

  • title
  • message
  • app name

搜索应在 UI model 层处理,而不是每按一个键都请求 Gotify Server。

过滤:

All
Low
Normal
High
Max

V1 不需要复杂 query language。


37. 消息列表性能

不要为 1000 条消息一次性创建 1000 个复杂控件。

使用 Slint model/view 机制,只维护必要的可视数据。

目标:

100
500
1000

条消息滚动不卡顿。

默认只保留最近 N 条,例如:

200

以后再开放配置。


38. 安全边界

输入永远视为不可信:

  • Server URL
  • App Token
  • Message title
  • Message body
  • click URL
  • extras

特别注意:

click URL
message extras
markdown

不能直接把未验证内容当 HTML、脚本或 shell 命令执行。


39. Markdown 策略

第一阶段:

text/plain

第二阶段:

text/markdown

禁止为了 Markdown 引入 WebView。

优先:

  • 纯 Rust Markdown parser
  • Slint 富文本能力
  • 或安全降级为纯文本

若 Slint 当前版本无法优雅支持完整 Markdown,V1 直接 plain text 是可接受的。


40. 测试

必须有自动化测试:

Unit

  • JSON config parse
  • state serialization
  • URL validation
  • priority mapping
  • deduplication
  • reconnect backoff
  • time formatting

Integration

  • Gotify API mock
  • WebSocket mock
  • connection loss
  • reconnect
  • message ordering
  • duplicate message

Manual Windows

  • Windows 10 x64
  • Windows 11 x64
  • 高 DPI 125%
  • 高 DPI 150%
  • 中文 Windows 用户环境
  • 系统深色模式
  • 系统浅色模式
  • 开机启动
  • 托盘
  • 第二次启动单实例
  • Toast 点击
  • 断网重连
  • 睡眠/唤醒

41. CI/CD

GitHub/Gitea 均可。

至少:

cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test
cargo build --release

Windows Release 构建:

x86_64-pc-windows-msvc

ARM64:

aarch64-pc-windows-msvc

是否最终发布 ARM64,取决于依赖兼容性。


42. Release 构建

推荐:

[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"
strip = true

但每项设置都需要实际 benchmark。

不要仅为了“代码更小”牺牲明显的启动速度。

推荐先构建两份:

release-balanced
release-small

实测后选默认发布配置。


43. Windows 子系统

Release 版本不显示控制台窗口。

可以采用 Slint 官方推荐的:

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

Debug 保留 console 方便排错。


44. Cargo 依赖最小化原则

Cargo.toml 目标类似:

[dependencies]
slint = "1.17"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
reqwest = { version = "0.x", default-features = false, features = ["blocking", "json", "rustls-tls"] }
tungstenite = "0.x"
url = "2"
tracing = "0.x"
tracing-subscriber = "0.x"
anyhow = "1"
thiserror = "2"

Windows-specific dependency只引入确实使用的功能。

注意:版本号只是起始模板,Agent 在初始化项目时必须根据当前稳定版本与 Rust toolchain 做兼容验证,并提交 Cargo.lock。


45. 为什么 HTTP 默认考虑 rustls

不要无脑依赖平台 OpenSSL。

目标:

single Windows executable

使用 rustls 可以避免在 Windows 上额外依赖 OpenSSL runtime 的复杂部署。

但必须在 release 构建实际验证证书兼容性和体积。


46. 网络线程设计

V1 推荐一个 network worker:

NetworkWorker
    ├── HTTP client
    └── WebSocket

消息方向:

AppCore
  ↓ AppCommand
NetworkWorker

NetworkWorker
  ↓ NetworkEvent
AppCore

Channel:

std::sync::mpsc

或者当前 Rust 项目中更适合的 channel,但避免无意义引入完整 async runtime。


47. 生命周期

启动:

main
 ↓
single instance
 ↓
load config
 ↓
load state
 ↓
initialize AppCore
 ↓
start NetworkWorker
 ↓
create Slint UI
 ↓
create tray
 ↓
run UI event loop

关闭:

Quit
 ↓
stop accepting UI actions
 ↓
stop NetworkWorker
 ↓
flush state
 ↓
remove temp files
 ↓
destroy tray
 ↓
exit

48. 首次启动体验

没有配置时:

Welcome to Gotify

Connect your first Gotify server

Server URL
[ https://gotify.example.com            ]

Application Token
[ •••••••••••••••                     ]

[ Test Connection ]

                  [ Continue ]

成功:

✓ Connected

You're ready to receive notifications.

不要首次启动就弹出复杂设置窗口。


49. 连接测试

点击 Test Connection:

Testing...

成功:

✓ Server reachable
✓ Token valid

失败:

✕ Unable to connect
Check URL / token / TLS / network

UI 不显示底层 panic 或 stack trace。


50. Message Notification 去重

如果:

WebSocket 收到消息

已经显示过一次后,不允许因为:

HTTP catch-up

再次通知用户。

正确流程:

incoming message
     ↓
Dedup check
     ↓
new?
 ┌───┴───┐
 no      yes
 │        │
ignore   store
          │
          ├── UI
          └── Notify

51. 日志与隐私

敏感数据:

token
full Authorization header
private message body(可选)

默认不记录。

配置中加入:

[ ] Include message body in debug logs

默认关闭。


52. 颜色系统

不要在 .slint 每个组件里直接写大量颜色值。

统一定义:

Background
Surface
SurfaceElevated
Border
TextPrimary
TextSecondary
TextMuted
Accent
Success
Warning
Danger

Light:

明亮、低饱和、中性

Dark:

深灰,而不是纯黑

Accent 只用于:

  • selected item
  • connection status
  • primary button
  • focus

不要整个 UI 变成“蓝色海洋”。


53. 圆角与间距

建立统一 spacing scale:

4
8
12
16
20
24
32

Radius:

6
8
12
16

遵循统一系统。


54. 可访问性

最低要求:

  • 键盘可导航
  • Tab 顺序合理
  • Enter 执行主要按钮
  • Escape 关闭对话框
  • 文本对比度可读
  • 不仅依靠颜色表达 priority

未来如果 Slint/Windows Accessibility 支持允许,再扩展完整无障碍。


55. 国际化

V1 默认中文 + English 架构可扩展。

不要把所有 UI 字符串硬编码到业务 Rust 逻辑里。

至少做到:

UI strings
    ↓
centralized resource

默认语言:

简体中文

英文作为 fallback。

如果实现成本过高,V1 先 English/Chinese 单语言构建也可,但字符串必须集中管理。


56. README 要写清楚

README 至少包含:

  1. 截图
  2. 特性
  3. 系统要求
  4. 下载
  5. 配置方式
  6. Gotify 兼容性
  7. 开发环境
  8. 编译方式
  9. Release 构建
  10. 隐私说明
  11. License

不要堆大量理论说明。


57. Agent 的实施顺序

严格按照以下阶段执行。

Phase 1 — Bootstrap

完成:

  • Cargo project
  • Slint hello window
  • release profile
  • Windows subsystem
  • logging
  • error handling

验收:

cargo run
cargo build --release

可以打开无 console 的 Windows GUI。

Phase 2 — UI Shell

完成:

  • MainWindow
  • Sidebar
  • Message list
  • Empty state
  • Settings
  • Dark/Light/System
  • Window state

此阶段先使用 mock messages,不接网络。

Phase 3 — Gotify API

完成:

  • Server config
  • HTTP client
  • connection test
  • fetch applications if needed
  • message fetch

Phase 4 — WebSocket

完成:

  • connection state
  • realtime message
  • reconnect backoff
  • graceful shutdown

Phase 5 — State

完成:

  • config.json
  • state.json
  • atomic save
  • debounce checkpoint

Phase 6 — Windows Integration

完成:

  • tray
  • toast
  • URL open
  • startup
  • single instance

Phase 7 — Polish

完成:

  • animation
  • typography
  • icons
  • empty states
  • error states
  • loading states
  • high DPI
  • keyboard navigation

Phase 8 — Performance

完成:

  • profile release
  • measure RAM
  • measure CPU
  • startup time
  • executable size
  • message burst test

Phase 9 — Release

完成:

  • installer / portable zip
  • checksum
  • version
  • release notes
  • clean machine validation

58. Agent 工作规则

Rule 1

不要一次性写完整应用。

必须每阶段可运行、可编译。

Rule 2

每次修改后运行:

cargo fmt
cargo check
cargo clippy
cargo test

适用时再执行 Windows release build。

Rule 3

如果 Slint 某个 UI API 与预期不一致,先查当前版本官方文档,再实现。

不要凭记忆发明 API。

Rule 4

如果 windows-rs API 不确定,优先查 focused crate 文档和官方示例。

Rule 5

不要新增依赖来解决一个可以用标准库解决的小问题。

Rule 6

不要为了抽象而抽象。

V1 需要的是:

简单
稳定
清晰

Rule 7

任何网络线程都不能直接操作 UI。

Rule 8

任何 Windows API 调用都尽量封装在 src/windows/。

Rule 9

Token 绝不能进入普通日志。

Rule 10

每一个新增第三方依赖都要回答:

为什么标准库/Slint/windows-rs 不够?

59. Commit 规则

建议:

feat(ui): add main window shell
feat(gotify): add REST client
feat(gotify): add websocket worker
feat(windows): add tray integration
feat(windows): add toast notifications
feat(storage): add atomic state persistence
fix(gotify): handle reconnect correctly
perf(ui): batch message model updates
refactor(core): decouple network from UI

每个 commit 尽可能保持单一职责。


60. 最终验收清单

产品

  • 首次启动可完成配置
  • 可以连接 Gotify
  • WebSocket 正常收消息
  • 断线自动重连
  • 重启后可以补消息
  • 不重复通知
  • Windows Toast 正常
  • 点击 URL 正常
  • 托盘正常
  • 关闭窗口默认不退出
  • 托盘 Quit 正常退出
  • 开机启动可用
  • 第二次启动不创建第二实例

UI

  • Light
  • Dark
  • System
  • Empty state
  • Loading state
  • Error state
  • Message detail
  • Settings
  • High DPI
  • 中文
  • Emoji
  • 键盘操作

工程

  • cargo fmt
  • cargo clippy
  • cargo test
  • cargo build --release
  • 无 Node
  • 无 WebView2
  • 无 .NET runtime
  • 无 Windows App SDK
  • 无 OpenSSL runtime 依赖(如果选 rustls)

性能

  • 记录 Release EXE 大小
  • 记录冷启动时间
  • 记录 Idle RAM
  • 记录 Idle CPU
  • 记录 1000 条消息测试结果
  • 记录 reconnect 压测结果

61. 推荐的最终产品形态

最终应该形成:

Windows-Gotify-Client-Rust

       ┌─────────────────────────────┐
       │                             │
       │       Beautiful UI          │
       │          Slint              │
       │                             │
       └──────────────┬──────────────┘
                      │
                   AppCore
                      │
          ┌───────────┼───────────┐
          │           │           │
       Gotify       Storage     Windows
          │           │           │
     REST + WS     JSON        Tray/Toast
          │                       Startup
          │                       Mutex
          ▼
      Gotify Server

产品气质:

打开时精致,后台时安静。

不要追求“功能最多”,而是让它成为一个 安装后几乎不用管,但消息来了马上可靠提醒 的 Windows 小工具。


62. 第一版完成定义(Definition of Done)

当以下条件全部满足时,V1 才算完成:

  1. 全部核心网络逻辑与 UI 解耦。
  2. Slint 负责桌面 UI。
  3. Rust 负责业务与网络。
  4. Windows 原生能力集中在 Windows adapter 层。
  5. WebSocket 有稳定自动重连。
  6. 离线补偿经过实际 Gotify Server 验证。
  7. 消息去重可靠。
  8. Tray / Toast / Startup / Single Instance 可用。
  9. 配置与状态写盘具备原子性。
  10. Release 为单独的 Windows 原生应用,不依赖 WebView2、.NET、Node 或 Windows App SDK。
  11. Light / Dark / System 三套主题视觉完整。
  12. UI 在 1000 条消息规模下保持流畅。
  13. 完成 Windows 10/11 实机验证。
  14. README 与发布包完整。

63. 开始编码时的第一条任务

Agent 不要立即实现 Gotify。

第一步只做:

Phase 1
+
Phase 2 UI Shell
+
Mock Message Data

先把下面这个界面做到成品级:

┌─────────────────────────────────────────────────────────────┐
│ Gotify                                  ● Connected         │
├──────────────┬──────────────────────────────────────────────┤
│ All Messages │ Messages                                     │
│              │                                              │
│ Servers      │  Build succeeded                             │
│  Home        │  GitLab Runner · Production                  │
│  NAS         │  2 min ago                                   │
│              │                                              │
│ Filters      │  Backup finished                              │
│  Normal      │  NAS · Backup                                │
│  High        │  8 min ago                                   │
│  Max         │                                              │
│              │                                              │
│ Settings     │                                              │
└──────────────┴──────────────────────────────────────────────┘

要求:

  • 真实可操作
  • 深色/浅色
  • hover 状态
  • selected 状态
  • 空状态
  • loading 状态
  • error 状态
  • 高 DPI 正常
  • 中文正常

完成 UI Shell 后再进入网络层。


64. 最终设计判断

优先级顺序固定为:

可靠性
  >
简洁性
  >
资源占用
  >
可维护性
  >
动画与装饰

任何新功能如果会显著增加:

  • runtime
  • binary size
  • memory
  • dependency count
  • Windows deployment complexity

必须重新评估是否值得加入。

这个项目的核心竞争力不是功能数量,而是:

轻、快、稳、漂亮。


官方参考