trading-platform-database-v2/ddl/schemas/education/tables/17-instructors.sql
Adrian Flores Cortes c651fe5a30 [TASK-2026-02-03-ANALISIS-DDL-MODELADO] feat(ddl): FASE-1 Gaps Críticos P0
ST-1.1: financial.refunds - Already exists with approval flow
ST-1.2: education.instructors - Created with GIN indexes
ST-1.3: trading.price_alerts - FK exists, idempotent migration added
ST-1.4: ml.prediction_overlays - New table + overlay columns

New files:
- ddl/schemas/education/tables/17-instructors.sql
- ddl/schemas/ml/tables/12-prediction_overlays.sql
- migrations/2026-02-03_add_predictions_overlay.sql
- migrations/2026-02-03_add_price_alerts_symbol_fk.sql

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 23:45:39 -06:00

84 lines
4.1 KiB
SQL

-- =====================================================
-- TABLE: education.instructors
-- =====================================================
-- Proyecto: OrbiQuant IA (Trading Platform)
-- Modulo: OQI-002 - Education
-- Purpose: Instructor profiles for educational content
-- Related: OQI-002 Education Module
-- Gap: GAP-DDL-001
-- Created: 2026-02-03
-- Updated: 2026-02-03
-- =====================================================
CREATE TABLE IF NOT EXISTS education.instructors (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL UNIQUE REFERENCES auth.users(id) ON DELETE CASCADE,
display_name VARCHAR(100) NOT NULL,
bio TEXT,
avatar_url VARCHAR(500),
expertise TEXT[] DEFAULT '{}',
social_links JSONB DEFAULT '{}',
total_courses INTEGER NOT NULL DEFAULT 0,
total_students INTEGER NOT NULL DEFAULT 0,
total_reviews INTEGER NOT NULL DEFAULT 0,
average_rating DECIMAL(3, 2),
is_verified BOOLEAN NOT NULL DEFAULT false,
verified_at TIMESTAMPTZ,
is_active BOOLEAN NOT NULL DEFAULT true,
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT instructors_rating_range CHECK (average_rating IS NULL OR (average_rating >= 0 AND average_rating <= 5)),
CONSTRAINT instructors_counts_positive CHECK (total_courses >= 0 AND total_students >= 0 AND total_reviews >= 0)
);
-- Indexes
CREATE INDEX idx_instructors_user_id ON education.instructors(user_id);
CREATE INDEX idx_instructors_is_verified ON education.instructors(is_verified) WHERE is_verified = true;
CREATE INDEX idx_instructors_is_active ON education.instructors(is_active) WHERE is_active = true;
CREATE INDEX idx_instructors_average_rating ON education.instructors(average_rating DESC NULLS LAST);
CREATE INDEX idx_instructors_expertise ON education.instructors USING GIN(expertise);
-- Trigger for updated_at
CREATE TRIGGER trg_instructors_updated_at
BEFORE UPDATE ON education.instructors
FOR EACH ROW
EXECUTE FUNCTION education.update_updated_at();
-- Comments
COMMENT ON TABLE education.instructors IS 'Instructor profiles linked to auth.users';
COMMENT ON COLUMN education.instructors.user_id IS 'Reference to auth.users - one user can only be one instructor';
COMMENT ON COLUMN education.instructors.display_name IS 'Public display name for the instructor';
COMMENT ON COLUMN education.instructors.expertise IS 'Array of expertise areas (e.g., trading, forex, crypto)';
COMMENT ON COLUMN education.instructors.social_links IS 'JSON with social media links (twitter, linkedin, youtube)';
COMMENT ON COLUMN education.instructors.total_courses IS 'Denormalized count of active courses';
COMMENT ON COLUMN education.instructors.total_students IS 'Denormalized count of unique students';
COMMENT ON COLUMN education.instructors.total_reviews IS 'Denormalized count of course reviews';
COMMENT ON COLUMN education.instructors.average_rating IS 'Calculated average rating from course reviews';
COMMENT ON COLUMN education.instructors.metadata IS 'Additional metadata in JSON format';
-- =====================================================
-- MIGRATION NOTE: education.courses.instructor_id
-- =====================================================
-- The current education.courses table has instructor_id
-- referencing auth.users(id). A migration is needed to:
--
-- 1. Ensure instructors exist for current course instructors:
-- INSERT INTO education.instructors (user_id, display_name)
-- SELECT DISTINCT instructor_id, instructor_name
-- FROM education.courses
-- WHERE instructor_id NOT IN (SELECT user_id FROM education.instructors);
--
-- 2. Change the FK reference (requires careful migration):
-- ALTER TABLE education.courses
-- DROP CONSTRAINT courses_instructor_id_fkey;
--
-- ALTER TABLE education.courses
-- ADD CONSTRAINT courses_instructor_id_fkey
-- FOREIGN KEY (instructor_id) REFERENCES education.instructors(id);
--
-- NOTE: This migration should be created in migrations/ folder
-- when the team decides to implement the full instructor system.
-- =====================================================