-- ===================================================== -- ORBIQUANT IA - WALLETS TABLE (UNIFIED) -- ===================================================== -- Description: Single source of truth for all wallet types -- Schema: financial -- ===================================================== -- UNIFICACIÓN: Esta tabla reemplaza definiciones previas en: -- - OQI-004 (trading schema) -- - OQI-005 (investment schema) -- - OQI-008 (financial schema - legacy) -- ===================================================== CREATE TABLE financial.wallets ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE RESTRICT, -- Tipo y estado wallet_type financial.wallet_type NOT NULL, status financial.wallet_status NOT NULL DEFAULT 'active', -- Balance (precisión de 8 decimales para soportar crypto) balance DECIMAL(20,8) NOT NULL DEFAULT 0.00, available_balance DECIMAL(20,8) NOT NULL DEFAULT 0.00, pending_balance DECIMAL(20,8) NOT NULL DEFAULT 0.00, -- Moneda currency financial.currency_code NOT NULL DEFAULT 'USD', -- Stripe integration (si aplica) stripe_account_id VARCHAR(255), stripe_customer_id VARCHAR(255), -- Límites operacionales daily_withdrawal_limit DECIMAL(15,2), monthly_withdrawal_limit DECIMAL(15,2), min_balance DECIMAL(15,2) DEFAULT 0.00, -- Tracking de uso last_transaction_at TIMESTAMPTZ, total_deposits DECIMAL(20,8) DEFAULT 0.00, total_withdrawals DECIMAL(20,8) DEFAULT 0.00, -- Metadata extensible metadata JSONB DEFAULT '{}', -- Timestamps created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), closed_at TIMESTAMPTZ, -- Constraints CONSTRAINT positive_balance CHECK (balance >= 0), CONSTRAINT positive_available CHECK (available_balance >= 0), CONSTRAINT positive_pending CHECK (pending_balance >= 0), CONSTRAINT available_lte_balance CHECK (available_balance <= balance), CONSTRAINT balance_equation CHECK (balance = available_balance + pending_balance), CONSTRAINT positive_limits CHECK ( (daily_withdrawal_limit IS NULL OR daily_withdrawal_limit > 0) AND (monthly_withdrawal_limit IS NULL OR monthly_withdrawal_limit > 0) ), CONSTRAINT unique_user_wallet_type UNIQUE(user_id, wallet_type, currency), CONSTRAINT closed_status_has_date CHECK ( (status = 'closed' AND closed_at IS NOT NULL) OR (status != 'closed' AND closed_at IS NULL) ) ); -- Indexes para performance CREATE INDEX idx_wallets_user_id ON financial.wallets(user_id); CREATE INDEX idx_wallets_wallet_type ON financial.wallets(wallet_type); CREATE INDEX idx_wallets_status ON financial.wallets(status) WHERE status = 'active'; CREATE INDEX idx_wallets_currency ON financial.wallets(currency); CREATE INDEX idx_wallets_user_type_currency ON financial.wallets(user_id, wallet_type, currency); CREATE INDEX idx_wallets_stripe_account ON financial.wallets(stripe_account_id) WHERE stripe_account_id IS NOT NULL; CREATE INDEX idx_wallets_last_transaction ON financial.wallets(last_transaction_at DESC NULLS LAST); -- Comments COMMENT ON TABLE financial.wallets IS 'Unified wallet table - single source of truth for all wallet types'; COMMENT ON COLUMN financial.wallets.wallet_type IS 'Type of wallet: trading, investment, earnings, referral'; COMMENT ON COLUMN financial.wallets.balance IS 'Total balance = available + pending'; COMMENT ON COLUMN financial.wallets.available_balance IS 'Balance available for immediate use'; COMMENT ON COLUMN financial.wallets.pending_balance IS 'Balance in pending transactions'; COMMENT ON COLUMN financial.wallets.stripe_account_id IS 'Stripe Connect account ID for payouts'; COMMENT ON COLUMN financial.wallets.stripe_customer_id IS 'Stripe Customer ID for payments'; COMMENT ON COLUMN financial.wallets.metadata IS 'Extensible JSON field for additional data';