-- ===================================================== -- SCHEMA: Onboarding Inteligente -- Epica: MCH-006 - Onboarding Inteligente -- Fecha: 2026-01-18 -- ===================================================== -- ENUM: Onboarding Status DO $$ BEGIN CREATE TYPE onboarding_status AS ENUM ( 'started', 'business_info', 'giro_selected', 'templates_loaded', 'products_added', 'completed', 'abandoned' ); EXCEPTION WHEN duplicate_object THEN null; END $$; -- ENUM: Onboarding Channel DO $$ BEGIN CREATE TYPE onboarding_channel AS ENUM ( 'whatsapp', 'web', 'app' ); EXCEPTION WHEN duplicate_object THEN null; END $$; -- ENUM: Scan Type DO $$ BEGIN CREATE TYPE scan_type AS ENUM ( 'photo', 'audio', 'barcode' ); EXCEPTION WHEN duplicate_object THEN null; END $$; -- ENUM: Scan Status DO $$ BEGIN CREATE TYPE scan_status AS ENUM ( 'pending', 'processing', 'detected', 'confirmed', 'rejected', 'failed' ); EXCEPTION WHEN duplicate_object THEN null; END $$; -- TABLA: onboarding_sessions CREATE TABLE IF NOT EXISTS auth.onboarding_sessions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID REFERENCES auth.tenants(id) ON DELETE SET NULL, phone_number VARCHAR(20) NOT NULL, channel onboarding_channel DEFAULT 'whatsapp', status onboarding_status DEFAULT 'started', current_step INTEGER DEFAULT 1, total_steps INTEGER DEFAULT 5, -- Business info collected business_name VARCHAR(100), business_giro VARCHAR(50), owner_name VARCHAR(100), -- Progress tracking templates_imported INTEGER DEFAULT 0, products_added INTEGER DEFAULT 0, photos_processed INTEGER DEFAULT 0, audios_processed INTEGER DEFAULT 0, -- Metadata metadata JSONB, last_message_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, started_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- INDICES para onboarding_sessions CREATE INDEX IF NOT EXISTS idx_onboarding_sessions_tenant_status ON auth.onboarding_sessions(tenant_id, status); CREATE INDEX IF NOT EXISTS idx_onboarding_sessions_phone ON auth.onboarding_sessions(phone_number); CREATE INDEX IF NOT EXISTS idx_onboarding_sessions_status ON auth.onboarding_sessions(status) WHERE status != 'completed'; -- TABLA: product_scans CREATE TABLE IF NOT EXISTS catalog.product_scans ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), session_id UUID NOT NULL REFERENCES auth.onboarding_sessions(id) ON DELETE CASCADE, tenant_id UUID REFERENCES auth.tenants(id) ON DELETE SET NULL, type scan_type NOT NULL, status scan_status DEFAULT 'pending', -- Input data media_url TEXT, media_mime_type VARCHAR(50), raw_text TEXT, -- OCR/Transcription results detected_name VARCHAR(150), detected_price DECIMAL(10,2), detected_barcode VARCHAR(50), confidence_score DECIMAL(3,2), -- Matched template template_id UUID REFERENCES catalog.product_templates(id) ON DELETE SET NULL, template_match_score DECIMAL(3,2), -- Final product created product_id UUID REFERENCES catalog.products(id) ON DELETE SET NULL, -- User corrections user_confirmed_name VARCHAR(150), user_confirmed_price DECIMAL(10,2), -- Metadata metadata JSONB, error_message TEXT, processing_time_ms INTEGER, created_at TIMESTAMPTZ DEFAULT NOW() ); -- INDICES para product_scans CREATE INDEX IF NOT EXISTS idx_product_scans_session_status ON catalog.product_scans(session_id, status); CREATE INDEX IF NOT EXISTS idx_product_scans_template ON catalog.product_scans(template_id) WHERE template_id IS NOT NULL; -- TRIGGER: Actualizar updated_at en onboarding_sessions CREATE OR REPLACE FUNCTION update_onboarding_sessions_updated_at() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER IF EXISTS trg_onboarding_sessions_updated_at ON auth.onboarding_sessions; CREATE TRIGGER trg_onboarding_sessions_updated_at BEFORE UPDATE ON auth.onboarding_sessions FOR EACH ROW EXECUTE FUNCTION update_onboarding_sessions_updated_at(); -- ===================================================== -- FIN DEL SCHEMA -- =====================================================