diff --git a/.gitignore b/.gitignore index 55ee0ec..96f7a14 100644 --- a/.gitignore +++ b/.gitignore @@ -58,5 +58,6 @@ bin/ legalconsenthub/.api-client legalconsenthub/.api-client-middleware -### PostgreSQL persistent data ### +### TestContainers persistent data ### legalconsenthub-backend/postgres-data/ + diff --git a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/config/TestContainersConfig.kt b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/config/TestContainersConfig.kt index abade63..f0414db 100644 --- a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/config/TestContainersConfig.kt +++ b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/config/TestContainersConfig.kt @@ -24,6 +24,7 @@ class TestContainersConfig { .withPassword("legalconsenthub") .withExposedPorts(5432) .withCreateContainerCmdModifier { cmd -> + cmd.withName("legalconsenthub-backend") cmd.withHostConfig( HostConfig().apply { this.withPortBindings( diff --git a/legalconsenthub-backend/src/main/resources/legalconsenthub-db-backup.sql b/legalconsenthub-backend/src/main/resources/legalconsenthub-db-backup.sql new file mode 100644 index 0000000..65a086a --- /dev/null +++ b/legalconsenthub-backend/src/main/resources/legalconsenthub-db-backup.sql @@ -0,0 +1,450 @@ +-- +-- PostgreSQL database dump +-- +-- AG Invitation URL: http://192.168.178.114:3001/accept-invitation/CxVPVaWD0u0hztcwBbV4Pyub0tHIds5o + +-- Dumped from database version 17.5 +-- Dumped by pg_dump version 17.5 + +-- +-- Force drop all tables and constraints to ensure clean restoration +-- + +DROP TABLE IF EXISTS public.user_organization_roles CASCADE; +DROP TABLE IF EXISTS public.notification CASCADE; +DROP TABLE IF EXISTS public.form_element_section CASCADE; +DROP TABLE IF EXISTS public.form_element_options CASCADE; +DROP TABLE IF EXISTS public.form_element CASCADE; +DROP TABLE IF EXISTS public.comment CASCADE; +DROP TABLE IF EXISTS public.application_form CASCADE; +DROP TABLE IF EXISTS public.app_user CASCADE; +DROP TABLE IF EXISTS public.databasechangeloglock CASCADE; +DROP TABLE IF EXISTS public.databasechangelog CASCADE; + +-- Drop any remaining sequences, views, or other objects +DROP SEQUENCE IF EXISTS public.hibernate_sequence CASCADE; + +-- Reset database configuration +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET transaction_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- Name: app_user; Type: TABLE; Schema: public; Owner: legalconsenthub +-- + +CREATE TABLE public.app_user ( + created_at timestamp(6) without time zone NOT NULL, + modified_at timestamp(6) without time zone NOT NULL, + id character varying(255) NOT NULL, + name character varying(255) NOT NULL, + status character varying(255) NOT NULL, + CONSTRAINT app_user_status_check CHECK (((status)::text = ANY ((ARRAY['INVITED'::character varying, 'ACTIVE'::character varying, 'BLOCKED'::character varying, 'SUSPENDED_SUBSCRIPTION'::character varying])::text[]))) +); + + +ALTER TABLE public.app_user OWNER TO legalconsenthub; + +-- +-- Name: application_form; Type: TABLE; Schema: public; Owner: legalconsenthub +-- + +CREATE TABLE public.application_form ( + is_template boolean NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + modified_at timestamp(6) without time zone NOT NULL, + id uuid NOT NULL, + created_by_id character varying(255) NOT NULL, + last_modified_by_id character varying(255) NOT NULL, + name character varying(255) NOT NULL, + organization_id character varying(255), + status character varying(255) NOT NULL, + CONSTRAINT application_form_status_check CHECK (((status)::text = ANY ((ARRAY['DRAFT'::character varying, 'SUBMITTED'::character varying, 'APPROVED'::character varying, 'REJECTED'::character varying, 'SIGNED'::character varying])::text[]))) +); + + +ALTER TABLE public.application_form OWNER TO legalconsenthub; + +-- +-- Name: comment; Type: TABLE; Schema: public; Owner: legalconsenthub +-- + +CREATE TABLE public.comment ( + created_at timestamp(6) without time zone NOT NULL, + modified_at timestamp(6) without time zone NOT NULL, + application_form_id uuid NOT NULL, + form_element_id uuid NOT NULL, + id uuid NOT NULL, + created_by_id character varying(255) NOT NULL, + message character varying(255) NOT NULL +); + + +ALTER TABLE public.comment OWNER TO legalconsenthub; + +-- +-- Name: databasechangelog; Type: TABLE; Schema: public; Owner: legalconsenthub +-- + +CREATE TABLE public.databasechangelog ( + id character varying(255) NOT NULL, + author character varying(255) NOT NULL, + filename character varying(255) NOT NULL, + dateexecuted timestamp without time zone NOT NULL, + orderexecuted integer NOT NULL, + exectype character varying(10) NOT NULL, + md5sum character varying(35), + description character varying(255), + comments character varying(255), + tag character varying(255), + liquibase character varying(20), + contexts character varying(255), + labels character varying(255), + deployment_id character varying(10) +); + + +ALTER TABLE public.databasechangelog OWNER TO legalconsenthub; + +-- +-- Name: databasechangeloglock; Type: TABLE; Schema: public; Owner: legalconsenthub +-- + +CREATE TABLE public.databasechangeloglock ( + id integer NOT NULL, + locked boolean NOT NULL, + lockgranted timestamp without time zone, + lockedby character varying(255) +); + + +ALTER TABLE public.databasechangeloglock OWNER TO legalconsenthub; + +-- +-- Name: form_element; Type: TABLE; Schema: public; Owner: legalconsenthub +-- + +CREATE TABLE public.form_element ( + type smallint NOT NULL, + form_element_section_id uuid NOT NULL, + id uuid NOT NULL, + description character varying(255), + title character varying(255), + CONSTRAINT form_element_type_check CHECK (((type >= 0) AND (type <= 4))) +); + + +ALTER TABLE public.form_element OWNER TO legalconsenthub; + +-- +-- Name: form_element_options; Type: TABLE; Schema: public; Owner: legalconsenthub +-- + +CREATE TABLE public.form_element_options ( + employee_data_category smallint NOT NULL, + processing_purpose smallint NOT NULL, + form_element_id uuid NOT NULL, + label character varying(255) NOT NULL, + option_value character varying(255) NOT NULL, + CONSTRAINT form_element_options_employee_data_category_check CHECK (((employee_data_category >= 0) AND (employee_data_category <= 3))), + CONSTRAINT form_element_options_processing_purpose_check CHECK (((processing_purpose >= 0) AND (processing_purpose <= 3))) +); + + +ALTER TABLE public.form_element_options OWNER TO legalconsenthub; + +-- +-- Name: form_element_section; Type: TABLE; Schema: public; Owner: legalconsenthub +-- + +CREATE TABLE public.form_element_section ( + application_form_id uuid NOT NULL, + id uuid NOT NULL, + description character varying(255), + short_title character varying(255), + title character varying(255) NOT NULL +); + + +ALTER TABLE public.form_element_section OWNER TO legalconsenthub; + +-- +-- Name: notification; Type: TABLE; Schema: public; Owner: legalconsenthub +-- + +CREATE TABLE public.notification ( + is_read boolean NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + id uuid NOT NULL, + click_target character varying(255) NOT NULL, + message text NOT NULL, + organization_id character varying(255) NOT NULL, + recipient_id character varying(255), + role character varying(255) NOT NULL, + title character varying(255) NOT NULL, + type character varying(255) NOT NULL, + CONSTRAINT notification_type_check CHECK (((type)::text = ANY ((ARRAY['INFO'::character varying, 'WARNING'::character varying, 'ERROR'::character varying])::text[]))) +); + + +ALTER TABLE public.notification OWNER TO legalconsenthub; + +-- +-- Name: user_organization_roles; Type: TABLE; Schema: public; Owner: legalconsenthub +-- + +CREATE TABLE public.user_organization_roles ( + organization_id character varying(255) NOT NULL, + role character varying(255) NOT NULL, + user_id character varying(255) NOT NULL +); + + +ALTER TABLE public.user_organization_roles OWNER TO legalconsenthub; + +-- +-- Data for Name: app_user; Type: TABLE DATA; Schema: public; Owner: legalconsenthub +-- + +COPY public.app_user (created_at, modified_at, id, name, status) FROM stdin; +2025-09-27 08:25:18.821058 2025-09-27 08:25:18.845236 umgS7DllaoSY17iNDK2FizXKeGJHQs2g Denis Lugowski ACTIVE +2025-09-27 08:26:08.333312 2025-09-27 08:26:08.335975 wMZ2SEChna9CdzLOhwfZ3Qb5vxh5YUmD BR ACTIVE +2025-09-27 08:27:28.27983 2025-09-27 08:27:28.282089 ZHbzeqHRYWe2USuDQuIHINAL22EjXVyb AG ACTIVE +\. + + +-- +-- Data for Name: application_form; Type: TABLE DATA; Schema: public; Owner: legalconsenthub +-- + +COPY public.application_form (is_template, created_at, modified_at, id, created_by_id, last_modified_by_id, name, organization_id, status) FROM stdin; +\. + + +-- +-- Data for Name: comment; Type: TABLE DATA; Schema: public; Owner: legalconsenthub +-- + +COPY public.comment (created_at, modified_at, application_form_id, form_element_id, id, created_by_id, message) FROM stdin; +\. + + +-- +-- Data for Name: databasechangelog; Type: TABLE DATA; Schema: public; Owner: legalconsenthub +-- + +COPY public.databasechangelog (id, author, filename, dateexecuted, orderexecuted, exectype, md5sum, description, comments, tag, liquibase, contexts, labels, deployment_id) FROM stdin; +raw includeAll db/migrations/001-schema.sql 2025-09-27 08:24:34.933234 1 EXECUTED 9:1ffb09d62ed861ad7fac642fc83efeaf sql \N 4.29.2 \N \N 8954274880 +\. + + +-- +-- Data for Name: databasechangeloglock; Type: TABLE DATA; Schema: public; Owner: legalconsenthub +-- + +COPY public.databasechangeloglock (id, locked, lockgranted, lockedby) FROM stdin; +1 f \N \N +\. + + +-- +-- Data for Name: form_element; Type: TABLE DATA; Schema: public; Owner: legalconsenthub +-- + +COPY public.form_element (type, form_element_section_id, id, description, title) FROM stdin; +\. + + +-- +-- Data for Name: form_element_options; Type: TABLE DATA; Schema: public; Owner: legalconsenthub +-- + +COPY public.form_element_options (employee_data_category, processing_purpose, form_element_id, label, option_value) FROM stdin; +\. + + +-- +-- Data for Name: form_element_section; Type: TABLE DATA; Schema: public; Owner: legalconsenthub +-- + +COPY public.form_element_section (application_form_id, id, description, short_title, title) FROM stdin; +\. + + +-- +-- Data for Name: notification; Type: TABLE DATA; Schema: public; Owner: legalconsenthub +-- + +COPY public.notification (is_read, created_at, id, click_target, message, organization_id, recipient_id, role, title, type) FROM stdin; +\. + + +-- +-- Data for Name: user_organization_roles; Type: TABLE DATA; Schema: public; Owner: legalconsenthub +-- + +COPY public.user_organization_roles (organization_id, role, user_id) FROM stdin; +AHA19yfn1CQW3gzsbtFRIpqKZUQqbh9V works_council_member wMZ2SEChna9CdzLOhwfZ3Qb5vxh5YUmD +\. + + +-- +-- Name: app_user app_user_pkey; Type: CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.app_user + ADD CONSTRAINT app_user_pkey PRIMARY KEY (id); + + +-- +-- Name: application_form application_form_pkey; Type: CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.application_form + ADD CONSTRAINT application_form_pkey PRIMARY KEY (id); + + +-- +-- Name: comment comment_pkey; Type: CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.comment + ADD CONSTRAINT comment_pkey PRIMARY KEY (id); + + +-- +-- Name: databasechangeloglock databasechangeloglock_pkey; Type: CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.databasechangeloglock + ADD CONSTRAINT databasechangeloglock_pkey PRIMARY KEY (id); + + +-- +-- Name: form_element form_element_pkey; Type: CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.form_element + ADD CONSTRAINT form_element_pkey PRIMARY KEY (id); + + +-- +-- Name: form_element_section form_element_section_pkey; Type: CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.form_element_section + ADD CONSTRAINT form_element_section_pkey PRIMARY KEY (id); + + +-- +-- Name: notification notification_pkey; Type: CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.notification + ADD CONSTRAINT notification_pkey PRIMARY KEY (id); + + +-- +-- Name: user_organization_roles user_organization_roles_pkey; Type: CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.user_organization_roles + ADD CONSTRAINT user_organization_roles_pkey PRIMARY KEY (organization_id, role, user_id); + + +-- +-- Name: application_form fk5yewx8bespw0uiivxioeh7q0d; Type: FK CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.application_form + ADD CONSTRAINT fk5yewx8bespw0uiivxioeh7q0d FOREIGN KEY (last_modified_by_id) REFERENCES public.app_user(id); + + +-- +-- Name: comment fkbbjqikfmgeacfsnaasxxqoygh; Type: FK CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.comment + ADD CONSTRAINT fkbbjqikfmgeacfsnaasxxqoygh FOREIGN KEY (created_by_id) REFERENCES public.app_user(id); + + +-- +-- Name: form_element fkdpr6k93m4hqllqjsvoa4or6mp; Type: FK CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.form_element + ADD CONSTRAINT fkdpr6k93m4hqllqjsvoa4or6mp FOREIGN KEY (form_element_section_id) REFERENCES public.form_element_section(id); + + +-- +-- Name: notification fkeg1j4hnp0y4lbm0y35hgr4e8r; Type: FK CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.notification + ADD CONSTRAINT fkeg1j4hnp0y4lbm0y35hgr4e8r FOREIGN KEY (recipient_id) REFERENCES public.app_user(id); + + +-- +-- Name: comment fkfg84w0i76tw9os13950272c6f; Type: FK CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.comment + ADD CONSTRAINT fkfg84w0i76tw9os13950272c6f FOREIGN KEY (form_element_id) REFERENCES public.form_element(id); + + +-- +-- Name: user_organization_roles fkhgmm93qre3up6hy63wcef3yqk; Type: FK CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.user_organization_roles + ADD CONSTRAINT fkhgmm93qre3up6hy63wcef3yqk FOREIGN KEY (user_id) REFERENCES public.app_user(id); + + +-- +-- Name: application_form fkhtad5onoy2jknhtyfmx6cvvey; Type: FK CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.application_form + ADD CONSTRAINT fkhtad5onoy2jknhtyfmx6cvvey FOREIGN KEY (created_by_id) REFERENCES public.app_user(id); + + +-- +-- Name: comment fklavy9axrt26sepreg5lqtuoap; Type: FK CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.comment + ADD CONSTRAINT fklavy9axrt26sepreg5lqtuoap FOREIGN KEY (application_form_id) REFERENCES public.application_form(id); + + +-- +-- Name: form_element_options fknq0lpby5nspv1xi27n9el6us6; Type: FK CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.form_element_options + ADD CONSTRAINT fknq0lpby5nspv1xi27n9el6us6 FOREIGN KEY (form_element_id) REFERENCES public.form_element(id); + + +-- +-- Name: form_element_section fktn0lreovauwf2v29doo70o3qs; Type: FK CONSTRAINT; Schema: public; Owner: legalconsenthub +-- + +ALTER TABLE ONLY public.form_element_section + ADD CONSTRAINT fktn0lreovauwf2v29doo70o3qs FOREIGN KEY (application_form_id) REFERENCES public.application_form(id); + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/legalconsenthub/sqlite-backup.db b/legalconsenthub/sqlite-backup.db new file mode 100644 index 0000000..e8c05c4 Binary files /dev/null and b/legalconsenthub/sqlite-backup.db differ diff --git a/manage-db.sh b/manage-db.sh new file mode 100755 index 0000000..228c32f --- /dev/null +++ b/manage-db.sh @@ -0,0 +1,327 @@ +#!/bin/bash + +# Database Management Script +# Handles backup and restore operations for both SQLite (frontend) and PostgreSQL (backend) + +set -e # Exit on any error + +# Configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BACKEND_DIR="$SCRIPT_DIR/legalconsenthub-backend" +FRONTEND_DIR="$SCRIPT_DIR/legalconsenthub" + +# Database files +SQLITE_DB="$FRONTEND_DIR/sqlite.db" +SQLITE_BACKUP="$FRONTEND_DIR/sqlite-backup.db" +POSTGRES_BACKUP="$BACKEND_DIR/src/main/resources/legalconsenthub-db-backup.sql" + +# PostgreSQL connection details +POSTGRES_HOST="localhost" +POSTGRES_PORT="5432" +POSTGRES_DB="legalconsenthub" +POSTGRES_USER="legalconsenthub" +POSTGRES_PASSWORD="legalconsenthub" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Helper functions +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check if PostgreSQL container is running +check_postgres() { + # Check if the legalconsenthub-backend container is running + if docker ps --format "table {{.Names}}\t{{.Status}}" | grep -q "legalconsenthub-backend.*Up"; then + # Additional check to see if the database is ready + if docker exec legalconsenthub-backend pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" &>/dev/null; then + return 0 + fi + fi + return 1 +} + +# Check if PostgreSQL container exists and is running +ensure_postgres_running() { + if ! check_postgres; then + log_error "PostgreSQL container 'legalconsenthub-backend' is not running." + log_error "Please start the container before running backup/restore operations." + exit 1 + fi +} + +# Create backup of current SQLite database +backup_sqlite() { + log_info "Creating SQLite backup..." + if [ -f "$SQLITE_DB" ]; then + cp "$SQLITE_DB" "$SQLITE_BACKUP" + log_success "SQLite backup created: $SQLITE_BACKUP" + else + log_warning "SQLite database not found: $SQLITE_DB" + fi +} + +# Create backup of current PostgreSQL database +backup_postgres() { + log_info "Creating PostgreSQL backup..." + ensure_postgres_running + + # Create temporary backup file + local temp_backup="${POSTGRES_BACKUP}.tmp" + + # Generate backup with pg_dump + docker exec legalconsenthub-backend pg_dump \ + -U "$POSTGRES_USER" \ + -d "$POSTGRES_DB" \ + --no-owner \ + --no-privileges \ + --clean \ + --if-exists \ + > "$temp_backup" + + # Add force DROP statements at the beginning + { + echo "--" + echo "-- PostgreSQL database dump" + echo "--" + echo "" + echo "--" + echo "-- Force drop all tables and constraints to ensure clean restoration" + echo "--" + echo "" + echo "DROP TABLE IF EXISTS public.user_organization_roles CASCADE;" + echo "DROP TABLE IF EXISTS public.notification CASCADE;" + echo "DROP TABLE IF EXISTS public.form_element_section CASCADE;" + echo "DROP TABLE IF EXISTS public.form_element_options CASCADE;" + echo "DROP TABLE IF EXISTS public.form_element CASCADE;" + echo "DROP TABLE IF EXISTS public.comment CASCADE;" + echo "DROP TABLE IF EXISTS public.application_form CASCADE;" + echo "DROP TABLE IF EXISTS public.app_user CASCADE;" + echo "DROP TABLE IF EXISTS public.databasechangeloglock CASCADE;" + echo "DROP TABLE IF EXISTS public.databasechangelog CASCADE;" + echo "" + echo "-- Drop any remaining sequences, views, or other objects" + echo "DROP SEQUENCE IF EXISTS public.hibernate_sequence CASCADE;" + echo "" + echo "-- Reset database configuration" + + # Skip the first few lines of the original dump (headers) and append the rest + tail -n +4 "$temp_backup" + } > "$POSTGRES_BACKUP" + + # Remove temporary file + rm "$temp_backup" + + log_success "PostgreSQL backup created with force DROP statements: $POSTGRES_BACKUP" +} + +# Restore SQLite database from backup +restore_sqlite() { + log_info "Restoring SQLite database from backup..." + if [ -f "$SQLITE_BACKUP" ]; then + # Remove current database if it exists + if [ -f "$SQLITE_DB" ]; then + rm "$SQLITE_DB" + log_info "Removed current SQLite database" + fi + + # Copy backup to current database + cp "$SQLITE_BACKUP" "$SQLITE_DB" + log_success "SQLite database restored from: $SQLITE_BACKUP" + else + log_error "SQLite backup not found: $SQLITE_BACKUP" + exit 1 + fi +} + +# Restore PostgreSQL database from backup +restore_postgres() { + log_info "Restoring PostgreSQL database from backup..." + + if [ ! -f "$POSTGRES_BACKUP" ]; then + log_error "PostgreSQL backup not found: $POSTGRES_BACKUP" + exit 1 + fi + + ensure_postgres_running + + # Terminate all connections and drop/recreate database + log_info "Terminating all connections to PostgreSQL database..." + docker exec legalconsenthub-backend psql \ + -U "$POSTGRES_USER" \ + -d "postgres" \ + -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$POSTGRES_DB' AND pid <> pg_backend_pid();" + + log_info "Dropping and recreating PostgreSQL database..." + docker exec legalconsenthub-backend psql \ + -U "$POSTGRES_USER" \ + -d "postgres" \ + -c "DROP DATABASE IF EXISTS $POSTGRES_DB;" + + docker exec legalconsenthub-backend psql \ + -U "$POSTGRES_USER" \ + -d "postgres" \ + -c "CREATE DATABASE $POSTGRES_DB OWNER $POSTGRES_USER;" + + # Restore from backup + log_info "Restoring database from backup file..." + docker exec -i legalconsenthub-backend psql \ + -U "$POSTGRES_USER" \ + -d "$POSTGRES_DB" \ + < "$POSTGRES_BACKUP" + + log_success "PostgreSQL database restored from: $POSTGRES_BACKUP" +} + +# Show usage information +show_usage() { + echo "Database Management Script" + echo "" + echo "Usage: $0 [COMMAND]" + echo "" + echo "Commands:" + echo " backup Create backups of current databases" + echo " restore Restore databases from backups" + echo " backup-sqlite Create backup of SQLite database only" + echo " backup-postgres Create backup of PostgreSQL database only" + echo " restore-sqlite Restore SQLite database from backup only" + echo " restore-postgres Restore PostgreSQL database from backup only" + echo " status Show current status" + echo " help Show this help message" + echo "" + echo "Note: PostgreSQL operations require the 'legalconsenthub-backend' container to be running." + echo "" + echo "Examples:" + echo " $0 backup # Create backups of both databases" + echo " $0 restore # Restore both databases from backups" + echo " $0 backup-sqlite # Backup only SQLite database" + echo " $0 status # Check database status" +} + +# Show current status +show_status() { + log_info "Database Status:" + echo "" + + # SQLite status + echo "SQLite Database:" + if [ -f "$SQLITE_DB" ]; then + local size=$(du -h "$SQLITE_DB" | cut -f1) + local modified=$(stat -c "%y" "$SQLITE_DB" 2>/dev/null || stat -f "%Sm" "$SQLITE_DB" 2>/dev/null || echo "Unknown") + echo " Current DB: ✅ $SQLITE_DB ($size, modified: $modified)" + else + echo " Current DB: ❌ Not found" + fi + + if [ -f "$SQLITE_BACKUP" ]; then + local backup_size=$(du -h "$SQLITE_BACKUP" | cut -f1) + local backup_modified=$(stat -c "%y" "$SQLITE_BACKUP" 2>/dev/null || stat -f "%Sm" "$SQLITE_BACKUP" 2>/dev/null || echo "Unknown") + echo " Backup: ✅ $SQLITE_BACKUP ($backup_size, modified: $backup_modified)" + else + echo " Backup: ❌ Not found" + fi + + echo "" + + # PostgreSQL status + echo "PostgreSQL Database:" + if check_postgres; then + echo " Container: ✅ legalconsenthub-backend (Running)" + local db_size=$(docker exec legalconsenthub-backend psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -t -c "SELECT pg_size_pretty(pg_database_size('$POSTGRES_DB'));" 2>/dev/null | xargs || echo "Unknown") + echo " Database: ✅ $POSTGRES_DB ($db_size)" + else + echo " Container: ❌ legalconsenthub-backend (Not running or not found)" + echo " Database: ❓ Cannot check (container not available)" + fi + + if [ -f "$POSTGRES_BACKUP" ]; then + local backup_size=$(du -h "$POSTGRES_BACKUP" | cut -f1) + local backup_modified=$(stat -c "%y" "$POSTGRES_BACKUP" 2>/dev/null || stat -f "%Sm" "$POSTGRES_BACKUP" 2>/dev/null || echo "Unknown") + echo " Backup: ✅ $POSTGRES_BACKUP ($backup_size, modified: $backup_modified)" + else + echo " Backup: ❌ Not found" + fi +} + +# Main script logic +main() { + case "${1:-help}" in + "backup") + log_info "Creating backups of both databases..." + backup_sqlite + backup_postgres + log_success "All backups completed successfully!" + ;; + "restore") + log_info "Restoring both databases from backups..." + restore_sqlite + restore_postgres + log_success "All databases restored successfully!" + ;; + "backup-sqlite") + backup_sqlite + ;; + "backup-postgres") + backup_postgres + ;; + "restore-sqlite") + restore_sqlite + ;; + "restore-postgres") + restore_postgres + ;; + "status") + show_status + ;; + "help"|"-h"|"--help") + show_usage + ;; + *) + log_error "Unknown command: $1" + echo "" + show_usage + exit 1 + ;; + esac +} + +# Check for required tools +check_dependencies() { + local missing_tools=() + + # Check for Docker + if ! command -v docker &> /dev/null; then + missing_tools+=("docker") + fi + + if [ ${#missing_tools[@]} -gt 0 ]; then + log_error "Missing required tools:" + for tool in "${missing_tools[@]}"; do + echo " - $tool" + done + echo "" + echo "Please install the missing tools and try again." + exit 1 + fi +} + +# Run dependency check and main function +check_dependencies +main "$@"