-- ============================================================ -- COMPLETE SCHEMA MIGRATION FOR COOLIFY -- Run this first to update the database schema -- ============================================================ -- Create ENUMs for AI Kurzy (if not exist) DO $$ BEGIN CREATE TYPE "forma_kurzu_enum" AS ENUM('prezencne', 'online', 'hybridne'); EXCEPTION WHEN duplicate_object THEN NULL; END $$; DO $$ BEGIN CREATE TYPE "stav_registracie_enum" AS ENUM('potencialny', 'registrovany', 'potvrdeny', 'absolvoval', 'zruseny'); EXCEPTION WHEN duplicate_object THEN NULL; END $$; DO $$ BEGIN CREATE TYPE "typ_prilohy_enum" AS ENUM('certifikat', 'faktura', 'prihlaska', 'doklad_o_platbe', 'ine'); EXCEPTION WHEN duplicate_object THEN NULL; END $$; -- ============================================================ -- NEW TABLES -- ============================================================ -- Chat Groups CREATE TABLE IF NOT EXISTS "chat_groups" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "name" text NOT NULL, "created_by_id" uuid REFERENCES "users"("id") ON DELETE SET NULL, "created_at" timestamp DEFAULT now() NOT NULL, "updated_at" timestamp DEFAULT now() NOT NULL ); -- Chat Group Members CREATE TABLE IF NOT EXISTS "chat_group_members" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "group_id" uuid NOT NULL REFERENCES "chat_groups"("id") ON DELETE CASCADE, "user_id" uuid NOT NULL REFERENCES "users"("id") ON DELETE CASCADE, "joined_at" timestamp DEFAULT now() NOT NULL, "last_read_at" timestamp DEFAULT now() NOT NULL, CONSTRAINT "chat_group_member_unique" UNIQUE("group_id","user_id") ); -- Group Messages CREATE TABLE IF NOT EXISTS "group_messages" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "group_id" uuid NOT NULL REFERENCES "chat_groups"("id") ON DELETE CASCADE, "sender_id" uuid REFERENCES "users"("id") ON DELETE SET NULL, "content" text NOT NULL, "created_at" timestamp DEFAULT now() NOT NULL ); -- Push Subscriptions CREATE TABLE IF NOT EXISTS "push_subscriptions" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "user_id" uuid NOT NULL REFERENCES "users"("id") ON DELETE CASCADE, "endpoint" text NOT NULL, "p256dh" text NOT NULL, "auth" text NOT NULL, "created_at" timestamp DEFAULT now() NOT NULL, CONSTRAINT "push_subscription_endpoint_unique" UNIQUE("user_id","endpoint") ); -- Email Signatures CREATE TABLE IF NOT EXISTS "email_signatures" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "user_id" uuid NOT NULL UNIQUE REFERENCES "users"("id") ON DELETE CASCADE, "full_name" text, "position" text, "phone" text, "email" text, "company_name" text, "website" text, "is_enabled" boolean DEFAULT true NOT NULL, "created_at" timestamp DEFAULT now() NOT NULL, "updated_at" timestamp DEFAULT now() NOT NULL ); -- Services CREATE TABLE IF NOT EXISTS "services" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "name" text NOT NULL, "price" text NOT NULL, "description" text, "created_by" uuid REFERENCES "users"("id") ON DELETE SET NULL, "created_at" timestamp DEFAULT now() NOT NULL, "updated_at" timestamp DEFAULT now() NOT NULL ); -- Service Folders CREATE TABLE IF NOT EXISTS "service_folders" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "name" text NOT NULL, "created_by" uuid REFERENCES "users"("id") ON DELETE SET NULL, "created_at" timestamp DEFAULT now() NOT NULL, "updated_at" timestamp DEFAULT now() NOT NULL ); -- Service Documents CREATE TABLE IF NOT EXISTS "service_documents" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "folder_id" uuid NOT NULL REFERENCES "service_folders"("id") ON DELETE CASCADE, "file_name" text NOT NULL, "original_name" text NOT NULL, "file_path" text NOT NULL, "file_type" text NOT NULL, "file_size" integer NOT NULL, "description" text, "uploaded_by" uuid REFERENCES "users"("id") ON DELETE SET NULL, "uploaded_at" timestamp DEFAULT now() NOT NULL, "created_at" timestamp DEFAULT now() NOT NULL ); -- Company Documents CREATE TABLE IF NOT EXISTS "company_documents" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "company_id" uuid NOT NULL REFERENCES "companies"("id") ON DELETE CASCADE, "file_name" text NOT NULL, "original_name" text NOT NULL, "file_path" text NOT NULL, "file_type" text NOT NULL, "file_size" integer NOT NULL, "description" text, "uploaded_by" uuid REFERENCES "users"("id") ON DELETE SET NULL, "uploaded_at" timestamp DEFAULT now() NOT NULL, "created_at" timestamp DEFAULT now() NOT NULL ); -- Project Documents CREATE TABLE IF NOT EXISTS "project_documents" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "project_id" uuid NOT NULL REFERENCES "projects"("id") ON DELETE CASCADE, "file_name" text NOT NULL, "original_name" text NOT NULL, "file_path" text NOT NULL, "file_type" text NOT NULL, "file_size" integer NOT NULL, "description" text, "uploaded_by" uuid REFERENCES "users"("id") ON DELETE SET NULL, "uploaded_at" timestamp DEFAULT now() NOT NULL, "created_at" timestamp DEFAULT now() NOT NULL ); -- ============================================================ -- AI KURZY TABLES -- ============================================================ -- Kurzy (Courses) - without dates (dates are per registration) CREATE TABLE IF NOT EXISTS "kurzy" ( "id" serial PRIMARY KEY NOT NULL, "nazov" varchar(255) NOT NULL, "typ_kurzu" varchar(100) NOT NULL, "popis" text, "cena" numeric(10, 2) NOT NULL, "max_kapacita" integer, "aktivny" boolean DEFAULT true NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL ); -- Ucastnici (Participants) CREATE TABLE IF NOT EXISTS "ucastnici" ( "id" serial PRIMARY KEY NOT NULL, "titul" varchar(50), "meno" varchar(100) NOT NULL, "priezvisko" varchar(100) NOT NULL, "email" varchar(255) NOT NULL UNIQUE, "telefon" varchar(50), "firma" varchar(255), "mesto" varchar(100), "ulica" varchar(255), "psc" varchar(10), "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL ); CREATE UNIQUE INDEX IF NOT EXISTS "ucastnici_email_idx" ON "ucastnici" USING btree ("email"); -- Registracie (Registrations) - with dates CREATE TABLE IF NOT EXISTS "registracie" ( "id" serial PRIMARY KEY NOT NULL, "kurz_id" integer NOT NULL REFERENCES "kurzy"("id") ON DELETE CASCADE, "ucastnik_id" integer NOT NULL REFERENCES "ucastnici"("id") ON DELETE CASCADE, "datum_od" date, "datum_do" date, "forma_kurzu" "forma_kurzu_enum" DEFAULT 'prezencne' NOT NULL, "pocet_ucastnikov" integer DEFAULT 1 NOT NULL, "faktura_cislo" varchar(100), "faktura_vystavena" boolean DEFAULT false NOT NULL, "zaplatene" boolean DEFAULT false NOT NULL, "stav" "stav_registracie_enum" DEFAULT 'registrovany' NOT NULL, "poznamka" text, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL ); CREATE UNIQUE INDEX IF NOT EXISTS "registracie_kurz_ucastnik_idx" ON "registracie" USING btree ("kurz_id","ucastnik_id"); -- Prilohy (Attachments) CREATE TABLE IF NOT EXISTS "prilohy" ( "id" serial PRIMARY KEY NOT NULL, "registracia_id" integer NOT NULL REFERENCES "registracie"("id") ON DELETE CASCADE, "nazov_suboru" varchar(255) NOT NULL, "typ_prilohy" "typ_prilohy_enum" DEFAULT 'ine' NOT NULL, "cesta_k_suboru" varchar(500) NOT NULL, "mime_type" varchar(100), "velkost_suboru" bigint, "popis" text, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL ); -- ============================================================ -- ALTER EXISTING TABLES (add new columns) -- ============================================================ -- Add completed_notified_at to todos (if not exists) DO $$ BEGIN ALTER TABLE "todos" ADD COLUMN "completed_notified_at" timestamp; EXCEPTION WHEN duplicate_column THEN NULL; END $$; -- Make phone nullable in personal_contacts (if needed) ALTER TABLE "personal_contacts" ALTER COLUMN "phone" DROP NOT NULL; -- ============================================================ -- DONE -- ============================================================ SELECT 'Schema migration completed successfully!' as status;