diff --git a/supabase/migrations/20260122192101_cambios_a_remoto.sql b/supabase/migrations/20260122192101_cambios_a_remoto.sql deleted file mode 100644 index dd89fe9..0000000 --- a/supabase/migrations/20260122192101_cambios_a_remoto.sql +++ /dev/null @@ -1,71 +0,0 @@ -alter type "public"."tipo_cambio" rename to "tipo_cambio__old_version_to_be_dropped"; - -create type "public"."tipo_cambio" as enum ('ACTUALIZACION_CAMPO', 'ACTUALIZACION_MAPA', 'TRANSICION_ESTADO', 'OTRO', 'CREACION'); - -alter table "public"."cambios_asignatura" alter column tipo type "public"."tipo_cambio" using tipo::text::"public"."tipo_cambio"; - -alter table "public"."cambios_plan" alter column tipo type "public"."tipo_cambio" using tipo::text::"public"."tipo_cambio"; - -drop type "public"."tipo_cambio__old_version_to_be_dropped"; - -set check_function_bodies = off; - -create or replace view "public"."plantilla_plan" as SELECT plan.id AS plan_estudio_id, - struct.id AS estructura_id, - struct.template_id - FROM (public.planes_estudio plan - JOIN public.estructuras_plan struct ON ((plan.estructura_id = struct.id))); - -CREATE OR REPLACE FUNCTION public.set_actualizado_en() - RETURNS trigger - LANGUAGE plpgsql -AS $function$ -begin - new.actualizado_en = now(); - return new; -end; -$function$ -; - -CREATE OR REPLACE FUNCTION public.unaccent_immutable(text) - RETURNS text - LANGUAGE sql - IMMUTABLE PARALLEL SAFE STRICT -AS $function$ - SELECT public.unaccent('public.unaccent', $1); -$function$ -; - -CREATE OR REPLACE FUNCTION public.validar_numero_ciclo_asignatura() - RETURNS trigger - LANGUAGE plpgsql -AS $function$ -declare - v_numero_ciclos int; -begin - if new.numero_ciclo is null then - return new; - end if; - - select pe.numero_ciclos into v_numero_ciclos - from planes_estudio pe - where pe.id = new.plan_estudio_id; - - if v_numero_ciclos is null then - raise exception 'plan_estudio_id inv谩lido %, plan no encontrado', new.plan_estudio_id; - end if; - - if new.numero_ciclo < 1 then - raise exception 'numero_ciclo debe ser >= 1 (recibido %)', new.numero_ciclo; - end if; - - if new.numero_ciclo > v_numero_ciclos then - raise exception 'numero_ciclo % excede planes_estudio.numero_ciclos % para plan_estudio_id %', - new.numero_ciclo, v_numero_ciclos, new.plan_estudio_id; - end if; - - return new; -end; -$function$ -; - diff --git a/supabase/migrations/20260130215440_cambios_asignatura.sql b/supabase/migrations/20260130215440_cambios_asignatura.sql deleted file mode 100644 index cbf5fee..0000000 --- a/supabase/migrations/20260130215440_cambios_asignatura.sql +++ /dev/null @@ -1,21 +0,0 @@ --- alter table "public"."asignaturas" drop constraint "asignaturas_facultad_propietaria_id_fkey"; - --- alter table "public"."asignaturas" drop constraint "asignaturas_horas_semana_check"; - --- alter table "public"."asignaturas" drop column "facultad_propietaria_id"; - -alter table "public"."asignaturas" drop column "horas_semana"; - -alter table "public"."asignaturas" add column "horas_academicas" integer; - -alter table "public"."asignaturas" add column "horas_independientes" integer; - -alter table "public"."asignaturas" add constraint "asignaturas_horas_academicas_check" CHECK (((horas_academicas IS NULL) OR (horas_academicas >= 0))) not valid; - -alter table "public"."asignaturas" validate constraint "asignaturas_horas_academicas_check"; - -alter table "public"."asignaturas" add constraint "asignaturas_horas_independientes_check" CHECK (((horas_independientes IS NULL) OR (horas_independientes >= 0))) not valid; - -alter table "public"."asignaturas" validate constraint "asignaturas_horas_independientes_check"; - - diff --git a/supabase/migrations/20260203204213_sincronizacion_con_remoto.sql b/supabase/migrations/20260203204213_sincronizacion_con_remoto.sql deleted file mode 100644 index f5a9caf..0000000 --- a/supabase/migrations/20260203204213_sincronizacion_con_remoto.sql +++ /dev/null @@ -1,199 +0,0 @@ -create extension if not exists "http" with schema "extensions"; - -alter table "public"."asignaturas" drop constraint if exists "asignaturas_facultad_propietaria_id_fkey"; - -alter table "public"."cambios_plan" drop constraint "cambios_plan_plan_estudio_id_fkey"; - -alter type "public"."tipo_cambio" rename to "tipo_cambio__old_version_to_be_dropped"; - -create type "public"."tipo_cambio" as enum ('ACTUALIZACION_CAMPO', 'ACTUALIZACION_MAPA', 'TRANSICION_ESTADO', 'OTRO', 'CREACION', 'ACTUALIZACION'); - -alter table "public"."cambios_asignatura" alter column tipo type "public"."tipo_cambio" using tipo::text::"public"."tipo_cambio"; - -alter table "public"."cambios_plan" alter column tipo type "public"."tipo_cambio" using tipo::text::"public"."tipo_cambio"; - -drop type "public"."tipo_cambio__old_version_to_be_dropped"; - -alter table "public"."asignaturas" drop column if exists "facultad_propietaria_id"; - -alter table "public"."asignaturas" add column "asignatura_hash" text generated always as (encode(SUBSTRING(extensions.digest((id)::text, 'sha512'::text) FROM 1 FOR 12), 'hex'::text)) stored; - -alter table "public"."cambios_plan" drop column "interaccion_ia_id"; - -alter table "public"."cambios_plan" add column "response_id" text; - -alter table "public"."planes_estudio" add column "conversation_id" text; - -alter table "public"."planes_estudio" add column "plan_hash" text generated always as (encode(SUBSTRING(extensions.digest((id)::text, 'sha512'::text) FROM 1 FOR 12), 'hex'::text)) stored; - -CREATE UNIQUE INDEX planes_estudio_conversation_id_key ON public.planes_estudio USING btree (conversation_id); - -alter table "public"."planes_estudio" add constraint "planes_estudio_conversation_id_key" UNIQUE using index "planes_estudio_conversation_id_key"; - -set check_function_bodies = off; - -CREATE OR REPLACE FUNCTION public.fn_log_cambios_planes_estudio() - RETURNS trigger - LANGUAGE plpgsql -AS $function$declare - k text; - old_val jsonb; - new_val jsonb; - - v_response_id text; -begin - v_response_id := nullif(new.meta_origen->>'response_id',''); - - -- INSERT -> CREACION - if tg_op = 'INSERT' then - insert into public.cambios_plan ( - plan_estudio_id, - cambiado_por, - tipo, - campo, - valor_anterior, - valor_nuevo, - response_id - ) - values ( - new.id, - new.creado_por, - 'CREACION'::public.tipo_cambio, - null, - null, - to_jsonb(new), - null - ); - - return new; - end if; - - -- DELETE (opcional): si no lo quieres, b贸rralo - if tg_op = 'DELETE' then - insert into public.cambios_plan ( - plan_estudio_id, - cambiado_por, - tipo, - campo, - valor_anterior, - valor_nuevo, - response_id - ) - values ( - old.id, - old.actualizado_por, - 'OTRO'::public.tipo_cambio, - 'DELETE', - to_jsonb(old), - null, - null - ); - - return old; - end if; - - -- UPDATE ---------------------------------------------------------- - -- 1) Transici贸n de estado - if (new.estado_actual_id is distinct from old.estado_actual_id) then - insert into public.cambios_plan ( - plan_estudio_id, cambiado_por, tipo, campo, valor_anterior, valor_nuevo, response_id - ) - values ( - new.id, - new.actualizado_por, - 'TRANSICION_ESTADO'::public.tipo_cambio, - 'estado_actual_id', - to_jsonb(old.estado_actual_id), - to_jsonb(new.estado_actual_id), - null - ); - end if; - - -- 2) Cambios en JSONB "datos" (diff top-level por llave) - if (new.datos is distinct from old.datos) then - for k in - select distinct key - from ( - select jsonb_object_keys(coalesce(old.datos, '{}'::jsonb)) as key - union all - select jsonb_object_keys(coalesce(new.datos, '{}'::jsonb)) as key - ) t - loop - old_val := coalesce(old.datos, '{}'::jsonb) -> k; - new_val := coalesce(new.datos, '{}'::jsonb) -> k; - - if (old_val is distinct from new_val) then - insert into public.cambios_plan ( - plan_estudio_id, cambiado_por, tipo, campo, valor_anterior, valor_nuevo, response_id - ) - values ( - new.id, - new.actualizado_por, - 'ACTUALIZACION_CAMPO'::public.tipo_cambio, - k, - old_val, - new_val, - v_response_id - ); - end if; - end loop; - - end if; - - -- 3) Cambios en columnas "normales" (uno por columna) - if (new.nombre is distinct from old.nombre) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'nombre', to_jsonb(old.nombre), to_jsonb(new.nombre), null); - end if; - - if (new.nivel is distinct from old.nivel) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'nivel', to_jsonb(old.nivel), to_jsonb(new.nivel), null); - end if; - - if (new.tipo_ciclo is distinct from old.tipo_ciclo) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'tipo_ciclo', to_jsonb(old.tipo_ciclo), to_jsonb(new.tipo_ciclo), null); - end if; - - if (new.numero_ciclos is distinct from old.numero_ciclos) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'numero_ciclos', to_jsonb(old.numero_ciclos), to_jsonb(new.numero_ciclos), null); - end if; - - if (new.activo is distinct from old.activo) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'activo', to_jsonb(old.activo), to_jsonb(new.activo), null); - end if; - - if (new.carrera_id is distinct from old.carrera_id) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'carrera_id', to_jsonb(old.carrera_id), to_jsonb(new.carrera_id), null); - end if; - - if (new.estructura_id is distinct from old.estructura_id) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'estructura_id', to_jsonb(old.estructura_id), to_jsonb(new.estructura_id), null); - end if; - - if (new.tipo_origen is distinct from old.tipo_origen) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'tipo_origen', to_jsonb(old.tipo_origen), to_jsonb(new.tipo_origen), null); - end if; - - -- 馃敟 consumirlo para que NO se guarde en planes_estudio - if v_response_id is not null then - new.meta_origen := new.meta_origen - 'response_id'; - end if; - - return new; -end;$function$ -; - -CREATE TRIGGER "agregar-conversation_id-asignaturas" AFTER INSERT ON public.asignaturas FOR EACH ROW EXECUTE FUNCTION supabase_functions.http_request('https://exdkssurzmjnnhgtiama.supabase.co/functions/v1/create-chat-conversation', 'POST', '{"Content-type":"application/json","Authorization":"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImV4ZGtzc3Vyem1qbm5oZ3RpYW1hIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc0MTM3ODYzMiwiZXhwIjoyMDU2OTU0NjMyfQ.s-GHuwnYbIYoMZN9dFbAKgxNyAtQllRCRPLy-GIRaro"}', '{}', '5000'); - -CREATE TRIGGER "agregar-conversation_id-planes_estudio" AFTER INSERT ON public.planes_estudio FOR EACH ROW EXECUTE FUNCTION supabase_functions.http_request('https://exdkssurzmjnnhgtiama.supabase.co/functions/v1/create-chat-conversation', 'POST', '{"Content-type":"application/json","Authorization":"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImV4ZGtzc3Vyem1qbm5oZ3RpYW1hIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc0MTM3ODYzMiwiZXhwIjoyMDU2OTU0NjMyfQ.s-GHuwnYbIYoMZN9dFbAKgxNyAtQllRCRPLy-GIRaro"}', '{}', '5000'); - -CREATE TRIGGER trg_planes_estudio_log_cambios AFTER INSERT OR DELETE OR UPDATE ON public.planes_estudio FOR EACH ROW EXECUTE FUNCTION public.fn_log_cambios_planes_estudio(); - - diff --git a/supabase/migrations/20260212162718_crear_tablas_de_conversaciones.sql b/supabase/migrations/20260212162718_crear_tablas_de_conversaciones.sql deleted file mode 100644 index d4d1eb1..0000000 --- a/supabase/migrations/20260212162718_crear_tablas_de_conversaciones.sql +++ /dev/null @@ -1,208 +0,0 @@ -create type "public"."estado_conversacion" as enum ('ACTIVA', 'ARCHIVANDO', 'ARCHIVADA', 'ERROR'); - -alter table "public"."planes_estudio" drop constraint "planes_estudio_conversation_id_key"; - -drop view if exists "public"."plantilla_plan"; - -drop index if exists "public"."planes_estudio_conversation_id_key"; - - - create table "public"."conversaciones_asignatura" ( - "id" uuid not null default gen_random_uuid(), - "asignatura_id" uuid not null, - "openai_conversation_id" text not null, - "estado" public.estado_conversacion not null default 'ACTIVA'::public.estado_conversacion, - "conversacion_json" jsonb not null default '{}'::jsonb, - "creado_por" uuid, - "creado_en" timestamp with time zone not null default now(), - "archivado_por" uuid, - "archivado_en" timestamp with time zone, - "intento_archivado" integer not null default 0 - ); - - - - create table "public"."conversaciones_plan" ( - "id" uuid not null default gen_random_uuid(), - "plan_estudio_id" uuid not null, - "openai_conversation_id" text not null, - "estado" public.estado_conversacion not null default 'ACTIVA'::public.estado_conversacion, - "conversacion_json" jsonb not null default '{}'::jsonb, - "creado_por" uuid, - "creado_en" timestamp with time zone not null default now(), - "archivado_por" uuid, - "archivado_en" timestamp with time zone, - "intento_archivado" integer not null default 0 - ); - - -alter table "public"."planes_estudio" drop column "conversation_id"; - -CREATE UNIQUE INDEX conversaciones_asignatura_openai_id_unico ON public.conversaciones_asignatura USING btree (openai_conversation_id); - -CREATE UNIQUE INDEX conversaciones_asignatura_pkey ON public.conversaciones_asignatura USING btree (id); - -CREATE UNIQUE INDEX conversaciones_plan_openai_id_unico ON public.conversaciones_plan USING btree (openai_conversation_id); - -CREATE UNIQUE INDEX conversaciones_plan_pkey ON public.conversaciones_plan USING btree (id); - -CREATE INDEX idx_conv_asig_asignatura ON public.conversaciones_asignatura USING btree (asignatura_id); - -CREATE INDEX idx_conv_asig_estado ON public.conversaciones_asignatura USING btree (estado); - -CREATE INDEX idx_conv_plan_estado ON public.conversaciones_plan USING btree (estado); - -CREATE INDEX idx_conv_plan_plan_estudio ON public.conversaciones_plan USING btree (plan_estudio_id); - -alter table "public"."conversaciones_asignatura" add constraint "conversaciones_asignatura_pkey" PRIMARY KEY using index "conversaciones_asignatura_pkey"; - -alter table "public"."conversaciones_plan" add constraint "conversaciones_plan_pkey" PRIMARY KEY using index "conversaciones_plan_pkey"; - -alter table "public"."conversaciones_asignatura" add constraint "conversaciones_asignatura_archivado_por_fkey" FOREIGN KEY (archivado_por) REFERENCES public.usuarios_app(id) ON DELETE SET NULL not valid; - -alter table "public"."conversaciones_asignatura" validate constraint "conversaciones_asignatura_archivado_por_fkey"; - -alter table "public"."conversaciones_asignatura" add constraint "conversaciones_asignatura_asignatura_id_fkey" FOREIGN KEY (asignatura_id) REFERENCES public.asignaturas(id) ON DELETE CASCADE not valid; - -alter table "public"."conversaciones_asignatura" validate constraint "conversaciones_asignatura_asignatura_id_fkey"; - -alter table "public"."conversaciones_asignatura" add constraint "conversaciones_asignatura_creado_por_fkey" FOREIGN KEY (creado_por) REFERENCES public.usuarios_app(id) ON DELETE SET NULL not valid; - -alter table "public"."conversaciones_asignatura" validate constraint "conversaciones_asignatura_creado_por_fkey"; - -alter table "public"."conversaciones_asignatura" add constraint "conversaciones_asignatura_openai_id_unico" UNIQUE using index "conversaciones_asignatura_openai_id_unico"; - -alter table "public"."conversaciones_plan" add constraint "conversaciones_plan_archivado_por_fkey" FOREIGN KEY (archivado_por) REFERENCES public.usuarios_app(id) ON DELETE SET NULL not valid; - -alter table "public"."conversaciones_plan" validate constraint "conversaciones_plan_archivado_por_fkey"; - -alter table "public"."conversaciones_plan" add constraint "conversaciones_plan_creado_por_fkey" FOREIGN KEY (creado_por) REFERENCES public.usuarios_app(id) ON DELETE SET NULL not valid; - -alter table "public"."conversaciones_plan" validate constraint "conversaciones_plan_creado_por_fkey"; - -alter table "public"."conversaciones_plan" add constraint "conversaciones_plan_openai_id_unico" UNIQUE using index "conversaciones_plan_openai_id_unico"; - -alter table "public"."conversaciones_plan" add constraint "conversaciones_plan_plan_estudio_id_fkey" FOREIGN KEY (plan_estudio_id) REFERENCES public.planes_estudio(id) ON DELETE CASCADE not valid; - -alter table "public"."conversaciones_plan" validate constraint "conversaciones_plan_plan_estudio_id_fkey"; - -create or replace view "public"."plantilla_plan" as SELECT plan.id AS plan_estudio_id, - struct.id AS estructura_id, - struct.template_id - FROM (public.planes_estudio plan - JOIN public.estructuras_plan struct ON ((plan.estructura_id = struct.id))); - - -grant delete on table "public"."conversaciones_asignatura" to "anon"; - -grant insert on table "public"."conversaciones_asignatura" to "anon"; - -grant references on table "public"."conversaciones_asignatura" to "anon"; - -grant select on table "public"."conversaciones_asignatura" to "anon"; - -grant trigger on table "public"."conversaciones_asignatura" to "anon"; - -grant truncate on table "public"."conversaciones_asignatura" to "anon"; - -grant update on table "public"."conversaciones_asignatura" to "anon"; - -grant delete on table "public"."conversaciones_asignatura" to "authenticated"; - -grant insert on table "public"."conversaciones_asignatura" to "authenticated"; - -grant references on table "public"."conversaciones_asignatura" to "authenticated"; - -grant select on table "public"."conversaciones_asignatura" to "authenticated"; - -grant trigger on table "public"."conversaciones_asignatura" to "authenticated"; - -grant truncate on table "public"."conversaciones_asignatura" to "authenticated"; - -grant update on table "public"."conversaciones_asignatura" to "authenticated"; - -grant delete on table "public"."conversaciones_asignatura" to "postgres"; - -grant insert on table "public"."conversaciones_asignatura" to "postgres"; - -grant references on table "public"."conversaciones_asignatura" to "postgres"; - -grant select on table "public"."conversaciones_asignatura" to "postgres"; - -grant trigger on table "public"."conversaciones_asignatura" to "postgres"; - -grant truncate on table "public"."conversaciones_asignatura" to "postgres"; - -grant update on table "public"."conversaciones_asignatura" to "postgres"; - -grant delete on table "public"."conversaciones_asignatura" to "service_role"; - -grant insert on table "public"."conversaciones_asignatura" to "service_role"; - -grant references on table "public"."conversaciones_asignatura" to "service_role"; - -grant select on table "public"."conversaciones_asignatura" to "service_role"; - -grant trigger on table "public"."conversaciones_asignatura" to "service_role"; - -grant truncate on table "public"."conversaciones_asignatura" to "service_role"; - -grant update on table "public"."conversaciones_asignatura" to "service_role"; - -grant delete on table "public"."conversaciones_plan" to "anon"; - -grant insert on table "public"."conversaciones_plan" to "anon"; - -grant references on table "public"."conversaciones_plan" to "anon"; - -grant select on table "public"."conversaciones_plan" to "anon"; - -grant trigger on table "public"."conversaciones_plan" to "anon"; - -grant truncate on table "public"."conversaciones_plan" to "anon"; - -grant update on table "public"."conversaciones_plan" to "anon"; - -grant delete on table "public"."conversaciones_plan" to "authenticated"; - -grant insert on table "public"."conversaciones_plan" to "authenticated"; - -grant references on table "public"."conversaciones_plan" to "authenticated"; - -grant select on table "public"."conversaciones_plan" to "authenticated"; - -grant trigger on table "public"."conversaciones_plan" to "authenticated"; - -grant truncate on table "public"."conversaciones_plan" to "authenticated"; - -grant update on table "public"."conversaciones_plan" to "authenticated"; - -grant delete on table "public"."conversaciones_plan" to "postgres"; - -grant insert on table "public"."conversaciones_plan" to "postgres"; - -grant references on table "public"."conversaciones_plan" to "postgres"; - -grant select on table "public"."conversaciones_plan" to "postgres"; - -grant trigger on table "public"."conversaciones_plan" to "postgres"; - -grant truncate on table "public"."conversaciones_plan" to "postgres"; - -grant update on table "public"."conversaciones_plan" to "postgres"; - -grant delete on table "public"."conversaciones_plan" to "service_role"; - -grant insert on table "public"."conversaciones_plan" to "service_role"; - -grant references on table "public"."conversaciones_plan" to "service_role"; - -grant select on table "public"."conversaciones_plan" to "service_role"; - -grant trigger on table "public"."conversaciones_plan" to "service_role"; - -grant truncate on table "public"."conversaciones_plan" to "service_role"; - -grant update on table "public"."conversaciones_plan" to "service_role"; - - diff --git a/supabase/migrations/20260212211216_eliminar_triggers_que_daban_problema.sql b/supabase/migrations/20260212211216_eliminar_triggers_que_daban_problema.sql deleted file mode 100644 index d4582f7..0000000 --- a/supabase/migrations/20260212211216_eliminar_triggers_que_daban_problema.sql +++ /dev/null @@ -1,166 +0,0 @@ -drop trigger if exists "agregar-conversation_id-asignaturas" on "public"."asignaturas"; - -drop trigger if exists "agregar-conversation_id-planes_estudio" on "public"."planes_estudio"; - -set check_function_bodies = off; - -CREATE OR REPLACE FUNCTION public.fn_log_cambios_planes_estudio() - RETURNS trigger - LANGUAGE plpgsql -AS $function$declare - k text; - old_val jsonb; - new_val jsonb; - - v_response_id text; -begin - v_response_id := nullif(new.meta_origen->>'response_id',''); - - -- INSERT -> CREACION - if tg_op = 'INSERT' then - insert into public.cambios_plan ( - plan_estudio_id, - cambiado_por, - tipo, - campo, - valor_anterior, - valor_nuevo, - response_id - ) - values ( - new.id, - new.creado_por, - 'CREACION'::public.tipo_cambio, - null, - null, - to_jsonb(new), - null - ); - - return new; - end if; - - -- DELETE (opcional): si no lo quieres, b贸rralo - if tg_op = 'DELETE' then - insert into public.cambios_plan ( - plan_estudio_id, - cambiado_por, - tipo, - campo, - valor_anterior, - valor_nuevo, - response_id - ) - values ( - old.id, - old.actualizado_por, - 'OTRO'::public.tipo_cambio, - 'DELETE', - to_jsonb(old), - null, - null - ); - - return old; - end if; - - -- UPDATE ---------------------------------------------------------- - -- 1) Transici贸n de estado - if (new.estado_actual_id is distinct from old.estado_actual_id) then - insert into public.cambios_plan ( - plan_estudio_id, cambiado_por, tipo, campo, valor_anterior, valor_nuevo, response_id - ) - values ( - new.id, - new.actualizado_por, - 'TRANSICION_ESTADO'::public.tipo_cambio, - 'estado_actual_id', - to_jsonb(old.estado_actual_id), - to_jsonb(new.estado_actual_id), - null - ); - end if; - - -- 2) Cambios en JSONB "datos" (diff top-level por llave) - if (new.datos is distinct from old.datos) then - for k in - select distinct key - from ( - select jsonb_object_keys(coalesce(old.datos, '{}'::jsonb)) as key - union all - select jsonb_object_keys(coalesce(new.datos, '{}'::jsonb)) as key - ) t - loop - old_val := coalesce(old.datos, '{}'::jsonb) -> k; - new_val := coalesce(new.datos, '{}'::jsonb) -> k; - - if (old_val is distinct from new_val) then - insert into public.cambios_plan ( - plan_estudio_id, cambiado_por, tipo, campo, valor_anterior, valor_nuevo, response_id - ) - values ( - new.id, - new.actualizado_por, - 'ACTUALIZACION_CAMPO'::public.tipo_cambio, - k, - old_val, - new_val, - v_response_id - ); - end if; - end loop; - - end if; - - -- 3) Cambios en columnas "normales" (uno por columna) - if (new.nombre is distinct from old.nombre) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'nombre', to_jsonb(old.nombre), to_jsonb(new.nombre), null); - end if; - - if (new.nivel is distinct from old.nivel) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'nivel', to_jsonb(old.nivel), to_jsonb(new.nivel), null); - end if; - - if (new.tipo_ciclo is distinct from old.tipo_ciclo) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'tipo_ciclo', to_jsonb(old.tipo_ciclo), to_jsonb(new.tipo_ciclo), null); - end if; - - if (new.numero_ciclos is distinct from old.numero_ciclos) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'numero_ciclos', to_jsonb(old.numero_ciclos), to_jsonb(new.numero_ciclos), null); - end if; - - if (new.activo is distinct from old.activo) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'activo', to_jsonb(old.activo), to_jsonb(new.activo), null); - end if; - - if (new.carrera_id is distinct from old.carrera_id) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'carrera_id', to_jsonb(old.carrera_id), to_jsonb(new.carrera_id), null); - end if; - - if (new.estructura_id is distinct from old.estructura_id) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'estructura_id', to_jsonb(old.estructura_id), to_jsonb(new.estructura_id), null); - end if; - - if (new.tipo_origen is distinct from old.tipo_origen) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'tipo_origen', to_jsonb(old.tipo_origen), to_jsonb(new.tipo_origen), null); - end if; - - - -- 馃敟 consumirlo para que NO se guarde en planes_estudio - if v_response_id is not null then - new.meta_origen := new.meta_origen - 'response_id'; - end if; - - return new; -end;$function$ -; - - diff --git a/supabase/migrations/20260212214439_columna_estado_asignaturas.sql b/supabase/migrations/20260212214439_columna_estado_asignaturas.sql deleted file mode 100644 index e17a355..0000000 --- a/supabase/migrations/20260212214439_columna_estado_asignaturas.sql +++ /dev/null @@ -1,171 +0,0 @@ -create type "public"."estado_asignatura" as enum ('borrador', 'revisada', 'aprobada', 'generando'); - -alter table "public"."asignaturas" add column "estado" public.estado_asignatura not null default 'generando'::public.estado_asignatura; - -set check_function_bodies = off; - -CREATE OR REPLACE FUNCTION public.fn_log_cambios_planes_estudio() - RETURNS trigger - LANGUAGE plpgsql -AS $function$declare - k text; - old_val jsonb; - new_val jsonb; - - v_response_id text; -begin - v_response_id := nullif(new.meta_origen->>'response_id',''); - - -- INSERT -> CREACION - if tg_op = 'INSERT' then - insert into public.cambios_plan ( - plan_estudio_id, - cambiado_por, - tipo, - campo, - valor_anterior, - valor_nuevo, - response_id - ) - values ( - new.id, - new.creado_por, - 'CREACION'::public.tipo_cambio, - null, - null, - to_jsonb(new), - null - ); - - return new; - end if; - - -- DELETE (opcional): si no lo quieres, b贸rralo - if tg_op = 'DELETE' then - insert into public.cambios_plan ( - plan_estudio_id, - cambiado_por, - tipo, - campo, - valor_anterior, - valor_nuevo, - response_id - ) - values ( - old.id, - old.actualizado_por, - 'OTRO'::public.tipo_cambio, - 'DELETE', - to_jsonb(old), - null, - null - ); - - return old; - end if; - - -- UPDATE ---------------------------------------------------------- - -- 1) Transici贸n de estado - if (new.estado_actual_id is distinct from old.estado_actual_id) then - insert into public.cambios_plan ( - plan_estudio_id, cambiado_por, tipo, campo, valor_anterior, valor_nuevo, response_id - ) - values ( - new.id, - new.actualizado_por, - 'TRANSICION_ESTADO'::public.tipo_cambio, - 'estado_actual_id', - to_jsonb(old.estado_actual_id), - to_jsonb(new.estado_actual_id), - null - ); - end if; - - -- 2) Cambios en JSONB "datos" (diff top-level por llave) - if (new.datos is distinct from old.datos) then - for k in - select distinct key - from ( - select jsonb_object_keys(coalesce(old.datos, '{}'::jsonb)) as key - union all - select jsonb_object_keys(coalesce(new.datos, '{}'::jsonb)) as key - ) t - loop - old_val := coalesce(old.datos, '{}'::jsonb) -> k; - new_val := coalesce(new.datos, '{}'::jsonb) -> k; - - if (old_val is distinct from new_val) then - insert into public.cambios_plan ( - plan_estudio_id, cambiado_por, tipo, campo, valor_anterior, valor_nuevo, response_id - ) - values ( - new.id, - new.actualizado_por, - 'ACTUALIZACION_CAMPO'::public.tipo_cambio, - k, - old_val, - new_val, - v_response_id - ); - end if; - end loop; - - end if; - - -- 3) Cambios en columnas "normales" (uno por columna) - if (new.nombre is distinct from old.nombre) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'nombre', to_jsonb(old.nombre), to_jsonb(new.nombre), null); - end if; - - if (new.nivel is distinct from old.nivel) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'nivel', to_jsonb(old.nivel), to_jsonb(new.nivel), null); - end if; - - if (new.tipo_ciclo is distinct from old.tipo_ciclo) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'tipo_ciclo', to_jsonb(old.tipo_ciclo), to_jsonb(new.tipo_ciclo), null); - end if; - - if (new.numero_ciclos is distinct from old.numero_ciclos) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'numero_ciclos', to_jsonb(old.numero_ciclos), to_jsonb(new.numero_ciclos), null); - end if; - - if (new.activo is distinct from old.activo) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'activo', to_jsonb(old.activo), to_jsonb(new.activo), null); - end if; - - if (new.carrera_id is distinct from old.carrera_id) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'carrera_id', to_jsonb(old.carrera_id), to_jsonb(new.carrera_id), null); - end if; - - if (new.estructura_id is distinct from old.estructura_id) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'estructura_id', to_jsonb(old.estructura_id), to_jsonb(new.estructura_id), null); - end if; - - if (new.tipo_origen is distinct from old.tipo_origen) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'tipo_origen', to_jsonb(old.tipo_origen), to_jsonb(new.tipo_origen), null); - end if; - - - if (new.conversation_id is distinct from old.conversation_id) then - insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), - 'ACTUALIZACION'::public.tipo_cambio, 'conversation_id', to_jsonb(old.conversation_id), to_jsonb(new.conversation_id), null); - end if; - - -- 馃敟 consumirlo para que NO se guarde en planes_estudio - if v_response_id is not null then - new.meta_origen := new.meta_origen - 'response_id'; - end if; - - return new; -end;$function$ -; - - diff --git a/supabase/migrations/20260115192420_remote_schema.sql b/supabase/migrations/20260213180558_1.0.0.sql similarity index 72% rename from supabase/migrations/20260115192420_remote_schema.sql rename to supabase/migrations/20260213180558_1.0.0.sql index e944b46..b8ee7ea 100644 --- a/supabase/migrations/20260115192420_remote_schema.sql +++ b/supabase/migrations/20260213180558_1.0.0.sql @@ -12,6 +12,13 @@ SET client_min_messages = warning; SET row_security = off; +CREATE EXTENSION IF NOT EXISTS "pg_net" WITH SCHEMA "extensions"; + + + + + + CREATE EXTENSION IF NOT EXISTS "pgsodium"; @@ -23,6 +30,13 @@ COMMENT ON SCHEMA "public" IS 'standard public schema'; +CREATE EXTENSION IF NOT EXISTS "http" WITH SCHEMA "extensions"; + + + + + + CREATE EXTENSION IF NOT EXISTS "pg_graphql" WITH SCHEMA "graphql"; @@ -72,6 +86,28 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA "extensions"; +CREATE TYPE "public"."estado_asignatura" AS ENUM ( + 'borrador', + 'revisada', + 'aprobada', + 'generando' +); + + +ALTER TYPE "public"."estado_asignatura" OWNER TO "postgres"; + + +CREATE TYPE "public"."estado_conversacion" AS ENUM ( + 'ACTIVA', + 'ARCHIVANDO', + 'ARCHIVADA', + 'ERROR' +); + + +ALTER TYPE "public"."estado_conversacion" OWNER TO "postgres"; + + CREATE TYPE "public"."estado_tarea_revision" AS ENUM ( 'PENDIENTE', 'COMPLETADA', @@ -151,7 +187,9 @@ CREATE TYPE "public"."tipo_cambio" AS ENUM ( 'ACTUALIZACION_CAMPO', 'ACTUALIZACION_MAPA', 'TRANSICION_ESTADO', - 'OTRO' + 'OTRO', + 'CREACION', + 'ACTUALIZACION' ); @@ -222,6 +260,168 @@ CREATE TYPE "public"."tipo_origen" AS ENUM ( ALTER TYPE "public"."tipo_origen" OWNER TO "postgres"; +CREATE OR REPLACE FUNCTION "public"."fn_log_cambios_planes_estudio"() RETURNS "trigger" + LANGUAGE "plpgsql" + AS $$declare + k text; + old_val jsonb; + new_val jsonb; + + v_response_id text; +begin + v_response_id := nullif(new.meta_origen->>'response_id',''); + + -- INSERT -> CREACION + if tg_op = 'INSERT' then + insert into public.cambios_plan ( + plan_estudio_id, + cambiado_por, + tipo, + campo, + valor_anterior, + valor_nuevo, + response_id + ) + values ( + new.id, + new.creado_por, + 'CREACION'::public.tipo_cambio, + null, + null, + to_jsonb(new), + null + ); + + return new; + end if; + + -- DELETE (opcional): si no lo quieres, b贸rralo + if tg_op = 'DELETE' then + insert into public.cambios_plan ( + plan_estudio_id, + cambiado_por, + tipo, + campo, + valor_anterior, + valor_nuevo, + response_id + ) + values ( + old.id, + old.actualizado_por, + 'OTRO'::public.tipo_cambio, + 'DELETE', + to_jsonb(old), + null, + null + ); + + return old; + end if; + + -- UPDATE ---------------------------------------------------------- + -- 1) Transici贸n de estado + if (new.estado_actual_id is distinct from old.estado_actual_id) then + insert into public.cambios_plan ( + plan_estudio_id, cambiado_por, tipo, campo, valor_anterior, valor_nuevo, response_id + ) + values ( + new.id, + new.actualizado_por, + 'TRANSICION_ESTADO'::public.tipo_cambio, + 'estado_actual_id', + to_jsonb(old.estado_actual_id), + to_jsonb(new.estado_actual_id), + null + ); + end if; + + -- 2) Cambios en JSONB "datos" (diff top-level por llave) + if (new.datos is distinct from old.datos) then + for k in + select distinct key + from ( + select jsonb_object_keys(coalesce(old.datos, '{}'::jsonb)) as key + union all + select jsonb_object_keys(coalesce(new.datos, '{}'::jsonb)) as key + ) t + loop + old_val := coalesce(old.datos, '{}'::jsonb) -> k; + new_val := coalesce(new.datos, '{}'::jsonb) -> k; + + if (old_val is distinct from new_val) then + insert into public.cambios_plan ( + plan_estudio_id, cambiado_por, tipo, campo, valor_anterior, valor_nuevo, response_id + ) + values ( + new.id, + new.actualizado_por, + 'ACTUALIZACION_CAMPO'::public.tipo_cambio, + k, + old_val, + new_val, + v_response_id + ); + end if; + end loop; + + end if; + + -- 3) Cambios en columnas "normales" (uno por columna) + if (new.nombre is distinct from old.nombre) then + insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), + 'ACTUALIZACION'::public.tipo_cambio, 'nombre', to_jsonb(old.nombre), to_jsonb(new.nombre), null); + end if; + + if (new.nivel is distinct from old.nivel) then + insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), + 'ACTUALIZACION'::public.tipo_cambio, 'nivel', to_jsonb(old.nivel), to_jsonb(new.nivel), null); + end if; + + if (new.tipo_ciclo is distinct from old.tipo_ciclo) then + insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), + 'ACTUALIZACION'::public.tipo_cambio, 'tipo_ciclo', to_jsonb(old.tipo_ciclo), to_jsonb(new.tipo_ciclo), null); + end if; + + if (new.numero_ciclos is distinct from old.numero_ciclos) then + insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), + 'ACTUALIZACION'::public.tipo_cambio, 'numero_ciclos', to_jsonb(old.numero_ciclos), to_jsonb(new.numero_ciclos), null); + end if; + + if (new.activo is distinct from old.activo) then + insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), + 'ACTUALIZACION'::public.tipo_cambio, 'activo', to_jsonb(old.activo), to_jsonb(new.activo), null); + end if; + + if (new.carrera_id is distinct from old.carrera_id) then + insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), + 'ACTUALIZACION'::public.tipo_cambio, 'carrera_id', to_jsonb(old.carrera_id), to_jsonb(new.carrera_id), null); + end if; + + if (new.estructura_id is distinct from old.estructura_id) then + insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), + 'ACTUALIZACION'::public.tipo_cambio, 'estructura_id', to_jsonb(old.estructura_id), to_jsonb(new.estructura_id), null); + end if; + + if (new.tipo_origen is distinct from old.tipo_origen) then + insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(), + 'ACTUALIZACION'::public.tipo_cambio, 'tipo_origen', to_jsonb(old.tipo_origen), to_jsonb(new.tipo_origen), null); + end if; + + + + -- 馃敟 consumirlo para que NO se guarde en planes_estudio + if v_response_id is not null then + new.meta_origen := new.meta_origen - 'response_id'; + end if; + + return new; +end;$$; + + +ALTER FUNCTION "public"."fn_log_cambios_planes_estudio"() OWNER TO "postgres"; + + CREATE OR REPLACE FUNCTION "public"."set_actualizado_en"() RETURNS "trigger" LANGUAGE "plpgsql" AS $$ @@ -305,12 +505,10 @@ CREATE TABLE IF NOT EXISTS "public"."asignaturas" ( "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, "plan_estudio_id" "uuid" NOT NULL, "estructura_id" "uuid", - "facultad_propietaria_id" "uuid", "codigo" "text", "nombre" "text" NOT NULL, "tipo" "public"."tipo_asignatura" DEFAULT 'OBLIGATORIA'::"public"."tipo_asignatura" NOT NULL, "creditos" numeric NOT NULL, - "horas_semana" integer, "numero_ciclo" integer, "linea_plan_id" "uuid", "orden_celda" integer, @@ -322,9 +520,14 @@ CREATE TABLE IF NOT EXISTS "public"."asignaturas" ( "actualizado_por" "uuid", "creado_en" timestamp with time zone DEFAULT "now"() NOT NULL, "actualizado_en" timestamp with time zone DEFAULT "now"() NOT NULL, + "horas_academicas" integer, + "horas_independientes" integer, + "asignatura_hash" "text" GENERATED ALWAYS AS ("encode"(SUBSTRING("extensions"."digest"(("id")::"text", 'sha512'::"text") FROM 1 FOR 12), 'hex'::"text")) STORED, + "estado" "public"."estado_asignatura" DEFAULT 'borrador'::"public"."estado_asignatura" NOT NULL, CONSTRAINT "asignaturas_ciclo_chk" CHECK ((("numero_ciclo" IS NULL) OR ("numero_ciclo" > 0))), CONSTRAINT "asignaturas_creditos_check" CHECK (("creditos" >= (0)::numeric)), - CONSTRAINT "asignaturas_horas_semana_check" CHECK ((("horas_semana" IS NULL) OR ("horas_semana" >= 0))), + CONSTRAINT "asignaturas_horas_academicas_check" CHECK ((("horas_academicas" IS NULL) OR ("horas_academicas" >= 0))), + CONSTRAINT "asignaturas_horas_independientes_check" CHECK ((("horas_independientes" IS NULL) OR ("horas_independientes" >= 0))), CONSTRAINT "asignaturas_orden_celda_chk" CHECK ((("orden_celda" IS NULL) OR ("orden_celda" >= 0))) ); @@ -374,7 +577,7 @@ CREATE TABLE IF NOT EXISTS "public"."cambios_plan" ( "campo" "text", "valor_anterior" "jsonb", "valor_nuevo" "jsonb", - "interaccion_ia_id" "uuid" + "response_id" "text" ); @@ -396,6 +599,40 @@ CREATE TABLE IF NOT EXISTS "public"."carreras" ( ALTER TABLE "public"."carreras" OWNER TO "postgres"; +CREATE TABLE IF NOT EXISTS "public"."conversaciones_asignatura" ( + "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, + "asignatura_id" "uuid" NOT NULL, + "openai_conversation_id" "text" NOT NULL, + "estado" "public"."estado_conversacion" DEFAULT 'ACTIVA'::"public"."estado_conversacion" NOT NULL, + "conversacion_json" "jsonb" DEFAULT '{}'::"jsonb" NOT NULL, + "creado_por" "uuid", + "creado_en" timestamp with time zone DEFAULT "now"() NOT NULL, + "archivado_por" "uuid", + "archivado_en" timestamp with time zone, + "intento_archivado" integer DEFAULT 0 NOT NULL +); + + +ALTER TABLE "public"."conversaciones_asignatura" OWNER TO "postgres"; + + +CREATE TABLE IF NOT EXISTS "public"."conversaciones_plan" ( + "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, + "plan_estudio_id" "uuid" NOT NULL, + "openai_conversation_id" "text" NOT NULL, + "estado" "public"."estado_conversacion" DEFAULT 'ACTIVA'::"public"."estado_conversacion" NOT NULL, + "conversacion_json" "jsonb" DEFAULT '{}'::"jsonb" NOT NULL, + "creado_por" "uuid", + "creado_en" timestamp with time zone DEFAULT "now"() NOT NULL, + "archivado_por" "uuid", + "archivado_en" timestamp with time zone, + "intento_archivado" integer DEFAULT 0 NOT NULL +); + + +ALTER TABLE "public"."conversaciones_plan" OWNER TO "postgres"; + + CREATE TABLE IF NOT EXISTS "public"."estados_plan" ( "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, "clave" "text" NOT NULL, @@ -517,6 +754,7 @@ CREATE TABLE IF NOT EXISTS "public"."planes_estudio" ( "creado_en" timestamp with time zone DEFAULT "now"() NOT NULL, "actualizado_en" timestamp with time zone DEFAULT "now"() NOT NULL, "nombre_search" "text" GENERATED ALWAYS AS ("lower"("public"."unaccent_immutable"("nombre"))) STORED, + "plan_hash" "text" GENERATED ALWAYS AS ("encode"(SUBSTRING("extensions"."digest"(("id")::"text", 'sha512'::"text") FROM 1 FOR 12), 'hex'::"text")) STORED, CONSTRAINT "planes_estudio_numero_ciclos_check" CHECK (("numero_ciclos" > 0)) ); @@ -524,6 +762,17 @@ CREATE TABLE IF NOT EXISTS "public"."planes_estudio" ( ALTER TABLE "public"."planes_estudio" OWNER TO "postgres"; +CREATE OR REPLACE VIEW "public"."plantilla_plan" AS + SELECT "plan"."id" AS "plan_estudio_id", + "struct"."id" AS "estructura_id", + "struct"."template_id" + FROM ("public"."planes_estudio" "plan" + JOIN "public"."estructuras_plan" "struct" ON (("plan"."estructura_id" = "struct"."id"))); + + +ALTER TABLE "public"."plantilla_plan" OWNER TO "postgres"; + + CREATE TABLE IF NOT EXISTS "public"."responsables_asignatura" ( "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, "asignatura_id" "uuid" NOT NULL, @@ -645,6 +894,26 @@ ALTER TABLE ONLY "public"."carreras" +ALTER TABLE ONLY "public"."conversaciones_asignatura" + ADD CONSTRAINT "conversaciones_asignatura_openai_id_unico" UNIQUE ("openai_conversation_id"); + + + +ALTER TABLE ONLY "public"."conversaciones_asignatura" + ADD CONSTRAINT "conversaciones_asignatura_pkey" PRIMARY KEY ("id"); + + + +ALTER TABLE ONLY "public"."conversaciones_plan" + ADD CONSTRAINT "conversaciones_plan_openai_id_unico" UNIQUE ("openai_conversation_id"); + + + +ALTER TABLE ONLY "public"."conversaciones_plan" + ADD CONSTRAINT "conversaciones_plan_pkey" PRIMARY KEY ("id"); + + + ALTER TABLE ONLY "public"."estados_plan" ADD CONSTRAINT "estados_plan_clave_key" UNIQUE ("clave"); @@ -771,6 +1040,22 @@ CREATE INDEX "bibliografia_asignatura_idx" ON "public"."bibliografia_asignatura" +CREATE INDEX "idx_conv_asig_asignatura" ON "public"."conversaciones_asignatura" USING "btree" ("asignatura_id"); + + + +CREATE INDEX "idx_conv_asig_estado" ON "public"."conversaciones_asignatura" USING "btree" ("estado"); + + + +CREATE INDEX "idx_conv_plan_estado" ON "public"."conversaciones_plan" USING "btree" ("estado"); + + + +CREATE INDEX "idx_conv_plan_plan_estudio" ON "public"."conversaciones_plan" USING "btree" ("plan_estudio_id"); + + + CREATE INDEX "idx_planes_nombre_search" ON "public"."planes_estudio" USING "btree" ("nombre_search"); @@ -807,6 +1092,10 @@ CREATE OR REPLACE TRIGGER "trg_planes_estudio_actualizado_en" BEFORE UPDATE ON " +CREATE OR REPLACE TRIGGER "trg_planes_estudio_log_cambios" AFTER INSERT OR DELETE OR UPDATE ON "public"."planes_estudio" FOR EACH ROW EXECUTE FUNCTION "public"."fn_log_cambios_planes_estudio"(); + + + CREATE OR REPLACE TRIGGER "trg_usuarios_app_actualizado_en" BEFORE UPDATE ON "public"."usuarios_app" FOR EACH ROW EXECUTE FUNCTION "public"."set_actualizado_en"(); @@ -835,11 +1124,6 @@ ALTER TABLE ONLY "public"."asignaturas" -ALTER TABLE ONLY "public"."asignaturas" - ADD CONSTRAINT "asignaturas_facultad_propietaria_id_fkey" FOREIGN KEY ("facultad_propietaria_id") REFERENCES "public"."facultades"("id") ON DELETE SET NULL; - - - ALTER TABLE ONLY "public"."asignaturas" ADD CONSTRAINT "asignaturas_linea_plan_fk_compuesta" FOREIGN KEY ("linea_plan_id", "plan_estudio_id") REFERENCES "public"."lineas_plan"("id", "plan_estudio_id") ON DELETE SET NULL; @@ -875,16 +1159,41 @@ ALTER TABLE ONLY "public"."cambios_plan" -ALTER TABLE ONLY "public"."cambios_plan" - ADD CONSTRAINT "cambios_plan_plan_estudio_id_fkey" FOREIGN KEY ("plan_estudio_id") REFERENCES "public"."planes_estudio"("id") ON DELETE CASCADE; - - - ALTER TABLE ONLY "public"."carreras" ADD CONSTRAINT "carreras_facultad_id_fkey" FOREIGN KEY ("facultad_id") REFERENCES "public"."facultades"("id") ON DELETE RESTRICT; +ALTER TABLE ONLY "public"."conversaciones_asignatura" + ADD CONSTRAINT "conversaciones_asignatura_archivado_por_fkey" FOREIGN KEY ("archivado_por") REFERENCES "public"."usuarios_app"("id") ON DELETE SET NULL; + + + +ALTER TABLE ONLY "public"."conversaciones_asignatura" + ADD CONSTRAINT "conversaciones_asignatura_asignatura_id_fkey" FOREIGN KEY ("asignatura_id") REFERENCES "public"."asignaturas"("id") ON DELETE CASCADE; + + + +ALTER TABLE ONLY "public"."conversaciones_asignatura" + ADD CONSTRAINT "conversaciones_asignatura_creado_por_fkey" FOREIGN KEY ("creado_por") REFERENCES "public"."usuarios_app"("id") ON DELETE SET NULL; + + + +ALTER TABLE ONLY "public"."conversaciones_plan" + ADD CONSTRAINT "conversaciones_plan_archivado_por_fkey" FOREIGN KEY ("archivado_por") REFERENCES "public"."usuarios_app"("id") ON DELETE SET NULL; + + + +ALTER TABLE ONLY "public"."conversaciones_plan" + ADD CONSTRAINT "conversaciones_plan_creado_por_fkey" FOREIGN KEY ("creado_por") REFERENCES "public"."usuarios_app"("id") ON DELETE SET NULL; + + + +ALTER TABLE ONLY "public"."conversaciones_plan" + ADD CONSTRAINT "conversaciones_plan_plan_estudio_id_fkey" FOREIGN KEY ("plan_estudio_id") REFERENCES "public"."planes_estudio"("id") ON DELETE CASCADE; + + + ALTER TABLE ONLY "public"."interacciones_ia" ADD CONSTRAINT "interacciones_ia_asignatura_id_fkey" FOREIGN KEY ("asignatura_id") REFERENCES "public"."asignaturas"("id") ON DELETE CASCADE; @@ -1013,7 +1322,6 @@ ALTER PUBLICATION "supabase_realtime" OWNER TO "postgres"; - GRANT USAGE ON SCHEMA "public" TO "postgres"; GRANT USAGE ON SCHEMA "public" TO "anon"; GRANT USAGE ON SCHEMA "public" TO "authenticated"; @@ -1198,10 +1506,115 @@ GRANT USAGE ON SCHEMA "public" TO "service_role"; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +GRANT ALL ON FUNCTION "public"."fn_log_cambios_planes_estudio"() TO "anon"; +GRANT ALL ON FUNCTION "public"."fn_log_cambios_planes_estudio"() TO "authenticated"; +GRANT ALL ON FUNCTION "public"."fn_log_cambios_planes_estudio"() TO "service_role"; + + + GRANT ALL ON FUNCTION "public"."set_actualizado_en"() TO "anon"; GRANT ALL ON FUNCTION "public"."set_actualizado_en"() TO "authenticated"; GRANT ALL ON FUNCTION "public"."set_actualizado_en"() TO "service_role"; + + +GRANT ALL ON FUNCTION "public"."unaccent"("text") TO "postgres"; +GRANT ALL ON FUNCTION "public"."unaccent"("text") TO "anon"; +GRANT ALL ON FUNCTION "public"."unaccent"("text") TO "authenticated"; +GRANT ALL ON FUNCTION "public"."unaccent"("text") TO "service_role"; + + + +GRANT ALL ON FUNCTION "public"."unaccent"("regdictionary", "text") TO "postgres"; +GRANT ALL ON FUNCTION "public"."unaccent"("regdictionary", "text") TO "anon"; +GRANT ALL ON FUNCTION "public"."unaccent"("regdictionary", "text") TO "authenticated"; +GRANT ALL ON FUNCTION "public"."unaccent"("regdictionary", "text") TO "service_role"; + + + +GRANT ALL ON FUNCTION "public"."unaccent_immutable"("text") TO "anon"; +GRANT ALL ON FUNCTION "public"."unaccent_immutable"("text") TO "authenticated"; +GRANT ALL ON FUNCTION "public"."unaccent_immutable"("text") TO "service_role"; + + + +GRANT ALL ON FUNCTION "public"."unaccent_init"("internal") TO "postgres"; +GRANT ALL ON FUNCTION "public"."unaccent_init"("internal") TO "anon"; +GRANT ALL ON FUNCTION "public"."unaccent_init"("internal") TO "authenticated"; +GRANT ALL ON FUNCTION "public"."unaccent_init"("internal") TO "service_role"; + + + +GRANT ALL ON FUNCTION "public"."unaccent_lexize"("internal", "internal", "internal", "internal") TO "postgres"; +GRANT ALL ON FUNCTION "public"."unaccent_lexize"("internal", "internal", "internal", "internal") TO "anon"; +GRANT ALL ON FUNCTION "public"."unaccent_lexize"("internal", "internal", "internal", "internal") TO "authenticated"; +GRANT ALL ON FUNCTION "public"."unaccent_lexize"("internal", "internal", "internal", "internal") TO "service_role"; + + + GRANT ALL ON FUNCTION "public"."validar_numero_ciclo_asignatura"() TO "anon"; GRANT ALL ON FUNCTION "public"."validar_numero_ciclo_asignatura"() TO "authenticated"; GRANT ALL ON FUNCTION "public"."validar_numero_ciclo_asignatura"() TO "service_role"; @@ -1268,6 +1681,18 @@ GRANT ALL ON TABLE "public"."carreras" TO "service_role"; +GRANT ALL ON TABLE "public"."conversaciones_asignatura" TO "anon"; +GRANT ALL ON TABLE "public"."conversaciones_asignatura" TO "authenticated"; +GRANT ALL ON TABLE "public"."conversaciones_asignatura" TO "service_role"; + + + +GRANT ALL ON TABLE "public"."conversaciones_plan" TO "anon"; +GRANT ALL ON TABLE "public"."conversaciones_plan" TO "authenticated"; +GRANT ALL ON TABLE "public"."conversaciones_plan" TO "service_role"; + + + GRANT ALL ON TABLE "public"."estados_plan" TO "anon"; GRANT ALL ON TABLE "public"."estados_plan" TO "authenticated"; GRANT ALL ON TABLE "public"."estados_plan" TO "service_role"; @@ -1316,6 +1741,12 @@ GRANT ALL ON TABLE "public"."planes_estudio" TO "service_role"; +GRANT ALL ON TABLE "public"."plantilla_plan" TO "anon"; +GRANT ALL ON TABLE "public"."plantilla_plan" TO "authenticated"; +GRANT ALL ON TABLE "public"."plantilla_plan" TO "service_role"; + + + GRANT ALL ON TABLE "public"."responsables_asignatura" TO "anon"; GRANT ALL ON TABLE "public"."responsables_asignatura" TO "authenticated"; GRANT ALL ON TABLE "public"."responsables_asignatura" TO "service_role"; @@ -1417,4 +1848,9 @@ ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TAB + + +-- +-- Dumped schema changes for auth and storage +-- diff --git a/supabase/migrations/20260213180558_hotfix_estado_asignatura.sql b/supabase/migrations/20260213180558_hotfix_estado_asignatura.sql deleted file mode 100644 index 39f3776..0000000 --- a/supabase/migrations/20260213180558_hotfix_estado_asignatura.sql +++ /dev/null @@ -1,7 +0,0 @@ -alter table "public"."asignaturas" alter column "estado" drop default; - -alter table "public"."asignaturas" alter column estado type "public"."estado_asignatura" using estado::text::"public"."estado_asignatura"; - -alter table "public"."asignaturas" alter column "estado" set default 'borrador'::public.estado_asignatura; - -