# 桌面应用 ## Purpose TBD - 提供跨平台桌面应用支持,将后端服务与前端静态资源打包为单一可执行文件 ## Requirements ### Requirement: 桌面应用启动 系统 SHALL 支持作为桌面应用启动,将后端服务与前端静态资源打包为单一可执行文件。 #### Scenario: 双击启动 - **WHEN** 用户双击桌面应用可执行文件 - **THEN** 系统使用 `gofrs/flock` 尝试获取排他文件锁 - **AND** 锁文件路径为系统临时目录下的 `nex-gateway.lock` - **AND** 系统启动后端服务 - **AND** 系统托盘图标出现 - **AND** 浏览器自动打开 `http://localhost:9826` 显示管理界面 #### Scenario: 单实例检查 - **WHEN** 用户尝试启动第二个实例 - **THEN** 系统检测到已有实例持有文件锁 - **AND** 显示错误提示"已有 Nex 实例运行" - **AND** 新实例退出 #### Scenario: 退出释放锁 - **WHEN** 用户点击托盘菜单"退出" - **THEN** 系统释放文件锁 - **AND** 应用进程退出 ### Requirement: 系统托盘 系统 SHALL 提供跨平台系统托盘功能,支持托盘图标和菜单。图标格式 SHALL 根据平台自动选择。 #### Scenario: 托盘图标显示 - **WHEN** 桌面应用启动成功 - **THEN** 系统根据平台加载正确的图标格式 - **AND** 在 Windows 上加载 ICO 格式图标(`assets/icon.ico`) - **AND** 在 macOS 和 Linux 上加载 PNG 格式图标(`assets/icon.png`) - **AND** 托盘图标 tooltip 显示"AI Gateway" #### Scenario: 托盘菜单显示 - **WHEN** 用户点击托盘图标(左键或右键) - **THEN** 显示托盘菜单 - **AND** 菜单包含"打开管理界面"选项 - **AND** 菜单包含"状态: 运行中"选项(禁用状态) - **AND** 菜单包含"端口: 9826"选项(禁用状态) - **AND** 菜单包含"关于"选项 - **AND** 菜单包含"退出"选项 #### Scenario: 打开管理界面 - **WHEN** 用户点击托盘菜单"打开管理界面" - **THEN** 系统在浏览器中打开 `http://localhost:9826` #### Scenario: 浏览器打开失败 - **WHEN** 系统无法打开浏览器(浏览器未安装等) - **THEN** 托盘菜单仍可正常使用 - **AND** 用户可手动访问 `http://localhost:9826` #### Scenario: 退出应用 - **WHEN** 用户点击托盘菜单"退出" - **THEN** 系统优雅关闭后端服务 - **AND** 托盘图标消失 - **AND** 应用进程退出 ### Requirement: 静态文件服务 系统 SHALL 通过 Gin 同时服务 API 和前端静态资源。 #### Scenario: API 请求路由 - **WHEN** 请求路径以 `/api/` 或 `/v1/` 开头 - **THEN** 请求由现有业务 handler 处理 #### Scenario: 静态资源路由 - **WHEN** 请求路径为 `/assets/*` - **THEN** 返回嵌入的前端静态资源文件 #### Scenario: SPA 路由回退 - **WHEN** 请求路径不匹配任何 API 或静态资源路由 - **THEN** 返回 `index.html`(支持前端 SPA 路由) ### Requirement: 端口冲突检测 系统 SHALL 在启动前检测端口是否可用。 #### Scenario: 端口可用 - **WHEN** 端口 9826 未被占用 - **THEN** 服务正常启动 #### Scenario: 端口被占用 - **WHEN** 端口 9826 已被其他程序占用 - **THEN** 显示错误提示"端口 9826 已被占用" - **AND** 应用退出 ### Requirement: 跨平台构建 系统 SHALL 支持跨平台构建和打包。构建 target SHALL 按平台分离,产物文件名 SHALL 使用 `nex-{os}-{arch}[.exe]` 格式。 #### Scenario: macOS 构建 - **WHEN** 执行 `desktop-mac` 构建命令 - **THEN** 生成 `nex-mac-arm64` 和 `nex-mac-amd64` 可执行文件 - **AND** 可打包为 `.app` bundle #### Scenario: Windows 构建 - **WHEN** 执行 `desktop-win` 构建命令 - **THEN** 生成 `nex-win-amd64.exe` 可执行文件 - **AND** 使用 `-H=windowsgui` linker flag 隐藏控制台窗口 #### Scenario: Linux 构建 - **WHEN** 执行 `desktop-linux` 构建命令 - **THEN** 生成 `nex-linux-amd64` 可执行文件 ### Requirement: macOS .app 打包 系统 SHALL 支持打包为 macOS .app bundle。 #### Scenario: .app 结构 - **WHEN** 执行打包脚本 - **THEN** 生成 `Nex.app` 目录结构 - **AND** 包含 `Contents/Info.plist` 元数据 - **AND** 包含 `Contents/MacOS/nex` 可执行文件 - **AND** 包含 `Contents/Resources/AppIcon.icns` 图标 - **AND** `Info.plist` 中 `LSUIElement` 为 `true`(不显示 Dock 图标) ### Requirement: 关于对话框 系统 SHALL 提供关于对话框显示应用信息。在 Windows 上 SHALL 使用 `user32.dll` 的 `MessageBoxW` API 实现。 #### Scenario: 显示关于 - **WHEN** 用户点击托盘菜单"关于" - **THEN** 显示对话框包含应用名称、项目链接 - **AND** 在 Windows 上使用 `MessageBoxW` 原生对话框实现 ### Requirement: Windows 原生对话框 系统 SHALL 在 Windows 上使用 `user32.dll` 的 `MessageBoxW` API 显示错误和关于对话框,替代 `msg *` 命令。 #### Scenario: 错误提示对话框 - **WHEN** 应用在 Windows 上遇到启动错误(端口占用、配置加载失败等) - **THEN** 使用 `MessageBoxW` 显示模态对话框 - **AND** 对话框标题栏显示应用名称 - **AND** 对话框包含错误描述文本 - **AND** 对话框显示错误图标(MB_ICONERROR) #### Scenario: 关于对话框 - **WHEN** 用户在 Windows 上点击托盘菜单"关于" - **THEN** 使用 `MessageBoxW` 显示模态对话框 - **AND** 对话框标题栏显示"关于 Nex Gateway" - **AND** 对话框包含应用信息文本 - **AND** 对话框显示信息图标(MB_ICONINFORMATION) #### Scenario: 非 Windows 平台不受影响 - **WHEN** 应用运行在 macOS 或 Linux 上 - **THEN** 错误和关于对话框仍使用平台原有实现(osascript / zenity)