feat: AI Kurzy module, project/service documents, services SQL import

- Add AI Kurzy module with courses, participants, and registrations management
- Add project documents and service documents features
- Add service folders for document organization
- Add SQL import queries for services from firmy.slovensko.ai
- Update todo notifications and group messaging
- Various API improvements and bug fixes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
richardtekula
2026-01-21 11:32:49 +01:00
parent d9f16ad0a6
commit 4089bb4be2
37 changed files with 7514 additions and 35 deletions

230
sql/01_schema_migration.sql Normal file
View File

@@ -0,0 +1,230 @@
-- ============================================================
-- 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;