-- A learning path is deliberately only a curated, ordered collection of -- existing courses. Lessons remain owned by their courses, so a course edit -- is reflected everywhere that course appears. create table learning_paths ( id uuid primary key default gen_random_uuid(), title text not null check (char_length(trim(title)) between 1 and 160), description text not null default '', cover_image_url text, cover_image_zoom real not null default 1 check (cover_image_zoom between 1 and 2.5), cover_image_position_x real not null default 50 check (cover_image_position_x between 0 and 100), cover_image_position_y real not null default 50 check (cover_image_position_y between 0 and 100), status course_status not null default 'draft', published_at timestamptz, created_at timestamptz not null default now(), updated_at timestamptz not null default now(), constraint learning_paths_published_at_check check ( (status = 'published' and published_at is not null) or status <> 'published' ) ); create table learning_path_courses ( learning_path_id uuid not null references learning_paths(id) on delete cascade, course_id uuid not null references courses(id) on delete restrict, position integer not null check (position > 0), primary key (learning_path_id, course_id), unique (learning_path_id, position) ); create index learning_paths_published_index on learning_paths (published_at desc) where status = 'published'; create index learning_path_courses_position_index on learning_path_courses (learning_path_id, position); create trigger learning_paths_set_updated_at before update on learning_paths for each row execute function set_updated_at();