feat: simplify SOP to immediate-effect configuration

This commit is contained in:
Eric 1549169735@qq.com
2026-08-18 16:27:02 +08:00
parent c5ab886b70
commit 8de48fb05e
150 changed files with 6764 additions and 1626 deletions

View File

@@ -12,11 +12,12 @@ import (
)
type Config struct {
App AppConfig `yaml:"app"`
Server ServerConfig `yaml:"server"`
Database DatabaseConfig `yaml:"database"`
Auth AuthConfig `yaml:"auth"`
Seed SeedConfig `yaml:"seed"`
App AppConfig `yaml:"app"`
Server ServerConfig `yaml:"server"`
Database DatabaseConfig `yaml:"database"`
Auth AuthConfig `yaml:"auth"`
Seed SeedConfig `yaml:"seed"`
MultiTable MultiTableConfig `yaml:"multitable"`
}
type AppConfig struct {
@@ -63,6 +64,32 @@ type SeedConfig struct {
AdminDisplayName string `yaml:"admin_display_name" env:"APP_SEED_ADMIN_DISPLAY_NAME"`
}
type MultiTableConfig struct {
Enabled bool `yaml:"enabled" env:"APP_MULTITABLE_ENABLED" env-default:"false"`
BaseURL string `yaml:"base_url" env:"APP_MULTITABLE_BASE_URL" env-default:"https://table.iwork-ai.com/open/v1"`
APIKey string `yaml:"api_key" env:"APP_MULTITABLE_API_KEY"`
SyncInterval time.Duration `yaml:"sync_interval" env:"APP_MULTITABLE_SYNC_INTERVAL" env-default:"5s"`
RequestTimeout time.Duration `yaml:"request_timeout" env:"APP_MULTITABLE_REQUEST_TIMEOUT" env-default:"10s"`
BatchSize int `yaml:"batch_size" env:"APP_MULTITABLE_BATCH_SIZE" env-default:"20"`
MaxAttempts int `yaml:"max_attempts" env:"APP_MULTITABLE_MAX_ATTEMPTS" env-default:"12"`
Tables MultiTableTables `yaml:"tables"`
}
type MultiTableTables struct {
Scenarios uint64 `yaml:"scenarios" env:"APP_MULTITABLE_TABLES_SCENARIOS"`
ScenarioFields uint64 `yaml:"scenario_fields" env:"APP_MULTITABLE_TABLES_SCENARIO_FIELDS"`
ScenarioRules uint64 `yaml:"scenario_rules" env:"APP_MULTITABLE_TABLES_SCENARIO_RULES"`
SOPVersions uint64 `yaml:"sop_versions" env:"APP_MULTITABLE_TABLES_SOP_VERSIONS"`
SOPNodes uint64 `yaml:"sop_nodes" env:"APP_MULTITABLE_TABLES_SOP_NODES"`
SOPEdges uint64 `yaml:"sop_edges" env:"APP_MULTITABLE_TABLES_SOP_EDGES"`
KnowledgeItems uint64 `yaml:"knowledge_items" env:"APP_MULTITABLE_TABLES_KNOWLEDGE_ITEMS"`
KnowledgeRelations uint64 `yaml:"knowledge_relations" env:"APP_MULTITABLE_TABLES_KNOWLEDGE_RELATIONS"`
// KnowledgeVersions is retained only for replaying historical projection events.
KnowledgeVersions uint64 `yaml:"knowledge_versions" env:"APP_MULTITABLE_TABLES_KNOWLEDGE_VERSIONS"`
Runs uint64 `yaml:"runs" env:"APP_MULTITABLE_TABLES_RUNS"`
Feedback uint64 `yaml:"feedback" env:"APP_MULTITABLE_TABLES_FEEDBACK"`
}
type LoadOptions struct {
Environment string
ConfigDir string
@@ -138,5 +165,33 @@ func (c Config) Validate() error {
if c.App.Env == "prod" && c.Database.Password == "" {
return errors.New("database password is required in production")
}
if c.MultiTable.Enabled {
if !strings.HasPrefix(c.MultiTable.BaseURL, "https://") {
return errors.New("multitable.base_url must use https when multitable is enabled")
}
if strings.TrimSpace(c.MultiTable.APIKey) == "" {
return errors.New("APP_MULTITABLE_API_KEY is required when multitable is enabled")
}
if c.MultiTable.SyncInterval <= 0 || c.MultiTable.RequestTimeout <= 0 || c.MultiTable.BatchSize < 1 || c.MultiTable.MaxAttempts < 1 {
return errors.New("multitable retry and timeout settings must be positive")
}
ids := []uint64{
c.MultiTable.Tables.Scenarios,
c.MultiTable.Tables.ScenarioFields,
c.MultiTable.Tables.ScenarioRules,
c.MultiTable.Tables.SOPVersions,
c.MultiTable.Tables.SOPNodes,
c.MultiTable.Tables.SOPEdges,
c.MultiTable.Tables.KnowledgeItems,
c.MultiTable.Tables.KnowledgeRelations,
c.MultiTable.Tables.Runs,
c.MultiTable.Tables.Feedback,
}
for _, id := range ids {
if id == 0 {
return errors.New("all multitable table IDs are required when multitable is enabled")
}
}
}
return nil
}

View File

@@ -72,6 +72,34 @@ func TestLoadProductionRequiresEnvironmentSecrets(t *testing.T) {
}
}
func TestLoadMultiTableEnvironmentConfiguration(t *testing.T) {
dir := writeConfigs(t, "")
t.Setenv("APP_MULTITABLE_ENABLED", "true")
t.Setenv("APP_MULTITABLE_API_KEY", "test-key")
for key, value := range map[string]string{
"APP_MULTITABLE_TABLES_SCENARIOS": "46",
"APP_MULTITABLE_TABLES_SCENARIO_FIELDS": "47",
"APP_MULTITABLE_TABLES_SCENARIO_RULES": "54",
"APP_MULTITABLE_TABLES_SOP_VERSIONS": "48",
"APP_MULTITABLE_TABLES_SOP_NODES": "49",
"APP_MULTITABLE_TABLES_SOP_EDGES": "50",
"APP_MULTITABLE_TABLES_KNOWLEDGE_VERSIONS": "51",
"APP_MULTITABLE_TABLES_KNOWLEDGE_ITEMS": "55",
"APP_MULTITABLE_TABLES_KNOWLEDGE_RELATIONS": "56",
"APP_MULTITABLE_TABLES_RUNS": "52",
"APP_MULTITABLE_TABLES_FEEDBACK": "53",
} {
t.Setenv(key, value)
}
cfg, err := Load(LoadOptions{ConfigDir: dir})
if err != nil {
t.Fatalf("Load() error = %v", err)
}
if !cfg.MultiTable.Enabled || cfg.MultiTable.Tables.Scenarios != 46 || cfg.MultiTable.Tables.ScenarioRules != 54 || cfg.MultiTable.Tables.KnowledgeItems != 55 || cfg.MultiTable.Tables.KnowledgeRelations != 56 || cfg.MultiTable.Tables.Feedback != 53 {
t.Fatalf("unexpected multitable configuration: %+v", cfg.MultiTable)
}
}
func writeConfigs(t *testing.T, profile string) string {
t.Helper()
dir := t.TempDir()