feat: 初始化NewLife Studio项目,完成基础框架与数据管理模块
何炳宏 authored at 2026-05-26 12:09:09
22.72 KiB
NewLife.Studio
# NewLife.Studio — 详细实施计划 ## 1. 总体架构 ``` ┌──────────────────────────────────────────────────────────────┐ │ NewLife.Studio.App │ │ (Avalonia Desktop Shell) │ ├────────────┬────────────────────────────────────┬───────────┤ │ NavBar │ Content Area │ AI Panel │ │ ──────── │ ┌───────────────────────────────┐ │ (右侧 │ │ Data │ │ Active Module View │ │ 可折叠) │ │ Studio ● │ │ │ │ │ │ MQTT │ │ ┌─────────┐ ┌─────────────┐ │ │ Chat │ │ Studio │ │ │ 对象树 │ │ 编辑/结果区 │ │ │ History │ │ MQ │ │ │ (左侧) │ │ (右侧) │ │ │ │ │ Studio │ │ │ │ │ │ │ │ Input │ │ Redis │ │ └─────────┘ └─────────────┘ │ │ │ │ Studio │ │ │ │ │ │ ... │ └───────────────────────────────┘ │ │ ├────────────┴────────────────────────────────────┴───────────┤ │ StatusBar (当前连接/Module状态/后台任务) │ └──────────────────────────────────────────────────────────────┘ ``` **分层架构:** ``` src/ ├── Framework/ # 框架层 — 所有模块无条件引用 │ ├── NewLife.Studio.Core/ # IStudioModule, DTOs, StudioServices │ ├── NewLife.Studio.Store/ # 本地持久化 + 加密 │ └── NewLife.Studio.AI/ # IAIProvider + Tool Calling ├── Providers/ # 协议/基础设施提供者层 — 模块按需引用 │ ├── NewLife.Studio.Data/ # IDataProvider, IDbSession, SQLite │ ├── NewLife.Studio.Mqtt/ # IMqttService (后续) │ ├── NewLife.Studio.WebSocket/ # IWebSocketService (后续) │ └── NewLife.Studio.Mq/ # IMqService (后续) ├── App/ │ └── NewLife.Studio.App/ # Shell 壳程序 ├── Modules/ # UI 模块 — 实现 IStudioModule │ ├── DataStudio/ # MVP 首发 │ ├── MqttStudio/ # 预留 │ ├── MqStudio/ # 预留 │ ├── RedisStudio/ # 预留 │ └── ... ``` **依赖方向:** App → Modules → Providers → Framework,永远没有反向引用。Module 之间禁止直接引用。 *** ## 2. 解决方案项目结构 ``` NewLife.Studio/ ├── NewLife.Studio.sln ├── src/ │ ├── Framework/ │ │ ├── NewLife.Studio.Core/ # 核心抽象 │ │ │ ├── IStudioModule.cs # 模块接口 │ │ │ ├── ModuleInfo.cs # 模块元数据 │ │ │ ├── StudioServices.cs # 服务定位器 │ │ │ ├── DTOs/ # 共享 DTO │ │ │ │ ├── ConnectionInfo.cs │ │ │ │ ├── QueryRequest.cs │ │ │ │ ├── QueryResult.cs │ │ │ │ ├── TableInfo.cs │ │ │ │ ├── ColumnInfo.cs │ │ │ │ ├── QueryHistoryEntry.cs │ │ │ │ ├── AiProfile.cs │ │ │ │ └── AppPreference.cs │ │ │ └── Exceptions/ │ │ │ └── StudioException.cs │ │ │ │ │ ├── NewLife.Studio.Store/ # 本地持久化层 │ │ │ ├── IStoreService.cs # 存储服务接口 │ │ │ ├── StoreService.cs # JSON 文件实现 │ │ │ ├── SecretProtection.cs # 敏感信息保护 │ │ │ └── Models/ │ │ │ ├── StoredConnection.cs │ │ │ ├── StoredQueryHistory.cs │ │ │ ├── StoredAiProfile.cs │ │ │ └── StoredAppPreference.cs │ │ │ │ │ └── NewLife.Studio.AI/ # AI 助手层 │ │ ├── IAIProvider.cs # AI Provider 接口 │ │ ├── AIProviderFactory.cs │ │ ├── Models/ │ │ │ └── ChatModels.cs # 对话/工具调用模型 │ │ ├── Providers/ │ │ │ └── OpenAIProvider.cs │ │ ├── ToolCalling/ │ │ │ ├── ToolRegistry.cs # 工具注册中心 │ │ │ ├── AIService.cs # 对话管理 + Tool Calling 循环 │ │ │ └── BuiltInTools/ │ │ │ └── BuiltInDatabaseTools.cs │ │ └── Safety/ │ │ └── QuerySafetyFilter.cs # SQL 安全检查 │ │ │ ├── Providers/ │ │ └── NewLife.Studio.Data/ # 数据访问抽象层 │ │ ├── IDataProvider.cs # 数据库 Provider 接口 │ │ ├── IDbSession.cs # 会话抽象 │ │ └── Providers/ │ │ └── SQLite/ │ │ ├── SQLiteProvider.cs │ │ ├── SQLiteSession.cs │ │ └── SQLiteMetadataReader.cs │ │ │ ├── App/ │ │ └── NewLife.Studio.App/ # Avalonia 主项目 (Shell) │ │ ├── App.axaml / App.axaml.cs # 应用入口 │ │ ├── MainWindow.axaml/.cs # 主窗口 (Shell 布局) │ │ ├── Program.cs # Main 入口 │ │ ├── Controls/ │ │ │ ├── NavBar.axaml/.cs # 左侧导航栏 │ │ │ ├── StatusBar.axaml/.cs # 底部状态栏 │ │ │ ├── ModuleHost.axaml/.cs # 模块内容容器 │ │ │ └── AIPanel.axaml/.cs # AI 助手面板 │ │ ├── Services/ │ │ │ └── ModuleLoader.cs # 模块扫描与加载 │ │ └── ViewModels/ │ │ └── ViewModelBase.cs │ │ │ └── Modules/ │ └── DataStudio/ # Data Studio 模块 (MVP) │ ├── DataStudioModule.cs # IStudioModule 实现 │ ├── ViewModels/ │ │ ├── DataStudioViewModel.cs │ │ ├── ConnectionListViewModel.cs │ │ ├── ObjectTreeViewModel.cs │ │ ├── SqlEditorViewModel.cs │ │ └── ResultGridViewModel.cs │ └── Views/ │ ├── DataStudioView.axaml/.cs │ ├── ConnectionListView.axaml/.cs │ ├── ObjectTreeView.axaml/.cs │ ├── SqlEditorView.axaml/.cs │ └── ResultGridView.axaml/.cs │ └── tests/ ├── NewLife.Studio.Core.Tests/ ├── NewLife.Studio.Store.Tests/ ├── NewLife.Studio.Data.Tests/ ├── NewLife.Studio.AI.Tests/ └── NewLife.Studio.Modules.DataStudio.Tests/ ``` *** ## 3. 核心接口设计 ### 3.1 IStudioModule — 模块注册接口 ```csharp namespace NewLife.Studio.Core; /// <summary>Studio 模块标准接口</summary> public interface IStudioModule { /// <summary>模块唯一标识</summary> string Id { get; } /// <summary>显示名称</summary> string DisplayName { get; } /// <summary>导航栏图标 (Material/Path icon key)</summary> string Icon { get; } /// <summary>导航排序 (越小越靠前)</summary> int Order { get; } /// <summary>模块激活时调用</summary> Task OnActivateAsync(CancellationToken ct = default); /// <summary>模块停用时调用</summary> Task OnDeactivateAsync(CancellationToken ct = default); /// <summary>获取模块主视图 (返回 Avalonia UserControl)</summary> Control GetView(); } ``` ### 3.2 IDataProvider — 数据库 Provider 接口 ```csharp namespace NewLife.Studio.Data; public interface IDataProvider { string ProviderName { get; } string[] SupportedSchemes { get; } // e.g. ["sqlite", "sqlite3"] bool CanTestConnection { get; } Task<bool> TestConnectionAsync(ConnectionInfo conn, CancellationToken ct = default); Task<IDbSession> OpenSessionAsync(ConnectionInfo conn, CancellationToken ct = default); } public interface IDbSession : IDisposable { string SessionId { get; } ConnectionInfo Connection { get; } bool IsOpen { get; } Task<TableInfo[]> GetTablesAsync(CancellationToken ct = default); Task<ColumnInfo[]> GetColumnsAsync(string tableName, CancellationToken ct = default); Task<QueryResult> ExecuteQueryAsync(QueryRequest request, CancellationToken ct = default); Task CloseAsync(); } ``` ### 3.3 IStoreService — 本地存储接口 ```csharp namespace NewLife.Studio.Store; public interface IStoreService { // 连接管理 Task<ConnectionInfo[]> ListConnectionsAsync(); Task SaveConnectionAsync(ConnectionInfo conn); Task DeleteConnectionAsync(string id); // 查询历史 Task AddQueryHistoryAsync(QueryHistoryEntry entry); Task<QueryHistoryEntry[]> GetRecentQueriesAsync(int count = 50); // AI 配置 Task<AIProfile> GetAIProfileAsync(); Task SaveAIProfileAsync(AIProfile profile); // 应用偏好 Task<AppPreference> GetPreferencesAsync(); Task SavePreferencesAsync(AppPreference pref); } ``` ### 3.4 IAIProvider — AI Provider 接口 ```csharp namespace NewLife.Studio.AI; public interface IAIProvider { string ProviderName { get; } Task<ChatResponse> ChatAsync( ChatRequest request, CancellationToken ct = default); } public class ChatRequest { public List<ChatMessage> Messages { get; set; } public List<ToolDefinition> Tools { get; set; } public string Model { get; set; } public int MaxTokens { get; set; } = 4096; } public class ChatResponse { public string Content { get; set; } public List<ToolCall> ToolCalls { get; set; } public long InputTokens { get; set; } public long OutputTokens { get; set; } } ``` *** ## 4. 核心数据模型 (DTO) | DTO | 关键字段 | 说明 | | ------------------- | --------------------------------------------------------------- | ----- | | `ConnectionInfo` | Id, Name, ConnectionString, ProviderType, LastUsedAt, Group | 连接配置 | | `QueryRequest` | Sql, ConnectionId, MaxRows(默认1000), TimeoutSeconds(默认30) | 查询请求 | | `QueryResult` | Columns\[], Rows\[]\[], RowCount, ElapsedMs, Truncated, Error | 查询结果 | | `TableInfo` | Name, Schema, RowCount(可选) | 表信息 | | `ColumnInfo` | Name, DataType, IsNullable, DefaultValue, IsPrimaryKey, Ordinal | 列信息 | | `QueryHistoryEntry` | Id, Sql, ConnectionName, ExecutedAt, ElapsedMs, RowCount | 历史记录 | | `AIProfile` | ProviderType, Endpoint, ApiKey, Model | AI 配置 | | `AppPreference` | MaxRows, DefaultExportPath, Theme, Language | 用户偏好 | *** ## 5. UI 组件树 ``` MainWindow ├── NavBar (左侧, 48px 宽) │ └── ModuleNavItem[] (按 Order 排序) │ ├── Icon │ ├── DisplayName (ToolTip) │ └── IsActive (高亮指示) │ ├── ModuleHost (中间, 填充剩余) │ └── ActiveView (当前激活 Module 的 GetView() 返回值) │ │ │ │ ★ DataStudio 模块内部布局: │ │ ┌──────────────────────────────────────┐ │ │ │ Toolbar (新建连接/断开/导出) │ │ │ ├────────────┬─────────────────────────┤ │ │ │ ObjectTree │ TabControl │ │ │ │ ───────── │ ├── Query1 (SQL编辑器 │ │ │ │ ▸ conn-1 │ │ + 结果网格) │ │ │ │ ▸ tables │ ├── Query2 │ │ │ │ ▸ views │ └── + 新查询 │ │ │ │ ▸ conn-2 │ │ │ │ └────────────┴─────────────────────────┘ │ └────────────────────────────────────────── │ ├── AIPanel (右侧, 可折叠, 300px) │ ├── ChatMessageList │ │ └── ChatBubble[] │ │ ├── Role (User/Assistant/Tool) │ │ ├── Content (Markdown) │ │ └── ToolCallInfo (展开查看工具调用) │ └── ChatInput (多行输入 + 发送按钮) │ └── StatusBar (底部, 24px) ├── ActiveConnection ├── BackgroundTaskIndicator └── ModuleName ``` *** ## 6. 数据流 ### 6.1 用户执行 SQL 查询流程 ``` 用户输入 SQL → SqlEditorViewModel.ExecuteCommand → QueryRequest { Sql, ConnectionId, MaxRows } → IDbSession.ExecuteQueryAsync() → SQLite 执行 (Microsoft.Data.Sqlite) → QueryResult { Columns[], Rows[][], ElapsedMs, Truncated } → ResultGridViewModel.Result ← QueryResult → UI 绑定刷新 DataGrid → Store.AddQueryHistoryAsync() (异步、不阻塞 UI) ``` ### 6.2 AI 工具调用闭环流程 ``` 用户提问 ──────────────────────────────────────────────────────┐ │ │ ▼ │ ChatInput → AIService.ChatAsync() │ │ │ ▼ │ IAIProvider.ChatAsync(messages + tools) ──► AI 模型 │ │ │ │ │◄────── ChatResponse { Content / ToolCalls } │ │ │ ├── 有 ToolCalls? ──YES──► ToolExecutor.Execute(toolCall) │ │ │ │ │ ▼ │ │ 内置工具执行 (安全过滤) │ │ │ │ │ ▼ │ │ ToolResult { Output, Error } │ │ │ │ │ ▼ │ │ 追加 Assistant(tool_call) + │ │ Tool(result) 消息到对话 │ │ │ │ │ └──► 回到 ChatAsync() 继续推理 │ │ │ └── NO ToolCalls ──► 直接展示 Markdown 回复 │ ``` ### 6.3 模块切换流程 ``` 用户点击 NavBar 上的 ModuleNavItem → ModuleLoader.SwitchTo(moduleId) → 当前 Module.OnDeactivateAsync() (保存状态, 不关闭连接) → 目标 Module.OnActivateAsync() → ModuleHost.Content ← 目标 Module.GetView() → NavBar 更新激活指示 → StatusBar 更新当前模块名 ``` *** ## 7. 安全策略 ### 7.1 AI SQL 安全过滤 所有通过 AI Tool Calling 执行的 SQL 在 `QuerySafetyFilter` 中检查: | 规则 | 行为 | | -------------------------------------- | -------------------- | | 仅允许 SELECT / EXPLAIN / PRAGMA (只读) | 拒绝并返回错误 | | INSERT/UPDATE/DELETE/DROP/ALTER/CREATE | 拒绝,提示"AI 模式不支持写操作" | | 多语句 (分号分隔) | 拒绝 | | 结果行数 > MaxRows | 裁剪并标注 Truncated=true | | 查询超时 > TimeoutSeconds | 取消 CancellationToken | ### 7.2 敏感信息保护 | 数据 | 保护方式 | | ---------- | --------------------- | | 数据库密码 | AES 加密存储 / 系统凭据库 | | AI API Key | AES 加密存储 | | 连接字符串 | 脱敏存储 (密码部分替换为 \*\*\*) | *** ## 8. 关键技术选型 | 层 | 技术 | 说明 | | ----- | ---------------------------------------- | ----------------------------- | | UI 框架 | Avalonia 11.x | 跨平台桌面 (Windows/Linux/macOS) | | MVVM | CommunityToolkit.Mvvm | 简化 ViewModel 与绑定 | | 数据访问 | Microsoft.Data.Sqlite + NewLife.XCode | SQLite MVP; XCode 为多数据库扩展 | | AI | OpenAI-compatible API | 支持 OpenAI / Azure / 本地 Ollama | | 存储 | System.Text.Json + 本地文件 | JSON 文件存储,AppData 目录 | | 加密 | System.Security.Cryptography (AES) | 敏感信息加密 | | 日志 | NewLife.Core (XTrace) | 统一日志 | | 依赖注入 | Microsoft.Extensions.DependencyInjection | 模块注册与服务管理 | *** ## 9. 实施阶段 (8 个 Task) ### Phase 1: 骨架搭建 (Task 1-2, 约 40%) ``` Task 1: 解决方案 + Shell + Module 接口 ├── dotnet new avalonia.app → NewLife.Studio.App ├── dotnet new classlib → Core / Store / Data / AI / Shared ├── 定义 IStudioModule 接口 ├── 实现 Shell 布局 (NavBar + ModuleHost + StatusBar) ├── 实现 ModuleLoader (Assembly 扫描 + 注册) └── 验证: 空 Shell 窗口启动,显示导航栏骨架 Task 2: 本地存储 ├── 定义 StoredConnection / QueryHistory / AIProfile / AppPreference ├── 实现 StoreService (JSON 读写) ├── 实现 SecretProtection (AES 占位) └── 验证: 连接信息写入/读取/重启恢复 ``` ### Phase 2: Data Studio 核心 (Task 3-4, 约 25%) ``` Task 3: SQLite Provider ├── 定义 IDataProvider / IDbSession ├── 实现 SQLiteProvider (连接测试 + 打开会话) ├── 实现 SQLiteMetadataReader (表/列/主键信息) └── 验证: 打开 SQLite 文件,读取元数据 Task 4: 查询执行 ├── 定义 QueryRequest / QueryResult ├── 实现 SELECT 执行 + 结果封装 ├── 实现 MaxRows 裁剪 + 耗时统计 ├── 实现历史记录写入 └── 验证: 执行 SELECT,返回网格数据 ``` ### Phase 3: Data Studio UI (Task 5-6, 约 20%) ``` Task 5: UI 闭环 ├── ConnectionListView (连接 CRUD + 测试按钮) ├── ObjectTreeView (递归树: 连接→表→列) ├── SqlEditorView (多 Tab 编辑器 + 执行按钮) ├── ResultGridView (DataGrid 绑定 + 耗时显示) ├── DataStudioModule 实现 IStudioModule 并注册 └── 验证: 完整 UI 交互闭环 Task 6: 导出 ├── CSV 导出 (UTF-8 + 逗号分隔) ├── JSON 导出 (数组格式) └── 验证: 结果集导出为 CSV/JSON 文件 ``` ### Phase 4: AI 助手 (Task 7, 约 10%) ``` Task 7: AI Tool Calling ├── IAIProvider 接口 + OpenAI 实现 ├── ToolRegistry (6 个内置工具) ├── QuerySafetyFilter (只读 + 行限制) ├── AI 面板 UI (Chat + 工具调用可视化) └── 验证: AI 分析数据库闭环 ``` ### Phase 5: 打包验证 (Task 8, 约 5%) ``` Task 8: 打包与验证 ├── 端到端验证 (连接→查询→导出→AI 分析) ├── 跨平台发布配置 (dotnet publish) └── 验证: Windows/Linux/macOS 可运行 ``` *** ## 10. 依赖关系图 ``` Task 1 (Shell + Module接口) ├──► Task 2 (Store) │ └──► Task 4 (查询执行) ──► Task 5 (UI) ──► Task 6 (导出) │ │ │ │ ├──► Task 3 (SQLite) │ │ └──► Task 4 ──────────────────┘ │ │ Task 7 (AI) ─── requires Task 1,2,3,4 ──────────┤ │ Task 8 (打包) ─── requires Task 5,6,7 ───────────┘ ``` *** ## 11. 风险与缓解 | 风险 | 影响 | 缓解 | | ----------------- | ---------- | --------------------------------------- | | Avalonia 跨平台渲染不一致 | UI 布局差异 | 早期三平台验证;使用 Grid/StackPanel 避免绝对定位 | | SQLite 大文件性能 | 元数据浏览卡顿 | 异步加载 + 虚拟化树;元数据缓存 | | AI API 不可用/超时 | AI 助手不可用 | 降级策略:AI 面板显示连接错误,不影响其他功能 | | 后续模块接口不足 | 大改 Core 接口 | IStudioModule 保持最小集合;Module 间通过 DI 获取服务 | | 跨平台文件路径差异 | 存储/导出路径错误 | 统一使用 `Environment.SpecialFolder` |