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>
84 lines
4.1 KiB
SQL
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.
|
|
-- =====================================================
|