From 551e0dec26d4e25cb68b1e19ccf46a1bfb4d6088 Mon Sep 17 00:00:00 2001 From: Ivo Oskamp Date: Tue, 6 Jan 2026 11:29:00 +0100 Subject: [PATCH] Auto-commit local changes before build (2026-01-06 11:29:00) --- .last-branch | 2 +- .../src/backend/app/main/routes_customers.py | 3 ++ .../src/backend/app/migrations.py | 33 +++++++++++++++++++ docs/changelog.md | 8 +++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/.last-branch b/.last-branch index b69a15b..53aafa4 100644 --- a/.last-branch +++ b/.last-branch @@ -1 +1 @@ -v20260106-05-jobs-row-click-and-archive-button-move +v20260106-06-customers-delete-fk-cascade-fix diff --git a/containers/backupchecks/src/backend/app/main/routes_customers.py b/containers/backupchecks/src/backend/app/main/routes_customers.py index 9e53b7d..f4348ae 100644 --- a/containers/backupchecks/src/backend/app/main/routes_customers.py +++ b/containers/backupchecks/src/backend/app/main/routes_customers.py @@ -100,6 +100,9 @@ def customers_delete(customer_id: int): customer = Customer.query.get_or_404(customer_id) try: + # Prevent FK violations on older schemas and keep jobs for historical reporting. + # Jobs are not deleted when removing a customer; they are simply unlinked. + Job.query.filter_by(customer_id=customer.id).update({"customer_id": None}) db.session.delete(customer) db.session.commit() flash("Customer deleted.", "success") diff --git a/containers/backupchecks/src/backend/app/migrations.py b/containers/backupchecks/src/backend/app/migrations.py index 94f376f..5980336 100644 --- a/containers/backupchecks/src/backend/app/migrations.py +++ b/containers/backupchecks/src/backend/app/migrations.py @@ -1137,6 +1137,39 @@ def migrate_object_persistence_tables() -> None: ''' ) ) + + # Ensure existing installations also have ON DELETE CASCADE on customer_objects.customer_id. + # Older schemas created the FK without cascade, which blocks deleting customers. + conn.execute( + text( + ''' + DO $$ + BEGIN + IF EXISTS ( + SELECT 1 + FROM information_schema.table_constraints tc + WHERE tc.table_name = 'customer_objects' + AND tc.constraint_type = 'FOREIGN KEY' + AND tc.constraint_name = 'customer_objects_customer_id_fkey' + ) THEN + ALTER TABLE customer_objects + DROP CONSTRAINT customer_objects_customer_id_fkey; + END IF; + + -- Recreate with cascade (idempotent via the drop above) + ALTER TABLE customer_objects + ADD CONSTRAINT customer_objects_customer_id_fkey + FOREIGN KEY (customer_id) + REFERENCES customers(id) + ON DELETE CASCADE; + EXCEPTION + WHEN duplicate_object THEN + -- Constraint already exists with the correct name. + NULL; + END $$; + ''' + ) + ) conn.execute( text( 'CREATE INDEX IF NOT EXISTS idx_customer_objects_customer_name ON customer_objects (customer_id, object_name)' diff --git a/docs/changelog.md b/docs/changelog.md index dc1de2f..0ca8b57 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -38,6 +38,14 @@ - Moved the Archive action from the Jobs table to the Job Details page. - Placed the Archive button next to the existing Delete job button for better consistency. +--- + +## v20260106-06-customers-delete-fk-cascade-fix + +- Fixed customer deletion failing with FK constraint errors caused by existing customer_objects rows. +- Migration: enforced ON DELETE CASCADE on customer_objects.customer_id by recreating the FK constraint if needed (idempotent). +- Customer delete flow: unlinks jobs (sets jobs.customer_id to NULL) before deleting the customer, so historical job/run data remains intact. + ================================================================================================================================================ ## v0.1.16 -- 2.45.2