CREATE TYPE "public"."calidad" AS ENUM('basica', 'media', 'premium'); CREATE TYPE "public"."categoria_material" AS ENUM('suelo', 'pared', 'pintura', 'mobiliario'); CREATE TYPE "public"."envio_presupuesto_mode" AS ENUM('automatico', 'revision'); CREATE TYPE "public"."lead_estado" AS ENUM('nuevo', 'contactado', 'visita_agendada', 'presupuesto_enviado', 'ganado', 'perdido'); CREATE TYPE "public"."pipeline_stage" AS ENUM('form_completado', 'fotos_subidas', 'prellamada_enviada', 'llamada_completada', 'render_generado', 'presupuesto_generado', 'whatsapp_entregado'); CREATE TYPE "public"."subscription_status" AS ENUM('trial', 'activo', 'cancelado', 'vencido'); CREATE TYPE "public"."testimonio_estado" AS ENUM('pendiente', 'publicado', 'oculto'); CREATE TYPE "public"."tipo_reforma" AS ENUM('cocina', 'bano', 'salon', 'comedor', 'integral', 'otro'); CREATE TYPE "public"."unidad_medida" AS ENUM('m2', 'ml', 'ud'); CREATE TYPE "public"."urgencia" AS ENUM('alta', 'media', 'baja'); CREATE TYPE "public"."user_role" AS ENUM('reformista', 'admin'); CREATE TYPE "public"."user_status" AS ENUM('activo', 'deshabilitado'); CREATE TABLE "catalog_items" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "tenant_id" uuid NOT NULL, "categoria" "categoria_material" NOT NULL, "nombre" text NOT NULL, "calidad" "calidad" NOT NULL, "precio_unit" integer NOT NULL, "unidad" "unidad_medida" NOT NULL, "descriptor_render" text DEFAULT '' NOT NULL, "es_default" boolean DEFAULT false NOT NULL, "sku" text NOT NULL ); CREATE TABLE "galeria_fotos" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "tenant_id" uuid NOT NULL, "url" text NOT NULL, "titulo" text, "orden" integer DEFAULT 0 NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL ); CREATE TABLE "lead_estado_history" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "lead_id" uuid NOT NULL, "estado" "lead_estado" NOT NULL, "changed_at" timestamp with time zone DEFAULT now() NOT NULL, "changed_by" text ); CREATE TABLE "lead_fotos" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "lead_id" uuid NOT NULL, "url" text NOT NULL, "orden" integer DEFAULT 0 NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL ); CREATE TABLE "lead_pipeline_eventos" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "lead_id" uuid NOT NULL, "stage" "pipeline_stage" NOT NULL, "occurred_at" timestamp with time zone DEFAULT now() NOT NULL, "metadata" jsonb ); CREATE TABLE "leads" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "tenant_id" uuid NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL, "nombre" text NOT NULL, "telefono" text NOT NULL, "email" text NOT NULL, "provincia" text, "tipo_reforma" "tipo_reforma", "consent_privacidad" boolean DEFAULT false NOT NULL, "consent_contratacion" boolean DEFAULT false NOT NULL, "pipeline_stage" "pipeline_stage" DEFAULT 'form_completado' NOT NULL, "estado" "lead_estado" DEFAULT 'nuevo' NOT NULL, "presupuesto_estimado" integer, "transcripcion" text, "entidades" jsonb, "render_url" text, "pdf_url" text, "audio_url" text, "notas" text, "testimonio_solicitado_at" timestamp with time zone, "m2_suelo" double precision, "altura_techo" double precision, "calidad_global" "calidad", "estructural" boolean DEFAULT false NOT NULL, "material_selections" jsonb DEFAULT '{}'::jsonb NOT NULL, "desglose_snapshot" jsonb, "urgencia" "urgencia", "presupuesto_target" integer, "taste_text" text, "preferences_snapshot" jsonb ); CREATE TABLE "plans" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "slug" text NOT NULL, "nombre" text NOT NULL, "precio_mensual" integer NOT NULL, "leads_incluidos" integer NOT NULL, "features" jsonb DEFAULT '[]'::jsonb NOT NULL, "activo" boolean DEFAULT true NOT NULL, CONSTRAINT "plans_slug_unique" UNIQUE("slug") ); CREATE TABLE "precision_history" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "lead_id" uuid NOT NULL, "estimated" integer NOT NULL, "final" integer NOT NULL, "delta_pct" numeric(6, 2) NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL ); CREATE TABLE "pricing_config" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "tenant_id" uuid NOT NULL, "altura_techo_default" double precision DEFAULT 2.5 NOT NULL, "factor_zona" jsonb DEFAULT '{}'::jsonb NOT NULL, "mano_obra" jsonb DEFAULT '{}'::jsonb NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT "pricing_config_tenant_id_unique" UNIQUE("tenant_id") ); CREATE TABLE "sessions" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "user_id" uuid NOT NULL, "token_hash" text NOT NULL, "expires_at" timestamp with time zone NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT "sessions_token_hash_unique" UNIQUE("token_hash") ); CREATE TABLE "tenants" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "slug" text NOT NULL, "nombre_empresa" text NOT NULL, "logo_url" text, "provincia" text, "whatsapp_business" text, "seo_title" text, "seo_description" text, "about_enabled" boolean DEFAULT false NOT NULL, "about_foto_url" text, "about_texto" text, "anios_experiencia" integer, "theme_preset" text DEFAULT 'pizarra' NOT NULL, "theme_color" text, "cif" text, "direccion" text, "telefono" text, "email" text, "web" text, "plan_id" uuid, "subscription_status" "subscription_status" DEFAULT 'trial' NOT NULL, "envio_presupuesto" "envio_presupuesto_mode" DEFAULT 'automatico' NOT NULL, "trial_ends_at" timestamp with time zone, "stripe_customer_id" text, "created_at" timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT "tenants_slug_unique" UNIQUE("slug") ); CREATE TABLE "testimonio_fotos" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "testimonio_id" uuid NOT NULL, "url" text NOT NULL, "orden" integer DEFAULT 0 NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL ); CREATE TABLE "testimonios" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "tenant_id" uuid NOT NULL, "lead_id" uuid, "nombre" text NOT NULL, "contexto" text, "rating" integer NOT NULL, "texto" text NOT NULL, "estado" "testimonio_estado" DEFAULT 'pendiente' NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL ); CREATE TABLE "users" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "email" text NOT NULL, "password_hash" text NOT NULL, "nombre" text, "role" "user_role" DEFAULT 'reformista' NOT NULL, "tenant_id" uuid, "status" "user_status" DEFAULT 'activo' NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT "users_email_unique" UNIQUE("email") ); ALTER TABLE "catalog_items" ADD CONSTRAINT "catalog_items_tenant_id_tenants_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "galeria_fotos" ADD CONSTRAINT "galeria_fotos_tenant_id_tenants_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "lead_estado_history" ADD CONSTRAINT "lead_estado_history_lead_id_leads_id_fk" FOREIGN KEY ("lead_id") REFERENCES "public"."leads"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "lead_fotos" ADD CONSTRAINT "lead_fotos_lead_id_leads_id_fk" FOREIGN KEY ("lead_id") REFERENCES "public"."leads"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "lead_pipeline_eventos" ADD CONSTRAINT "lead_pipeline_eventos_lead_id_leads_id_fk" FOREIGN KEY ("lead_id") REFERENCES "public"."leads"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "leads" ADD CONSTRAINT "leads_tenant_id_tenants_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "precision_history" ADD CONSTRAINT "precision_history_lead_id_leads_id_fk" FOREIGN KEY ("lead_id") REFERENCES "public"."leads"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "pricing_config" ADD CONSTRAINT "pricing_config_tenant_id_tenants_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "tenants" ADD CONSTRAINT "tenants_plan_id_plans_id_fk" FOREIGN KEY ("plan_id") REFERENCES "public"."plans"("id") ON DELETE no action ON UPDATE no action; ALTER TABLE "testimonio_fotos" ADD CONSTRAINT "testimonio_fotos_testimonio_id_testimonios_id_fk" FOREIGN KEY ("testimonio_id") REFERENCES "public"."testimonios"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "testimonios" ADD CONSTRAINT "testimonios_tenant_id_tenants_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "testimonios" ADD CONSTRAINT "testimonios_lead_id_leads_id_fk" FOREIGN KEY ("lead_id") REFERENCES "public"."leads"("id") ON DELETE set null ON UPDATE no action; ALTER TABLE "users" ADD CONSTRAINT "users_tenant_id_tenants_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE cascade ON UPDATE no action; CREATE INDEX "catalog_tenant_idx" ON "catalog_items" USING btree ("tenant_id"); CREATE UNIQUE INDEX "catalog_tenant_sku_idx" ON "catalog_items" USING btree ("tenant_id","sku"); CREATE INDEX "galeria_tenant_idx" ON "galeria_fotos" USING btree ("tenant_id"); CREATE INDEX "leads_tenant_created_idx" ON "leads" USING btree ("tenant_id","created_at"); CREATE INDEX "leads_estado_idx" ON "leads" USING btree ("estado"); CREATE INDEX "sessions_user_idx" ON "sessions" USING btree ("user_id"); CREATE INDEX "testimonios_tenant_estado_idx" ON "testimonios" USING btree ("tenant_id","estado"); CREATE INDEX "testimonios_lead_idx" ON "testimonios" USING btree ("lead_id"); CREATE INDEX "users_tenant_idx" ON "users" USING btree ("tenant_id");