-- ============================================================ -- Migration 004: Full Schema Sync -- Date: 2026-02-07 -- Purpose: Create missing tables, add missing columns, -- and align DB schema with application code. -- ============================================================ -- ──────────────────────────────────────────────────────────── -- 1. TRADE_PROFILES TABLE (Missing CREATE TABLE) -- ──────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS trade_profiles ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), user_id uuid REFERENCES auth.users NOT NULL, name text NOT NULL, allocated_capital numeric DEFAULT 1000, risk_per_trade_percent numeric DEFAULT 1.0, symbols text DEFAULT 'BTC/USDT, ETH/USDT', is_active boolean DEFAULT true, strategy_config jsonb DEFAULT '{ "rules": [ { "ruleId": "TrendBiasRule", "enabled": true, "params": { "timeframe": "4h", "emaFast": 50, "emaSlow": 200 } }, { "ruleId": "SessionRule", "enabled": true, "params": { "allowedSessions": ["NY", "LDN"] } }, { "ruleId": "ZoneRule", "enabled": true, "params": { "emaPeriod": 20, "tolerancePercent": 0.5 } }, { "ruleId": "MomentumRule", "enabled": true, "params": { "timeframe": "1h", "rsiPeriod": 14, "rsiOverbought": 70, "rsiOversold": 30 } }, { "ruleId": "EntryTriggerRule", "enabled": true, "params": { "triggerType": "ema_cross" } }, { "ruleId": "RiskManagementRule", "enabled": true, "params": { "atrPeriod": 14, "riskRewardRatio": 1.5 } }, { "ruleId": "AIAnalysisRule", "enabled": false, "params": { "minConfidence": 80 } } ], "riskLimits": { "maxDailyLossUsd": 50, "maxConsecutiveLosses": 2, "maxOpenTrades": 3 }, "execution": { "orderType": "market", "cooldownMinutes": 30, "entryMode": "both" } }'::jsonb, created_at timestamptz DEFAULT now() ); COMMENT ON TABLE trade_profiles IS 'Trading strategy profiles with per-profile rule config, risk limits, and execution settings'; COMMENT ON COLUMN trade_profiles.strategy_config IS 'JSON configuration: { rules[], riskLimits{}, execution{} }'; CREATE INDEX IF NOT EXISTS idx_trade_profiles_user_id ON trade_profiles(user_id); CREATE INDEX IF NOT EXISTS idx_trade_profiles_is_active ON trade_profiles(is_active); -- RLS ALTER TABLE trade_profiles ENABLE ROW LEVEL SECURITY; DROP POLICY IF EXISTS "Users can manage own profiles" ON trade_profiles; CREATE POLICY "Users can manage own profiles" ON trade_profiles USING (auth.uid() = user_id) WITH CHECK (auth.uid() = user_id); -- ──────────────────────────────────────────────────────────── -- 2. ORDERS TABLE — Add missing columns -- ──────────────────────────────────────────────────────────── -- profile_id: links order to the trade profile that triggered it ALTER TABLE orders ADD COLUMN IF NOT EXISTS profile_id uuid REFERENCES trade_profiles(id) ON DELETE SET NULL; -- stop_loss & take_profit: stored by TradeExecutor.logOrderToDb() ALTER TABLE orders ADD COLUMN IF NOT EXISTS stop_loss numeric; ALTER TABLE orders ADD COLUMN IF NOT EXISTS take_profit numeric; CREATE INDEX IF NOT EXISTS idx_orders_profile_id ON orders(profile_id); COMMENT ON COLUMN orders.profile_id IS 'Trade profile that triggered this order (NULL = manual)'; COMMENT ON COLUMN orders.stop_loss IS 'Stop loss price set at order time'; COMMENT ON COLUMN orders.take_profit IS 'Take profit price set at order time'; -- ──────────────────────────────────────────────────────────── -- 3. TRADE_HISTORY TABLE — Add missing columns -- ──────────────────────────────────────────────────────────── -- profile_id: links trade to the profile that triggered it ALTER TABLE trade_history ADD COLUMN IF NOT EXISTS profile_id uuid REFERENCES trade_profiles(id) ON DELETE SET NULL; -- stop_loss & take_profit: for post-trade analysis ALTER TABLE trade_history ADD COLUMN IF NOT EXISTS stop_loss numeric; ALTER TABLE trade_history ADD COLUMN IF NOT EXISTS take_profit numeric; -- rules_metadata: stores which rules passed/failed for this trade ALTER TABLE trade_history ADD COLUMN IF NOT EXISTS rules_metadata jsonb; CREATE INDEX IF NOT EXISTS idx_trade_history_profile_id ON trade_history(profile_id); COMMENT ON COLUMN trade_history.profile_id IS 'Trade profile that triggered this trade (NULL = manual)'; COMMENT ON COLUMN trade_history.stop_loss IS 'Stop loss price at trade entry'; COMMENT ON COLUMN trade_history.take_profit IS 'Take profit price at trade entry'; COMMENT ON COLUMN trade_history.rules_metadata IS 'JSON snapshot of rule statuses at trade time: { ruleName: { passed, reason } }'; -- ──────────────────────────────────────────────────────────── -- 4. BOT_CONFIG TABLE (Missing CREATE TABLE) -- Used by: ConfigTab.tsx, GlobalConfigManager.tsx -- ──────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS bot_config ( key text PRIMARY KEY, value text, description text, updated_at timestamptz DEFAULT now() ); COMMENT ON TABLE bot_config IS 'Key-value store for global bot configuration (editable from dashboard)'; -- RLS: allow authenticated users to read, admins to write ALTER TABLE bot_config ENABLE ROW LEVEL SECURITY; DROP POLICY IF EXISTS "Authenticated users can read bot_config" ON bot_config; CREATE POLICY "Authenticated users can read bot_config" ON bot_config FOR SELECT USING (auth.role() = 'authenticated'); DROP POLICY IF EXISTS "Admins can manage bot_config" ON bot_config; CREATE POLICY "Admins can manage bot_config" ON bot_config USING ( EXISTS (SELECT 1 FROM users WHERE user_id = auth.uid() AND role = 'admin') ) WITH CHECK ( EXISTS (SELECT 1 FROM users WHERE user_id = auth.uid() AND role = 'admin') ); -- ──────────────────────────────────────────────────────────── -- 5. DYNAMIC_CONFIG TABLE (Missing CREATE TABLE) -- Used by: bot-service config/index.ts (loadDynamicConfig) -- ──────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS dynamic_config ( key text PRIMARY KEY, value text, updated_at timestamptz DEFAULT now() ); COMMENT ON TABLE dynamic_config IS 'Runtime-overridable bot settings loaded at startup (SYMBOLS, intervals, etc.)'; -- ──────────────────────────────────────────────────────────── -- 6. UPDATE schema_reference.sql sync comment -- ──────────────────────────────────────────────────────────── -- After running this migration, all 7 tables are fully defined: -- 1. users (auth trigger-created) -- 2. entries (watchlist & manual positions) -- 3. trade_history (completed trade ledger) -- 4. orders (active/pending orders) -- 5. trade_profiles (strategy profiles with rule config) -- 6. bot_config (global config key-value store) -- 7. dynamic_config (runtime config overrides)