= Advanced Database Development == Data constraints requirements: Enrollment-Subscription consistency + single enrollment per course === Data requirements description Course enrollments must remain consistent with the subscription and participation rules of the platform: # A user must have an ACTIVE subscription in order to enroll in a course. # A user cannot enroll in the same course more than once. # enrollment status changes must follow a valid transition model. # Each enrollment must reference a valid user and a valid course. **This ensures that only users with valid subscriptions can access course content, prevents duplicate enrollments, and maintains consistency between subscription and course participation data. It also improves data integrity and reduces the possibility of invalid or inconsistent records in the system.** === Implementation {{{Triggers}}} {{{ -- status transition helper CREATE OR REPLACE FUNCTION olpms_is_valid_enrollment_transition(p_old text, p_new text) RETURNS boolean LANGUAGE sql AS $$ SELECT CASE WHEN p_old IS NULL AND p_new IN ('IN_PROGRESS', 'COMPLETED', 'CANCELLED') THEN true WHEN p_old = p_new THEN true WHEN p_old = 'IN_PROGRESS' AND p_new IN ('COMPLETED', 'CANCELLED') THEN true WHEN p_old = 'COMPLETED' AND p_new = 'COMPLETED' THEN true WHEN p_old = 'CANCELLED' AND p_new = 'CANCELLED' THEN true ELSE false END; $$; -- main enrollment consistency trigger function CREATE OR REPLACE FUNCTION olpms_trg_enrollment_enforce() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE v_active_subscription_count integer; BEGIN -- user must have an active subscription when inserting enrollment IF TG_OP = 'INSERT' THEN SELECT COUNT(*) INTO v_active_subscription_count FROM user_subscription us WHERE us.user_id = NEW.user_id AND us.status = 'ACTIVE' AND CURRENT_DATE BETWEEN us.start_date AND us.end_date; IF v_active_subscription_count = 0 THEN RAISE EXCEPTION 'User % does not have an active subscription', NEW.user_id; END IF; END IF; -- prevent duplicate enrollment for the same user and the same course IF EXISTS ( SELECT 1 FROM enrollment e WHERE e.user_id = NEW.user_id AND e.course_id = NEW.course_id AND (TG_OP <> 'UPDATE' OR e.enrollment_id <> NEW.enrollment_id) ) THEN RAISE EXCEPTION 'User % is already enrolled in course %', NEW.user_id, NEW.course_id; END IF; -- validate completion_status transition on UPDATE IF TG_OP = 'UPDATE' THEN IF NOT olpms_is_valid_enrollment_transition(OLD.completion_status, NEW.completion_status) THEN RAISE EXCEPTION 'Invalid enrollment status transition: % -> %', OLD.completion_status, NEW.completion_status; END IF; END IF; RETURN NEW; END; $$; DROP TRIGGER IF EXISTS trg_enrollment_enforce ON enrollment; CREATE TRIGGER trg_enrollment_enforce BEFORE INSERT OR UPDATE ON enrollment FOR EACH ROW EXECUTE FUNCTION olpms_trg_enrollment_enforce(); }}} {{{Stored procedures / functions}}} {{{ CREATE OR REPLACE FUNCTION olpms_is_valid_enrollment_transition(p_old text, p_new text) RETURNS boolean LANGUAGE sql AS $$ SELECT CASE WHEN p_old IS NULL AND p_new IN ('IN_PROGRESS', 'COMPLETED', 'CANCELLED') THEN true WHEN p_old = p_new THEN true WHEN p_old = 'IN_PROGRESS' AND p_new IN ('COMPLETED', 'CANCELLED') THEN true WHEN p_old = 'COMPLETED' AND p_new = 'COMPLETED' THEN true WHEN p_old = 'CANCELLED' AND p_new = 'CANCELLED' THEN true ELSE false END; $$; CREATE OR REPLACE FUNCTION olpms_trg_enrollment_enforce() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE v_active_subscription_count integer; BEGIN IF TG_OP = 'INSERT' THEN SELECT COUNT(*) INTO v_active_subscription_count FROM user_subscription us WHERE us.user_id = NEW.user_id AND us.status = 'ACTIVE' AND CURRENT_DATE BETWEEN us.start_date AND us.end_date; IF v_active_subscription_count = 0 THEN RAISE EXCEPTION 'User % does not have an active subscription', NEW.user_id; END IF; END IF; IF EXISTS ( SELECT 1 FROM enrollment e WHERE e.user_id = NEW.user_id AND e.course_id = NEW.course_id AND (TG_OP <> 'UPDATE' OR e.enrollment_id <> NEW.enrollment_id) ) THEN RAISE EXCEPTION 'User % is already enrolled in course %', NEW.user_id, NEW.course_id; END IF; IF TG_OP = 'UPDATE' THEN IF NOT olpms_is_valid_enrollment_transition(OLD.completion_status, NEW.completion_status) THEN RAISE EXCEPTION 'Invalid enrollment status transition: % -> %', OLD.completion_status, NEW.completion_status; END IF; END IF; RETURN NEW; END; $$; }}} {{{Views}}} {{{ CREATE OR REPLACE VIEW v_enrollments_enriched AS SELECT e.enrollment_id, e.user_id, ue.first_name, ue.last_name, ue.email, e.course_id, c.name AS course_name, e.enroll_date, e.completion_status, e.progress_percentage, us.subscription_id, us.status AS subscription_status, us.start_date AS subscription_start_date, us.end_date AS subscription_end_date FROM enrollment e JOIN users u ON u.id = e.user_id JOIN user_entity ue ON ue.id = u.id JOIN course c ON c.course_id = e.course_id LEFT JOIN user_subscription us ON us.user_id = e.user_id AND us.status = 'ACTIVE' AND CURRENT_DATE BETWEEN us.start_date AND us.end_date; }}} == Data constraints requirements: Certificate generation consistency + one certificate per completed enrollment === Data requirements description Certificates must obey completion and consistency rules: * A certificate can only be issued for an enrollment whose completion status is COMPLETED. * The same enrollment cannot have more than one certificate. * A certificate must always refer to a valid enrollment. * Issuing a certificate before course completion is blocked. **This ensures that certificates are only issued for successfully completed courses, preventing invalid or premature certification. It also maintains the integrity and reliability of the certification system within the platform.** === Implementation {{{Triggers}}} {{{ CREATE OR REPLACE FUNCTION olpms_trg_certificate_enforce() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE v_completion_status VARCHAR(30); BEGIN -- find the status of the referenced enrollment SELECT e.completion_status INTO v_completion_status FROM enrollment e WHERE e.enrollment_id = NEW.enrollment_id; IF v_completion_status IS NULL THEN RAISE EXCEPTION 'Enrollment % does not exist or has no completion status', NEW.enrollment_id; END IF; -- certificate can only be issued for completed enrollments IF v_completion_status <> 'COMPLETED' THEN RAISE EXCEPTION 'Certificate cannot be issued because enrollment % is not COMPLETED', NEW.enrollment_id; END IF; -- prevent more than one certificate for the same enrollment IF EXISTS ( SELECT 1 FROM certificate c WHERE c.enrollment_id = NEW.enrollment_id AND (TG_OP <> 'UPDATE' OR c.certificate_id <> NEW.certificate_id) ) THEN RAISE EXCEPTION 'Enrollment % already has a certificate', NEW.enrollment_id; END IF; RETURN NEW; END; $$; DROP TRIGGER IF EXISTS trg_certificate_enforce ON certificate; CREATE TRIGGER trg_certificate_enforce BEFORE INSERT OR UPDATE ON certificate FOR EACH ROW EXECUTE FUNCTION olpms_trg_certificate_enforce(); }}} {{{Views}}} {{{ CREATE OR REPLACE VIEW v_certificates_enriched AS SELECT c.certificate_id, c.enrollment_id, c.issue_date, c.certificate_code, c.status AS certificate_status, e.user_id, ue.first_name, ue.last_name, ue.email, e.course_id, cr.name AS course_name, e.enroll_date, e.completion_status, e.progress_percentage FROM certificate c JOIN enrollment e ON e.enrollment_id = c.enrollment_id JOIN users u ON u.id = e.user_id JOIN user_entity ue ON ue.id = u.id JOIN course cr ON cr.course_id = e.course_id; }}} == Data constraints requirements: Quiz attempt validity + score consistency === Data requirements description Quiz attempts must obey assessment consistency rules: * A quiz attempt must always refer to a valid user and a valid quiz. * The achieved score must be between 0 and the quiz total_points. * A user should only attempt quizzes that belong to lessons from courses in which the user is enrolled. * Invalid quiz attempts are blocked **This ensures that quiz attempts are valid and consistent with course participation, preventing unauthorized access to assessments. It also guarantees accurate scoring and improves the reliability of evaluation results within the platform.** === Implementation {{{Triggers}}} {{{ CREATE OR REPLACE FUNCTION olpms_trg_quiz_attempt_enforce() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE v_total_points INT; BEGIN IF NEW.user_id IS NULL THEN RAISE EXCEPTION 'Quiz attempt must reference a valid user'; END IF; IF NEW.quiz_id IS NULL THEN RAISE EXCEPTION 'Quiz attempt must reference a valid quiz'; END IF; SELECT q.total_points INTO v_total_points FROM quiz q WHERE q.quiz_id = NEW.quiz_id; IF v_total_points IS NULL THEN RAISE EXCEPTION 'Quiz % does not exist', NEW.quiz_id; END IF; IF NEW.score IS NULL THEN RAISE EXCEPTION 'Quiz attempt score must not be NULL'; END IF; IF NEW.score < 0 OR NEW.score > v_total_points THEN RAISE EXCEPTION 'Invalid score % for quiz %, allowed range is 0 to %', NEW.score, NEW.quiz_id, v_total_points; END IF; IF NOT EXISTS ( SELECT 1 FROM enrollment e JOIN module m ON m.course_id = e.course_id JOIN lesson l ON l.module_id = m.module_id JOIN quiz q ON q.lesson_id = l.lesson_id WHERE e.user_id = NEW.user_id AND q.quiz_id = NEW.quiz_id ) THEN RAISE EXCEPTION 'User % is not enrolled in the course associated with quiz %', NEW.user_id, NEW.quiz_id; END IF; RETURN NEW; END; $$; DROP TRIGGER IF EXISTS trg_quiz_attempt_enforce ON quiz_attempt; CREATE TRIGGER trg_quiz_attempt_enforce BEFORE INSERT OR UPDATE ON quiz_attempt FOR EACH ROW EXECUTE FUNCTION olpms_trg_quiz_attempt_enforce(); }}} {{{Views}}} {{{ CREATE OR REPLACE VIEW v_quiz_attempts_enriched AS SELECT qa.attempt_id, qa.attempt_date, qa.score, qa.user_id, ue.first_name, ue.last_name, ue.email, qa.quiz_id, q.total_points, q.passing_score, l.lesson_id, l.title AS lesson_title, m.module_id, m.title AS module_title, c.course_id, c.name AS course_name, CASE WHEN qa.score >= q.passing_score THEN 'PASSED' ELSE 'FAILED' END AS result_status FROM quiz_attempt qa JOIN users u ON u.id = qa.user_id JOIN user_entity ue ON ue.id = u.id JOIN quiz q ON q.quiz_id = qa.quiz_id JOIN lesson l ON l.lesson_id = q.lesson_id JOIN module m ON m.module_id = l.module_id JOIN course c ON c.course_id = m.course_id; }}} == Data constraints requirements: Support ticket status consistency + validated ticket attributes === Data requirements description Support tickets must remain consistent and well-structured throughout their lifecycle: * Ticket statuses must follow a controlled set of allowed values. * Ticket subjects must not be empty. * Ticket handling should support valid status transitions. * Ticket data should be easy to inspect together with the related user and administrator information. **This ensures that support tickets remain structured and consistent throughout their lifecycle, preventing invalid or incomplete data. It also improves data quality and enables easier monitoring, management, and reporting of support activities within the system.** === Implementation {{{Stored procedures / functions}}} {{{ CREATE OR REPLACE FUNCTION olpms_is_valid_ticket_transition(p_old text, p_new text) RETURNS boolean LANGUAGE sql AS $$ SELECT CASE WHEN p_old = p_new THEN true WHEN p_old = 'OPEN' AND p_new IN ('IN_PROGRESS', 'RESOLVED') THEN true WHEN p_old = 'IN_PROGRESS' AND p_new IN ('RESOLVED') THEN true WHEN p_old = 'RESOLVED' AND p_new = 'RESOLVED' THEN true ELSE false END; $$; }}} {{{Views}}} {{{ CREATE OR REPLACE VIEW v_support_tickets_enriched AS SELECT st.ticket_id, st.subject, st.description, st.status, st.created_at, st.user_id, u.first_name AS user_first_name, u.last_name AS user_last_name, u.email AS user_email, st.admin_id, a.first_name AS admin_first_name, a.last_name AS admin_last_name, a.email AS admin_email FROM support_ticket st JOIN user_entity u ON u.id = st.user_id JOIN user_entity a ON a.id = st.admin_id; }}} {{{Custom domains}}} {{{ CREATE DOMAIN ticket_status_domain AS VARCHAR(30) CHECK (VALUE IN ('OPEN', 'IN_PROGRESS', 'RESOLVED')); CREATE DOMAIN non_empty_subject_domain AS VARCHAR(200) CHECK (LENGTH(TRIM(VALUE)) > 0); }}}