# Design Document ## Overview 本设计将系统提示词管理从文件系统迁移到数据库配置系统。核心目标是提供灵活的后台管理界面,支持在线编辑、版本控制和动态切换,同时确保完全移除对文件系统的依赖,避免配置不一致导致的严重bug。 ## Architecture ### 系统架构层次 ``` ┌─────────────────────────────────────────────────────────────┐ │ Frontend (React) │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ SystemSettings │ │ TraderConfig │ │ │ │ (Prompt Tab) │ │ (Template Select)│ │ │ └──────────────────┘ └──────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ API Layer (Gin) │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ PromptTemplateController │ │ │ │ - List/Create/Update/Delete Templates │ │ │ │ - Version Management │ │ │ │ - Import/Export │ │ │ └──────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Business Logic Layer │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ PromptManager (Refactored) │ │ │ │ - Load from Database │ │ │ │ - Cache Management │ │ │ │ - Template Resolution │ │ │ └──────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Data Access Layer │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ Database (SQLite) │ │ │ │ - prompt_templates │ │ │ │ - prompt_template_versions │ │ │ │ - traders (system_prompt_template FK) │ │ │ └──────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` ### 数据流 1. **配置流**: Admin UI → API → Database → Cache 2. **使用流**: Trader → PromptManager → Cache/Database → AI Engine 3. **迁移流**: File System → Migration Tool → Database ## Components and Interfaces ### 1. Database Schema #### prompt_templates 表 ```sql CREATE TABLE prompt_templates ( id TEXT PRIMARY KEY, name TEXT UNIQUE NOT NULL, description TEXT DEFAULT '', content TEXT NOT NULL, is_default BOOLEAN DEFAULT 0, enabled BOOLEAN DEFAULT 1, created_by TEXT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL ); ``` #### prompt_template_versions 表 ```sql CREATE TABLE prompt_template_versions ( id INTEGER PRIMARY KEY AUTOINCREMENT, template_id TEXT NOT NULL, version_number INTEGER NOT NULL, content TEXT NOT NULL, created_by TEXT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, change_note TEXT DEFAULT '', FOREIGN KEY (template_id) REFERENCES prompt_templates(id) ON DELETE CASCADE, FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL, UNIQUE(template_id, version_number) ); ``` #### 迁移状态表 ```sql CREATE TABLE prompt_migration_status ( id INTEGER PRIMARY KEY AUTOINCREMENT, migration_type TEXT NOT NULL, status TEXT NOT NULL, started_at DATETIME DEFAULT CURRENT_TIMESTAMP, completed_at DATETIME, error_message TEXT DEFAULT '', templates_migrated INTEGER DEFAULT 0, templates_failed INTEGER DEFAULT 0 ); ``` ### 2. Backend Components #### PromptTemplateController (新增) ```go type PromptTemplateController struct { db *config.Database } // API端点 func (c *PromptTemplateController) ListTemplates(ctx *gin.Context) func (c *PromptTemplateController) GetTemplate(ctx *gin.Context) func (c *PromptTemplateController) CreateTemplate(ctx *gin.Context) func (c *PromptTemplateController) UpdateTemplate(ctx *gin.Context) func (c *PromptTemplateController) DeleteTemplate(ctx *gin.Context) func (c *PromptTemplateController) GetVersionHistory(ctx *gin.Context) func (c *PromptTemplateController) RollbackToVersion(ctx *gin.Context) func (c *PromptTemplateController) ExportTemplates(ctx *gin.Context) func (c *PromptTemplateController) ImportTemplates(ctx *gin.Context) func (c *PromptTemplateController) PreviewTemplate(ctx *gin.Context) ``` #### PromptManager (重构) ```go type PromptManager struct { db *config.Database cache map[string]*PromptTemplate mu sync.RWMutex } // 核心方法 func (pm *PromptManager) LoadFromDatabase() error func (pm *PromptManager) GetTemplate(name string) (*PromptTemplate, error) func (pm *PromptManager) RefreshCache() error func (pm *PromptManager) GetAllTemplates() []*PromptTemplate ``` #### Database Methods (新增) ```go // 提示词模板管理 func (d *Database) CreatePromptTemplate(template *PromptTemplate) error func (d *Database) GetPromptTemplate(id string) (*PromptTemplate, error) func (d *Database) GetPromptTemplateByName(name string) (*PromptTemplate, error) func (d *Database) ListPromptTemplates(enabledOnly bool) ([]*PromptTemplate, error) func (d *Database) UpdatePromptTemplate(id string, content string, updatedBy string) error func (d *Database) DeletePromptTemplate(id string) error func (d *Database) SetDefaultPromptTemplate(id string) error // 版本管理 func (d *Database) CreatePromptTemplateVersion(templateID string, content string, createdBy string, note string) error func (d *Database) GetPromptTemplateVersions(templateID string, limit int) ([]*PromptTemplateVersion, error) func (d *Database) RollbackPromptTemplate(templateID string, versionNumber int, rolledBackBy string) error // 迁移相关 func (d *Database) MigratePromptsFromFiles() error func (d *Database) GetMigrationStatus() (*PromptMigrationStatus, error) func (d *Database) InitializeDefaultPrompts() error ``` ### 3. Frontend Components #### PromptManagementTab (新增) ```typescript interface PromptTemplate { id: string; name: string; description: string; content: string; is_default: boolean; enabled: boolean; created_by: string; created_at: string; updated_at: string; } interface PromptManagementTabProps { language: 'zh' | 'en'; } export function PromptManagementTab({ language }: PromptManagementTabProps) { // 状态管理 const [templates, setTemplates] = useState([]); const [selectedTemplate, setSelectedTemplate] = useState(null); const [isEditing, setIsEditing] = useState(false); const [showVersionHistory, setShowVersionHistory] = useState(false); // 核心功能 const loadTemplates = async () => { /* ... */ }; const createTemplate = async (data: CreateTemplateRequest) => { /* ... */ }; const updateTemplate = async (id: string, content: string) => { /* ... */ }; const deleteTemplate = async (id: string) => { /* ... */ }; const previewTemplate = async (content: string) => { /* ... */ }; const exportTemplates = async () => { /* ... */ }; const importTemplates = async (file: File) => { /* ... */ }; return (
{/* 模板列表 */} {/* 编辑器 */} {/* 版本历史 */} {/* 导入导出 */}
); } ``` #### TraderConfigModal (修改) ```typescript // 添加提示词模板选择器
``` ## Data Models ### PromptTemplate ```go type PromptTemplate struct { ID string `json:"id"` Name string `json:"name"` Description string `json:"description"` Content string `json:"content"` IsDefault bool `json:"is_default"` Enabled bool `json:"enabled"` CreatedBy string `json:"created_by"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } ``` ### PromptTemplateVersion ```go type PromptTemplateVersion struct { ID int `json:"id"` TemplateID string `json:"template_id"` VersionNumber int `json:"version_number"` Content string `json:"content"` CreatedBy string `json:"created_by"` CreatedAt time.Time `json:"created_at"` ChangeNote string `json:"change_note"` } ``` ### PromptMigrationStatus ```go type PromptMigrationStatus struct { ID int `json:"id"` MigrationType string `json:"migration_type"` Status string `json:"status"` StartedAt time.Time `json:"started_at"` CompletedAt *time.Time `json:"completed_at"` ErrorMessage string `json:"error_message"` TemplatesMigrated int `json:"templates_migrated"` TemplatesFailed int `json:"templates_failed"` } ``` ## Correctness Properties *A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.* ### Property 1: Database-only prompt loading *For any* prompt template request, the system should query the database and never attempt to read from the file system **Validates: Requirements 2.2, 6.2** ### Property 2: Template uniqueness *For any* two prompt templates in the database, their names should be unique **Validates: Requirements 1.3** ### Property 3: Version history preservation *For any* prompt template update, the system should create a version history record before applying the change **Validates: Requirements 4.1** ### Property 4: Deletion safety check *For any* prompt template deletion request, if any trader is using that template, the deletion should be rejected **Validates: Requirements 1.5** ### Property 5: Default template existence *For any* system state, there should exist exactly one prompt template marked as default **Validates: Requirements 2.4** ### Property 6: Cache consistency *For any* prompt template update in the database, the cache should be invalidated and refreshed **Validates: Requirements 2.3** ### Property 7: Migration idempotency *For any* migration execution, running the migration multiple times should produce the same result as running it once **Validates: Requirements 8.4** ### Property 8: Template content preservation *For any* prompt template, exporting then importing should preserve the exact content **Validates: Requirements 5.1, 5.3** ### Property 9: Version rollback correctness *For any* version rollback operation, the template content should match the selected historical version **Validates: Requirements 4.4** ### Property 10: Trader template reference integrity *For any* trader configuration, the system_prompt_template field should reference an existing enabled template **Validates: Requirements 3.3** ## Error Handling ### 错误类型 1. **TemplateNotFoundError**: 请求的模板不存在 2. **TemplateInUseError**: 模板正在被使用,无法删除 3. **DuplicateTemplateNameError**: 模板名称已存在 4. **InvalidTemplateContentError**: 模板内容格式错误 5. **MigrationFailedError**: 迁移过程失败 6. **CacheRefreshError**: 缓存刷新失败 7. **VersionLimitExceededError**: 版本历史超过限制 ### 错误处理策略 ```go // 统一错误响应格式 type ErrorResponse struct { Error string `json:"error"` Message string `json:"message"` Code string `json:"code"` } // 错误处理中间件 func HandlePromptError(err error) *ErrorResponse { switch err.(type) { case *TemplateNotFoundError: return &ErrorResponse{ Error: "template_not_found", Message: "提示词模板不存在", Code: "PROMPT_404", } case *TemplateInUseError: return &ErrorResponse{ Error: "template_in_use", Message: "模板正在被使用,无法删除", Code: "PROMPT_409", } // ... 其他错误类型 } } ``` ### 降级策略 1. **数据库查询失败**: 使用内存缓存的模板 2. **缓存刷新失败**: 记录错误但不阻塞请求 3. **版本创建失败**: 仍然保存主模板,记录警告 4. **迁移失败**: 回滚到迁移前状态,使用内置默认模板 ## Testing Strategy ### Unit Tests 1. **Database Operations** - 测试CRUD操作的正确性 - 测试唯一性约束 - 测试外键约束 2. **PromptManager** - 测试从数据库加载 - 测试缓存机制 - 测试模板解析 3. **Migration Logic** - 测试文件到数据库的迁移 - 测试幂等性 - 测试错误处理 ### Property-Based Tests 使用 [gopter](https://github.com/leanovate/gopter) 进行属性测试: 1. **Property 1: Database-only loading** ```go // Feature: prompt-config-system, Property 1: Database-only prompt loading func TestPromptLoadingFromDatabase(t *testing.T) { properties := gopter.NewProperties(nil) properties.Property("should never read from file system", prop.ForAll( func(templateName string) bool { // 验证GetTemplate不访问文件系统 pm := NewPromptManager(db) _, err := pm.GetTemplate(templateName) // 检查没有文件系统调用 return !fileSystemAccessed() }, gen.AlphaString(), )) properties.TestingRun(t) } ``` 2. **Property 3: Version history preservation** ```go // Feature: prompt-config-system, Property 3: Version history preservation func TestVersionHistoryPreservation(t *testing.T) { properties := gopter.NewProperties(nil) properties.Property("should create version before update", prop.ForAll( func(templateID string, newContent string) bool { versionsBefore := getVersionCount(templateID) db.UpdatePromptTemplate(templateID, newContent, "test-user") versionsAfter := getVersionCount(templateID) return versionsAfter == versionsBefore + 1 }, gen.UUIDString(), gen.AlphaString(), )) properties.TestingRun(t) } ``` 3. **Property 7: Migration idempotency** ```go // Feature: prompt-config-system, Property 7: Migration idempotency func TestMigrationIdempotency(t *testing.T) { properties := gopter.NewProperties(nil) properties.Property("should produce same result when run multiple times", prop.ForAll( func() bool { // 第一次迁移 db.MigratePromptsFromFiles() state1 := captureDBState() // 第二次迁移 db.MigratePromptsFromFiles() state2 := captureDBState() return reflect.DeepEqual(state1, state2) }, )) properties.TestingRun(t) } ``` ### Integration Tests 1. **End-to-End Template Management** - 创建 → 编辑 → 版本回滚 → 删除 - 导出 → 导入 → 验证 2. **Trader Integration** - 创建交易员 → 选择模板 → 执行决策 - 验证使用正确的提示词 3. **Migration Flow** - 文件系统 → 数据库 → 验证完整性 - 测试错误恢复 ### Manual Testing Checklist - [ ] 管理员可以创建新提示词模板 - [ ] 管理员可以编辑现有模板 - [ ] 编辑后立即生效(无需重启) - [ ] 版本历史正确记录 - [ ] 可以回滚到历史版本 - [ ] 删除时检查使用情况 - [ ] 导出包含所有模板 - [ ] 导入处理名称冲突 - [ ] 交易员可以选择模板 - [ ] 交易员使用正确的模板 - [ ] 迁移成功完成 - [ ] 迁移后文件不再被读取