From 86112cf73a0704a370ba3a9f1abda3a6b8e112b7 Mon Sep 17 00:00:00 2001 From: Adrian Flores Cortes Date: Thu, 5 Feb 2026 23:17:19 -0600 Subject: [PATCH] [REMEDIATION] fix: Update trading enums and price_alerts table DDL Add missing enum values to trading schema and refactor price_alerts table structure to align with backend types. Addresses DDL gaps from analysis. Co-Authored-By: Claude Opus 4.6 --- ddl/schemas/trading/00-enums.sql | 20 ++++ .../trading/tables/11-price_alerts.sql | 91 ++++++++++++------- 2 files changed, 79 insertions(+), 32 deletions(-) diff --git a/ddl/schemas/trading/00-enums.sql b/ddl/schemas/trading/00-enums.sql index bf2205f..34cdcd3 100644 --- a/ddl/schemas/trading/00-enums.sql +++ b/ddl/schemas/trading/00-enums.sql @@ -107,3 +107,23 @@ CREATE TYPE trading.drawing_tool_type AS ENUM ( ); COMMENT ON TYPE trading.drawing_tool_type IS 'Types of drawing tools available on charts'; + +-- Tipo de alerta de precio +CREATE TYPE trading.alert_type AS ENUM ( + 'price_above', + 'price_below', + 'percent_change', + 'volume_spike' +); + +COMMENT ON TYPE trading.alert_type IS 'Types of price alerts: above/below threshold, percent change, volume spike'; + +-- Estado de alerta de precio +CREATE TYPE trading.alert_status AS ENUM ( + 'active', + 'triggered', + 'expired', + 'cancelled' +); + +COMMENT ON TYPE trading.alert_status IS 'Status of price alerts: active, triggered, expired, cancelled'; diff --git a/ddl/schemas/trading/tables/11-price_alerts.sql b/ddl/schemas/trading/tables/11-price_alerts.sql index 8cbeca0..10aec46 100644 --- a/ddl/schemas/trading/tables/11-price_alerts.sql +++ b/ddl/schemas/trading/tables/11-price_alerts.sql @@ -1,62 +1,89 @@ -- ============================================================================ -- Schema: trading -- Table: price_alerts --- Description: Alertas de precio configuradas por usuarios --- Gap: GAP-DDL-003 (RESOLVED - ST-1.3) +-- Description: Alertas de precio configuradas por usuarios para el módulo de trading +-- Dependencies: trading.alert_type, trading.alert_status, auth.users, trading.symbols -- Created: 2026-02-03 --- Migration: migrations/2026-02-03_add_price_alerts_symbol_fk.sql +-- Updated: 2026-02-04 -- ============================================================================ CREATE TABLE trading.price_alerts ( + -- Primary Key id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- Relaciones user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, symbol_id UUID NOT NULL REFERENCES trading.symbols(id) ON DELETE CASCADE, - -- Configuracion de alerta - condition VARCHAR(10) NOT NULL CHECK (condition IN ('above', 'below', 'crosses')), - target_price DECIMAL(20,8) NOT NULL CHECK (target_price > 0), - - -- Precio de referencia al crear - reference_price DECIMAL(20,8), + -- Configuración de alerta + alert_type trading.alert_type NOT NULL, + target_price DECIMAL(18,8), + percent_threshold DECIMAL(5,2), -- Estado - is_active BOOLEAN DEFAULT true, - is_recurring BOOLEAN DEFAULT false, + status trading.alert_status NOT NULL DEFAULT 'active', - -- Notificacion - notification_type VARCHAR(20) DEFAULT 'push' CHECK (notification_type IN ('push', 'email', 'both')), - notification_sent BOOLEAN DEFAULT false, - - -- Ejecucion + -- Ejecución triggered_at TIMESTAMPTZ, - triggered_price DECIMAL(20,8), - trigger_count INTEGER DEFAULT 0, + triggered_price DECIMAL(18,8), - -- Expiracion opcional + -- Expiración expires_at TIMESTAMPTZ, - -- Metadata - notes VARCHAR(255), + -- Notificación + notification_channels TEXT[] DEFAULT ARRAY['push', 'email'], + + -- Mensaje personalizado + message TEXT, -- Timestamps created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + + -- Constraints + CONSTRAINT chk_target_price_positive CHECK (target_price IS NULL OR target_price > 0), + CONSTRAINT chk_percent_threshold_valid CHECK (percent_threshold IS NULL OR (percent_threshold > 0 AND percent_threshold <= 100)), + CONSTRAINT chk_alert_config CHECK ( + (alert_type IN ('price_above', 'price_below') AND target_price IS NOT NULL) OR + (alert_type = 'percent_change' AND percent_threshold IS NOT NULL) OR + (alert_type = 'volume_spike') + ) ); --- Indices +-- Índices para performance CREATE INDEX idx_price_alerts_user ON trading.price_alerts(user_id); CREATE INDEX idx_price_alerts_symbol ON trading.price_alerts(symbol_id); -CREATE INDEX idx_price_alerts_active ON trading.price_alerts(is_active, symbol_id) - WHERE is_active = true; +CREATE INDEX idx_price_alerts_active ON trading.price_alerts(status) WHERE status = 'active'; CREATE INDEX idx_price_alerts_expiry ON trading.price_alerts(expires_at) - WHERE expires_at IS NOT NULL AND is_active = true; + WHERE expires_at IS NOT NULL AND status = 'active'; + +-- Trigger para actualizar updated_at +CREATE OR REPLACE FUNCTION trading.update_price_alerts_timestamp() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = NOW(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_price_alerts_updated_at + BEFORE UPDATE ON trading.price_alerts + FOR EACH ROW + EXECUTE FUNCTION trading.update_price_alerts_timestamp(); -- Comentarios -COMMENT ON TABLE trading.price_alerts IS 'Alertas de precio configuradas por usuarios'; -COMMENT ON COLUMN trading.price_alerts.condition IS 'Condicion: above (>=), below (<=), crosses'; -COMMENT ON COLUMN trading.price_alerts.target_price IS 'Precio objetivo para disparar alerta'; -COMMENT ON COLUMN trading.price_alerts.is_recurring IS 'Si es true, se reactiva despues de disparar'; -COMMENT ON COLUMN trading.price_alerts.notification_type IS 'Tipo de notificacion: push, email, both'; -COMMENT ON COLUMN trading.price_alerts.triggered_at IS 'Timestamp de ultima vez que se disparo'; +COMMENT ON TABLE trading.price_alerts IS 'Alertas de precio configuradas por usuarios para el módulo de trading'; +COMMENT ON COLUMN trading.price_alerts.id IS 'Identificador único de la alerta'; +COMMENT ON COLUMN trading.price_alerts.user_id IS 'Referencia al usuario (auth.users)'; +COMMENT ON COLUMN trading.price_alerts.symbol_id IS 'Referencia al símbolo de trading'; +COMMENT ON COLUMN trading.price_alerts.alert_type IS 'Tipo de alerta: price_above, price_below, percent_change, volume_spike'; +COMMENT ON COLUMN trading.price_alerts.target_price IS 'Precio objetivo para alertas de precio (price_above/price_below)'; +COMMENT ON COLUMN trading.price_alerts.percent_threshold IS 'Umbral porcentual para alertas de cambio porcentual'; +COMMENT ON COLUMN trading.price_alerts.status IS 'Estado de la alerta: active, triggered, expired, cancelled'; +COMMENT ON COLUMN trading.price_alerts.triggered_at IS 'Timestamp cuando se disparó la alerta'; +COMMENT ON COLUMN trading.price_alerts.triggered_price IS 'Precio al momento de dispararse la alerta'; +COMMENT ON COLUMN trading.price_alerts.expires_at IS 'Fecha de expiración opcional de la alerta'; +COMMENT ON COLUMN trading.price_alerts.notification_channels IS 'Canales de notificación: push, email, sms, etc.'; +COMMENT ON COLUMN trading.price_alerts.message IS 'Mensaje personalizado para la alerta'; +COMMENT ON COLUMN trading.price_alerts.created_at IS 'Timestamp de creación'; +COMMENT ON COLUMN trading.price_alerts.updated_at IS 'Timestamp de última actualización';