Przejdź do głównej zawartości

Feature toggles

White-label deploy rzadko ship każdy capability. Feature toggles daj operator turn main product features on/off — na deploy time via config, lub later na runtime, no redeploy. Wszystkie features default enabled; deployment tylko lists które change.

Model​

  • Core.Features.FeatureFlag — enum gateable features: Authoring, Backtesting, Execution, CopyTrading, Ai, PortfolioAgent, Alerts, PropGuard, PropFirm, Accounts, OpenApi, Mcp, Compliance. Core admin surfaces (dashboard, users, nodes, auth) nigdy gateable, nie tutaj.
  • Core.Options.FeaturesOptions — config baseline, bound z App:Features. Każdy property defaults true.
  • Core.Features.IFeatureGate — resolves effective state: config baseline overlaid z optional owner-set runtime override. Implemented przez Infrastructure.Features.FeatureGate, caches overrides briefly (FeatureSettings.OverrideCacheTtl), invalidates na change.

Runtime overrides stored jako AppSetting rows keyed feature.<FeatureFlag> (value true/false). No row = "use config baseline".

Dwie ways do disable feature​

1. Deployment configuration (baseline)​

Set flag false pod App:Features. Example appsettings.json:

{
"App": {
"Features": {
"CopyTrading": false,
"PropGuard": false
}
}
}

Lub via env vars (double underscore):

App__Features__CopyTrading=false

Baseline gates startup registration z background workers (Nodes.AddNodes) i MCP tools (Mcp server), więc feature disabled w config nigdy nie start hosted services ani expose MCP tools.

2. Runtime override (owner)​

Owner może flip każdy feature live z Settings → Features (/settings/features) lub API:

GET /api/features -> [{ "flag": "CopyTrading", "enabled": true }, ...] (Owner)
PUT /api/features/{flag} body { "enabled": false } -> set override (Owner)
PUT /api/features/{flag} body { "enabled": null } -> clear override (revert) (Owner)

Runtime changes take effect immediately dla request-time gates (navigation, API). Background workers i MCP tools gated na startup, pick up runtime change na next process restart.

Co każdy gate enforces​

LayerMechanismTiming
HTTP APIRouteGroupBuilder.RequireFeature(flag) endpoint filter → 404 gdy disabledRuntime
NavigationNavMenu hides links via IFeatureGate.IsEnabledRuntime
Background workersconditional AddHostedService w Nodes.AddNodesStartup (config)
MCP toolsconditional WithTools<> w MCP serverStartup (config)

Feature reached przez deep link gdy disabled renders empty page — jego API returns 404; nav no longer surfaces to.

Flag → surface map​

FlagAPI groupsNavWorkers / MCP
Authoring/api/cbots, /api/paramsets, /api/buildercBots group → cBots (param sets per-cBot dialog)MCP CBotTools
Backtesting(shares /api/instances)cBots group → Backtest—
Execution/api/instancescBots group → RunMCP InstanceTools
CopyTrading/api/copyCopy TradingCopyEngineSupervisor, OpenApiTokenRefreshService, MCP CopyTools
Ai/api/aiAI group → AI; Settings → AI (key)AiRiskGuard, MCP AiTools
PortfolioAgent/api/agentAI group → Portfolio AgentPortfolioAgentService
Alerts/api/alertsAI group → AlertsAlertEvaluator
PropGuard/api/propProp group → Prop GuardPropGuardService
PropFirm/api/prop-firmProp group → Challenges—
Accounts/api/ctidsTrading Accounts—
OpenApi/api/openapiSettings → Open API—
Mcp/api/mcp-keysAI group → MCP Keys—
Compliance/api/complianceSettings → Legal & Privacy—

Testy​

  • Unit — UnitTests/Features/FeaturesOptionsTests.cs: baseline defaults, per-flag mapping.
  • Integracja — IntegrationTests/FeatureGateTests.cs: config baseline, runtime override beats config i persists jako AppSetting, clearing reverts do baseline (real Postgres).
  • E2E — E2ETests/FeatureToggleTests.cs: disabling CopyTrading na runtime hides jego nav link i 404s /api/copy, re-enabling restores oba.