-- Add a human‐readable, sequential task number that is shown in the UI -- Format: YYYY-MM-##### (resetting each month). -- 1. Add the column (nullable for now so we can backfill) ALTER TABLE tasks ADD COLUMN task_number text; -- 2. Backfill existing rows using created_at as the timestamp basis. DO $$ DECLARE r RECORD; prefix text; cnt int; BEGIN FOR r IN SELECT id, created_at FROM tasks WHERE task_number IS NULL ORDER BY created_at LOOP prefix := to_char(r.created_at::timestamp, 'YYYY-MM-'); cnt := (SELECT count(*) FROM tasks t WHERE to_char(t.created_at::timestamp, 'YYYY-MM-') = prefix AND t.created_at <= r.created_at); UPDATE tasks SET task_number = prefix || lpad(cnt::text, 5, '0') WHERE id = r.id; END LOOP; END; $$ LANGUAGE plpgsql; -- 3. Create trigger function to generate numbers on new inserts CREATE OR REPLACE FUNCTION tasks_set_task_number() RETURNS trigger AS $$ DECLARE prefix text; seq int; BEGIN -- if caller already provided one, do not overwrite IF NEW.task_number IS NOT NULL THEN RETURN NEW; END IF; prefix := to_char(now(), 'YYYY-MM-'); SELECT COALESCE(MAX((substring(task_number FROM 8))::int), 0) + 1 INTO seq FROM tasks WHERE task_number LIKE prefix || '%'; NEW.task_number := prefix || lpad(seq::text, 5, '0'); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER tasks_set_task_number_before_insert BEFORE INSERT ON tasks FOR EACH ROW EXECUTE FUNCTION tasks_set_task_number(); -- 4. Enforce not-null and uniqueness now that every row has a value ALTER TABLE tasks ALTER COLUMN task_number SET NOT NULL; CREATE UNIQUE INDEX IF NOT EXISTS idx_tasks_task_number ON tasks (task_number);