Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save fadhilinsemwa/30540bb9583e4302e3c5f5527783398b to your computer and use it in GitHub Desktop.

Select an option

Save fadhilinsemwa/30540bb9583e4302e3c5f5527783398b to your computer and use it in GitHub Desktop.
TIMS Schema Diff: dev vs staging (2026-01-20)
╔════════════════════════════════════════════════════════════════╗
β•‘ TIMS Schema Diff Report β•‘
╠════════════════════════════════════════════════════════════════╣
β•‘ Source: dev
β•‘ Target: staging
β•‘ Generated: Tue Jan 20 12:27:20 EAT 2026
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
FULL SCHEMA DIFF:
════════════════════════════════════════════════════════════════
--- /Users/fadhilinsemwa/Documents/apps/tims/.schema-diff/dev_schema_20260120_122714.sql 2026-01-20 12:27:15
+++ /Users/fadhilinsemwa/Documents/apps/tims/.schema-diff/staging_schema_20260120_122714.sql 2026-01-20 12:27:20
@@ -2,7 +2,7 @@
-- PostgreSQL database dump
--
-\restrict 56P1AFLmECQP4C14SkiPUrItNfXjy5EQcIa9KjiDIyAuWQdvsFS9t7v15EdHUoA
+\restrict IUFQfJQrjUYMofJwdfyWaeH1zGTKdHYUIj80kUoecb3w9BionIrVhi5plZSbss2
-- Dumped from database version 15.14
-- Dumped by pg_dump version 15.14
@@ -146,6 +146,10 @@
DO UPDATE SET request_count = integration_rate_limits.request_count + 1
RETURNING request_count INTO current_count;
+ -- Clean old windows (older than 1 hour)
+ DELETE FROM integration_rate_limits
+ WHERE source_id = p_source_id AND window_start < NOW() - INTERVAL '1 hour';
+
RETURN current_count <= p_limit_rpm;
END;
$$;
@@ -177,7 +181,8 @@
BEGIN
year_part := TO_CHAR(NEW.receipt_date, 'YYYY');
- SELECT COALESCE(MAX(CAST(SUBSTRING(receipt_number FROM 4 FOR 7) AS INT)), 0) + 1
+ -- Extract sequence from position 8 (after RCP + year)
+ SELECT COALESCE(MAX(CAST(SUBSTRING(receipt_number FROM 8 FOR 7) AS INT)), 0) + 1
INTO seq_num
FROM payment_receipts
WHERE receipt_number LIKE 'RCP' || year_part || '%';
@@ -250,6 +255,41 @@
AND is_active = true;
RETURN v_next_stage_id;
+END;
+$$;
+
+
+--
+-- Name: get_or_create_external_mapping(uuid, character varying, character varying, uuid); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.get_or_create_external_mapping(p_source_id uuid, p_entity_type character varying, p_external_id character varying, p_tims_id uuid) RETURNS uuid
+ LANGUAGE plpgsql
+ AS $$
+DECLARE
+ v_mapping_id UUID;
+BEGIN
+ -- Try to find existing mapping
+ SELECT id INTO v_mapping_id
+ FROM external_id_mappings
+ WHERE source_id = p_source_id
+ AND entity_type = p_entity_type
+ AND external_id = p_external_id;
+
+ IF v_mapping_id IS NOT NULL THEN
+ -- Update usage stats
+ UPDATE external_id_mappings
+ SET last_used_at = NOW(), use_count = use_count + 1
+ WHERE id = v_mapping_id;
+ RETURN v_mapping_id;
+ END IF;
+
+ -- Create new mapping
+ INSERT INTO external_id_mappings (source_id, entity_type, external_id, tims_id, last_used_at, use_count)
+ VALUES (p_source_id, p_entity_type, p_external_id, p_tims_id, NOW(), 1)
+ RETURNING id INTO v_mapping_id;
+
+ RETURN v_mapping_id;
END;
$$;
@@ -589,6 +629,29 @@
--
+-- Name: update_integration_source_stats(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.update_integration_source_stats() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF TG_OP = 'INSERT' OR (TG_OP = 'UPDATE' AND OLD.status != NEW.status) THEN
+ UPDATE integration_sources
+ SET
+ webhook_count = webhook_count + CASE WHEN TG_OP = 'INSERT' THEN 1 ELSE 0 END,
+ success_count = success_count + CASE WHEN NEW.status = 'completed' THEN 1 ELSE 0 END,
+ failure_count = failure_count + CASE WHEN NEW.status IN ('failed', 'rejected') THEN 1 ELSE 0 END,
+ last_webhook_at = CASE WHEN TG_OP = 'INSERT' THEN NOW() ELSE last_webhook_at END,
+ updated_at = NOW()
+ WHERE id = NEW.source_id;
+ END IF;
+ RETURN NEW;
+END;
+$$;
+
+
+--
-- Name: update_updated_at_column(); Type: FUNCTION; Schema: public; Owner: -
--
@@ -778,7 +841,7 @@
rejection_notified_at timestamp with time zone,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT admission_batches_status_check CHECK (((status)::text = ANY ((ARRAY['draft'::character varying, 'processing'::character varying, 'review'::character varying, 'approved'::character varying, 'published'::character varying, 'cancelled'::character varying])::text[])))
+ CONSTRAINT admission_batches_status_check CHECK (((status)::text = ANY (ARRAY[('draft'::character varying)::text, ('processing'::character varying)::text, ('review'::character varying)::text, ('approved'::character varying)::text, ('published'::character varying)::text, ('cancelled'::character varying)::text])))
);
@@ -861,7 +924,8 @@
late_fee_amount numeric(10,2) DEFAULT 0,
tcu_submit_start date,
tcu_submit_end date,
- is_visible boolean DEFAULT true
+ is_visible boolean DEFAULT true,
+ description text
);
@@ -982,8 +1046,8 @@
expires_at date,
uploaded_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT applicant_documents_document_type_check CHECK (((document_type)::text = ANY ((ARRAY['birth_certificate'::character varying, 'national_id'::character varying, 'passport'::character varying, 'passport_photo'::character varying, 'csee_certificate'::character varying, 'acsee_certificate'::character varying, 'degree_certificate'::character varying, 'transcript'::character varying, 'professional_certificate'::character varying, 'work_letter'::character varying, 'recommendation_letter'::character varying, 'research_proposal'::character varying, 'cv_resume'::character varying, 'payslip'::character varying, 'sponsor_letter'::character varying, 'medical_report'::character varying, 'disability_certificate'::character varying, 'other'::character varying])::text[]))),
- CONSTRAINT applicant_documents_verification_status_check CHECK (((verification_status)::text = ANY ((ARRAY['pending'::character varying, 'verified'::character varying, 'rejected'::character varying, 'resubmit'::character varying])::text[])))
+ CONSTRAINT applicant_documents_document_type_check CHECK (((document_type)::text = ANY (ARRAY[('birth_certificate'::character varying)::text, ('national_id'::character varying)::text, ('passport'::character varying)::text, ('passport_photo'::character varying)::text, ('csee_certificate'::character varying)::text, ('acsee_certificate'::character varying)::text, ('degree_certificate'::character varying)::text, ('transcript'::character varying)::text, ('professional_certificate'::character varying)::text, ('work_letter'::character varying)::text, ('recommendation_letter'::character varying)::text, ('research_proposal'::character varying)::text, ('cv_resume'::character varying)::text, ('payslip'::character varying)::text, ('sponsor_letter'::character varying)::text, ('medical_report'::character varying)::text, ('disability_certificate'::character varying)::text, ('other'::character varying)::text]))),
+ CONSTRAINT applicant_documents_verification_status_check CHECK (((verification_status)::text = ANY (ARRAY[('pending'::character varying)::text, ('verified'::character varying)::text, ('rejected'::character varying)::text, ('resubmit'::character varying)::text])))
);
@@ -1014,7 +1078,7 @@
is_reseat boolean DEFAULT false,
original_sitting_id uuid,
reseat_reason text,
- CONSTRAINT applicant_exam_sittings_exam_type_check CHECK (((exam_type)::text = ANY ((ARRAY['CSEE'::character varying, 'ACSEE'::character varying, 'VETA'::character varying, 'NACTE'::character varying, 'FOREIGN'::character varying, 'DEGREE'::character varying, 'MASTERS'::character varying, 'OTHER'::character varying])::text[])))
+ CONSTRAINT applicant_exam_sittings_exam_type_check CHECK (((exam_type)::text = ANY (ARRAY[('CSEE'::character varying)::text, ('ACSEE'::character varying)::text, ('VETA'::character varying)::text, ('NACTE'::character varying)::text, ('FOREIGN'::character varying)::text, ('DEGREE'::character varying)::text, ('MASTERS'::character varying)::text, ('OTHER'::character varying)::text])))
);
@@ -1043,7 +1107,7 @@
ip_address character varying(45),
user_agent text,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT applicant_logs_log_type_check CHECK (((log_type)::text = ANY ((ARRAY['tcu_add'::character varying, 'tcu_check'::character varying, 'tcu_submit'::character varying, 'tcu_verify'::character varying, 'nacte_verify'::character varying, 'nacte_fetch'::character varying, 'necta_csee'::character varying, 'necta_acsee'::character varying, 'necta_reseat'::character varying, 'rita_avn'::character varying, 'rita_birth'::character varying, 'sms_sent'::character varying, 'email_sent'::character varying, 'control_number'::character varying, 'payment_callback'::character varying, 'status_change'::character varying, 'selection'::character varying, 'rejection'::character varying, 'transfer_internal'::character varying, 'transfer_external'::character varying, 'document_upload'::character varying, 'document_verify'::character varying, 'login'::character varying, 'logout'::character varying, 'password_reset'::character varying])::text[])))
+ CONSTRAINT applicant_logs_log_type_check CHECK (((log_type)::text = ANY (ARRAY[('tcu_add'::character varying)::text, ('tcu_check'::character varying)::text, ('tcu_submit'::character varying)::text, ('tcu_verify'::character varying)::text, ('nacte_verify'::character varying)::text, ('nacte_fetch'::character varying)::text, ('necta_csee'::character varying)::text, ('necta_acsee'::character varying)::text, ('necta_reseat'::character varying)::text, ('rita_avn'::character varying)::text, ('rita_birth'::character varying)::text, ('sms_sent'::character varying)::text, ('email_sent'::character varying)::text, ('control_number'::character varying)::text, ('payment_callback'::character varying)::text, ('status_change'::character varying)::text, ('selection'::character varying)::text, ('rejection'::character varying)::text, ('transfer_internal'::character varying)::text, ('transfer_external'::character varying)::text, ('document_upload'::character varying)::text, ('document_verify'::character varying)::text, ('login'::character varying)::text, ('logout'::character varying)::text, ('password_reset'::character varying)::text])))
);
@@ -1069,7 +1133,7 @@
is_emergency_contact boolean DEFAULT false,
is_sponsor boolean DEFAULT false,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT applicant_next_of_kin_relationship_check CHECK (((relationship)::text = ANY ((ARRAY['father'::character varying, 'mother'::character varying, 'guardian'::character varying, 'spouse'::character varying, 'sibling'::character varying, 'uncle'::character varying, 'aunt'::character varying, 'grandparent'::character varying, 'other'::character varying])::text[])))
+ CONSTRAINT applicant_next_of_kin_relationship_check CHECK (((relationship)::text = ANY (ARRAY[('father'::character varying)::text, ('mother'::character varying)::text, ('guardian'::character varying)::text, ('spouse'::character varying)::text, ('sibling'::character varying)::text, ('uncle'::character varying)::text, ('aunt'::character varying)::text, ('grandparent'::character varying)::text, ('other'::character varying)::text])))
);
@@ -1096,7 +1160,7 @@
is_primary_contact boolean DEFAULT false,
is_sponsor boolean DEFAULT false,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT applicant_parents_parent_type_check CHECK (((parent_type)::text = ANY ((ARRAY['father'::character varying, 'mother'::character varying, 'guardian'::character varying])::text[])))
+ CONSTRAINT applicant_parents_parent_type_check CHECK (((parent_type)::text = ANY (ARRAY[('father'::character varying)::text, ('mother'::character varying)::text, ('guardian'::character varying)::text])))
);
@@ -1124,8 +1188,8 @@
gateway_response jsonb,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT applicant_payments_payment_type_check CHECK (((payment_type)::text = ANY ((ARRAY['application_fee'::character varying, 'admission_fee'::character varying, 'registration_fee'::character varying])::text[]))),
- CONSTRAINT applicant_payments_status_check CHECK (((status)::text = ANY ((ARRAY['pending'::character varying, 'processing'::character varying, 'completed'::character varying, 'failed'::character varying, 'cancelled'::character varying, 'refunded'::character varying])::text[])))
+ CONSTRAINT applicant_payments_payment_type_check CHECK (((payment_type)::text = ANY (ARRAY[('application_fee'::character varying)::text, ('admission_fee'::character varying)::text, ('registration_fee'::character varying)::text]))),
+ CONSTRAINT applicant_payments_status_check CHECK (((status)::text = ANY (ARRAY[('pending'::character varying)::text, ('processing'::character varying)::text, ('completed'::character varying)::text, ('failed'::character varying)::text, ('cancelled'::character varying)::text, ('refunded'::character varying)::text])))
);
@@ -1172,7 +1236,7 @@
verified_by uuid,
verified_at timestamp with time zone,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT applicant_referees_referee_type_check CHECK (((referee_type)::text = ANY ((ARRAY['academic'::character varying, 'professional'::character varying, 'character'::character varying, 'employer'::character varying])::text[])))
+ CONSTRAINT applicant_referees_referee_type_check CHECK (((referee_type)::text = ANY (ARRAY[('academic'::character varying)::text, ('professional'::character varying)::text, ('character'::character varying)::text, ('employer'::character varying)::text])))
);
@@ -1195,8 +1259,8 @@
expires_at timestamp with time zone,
used_at timestamp with time zone,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT applicant_resubmissions_reason_check CHECK (((reason)::text = ANY ((ARRAY['technical_error'::character varying, 'incomplete_data'::character varying, 'payment_issue'::character varying, 'results_delay'::character varying, 'admin_error'::character varying, 'appeal_approved'::character varying])::text[]))),
- CONSTRAINT applicant_resubmissions_status_check CHECK (((status)::text = ANY ((ARRAY['pending'::character varying, 'approved'::character varying, 'rejected'::character varying, 'used'::character varying])::text[])))
+ CONSTRAINT applicant_resubmissions_reason_check CHECK (((reason)::text = ANY (ARRAY[('technical_error'::character varying)::text, ('incomplete_data'::character varying)::text, ('payment_issue'::character varying)::text, ('results_delay'::character varying)::text, ('admin_error'::character varying)::text, ('appeal_approved'::character varying)::text]))),
+ CONSTRAINT applicant_resubmissions_status_check CHECK (((status)::text = ANY (ARRAY[('pending'::character varying)::text, ('approved'::character varying)::text, ('rejected'::character varying)::text, ('used'::character varying)::text])))
);
@@ -1272,8 +1336,8 @@
rejection_reason text,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT applicant_transfers_status_check CHECK (((status)::text = ANY ((ARRAY['pending'::character varying, 'documents_submitted'::character varying, 'under_review'::character varying, 'approved'::character varying, 'rejected'::character varying, 'cancelled'::character varying])::text[]))),
- CONSTRAINT applicant_transfers_transfer_type_check CHECK (((transfer_type)::text = ANY ((ARRAY['internal'::character varying, 'external_in'::character varying, 'external_out'::character varying])::text[])))
+ CONSTRAINT applicant_transfers_status_check CHECK (((status)::text = ANY (ARRAY[('pending'::character varying)::text, ('documents_submitted'::character varying)::text, ('under_review'::character varying)::text, ('approved'::character varying)::text, ('rejected'::character varying)::text, ('cancelled'::character varying)::text]))),
+ CONSTRAINT applicant_transfers_transfer_type_check CHECK (((transfer_type)::text = ANY (ARRAY[('internal'::character varying)::text, ('external_in'::character varying)::text, ('external_out'::character varying)::text])))
);
@@ -1301,7 +1365,7 @@
verified_by uuid,
verified_at timestamp with time zone,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT applicant_upgraders_previous_qualification_check CHECK (((previous_qualification)::text = ANY ((ARRAY['certificate'::character varying, 'diploma'::character varying, 'advanced_diploma'::character varying, 'bachelor'::character varying, 'postgrad_diploma'::character varying])::text[])))
+ CONSTRAINT applicant_upgraders_previous_qualification_check CHECK (((previous_qualification)::text = ANY (ARRAY[('certificate'::character varying)::text, ('diploma'::character varying)::text, ('advanced_diploma'::character varying)::text, ('bachelor'::character varying)::text, ('postgrad_diploma'::character varying)::text])))
);
@@ -1330,7 +1394,7 @@
verification_letter_url text,
is_verified boolean DEFAULT false,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT applicant_work_experience_employment_type_check CHECK (((employment_type)::text = ANY ((ARRAY['full_time'::character varying, 'part_time'::character varying, 'contract'::character varying, 'internship'::character varying, 'volunteer'::character varying])::text[])))
+ CONSTRAINT applicant_work_experience_employment_type_check CHECK (((employment_type)::text = ANY (ARRAY[('full_time'::character varying)::text, ('part_time'::character varying)::text, ('contract'::character varying)::text, ('internship'::character varying)::text, ('volunteer'::character varying)::text])))
);
@@ -1573,11 +1637,18 @@
code character varying(20) NOT NULL,
name character varying(200) NOT NULL,
credits integer NOT NULL,
+ year_of_study integer,
+ semester integer,
is_elective boolean DEFAULT false,
is_active boolean DEFAULT true,
created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
description text,
- semester_num integer
+ semester_num integer DEFAULT 1,
+ lecture_hours integer DEFAULT 2,
+ practical_hours integer DEFAULT 0,
+ course_type character varying(20) DEFAULT 'core'::character varying,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
+ CONSTRAINT courses_type_check CHECK (((course_type)::text = ANY ((ARRAY['core'::character varying, 'elective'::character varying, 'general'::character varying])::text[])))
);
@@ -1637,7 +1708,7 @@
opened_at timestamp with time zone,
error_message text,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT email_logs_status_check CHECK (((status)::text = ANY ((ARRAY['pending'::character varying, 'sent'::character varying, 'delivered'::character varying, 'bounced'::character varying, 'failed'::character varying])::text[])))
+ CONSTRAINT email_logs_status_check CHECK (((status)::text = ANY (ARRAY[('pending'::character varying)::text, ('sent'::character varying)::text, ('delivered'::character varying)::text, ('bounced'::character varying)::text, ('failed'::character varying)::text])))
);
@@ -1657,7 +1728,7 @@
is_active boolean DEFAULT true,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT email_templates_category_check CHECK (((category)::text = ANY ((ARRAY['admission'::character varying, 'registration'::character varying, 'payment'::character varying, 'notification'::character varying, 'system'::character varying])::text[])))
+ CONSTRAINT email_templates_category_check CHECK (((category)::text = ANY (ARRAY[('admission'::character varying)::text, ('registration'::character varying)::text, ('payment'::character varying)::text, ('notification'::character varying)::text, ('system'::character varying)::text])))
);
@@ -1714,8 +1785,8 @@
verified_at timestamp with time zone,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT exams_exam_type_check CHECK (((exam_type)::text = ANY ((ARRAY['midterm'::character varying, 'final'::character varying, 'quiz'::character varying, 'assignment'::character varying, 'coursework'::character varying, 'practical'::character varying, 'project'::character varying])::text[]))),
- CONSTRAINT exams_status_check CHECK (((status)::text = ANY ((ARRAY['scheduled'::character varying, 'ongoing'::character varying, 'completed'::character varying, 'cancelled'::character varying, 'grading'::character varying])::text[])))
+ CONSTRAINT exams_exam_type_check CHECK (((exam_type)::text = ANY (ARRAY[('midterm'::character varying)::text, ('final'::character varying)::text, ('quiz'::character varying)::text, ('assignment'::character varying)::text, ('coursework'::character varying)::text, ('practical'::character varying)::text, ('project'::character varying)::text]))),
+ CONSTRAINT exams_status_check CHECK (((status)::text = ANY (ARRAY[('scheduled'::character varying)::text, ('ongoing'::character varying)::text, ('completed'::character varying)::text, ('cancelled'::character varying)::text, ('grading'::character varying)::text])))
);
@@ -1740,7 +1811,7 @@
health_status character varying(20),
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT external_api_configs_service_name_check CHECK (((service_name)::text = ANY ((ARRAY['tcu'::character varying, 'nacte'::character varying, 'necta'::character varying, 'rita'::character varying, 'gepg'::character varying, 'crdb'::character varying, 'nmb'::character varying, 'sms_gateway'::character varying, 'email_gateway'::character varying])::text[])))
+ CONSTRAINT external_api_configs_service_name_check CHECK (((service_name)::text = ANY (ARRAY[('tcu'::character varying)::text, ('nacte'::character varying)::text, ('necta'::character varying)::text, ('rita'::character varying)::text, ('gepg'::character varying)::text, ('crdb'::character varying)::text, ('nmb'::character varying)::text, ('sms_gateway'::character varying)::text, ('email_gateway'::character varying)::text])))
);
@@ -1754,15 +1825,22 @@
entity_type character varying(50) NOT NULL,
external_id character varying(255) NOT NULL,
tims_id uuid NOT NULL,
- external_metadata jsonb,
- last_used_at timestamp with time zone DEFAULT now(),
- use_count integer DEFAULT 1 NOT NULL,
+ external_metadata jsonb DEFAULT '{}'::jsonb,
+ last_used_at timestamp with time zone,
+ use_count integer DEFAULT 0,
created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now()
);
--
+-- Name: TABLE external_id_mappings; Type: COMMENT; Schema: public; Owner: -
+--
+
+COMMENT ON TABLE public.external_id_mappings IS 'Cache of external ID to TIMS ID mappings';
+
+
+--
-- Name: faculties; Type: TABLE; Schema: public; Owner: -
--
@@ -1874,14 +1952,22 @@
CREATE TABLE public.fee_structures (
id uuid DEFAULT gen_random_uuid() NOT NULL,
program_id uuid,
+ fee_type_id uuid,
academic_year_id uuid,
- fee_category_id uuid,
- amount numeric(12,2) NOT NULL,
- currency character varying(10) DEFAULT 'TZS'::character varying,
- semester_num integer,
+ nta_level character varying(20),
+ semester integer,
+ amount_local numeric(15,2) NOT NULL,
+ amount_international numeric(15,2),
+ currency character varying(3) DEFAULT 'TZS'::character varying,
+ installments_allowed integer DEFAULT 1,
+ first_installment_percent numeric(5,2) DEFAULT 100.00,
+ due_days_from_semester_start integer DEFAULT 30,
+ late_fee_percent numeric(5,2) DEFAULT 0,
is_active boolean DEFAULT true,
- created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
- updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP
+ created_by uuid,
+ created_at timestamp with time zone DEFAULT now(),
+ updated_at timestamp with time zone DEFAULT now(),
+ CONSTRAINT fee_structures_semester_check CHECK ((semester = ANY (ARRAY[1, 2])))
);
@@ -1889,7 +1975,7 @@
-- Name: TABLE fee_structures; Type: COMMENT; Schema: public; Owner: -
--
-COMMENT ON TABLE public.fee_structures IS 'Fee amounts per program, NTA level, and semester';
+COMMENT ON TABLE public.fee_structures IS 'Fee amounts per program, fee type, NTA level, and semester';
--
@@ -2020,9 +2106,9 @@
description text,
target_entity character varying(50) NOT NULL,
target_action character varying(30) DEFAULT 'upsert'::character varying NOT NULL,
- schema_definition jsonb,
- process_immediately boolean DEFAULT false NOT NULL,
- batch_size integer DEFAULT 100 NOT NULL,
+ schema_definition jsonb DEFAULT '{}'::jsonb NOT NULL,
+ process_immediately boolean DEFAULT true,
+ batch_size integer DEFAULT 100,
is_active boolean DEFAULT true NOT NULL,
created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now()
@@ -2030,6 +2116,13 @@
--
+-- Name: TABLE integration_data_types; Type: COMMENT; Schema: public; Owner: -
+--
+
+COMMENT ON TABLE public.integration_data_types IS 'Defines the types of data that external systems can send via webhooks. Each data type has a JSON schema for validation.';
+
+
+--
-- Name: integration_entity_matchers; Type: TABLE; Schema: public; Owner: -
--
@@ -2038,18 +2131,25 @@
source_id uuid NOT NULL,
entity_type character varying(50) NOT NULL,
tims_table character varying(50) NOT NULL,
- match_strategy character varying(30) DEFAULT 'field_match'::character varying NOT NULL,
+ match_strategy character varying(30) NOT NULL,
source_field character varying(100),
tims_field character varying(100),
- match_config jsonb,
- fallback_strategy character varying(30) DEFAULT 'reject'::character varying NOT NULL,
- priority integer DEFAULT 0 NOT NULL,
+ match_config jsonb DEFAULT '{}'::jsonb,
+ fallback_strategy character varying(30) DEFAULT 'reject'::character varying,
+ priority integer DEFAULT 0,
is_active boolean DEFAULT true NOT NULL,
created_at timestamp with time zone DEFAULT now()
);
--
+-- Name: TABLE integration_entity_matchers; Type: COMMENT; Schema: public; Owner: -
+--
+
+COMMENT ON TABLE public.integration_entity_matchers IS 'Defines how to match external entities (students, courses) to TIMS records. Supports multiple match strategies.';
+
+
+--
-- Name: integration_field_mappings; Type: TABLE; Schema: public; Owner: -
--
@@ -2059,16 +2159,23 @@
source_field character varying(100) NOT NULL,
target_field character varying(100) NOT NULL,
transform_type character varying(30) DEFAULT 'direct'::character varying NOT NULL,
- transform_config jsonb,
+ transform_config jsonb DEFAULT '{}'::jsonb,
is_required boolean DEFAULT false NOT NULL,
default_value text,
- validation_rules jsonb,
- sort_order integer DEFAULT 0 NOT NULL,
+ validation_rules jsonb DEFAULT '{}'::jsonb,
+ sort_order integer DEFAULT 0,
created_at timestamp with time zone DEFAULT now()
);
--
+-- Name: TABLE integration_field_mappings; Type: COMMENT; Schema: public; Owner: -
+--
+
+COMMENT ON TABLE public.integration_field_mappings IS 'Maps external webhook fields to internal TIMS database fields. Supports transformation rules for data conversion.';
+
+
+--
-- Name: integration_processing_results; Type: TABLE; Schema: public; Owner: -
--
@@ -2079,21 +2186,28 @@
record_key character varying(255),
target_entity character varying(50) NOT NULL,
target_id uuid,
- action character varying(30) NOT NULL,
+ action character varying(20) NOT NULL,
input_data jsonb,
mapped_data jsonb,
output_data jsonb,
- status character varying(30) NOT NULL,
+ status character varying(20) NOT NULL,
error_message text,
error_details jsonb,
match_strategy character varying(30),
match_field character varying(100),
- match_value text,
- processed_at timestamp with time zone DEFAULT now() NOT NULL
+ match_value character varying(255),
+ processed_at timestamp with time zone DEFAULT now()
);
--
+-- Name: TABLE integration_processing_results; Type: COMMENT; Schema: public; Owner: -
+--
+
+COMMENT ON TABLE public.integration_processing_results IS 'Per-record processing results';
+
+
+--
-- Name: integration_rate_limits; Type: TABLE; Schema: public; Owner: -
--
@@ -2101,6 +2215,7 @@
id uuid DEFAULT gen_random_uuid() NOT NULL,
source_id uuid NOT NULL,
window_start timestamp with time zone NOT NULL,
+ window_minutes integer DEFAULT 1 NOT NULL,
request_count integer DEFAULT 0 NOT NULL
);
@@ -2118,18 +2233,25 @@
reason character varying(50) NOT NULL,
reason_details text,
record_data jsonb NOT NULL,
- status character varying(30) DEFAULT 'pending'::character varying NOT NULL,
+ status character varying(20) DEFAULT 'pending'::character varying NOT NULL,
resolved_by uuid,
resolved_at timestamp with time zone,
- resolution_action character varying(50),
+ resolution_action character varying(30),
resolution_notes text,
matched_entity_type character varying(50),
matched_entity_id uuid,
- created_at timestamp with time zone DEFAULT now() NOT NULL
+ created_at timestamp with time zone DEFAULT now()
);
--
+-- Name: TABLE integration_review_queue; Type: COMMENT; Schema: public; Owner: -
+--
+
+COMMENT ON TABLE public.integration_review_queue IS 'Records needing manual review';
+
+
+--
-- Name: integration_sources; Type: TABLE; Schema: public; Owner: -
--
@@ -2141,13 +2263,13 @@
base_url character varying(255),
auth_type character varying(30) DEFAULT 'hmac'::character varying NOT NULL,
auth_config jsonb DEFAULT '{}'::jsonb NOT NULL,
- rate_limit_rpm integer DEFAULT 100 NOT NULL,
- rate_limit_burst integer DEFAULT 20 NOT NULL,
+ rate_limit_rpm integer DEFAULT 100,
+ rate_limit_burst integer DEFAULT 20,
is_active boolean DEFAULT true NOT NULL,
last_webhook_at timestamp with time zone,
- webhook_count integer DEFAULT 0 NOT NULL,
- success_count integer DEFAULT 0 NOT NULL,
- failure_count integer DEFAULT 0 NOT NULL,
+ webhook_count integer DEFAULT 0,
+ success_count integer DEFAULT 0,
+ failure_count integer DEFAULT 0,
created_by uuid,
created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now()
@@ -2155,6 +2277,13 @@
--
+-- Name: TABLE integration_sources; Type: COMMENT; Schema: public; Owner: -
+--
+
+COMMENT ON TABLE public.integration_sources IS 'Registry of external systems that can send data to TIMS';
+
+
+--
-- Name: integration_webhooks; Type: TABLE; Schema: public; Owner: -
--
@@ -2167,27 +2296,34 @@
request_id character varying(100),
request_payload jsonb NOT NULL,
request_headers jsonb,
- request_signature text,
- client_ip character varying(45),
- status character varying(30) DEFAULT 'received'::character varying NOT NULL,
+ request_signature character varying(255),
+ client_ip inet,
+ status character varying(20) DEFAULT 'received'::character varying NOT NULL,
status_message text,
error_details jsonb,
- received_at timestamp with time zone DEFAULT now() NOT NULL,
+ received_at timestamp with time zone DEFAULT now(),
validated_at timestamp with time zone,
processing_started_at timestamp with time zone,
processed_at timestamp with time zone,
- records_received integer DEFAULT 0 NOT NULL,
- records_succeeded integer DEFAULT 0 NOT NULL,
- records_failed integer DEFAULT 0 NOT NULL,
- records_skipped integer DEFAULT 0 NOT NULL,
- retry_count integer DEFAULT 0 NOT NULL,
- max_retries integer DEFAULT 3 NOT NULL,
+ records_received integer DEFAULT 0,
+ records_succeeded integer DEFAULT 0,
+ records_failed integer DEFAULT 0,
+ records_skipped integer DEFAULT 0,
+ retry_count integer DEFAULT 0,
+ max_retries integer DEFAULT 3,
next_retry_at timestamp with time zone,
last_error text
);
--
+-- Name: TABLE integration_webhooks; Type: COMMENT; Schema: public; Owner: -
+--
+
+COMMENT ON TABLE public.integration_webhooks IS 'Audit log of all incoming webhooks';
+
+
+--
-- Name: invoice_audit; Type: TABLE; Schema: public; Owner: -
--
@@ -2237,14 +2373,13 @@
student_id uuid,
academic_year_id uuid,
semester_id uuid,
- invoice_number character varying(50) NOT NULL,
+ invoice_no character varying(50) NOT NULL,
total_amount numeric(12,2) NOT NULL,
paid_amount numeric(12,2) DEFAULT 0,
status character varying(20) DEFAULT 'pending'::character varying,
due_date date,
created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
- invoice_no character varying(50),
balance numeric(12,2),
currency character varying(10) DEFAULT 'TZS'::character varying,
notes text
@@ -2432,8 +2567,8 @@
response_at timestamp with time zone,
submitted_by uuid,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT nacte_submissions_status_check CHECK (((status)::text = ANY ((ARRAY['pending'::character varying, 'submitted'::character varying, 'processing'::character varying, 'verified'::character varying, 'rejected'::character varying, 'error'::character varying])::text[]))),
- CONSTRAINT nacte_submissions_submission_type_check CHECK (((submission_type)::text = ANY ((ARRAY['verification'::character varying, 'admission'::character varying, 'enrollment'::character varying])::text[])))
+ CONSTRAINT nacte_submissions_status_check CHECK (((status)::text = ANY (ARRAY[('pending'::character varying)::text, ('submitted'::character varying)::text, ('processing'::character varying)::text, ('verified'::character varying)::text, ('rejected'::character varying)::text, ('error'::character varying)::text]))),
+ CONSTRAINT nacte_submissions_submission_type_check CHECK (((submission_type)::text = ANY (ARRAY[('verification'::character varying)::text, ('admission'::character varying)::text, ('enrollment'::character varying)::text])))
);
@@ -2480,7 +2615,7 @@
max_attempts integer DEFAULT 5,
expires_at timestamp with time zone NOT NULL,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT otp_verifications_otp_type_check CHECK (((otp_type)::text = ANY ((ARRAY['phone'::character varying, 'email'::character varying, 'password_reset'::character varying, 'login'::character varying])::text[])))
+ CONSTRAINT otp_verifications_otp_type_check CHECK (((otp_type)::text = ANY (ARRAY[('phone'::character varying)::text, ('email'::character varying)::text, ('password_reset'::character varying)::text, ('login'::character varying)::text])))
);
@@ -2808,15 +2943,7 @@
reference_number character varying(100),
status character varying(20) DEFAULT 'completed'::character varying,
paid_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
- recorded_by uuid,
- payment_no character varying(50),
- student_id uuid,
- currency character varying(10) DEFAULT 'TZS'::character varying,
- transaction_id character varying(100),
- received_by uuid,
- notes text,
- created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
- updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP
+ recorded_by uuid
);
@@ -2876,15 +3003,12 @@
department_id uuid,
name character varying(200) NOT NULL,
code character varying(20) NOT NULL,
+ degree_type character varying(50) NOT NULL,
+ duration_years integer NOT NULL,
+ total_credits integer,
is_active boolean DEFAULT true,
created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
- updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
- level character varying(50),
- duration integer,
- description text,
- degree_type character varying(50),
- duration_years integer,
- total_credits integer
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP
);
@@ -2935,8 +3059,8 @@
approved_at timestamp with time zone,
approval_status character varying(20),
approval_notes text,
- CONSTRAINT result_changes_approval_status_check CHECK (((approval_status)::text = ANY ((ARRAY['pending'::character varying, 'approved'::character varying, 'rejected'::character varying])::text[]))),
- CONSTRAINT result_changes_change_type_check CHECK (((change_type)::text = ANY ((ARRAY['create'::character varying, 'update'::character varying, 'delete'::character varying, 'verify'::character varying, 'publish'::character varying, 'appeal'::character varying, 'correction'::character varying])::text[])))
+ CONSTRAINT result_changes_approval_status_check CHECK (((approval_status)::text = ANY (ARRAY[('pending'::character varying)::text, ('approved'::character varying)::text, ('rejected'::character varying)::text]))),
+ CONSTRAINT result_changes_change_type_check CHECK (((change_type)::text = ANY (ARRAY[('create'::character varying)::text, ('update'::character varying)::text, ('delete'::character varying)::text, ('verify'::character varying)::text, ('publish'::character varying)::text, ('appeal'::character varying)::text, ('correction'::character varying)::text])))
);
@@ -2977,9 +3101,9 @@
options jsonb DEFAULT '{}'::jsonb,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT result_compilation_queue_file_type_check CHECK (((file_type)::text = ANY ((ARRAY['csv'::character varying, 'xlsx'::character varying, 'xls'::character varying, 'json'::character varying])::text[]))),
+ CONSTRAINT result_compilation_queue_file_type_check CHECK (((file_type)::text = ANY (ARRAY[('csv'::character varying)::text, ('xlsx'::character varying)::text, ('xls'::character varying)::text, ('json'::character varying)::text]))),
CONSTRAINT result_compilation_queue_priority_check CHECK (((priority >= 1) AND (priority <= 10))),
- CONSTRAINT result_compilation_queue_status_check CHECK (((status)::text = ANY ((ARRAY['pending'::character varying, 'validating'::character varying, 'processing'::character varying, 'completed'::character varying, 'failed'::character varying, 'cancelled'::character varying, 'partial'::character varying])::text[])))
+ CONSTRAINT result_compilation_queue_status_check CHECK (((status)::text = ANY (ARRAY[('pending'::character varying)::text, ('validating'::character varying)::text, ('processing'::character varying)::text, ('completed'::character varying)::text, ('failed'::character varying)::text, ('cancelled'::character varying)::text, ('partial'::character varying)::text])))
);
@@ -3010,8 +3134,8 @@
expires_at timestamp with time zone,
archived_at timestamp with time zone,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT result_upload_files_status_check CHECK (((status)::text = ANY ((ARRAY['uploaded'::character varying, 'validated'::character varying, 'processing'::character varying, 'processed'::character varying, 'failed'::character varying, 'archived'::character varying])::text[]))),
- CONSTRAINT result_upload_files_upload_type_check CHECK (((upload_type)::text = ANY ((ARRAY['results'::character varying, 'corrections'::character varying, 'appeals'::character varying, 'template'::character varying])::text[])))
+ CONSTRAINT result_upload_files_status_check CHECK (((status)::text = ANY (ARRAY[('uploaded'::character varying)::text, ('validated'::character varying)::text, ('processing'::character varying)::text, ('processed'::character varying)::text, ('failed'::character varying)::text, ('archived'::character varying)::text]))),
+ CONSTRAINT result_upload_files_upload_type_check CHECK (((upload_type)::text = ANY (ARRAY[('results'::character varying)::text, ('corrections'::character varying)::text, ('appeals'::character varying)::text, ('template'::character varying)::text])))
);
@@ -3069,20 +3193,11 @@
color character varying(20),
is_system boolean DEFAULT false,
created_by uuid,
- updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
- dashboard_type character varying(30) DEFAULT 'default'::character varying,
- CONSTRAINT roles_dashboard_type_check CHECK (((dashboard_type)::text = ANY ((ARRAY['admin'::character varying, 'registrar'::character varying, 'finance'::character varying, 'student'::character varying, 'teacher'::character varying, 'default'::character varying])::text[])))
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP
);
--
--- Name: COLUMN roles.dashboard_type; Type: COMMENT; Schema: public; Owner: -
---
-
-COMMENT ON COLUMN public.roles.dashboard_type IS 'Determines which dashboard UI to show users with this role. Options: admin, registrar, finance, student, teacher, default';
-
-
---
-- Name: roles_backup; Type: TABLE; Schema: public; Owner: -
--
@@ -3191,7 +3306,8 @@
is_current boolean DEFAULT false,
created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
number integer DEFAULT 1,
- updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
+ CONSTRAINT semesters_number_check CHECK (((number >= 1) AND (number <= 3)))
);
@@ -3233,8 +3349,8 @@
cost numeric(8,2),
currency character varying(3) DEFAULT 'TZS'::character varying,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT sms_notifications_message_type_check CHECK (((message_type)::text = ANY ((ARRAY['control_number'::character varying, 'payment_confirmation'::character varying, 'selection'::character varying, 'rejection'::character varying, 'admission_letter'::character varying, 'registration_reminder'::character varying, 'otp_verification'::character varying, 'password_reset'::character varying, 'general'::character varying])::text[]))),
- CONSTRAINT sms_notifications_status_check CHECK (((status)::text = ANY ((ARRAY['pending'::character varying, 'sent'::character varying, 'delivered'::character varying, 'failed'::character varying])::text[])))
+ CONSTRAINT sms_notifications_message_type_check CHECK (((message_type)::text = ANY (ARRAY[('control_number'::character varying)::text, ('payment_confirmation'::character varying)::text, ('selection'::character varying)::text, ('rejection'::character varying)::text, ('admission_letter'::character varying)::text, ('registration_reminder'::character varying)::text, ('otp_verification'::character varying)::text, ('password_reset'::character varying)::text, ('general'::character varying)::text]))),
+ CONSTRAINT sms_notifications_status_check CHECK (((status)::text = ANY (ARRAY[('pending'::character varying)::text, ('sent'::character varying)::text, ('delivered'::character varying)::text, ('failed'::character varying)::text])))
);
@@ -3382,18 +3498,14 @@
phone character varying(20),
gender character varying(10) NOT NULL,
date_of_birth date NOT NULL,
+ nationality character varying(50) DEFAULT 'Tanzanian'::character varying,
program_id uuid,
+ admission_year integer,
+ current_year integer DEFAULT 1,
status character varying(20) DEFAULT 'active'::character varying,
photo_url text,
created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
- updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
- national_id character varying(50),
- address text,
- city character varying(100),
- country character varying(100) DEFAULT 'Tanzania'::character varying,
- admission_date date DEFAULT CURRENT_DATE,
- graduation_date date,
- current_semester integer DEFAULT 1
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP
);
@@ -3421,8 +3533,8 @@
submitted_by uuid,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT tcu_submissions_status_check CHECK (((status)::text = ANY ((ARRAY['pending'::character varying, 'submitted'::character varying, 'processing'::character varying, 'verified'::character varying, 'rejected'::character varying, 'error'::character varying, 'timeout'::character varying])::text[]))),
- CONSTRAINT tcu_submissions_submission_type_check CHECK (((submission_type)::text = ANY ((ARRAY['verification'::character varying, 'admission'::character varying, 'enrollment'::character varying, 'results'::character varying])::text[])))
+ CONSTRAINT tcu_submissions_status_check CHECK (((status)::text = ANY (ARRAY[('pending'::character varying)::text, ('submitted'::character varying)::text, ('processing'::character varying)::text, ('verified'::character varying)::text, ('rejected'::character varying)::text, ('error'::character varying)::text, ('timeout'::character varying)::text]))),
+ CONSTRAINT tcu_submissions_submission_type_check CHECK (((submission_type)::text = ANY (ARRAY[('verification'::character varying)::text, ('admission'::character varying)::text, ('enrollment'::character varying)::text, ('results'::character varying)::text])))
);
@@ -3571,27 +3683,6 @@
--
--- Name: v_payment_summary; Type: VIEW; Schema: public; Owner: -
---
-
-CREATE VIEW public.v_payment_summary AS
- SELECT s.id AS student_id,
- s.registration_number,
- concat(s.first_name, ' ', COALESCE(((s.middle_name)::text || ' '::text), ''::text), s.last_name) AS student_name,
- p.name AS program_name,
- COALESCE(sum(i.total_amount), (0)::numeric) AS total_invoiced,
- COALESCE(sum(i.paid_amount), (0)::numeric) AS total_paid,
- COALESCE(sum(i.balance), (0)::numeric) AS total_balance,
- count(DISTINCT i.id) AS invoice_count,
- count(DISTINCT pay.id) AS payment_count
- FROM (((public.students s
- LEFT JOIN public.programs p ON ((s.program_id = p.id)))
- LEFT JOIN public.invoices i ON ((s.id = i.student_id)))
- LEFT JOIN public.payments pay ON (((i.id = pay.invoice_id) AND ((pay.status)::text = 'completed'::text))))
- GROUP BY s.id, s.registration_number, s.first_name, s.middle_name, s.last_name, p.name;
-
-
---
-- Name: workflow_approvals; Type: TABLE; Schema: public; Owner: -
--
@@ -4378,8 +4469,16 @@
ALTER TABLE ONLY public.fee_structures
ADD CONSTRAINT fee_structures_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: fee_structures fee_structures_program_id_fee_type_id_academic_year_id_nta__key; Type: CONSTRAINT; Schema: public; Owner: -
+--
+ALTER TABLE ONLY public.fee_structures
+ ADD CONSTRAINT fee_structures_program_id_fee_type_id_academic_year_id_nta__key UNIQUE (program_id, fee_type_id, academic_year_id, nta_level, semester);
+
--
-- Name: fee_types fee_types_code_key; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -4474,8 +4573,24 @@
ALTER TABLE ONLY public.integration_entity_matchers
ADD CONSTRAINT integration_entity_matchers_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: integration_entity_matchers integration_entity_matchers_source_id_entity_type_priority_key; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.integration_entity_matchers
+ ADD CONSTRAINT integration_entity_matchers_source_id_entity_type_priority_key UNIQUE (source_id, entity_type, priority);
+
+
+--
+-- Name: integration_field_mappings integration_field_mappings_data_type_id_source_field_key; Type: CONSTRAINT; Schema: public; Owner: -
+--
+ALTER TABLE ONLY public.integration_field_mappings
+ ADD CONSTRAINT integration_field_mappings_data_type_id_source_field_key UNIQUE (data_type_id, source_field);
+
--
-- Name: integration_field_mappings integration_field_mappings_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -4501,14 +4616,22 @@
--
--- Name: integration_rate_limits integration_rate_limits_source_id_window_start_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: integration_rate_limits integration_rate_limits_source_id_window_start_window_minut_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.integration_rate_limits
- ADD CONSTRAINT integration_rate_limits_source_id_window_start_key UNIQUE (source_id, window_start);
+ ADD CONSTRAINT integration_rate_limits_source_id_window_start_window_minut_key UNIQUE (source_id, window_start, window_minutes);
--
+-- Name: integration_rate_limits integration_rate_limits_source_window_unique; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.integration_rate_limits
+ ADD CONSTRAINT integration_rate_limits_source_window_unique UNIQUE (source_id, window_start);
+
+
+--
-- Name: integration_review_queue integration_review_queue_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -4561,7 +4684,7 @@
--
ALTER TABLE ONLY public.invoices
- ADD CONSTRAINT invoices_invoice_number_key UNIQUE (invoice_number);
+ ADD CONSTRAINT invoices_invoice_number_key UNIQUE (invoice_no);
--
@@ -4754,16 +4877,8 @@
ALTER TABLE ONLY public.payment_transactions
ADD CONSTRAINT payment_transactions_pkey PRIMARY KEY (id);
-
-
---
--- Name: payment_transactions payment_transactions_receipt_number_key; Type: CONSTRAINT; Schema: public; Owner: -
---
-ALTER TABLE ONLY public.payment_transactions
- ADD CONSTRAINT payment_transactions_receipt_number_key UNIQUE (receipt_number);
-
--
-- Name: payment_transactions payment_transactions_transaction_ref_key; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -5698,7 +5813,7 @@
-- Name: idx_compilation_queue_pending; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX idx_compilation_queue_pending ON public.result_compilation_queue USING btree (status, priority, queued_at) WHERE ((status)::text = ANY ((ARRAY['pending'::character varying, 'validating'::character varying])::text[]));
+CREATE INDEX idx_compilation_queue_pending ON public.result_compilation_queue USING btree (status, priority, queued_at) WHERE ((status)::text = ANY (ARRAY[('pending'::character varying)::text, ('validating'::character varying)::text]));
--
@@ -5783,8 +5898,22 @@
--
CREATE INDEX idx_course_registrations_student ON public.course_registrations USING btree (student_id);
+
+
+--
+-- Name: idx_courses_semester_num; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_courses_semester_num ON public.courses USING btree (semester_num);
+
+
+--
+-- Name: idx_courses_type; Type: INDEX; Schema: public; Owner: -
+--
+CREATE INDEX idx_courses_type ON public.courses USING btree (course_type);
+
--
-- Name: idx_disbursements_beneficiary; Type: INDEX; Schema: public; Owner: -
--
@@ -5891,6 +6020,13 @@
--
+-- Name: idx_external_id_mappings_tims; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_external_id_mappings_tims ON public.external_id_mappings USING btree (tims_id);
+
+
+--
-- Name: idx_features_module; Type: INDEX; Schema: public; Owner: -
--
@@ -5919,24 +6055,24 @@
--
--- Name: idx_fee_structures_academic_year; Type: INDEX; Schema: public; Owner: -
+-- Name: idx_fee_structures_fee_type; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX idx_fee_structures_academic_year ON public.fee_structures USING btree (academic_year_id);
+CREATE INDEX idx_fee_structures_fee_type ON public.fee_structures USING btree (fee_type_id);
--
--- Name: idx_fee_structures_active; Type: INDEX; Schema: public; Owner: -
+-- Name: idx_fee_structures_program; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX idx_fee_structures_active ON public.fee_structures USING btree (is_active);
+CREATE INDEX idx_fee_structures_program ON public.fee_structures USING btree (program_id);
--
--- Name: idx_fee_structures_program; Type: INDEX; Schema: public; Owner: -
+-- Name: idx_fee_structures_semester; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX idx_fee_structures_program ON public.fee_structures USING btree (program_id);
+CREATE INDEX idx_fee_structures_semester ON public.fee_structures USING btree (semester);
--
@@ -5972,27 +6108,104 @@
--
CREATE INDEX idx_hostel_rooms_status ON public.hostel_rooms USING btree (status);
+
+
+--
+-- Name: idx_integration_data_types_source; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_integration_data_types_source ON public.integration_data_types USING btree (source_id);
+
+
+--
+-- Name: idx_integration_entity_matchers_source; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_integration_entity_matchers_source ON public.integration_entity_matchers USING btree (source_id);
+
+
+--
+-- Name: idx_integration_field_mappings_data_type; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_integration_field_mappings_data_type ON public.integration_field_mappings USING btree (data_type_id);
+
+
+--
+-- Name: idx_integration_processing_results_status; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_integration_processing_results_status ON public.integration_processing_results USING btree (status);
+
+
+--
+-- Name: idx_integration_processing_results_target; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_integration_processing_results_target ON public.integration_processing_results USING btree (target_entity, target_id);
+
+
+--
+-- Name: idx_integration_processing_results_webhook; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_integration_processing_results_webhook ON public.integration_processing_results USING btree (webhook_id);
+
+
+--
+-- Name: idx_integration_rate_limits_lookup; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_integration_rate_limits_lookup ON public.integration_rate_limits USING btree (source_id, window_start);
+
+
+--
+-- Name: idx_integration_review_queue_source; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_integration_review_queue_source ON public.integration_review_queue USING btree (source_id);
--
-- Name: idx_integration_review_queue_status; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX idx_integration_review_queue_status ON public.integration_review_queue USING btree (status);
+CREATE INDEX idx_integration_review_queue_status ON public.integration_review_queue USING btree (status, created_at);
--
--- Name: idx_integration_webhooks_received; Type: INDEX; Schema: public; Owner: -
+-- Name: idx_integration_sources_active; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX idx_integration_webhooks_received ON public.integration_webhooks USING btree (received_at DESC);
+CREATE INDEX idx_integration_sources_active ON public.integration_sources USING btree (is_active) WHERE (is_active = true);
--
+-- Name: idx_integration_sources_code; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_integration_sources_code ON public.integration_sources USING btree (code);
+
+
+--
+-- Name: idx_integration_webhooks_request_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_integration_webhooks_request_id ON public.integration_webhooks USING btree (source_id, request_id) WHERE (request_id IS NOT NULL);
+
+
+--
+-- Name: idx_integration_webhooks_retry; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_integration_webhooks_retry ON public.integration_webhooks USING btree (status, next_retry_at) WHERE (((status)::text = ANY ((ARRAY['failed'::character varying, 'partial'::character varying])::text[])) AND (retry_count < max_retries));
+
+
+--
-- Name: idx_integration_webhooks_source; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX idx_integration_webhooks_source ON public.integration_webhooks USING btree (source_id);
+CREATE INDEX idx_integration_webhooks_source ON public.integration_webhooks USING btree (source_id, received_at DESC);
--
@@ -6273,15 +6486,8 @@
--
CREATE INDEX idx_role_capabilities_role ON public.role_capabilities USING btree (role_id);
-
-
---
--- Name: idx_roles_dashboard_type; Type: INDEX; Schema: public; Owner: -
---
-CREATE INDEX idx_roles_dashboard_type ON public.roles USING btree (dashboard_type);
-
--
-- Name: idx_room_allocations_room; Type: INDEX; Schema: public; Owner: -
--
@@ -6311,6 +6517,20 @@
--
+-- Name: idx_semesters_academic_year; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_semesters_academic_year ON public.semesters USING btree (academic_year_id);
+
+
+--
+-- Name: idx_semesters_is_current; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_semesters_is_current ON public.semesters USING btree (is_current) WHERE (is_current = true);
+
+
+--
-- Name: idx_sessions_token; Type: INDEX; Schema: public; Owner: -
--
@@ -6742,6 +6962,13 @@
--
CREATE INDEX idx_workflow_stages_workflow ON public.workflow_stages USING btree (workflow_id);
+
+
+--
+-- Name: payment_transactions_receipt_number_unique; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX payment_transactions_receipt_number_unique ON public.payment_transactions USING btree (receipt_number) WHERE ((receipt_number IS NOT NULL) AND ((receipt_number)::text <> ''::text));
--
@@ -6836,6 +7063,13 @@
--
+-- Name: integration_webhooks trg_update_integration_source_stats; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER trg_update_integration_source_stats AFTER INSERT OR UPDATE OF status ON public.integration_webhooks FOR EACH ROW EXECUTE FUNCTION public.update_integration_source_stats();
+
+
+--
-- Name: workflow_definitions trg_workflow_definitions_updated; Type: TRIGGER; Schema: public; Owner: -
--
@@ -7614,11 +7848,19 @@
--
--- Name: fee_structures fee_structures_fee_category_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: fee_structures fee_structures_created_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.fee_structures
- ADD CONSTRAINT fee_structures_fee_category_id_fkey FOREIGN KEY (fee_category_id) REFERENCES public.fee_categories(id);
+ ADD CONSTRAINT fee_structures_created_by_fkey FOREIGN KEY (created_by) REFERENCES public.users(id);
+
+
+--
+-- Name: fee_structures fee_structures_fee_type_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.fee_structures
+ ADD CONSTRAINT fee_structures_fee_type_id_fkey FOREIGN KEY (fee_type_id) REFERENCES public.fee_types(id) ON DELETE CASCADE;
--
@@ -7626,7 +7868,7 @@
--
ALTER TABLE ONLY public.fee_structures
- ADD CONSTRAINT fee_structures_program_id_fkey FOREIGN KEY (program_id) REFERENCES public.programs(id);
+ ADD CONSTRAINT fee_structures_program_id_fkey FOREIGN KEY (program_id) REFERENCES public.programs(id) ON DELETE CASCADE;
--
@@ -7714,10 +7956,18 @@
--
ALTER TABLE ONLY public.integration_review_queue
- ADD CONSTRAINT integration_review_queue_processing_result_id_fkey FOREIGN KEY (processing_result_id) REFERENCES public.integration_processing_results(id);
+ ADD CONSTRAINT integration_review_queue_processing_result_id_fkey FOREIGN KEY (processing_result_id) REFERENCES public.integration_processing_results(id) ON DELETE CASCADE;
--
+-- Name: integration_review_queue integration_review_queue_resolved_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.integration_review_queue
+ ADD CONSTRAINT integration_review_queue_resolved_by_fkey FOREIGN KEY (resolved_by) REFERENCES public.users(id);
+
+
+--
-- Name: integration_review_queue integration_review_queue_source_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -7731,6 +7981,14 @@
ALTER TABLE ONLY public.integration_review_queue
ADD CONSTRAINT integration_review_queue_webhook_id_fkey FOREIGN KEY (webhook_id) REFERENCES public.integration_webhooks(id) ON DELETE CASCADE;
+
+
+--
+-- Name: integration_sources integration_sources_created_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.integration_sources
+ ADD CONSTRAINT integration_sources_created_by_fkey FOREIGN KEY (created_by) REFERENCES public.users(id);
--
@@ -8093,28 +8351,12 @@
ADD CONSTRAINT payments_invoice_id_fkey FOREIGN KEY (invoice_id) REFERENCES public.invoices(id);
---
--- Name: payments payments_received_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-
-ALTER TABLE ONLY public.payments
- ADD CONSTRAINT payments_received_by_fkey FOREIGN KEY (received_by) REFERENCES public.users(id);
-
-
---
-- Name: payments payments_recorded_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.payments
ADD CONSTRAINT payments_recorded_by_fkey FOREIGN KEY (recorded_by) REFERENCES public.users(id);
-
-
---
--- Name: payments payments_student_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
---
-
-ALTER TABLE ONLY public.payments
- ADD CONSTRAINT payments_student_id_fkey FOREIGN KEY (student_id) REFERENCES public.students(id);
--
@@ -8881,5 +9123,5 @@
-- PostgreSQL database dump complete
--
-\unrestrict 56P1AFLmECQP4C14SkiPUrItNfXjy5EQcIa9KjiDIyAuWQdvsFS9t7v15EdHUoA
+\unrestrict IUFQfJQrjUYMofJwdfyWaeH1zGTKdHYUIj80kUoecb3w9BionIrVhi5plZSbss2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TIMS Schema Diff Report</title>
<style>
:root {
--teal: #319795;
--teal-dark: #2C7A7B;
--green: #38A169;
--red: #E53E3E;
--yellow: #D69E2E;
--gray-50: #F7FAFC;
--gray-100: #EDF2F7;
--gray-200: #E2E8F0;
--gray-600: #718096;
--gray-800: #2D3748;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: var(--gray-50);
color: var(--gray-800);
line-height: 1.6;
}
.container { max-width: 1200px; margin: 0 auto; padding: 2rem; }
header {
background: linear-gradient(135deg, var(--teal) 0%, var(--teal-dark) 100%);
color: white;
padding: 2rem;
border-radius: 12px;
margin-bottom: 2rem;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
header h1 { font-size: 1.75rem; margin-bottom: 0.5rem; }
header p { opacity: 0.9; font-size: 0.9rem; }
.meta { display: flex; gap: 2rem; margin-top: 1rem; font-size: 0.85rem; opacity: 0.8; }
.status-badge {
display: inline-block;
padding: 0.5rem 1rem;
border-radius: 9999px;
font-weight: 600;
font-size: 0.9rem;
margin-top: 1rem;
}
.status-badge.success { background: var(--green); }
.status-badge.warning { background: var(--yellow); color: var(--gray-800); }
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin-bottom: 2rem;
}
.stat-card {
background: white;
padding: 1.5rem;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
text-align: center;
}
.stat-card .number { font-size: 2rem; font-weight: 700; color: var(--teal); }
.stat-card .label { color: var(--gray-600); font-size: 0.85rem; }
.stat-card.danger .number { color: var(--red); }
.stat-card.warning .number { color: var(--yellow); }
.section {
background: white;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
margin-bottom: 1.5rem;
overflow: hidden;
}
.section-header {
background: var(--gray-100);
padding: 1rem 1.5rem;
font-weight: 600;
border-bottom: 1px solid var(--gray-200);
}
.section-content { padding: 1.5rem; }
.table-list { list-style: none; }
.table-list li {
padding: 0.75rem 1rem;
border-bottom: 1px solid var(--gray-100);
display: flex;
align-items: center;
gap: 0.75rem;
}
.table-list li:last-child { border-bottom: none; }
.table-list .icon { font-size: 1.25rem; }
.table-list .name { font-family: 'Monaco', 'Menlo', monospace; font-size: 0.9rem; }
.missing { color: var(--red); }
.extra { color: var(--yellow); }
.synced { color: var(--green); }
.diff-view {
background: var(--gray-800);
color: #E2E8F0;
padding: 1rem;
border-radius: 6px;
overflow-x: auto;
font-family: 'Monaco', 'Menlo', monospace;
font-size: 0.8rem;
max-height: 400px;
overflow-y: auto;
}
.diff-view .add { color: #68D391; }
.diff-view .remove { color: #FC8181; }
.diff-view .context { color: #A0AEC0; }
footer {
text-align: center;
padding: 2rem;
color: var(--gray-600);
font-size: 0.85rem;
}
.actions {
display: flex;
gap: 1rem;
margin-top: 1.5rem;
}
.btn {
padding: 0.75rem 1.5rem;
border-radius: 6px;
border: none;
font-weight: 500;
cursor: pointer;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.btn-primary { background: var(--teal); color: white; }
.btn-secondary { background: var(--gray-200); color: var(--gray-800); }
@media print {
.actions { display: none; }
body { background: white; }
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>πŸ—„οΈ TIMS Schema Diff Report</h1>
<p>Database schema comparison across environments</p>
<div class="meta">
<span>πŸ“Š Source: <strong>dev</strong></span>
<span>🎯 Target: <strong>staging</strong></span>
<span>πŸ“… Generated: <strong>Tue Jan 20 12:27:20 EAT 2026</strong></span>
</div>
<span class="status-badge success">βœ“ Schemas In Sync</span>
</header>
<div class="stats-grid">
<div class="stat-card">
<div class="number">125</div>
<div class="label">Tables in dev</div>
</div>
<div class="stat-card">
<div class="number">125</div>
<div class="label">Tables in staging</div>
</div>
<div class="stat-card ">
<div class="number">0</div>
<div class="label">Missing in staging</div>
</div>
<div class="stat-card ">
<div class="number">0</div>
<div class="label">Extra in staging</div>
</div>
</div>
<div class="section">
<div class="section-header">πŸ“‹ All Tables Comparison</div>
<div class="section-content">
<ul class="table-list">
<li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.academic_years</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.admission_batch_logs</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.admission_batches</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.admission_letters</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.admission_statistics</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.admission_windows</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.api_configurations</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.api_logs</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_accounts</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_choice_points</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_documents</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_exam_sittings</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_logs</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_next_of_kin</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_parents</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_payments</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_qualifications</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_referees</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_resubmissions</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_status_history</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_tokens</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_transfers</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_upgraders</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicant_work_experience</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.applicants</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.application_categories</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.audit_logs</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.campuses</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.capabilities</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.capability_audit</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.control_number_config</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.course_offerings</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.course_prerequisites</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.course_registrations</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.courses</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.departments</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.educational_backgrounds</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.email_logs</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.email_templates</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.enrollments</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.exam_sitting_subjects</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.exams</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.external_api_configs</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.external_id_mappings</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.faculties</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.features</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.fee_categories</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.fee_sponsors</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.fee_structure_limits</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.fee_structures</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.fee_types</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.gepg_bills</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.grading_schemes</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.hostel_rooms</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.hostels</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.integration_data_types</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.integration_entity_matchers</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.integration_field_mappings</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.integration_processing_results</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.integration_rate_limits</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.integration_review_queue</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.integration_sources</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.integration_webhooks</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.invoice_audit</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.invoice_items</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.invoices</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.loan_beneficiaries</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.loan_disbursements</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.loan_import_batches</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.modules</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.nacte_avn_verifications</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.nacte_programmes</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.nacte_submissions</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.notification_logs</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.otp_verifications</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.payment_audit</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.payment_audit_log</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.payment_control_numbers</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.payment_providers</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.payment_receipts</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.payment_reconciliations</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.payment_transactions</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.payment_webhook_logs</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.payments</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.permissions</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.points_configuration</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.program_choices</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.programs</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.qualification_subjects</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.result_changes</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.result_compilation_queue</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.result_upload_files</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.results</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.role_capabilities</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.role_permissions</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.roles</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.roles_backup</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.room_allocations</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.room_applications</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.rooms</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.semester_number_mapping</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.semesters</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.sessions</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.sms_notifications</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.sponsor_invoice_items</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.sponsor_invoices</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.sponsored_students</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.student_enrollments</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.student_results</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.students</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.tcu_submissions</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.time_slots</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.timetable_entries</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.user_roles</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.users</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.workflow_approvals</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.workflow_config_audit</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.workflow_definitions</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.workflow_execution_audit</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.workflow_instances</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.workflow_notifications</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.workflow_stage_actions</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.workflow_stage_requirements</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.workflow_stage_transitions</span></li><li><span class="icon synced">βœ“</span><span class="name">CREATE TABLE public.workflow_stages</span></li>
</ul>
</div>
</div>
<div class="actions">
<button class="btn btn-primary" onclick="window.print()">πŸ–¨οΈ Print Report</button>
<a href="diff_dev_vs_staging_20260120_122714.txt" class="btn btn-secondary">πŸ“„ View Raw Diff</a>
</div>
</div>
<footer>
<p>TIMS - Tandabui Institute Management System</p>
<p>Generated by schema-diff.sh</p>
</footer>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment