From 7a9b264170baa29cafcbc593c73c31838f53dc24 Mon Sep 17 00:00:00 2001 From: ValueOn AG Date: Mon, 19 Jan 2026 16:25:04 +0100 Subject: [PATCH] fixed transactions --- .../migration_export_20260119_085558.json | 1221 ----------------- tool_db_export_migration.py | 268 +++- 2 files changed, 264 insertions(+), 1225 deletions(-) delete mode 100644 local/backup/migration_export_20260119_085558.json diff --git a/local/backup/migration_export_20260119_085558.json b/local/backup/migration_export_20260119_085558.json deleted file mode 100644 index 50cc9e5a..00000000 --- a/local/backup/migration_export_20260119_085558.json +++ /dev/null @@ -1,1221 +0,0 @@ -{ - "meta": { - "exportedAt": "2026-01-19T07:55:59.185004Z", - "exportedFrom": "Development Instance Patrick", - "databaseName": "poweron_app", - "version": "1.0", - "tableCount": 6, - "excludedTables": [ - "_system" - ], - "includesMeta": false, - "totalRecords": 107 - }, - "tables": { - "AccessRule": [ - { - "id": "90990e75-ac45-4986-9c09-f299f198d2b3", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": null, - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "a9536849-a53b-458d-bab8-77a2a3ac2747", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": null, - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "n" - }, - { - "id": "54870935-d5a1-41b7-b088-30f70b4dc835", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": null, - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "a3743435-1015-4bd1-a256-4f91eda9f544", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": null, - "view": 1, - "read": "g", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "3e7b79b5-a68a-41b5-9e7f-f8159a310ed3", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "Mandate", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "e7e8818c-04ed-473a-b1da-c7095f98f99e", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "Mandate", - "view": 0, - "read": "n", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "61714126-2822-48cd-bbb5-175c141b2c0b", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "Mandate", - "view": 0, - "read": "n", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "0ae9dcb8-302a-44cb-b777-1f9d26af7190", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "Mandate", - "view": 0, - "read": "n", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "2ab27800-df9d-4307-aee3-d99064fbab5d", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "UserInDB", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "279c6538-401a-4cd3-a36a-d1399f8bd2e4", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "UserInDB", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "4ab1abbe-abf1-4510-8ba1-4afbb37b1fd1", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "UserInDB", - "view": 1, - "read": "m", - "create": "n", - "update": "m", - "delete": "n" - }, - { - "id": "86c384a7-a2b5-4207-9e62-42cc50a2d20b", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "UserInDB", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "542af362-50c8-4e19-af21-5db2e0b8733e", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "UserConnection", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "8e356f1c-134d-4115-962e-0d0b7b71cf65", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "UserConnection", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "061b7a09-1003-4250-9524-64d648135467", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "UserConnection", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "89704bf9-d742-4149-a1e2-dcaaba9957c9", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "UserConnection", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "d296b5fb-48c3-4351-aa84-70ec1593369e", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "DataNeutraliserConfig", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "6ac892f8-69b6-4c2f-b18c-f5d58f8c95d9", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "DataNeutraliserConfig", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "defc2070-098f-44e2-9c59-264189730cc7", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "DataNeutraliserConfig", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "5927b71b-51f7-4671-a91b-f4f300af04f7", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "DataNeutraliserConfig", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "5a1907e7-6772-4b3f-9d34-6b847db3c14c", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "DataNeutralizerAttributes", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "c4eac0f8-e9d2-4064-80bd-a4e9c9e68686", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "DataNeutralizerAttributes", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "77a76ccf-91bb-4348-9caf-912b2bd7fe02", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "DataNeutralizerAttributes", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "d059cf52-8c56-4273-80f9-e7b8b40ebb4b", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "DataNeutralizerAttributes", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "0ca0ed8b-9327-43ff-b7b5-dc5870fb09c2", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "ChatWorkflow", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "a72168c5-bf33-43ef-a708-fd40e8feb6ba", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "ChatWorkflow", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "9c80b57b-d2ed-4309-9e87-62a98fe144d0", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "ChatWorkflow", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "4e534940-33cc-43ac-b859-9360a2e60cf1", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "ChatWorkflow", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "b0b3e37e-ea48-471e-95f6-b8e1e62ad09b", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "Prompt", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "0f0f4c89-2aa5-4755-aeea-562bd020593d", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "Prompt", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "0185dcc1-3560-4255-9840-8ab5db8042f8", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "Prompt", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "c9c87948-21ce-47f4-8040-c02a0917aeb2", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "Prompt", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "9e5f6dd5-c7a7-4a22-a1d6-82d4c68630a0", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "Projekt", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "852f4f77-dac7-46de-8136-ebc46344101e", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "Projekt", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "61710630-3c71-4adf-a997-b9e61d06fc00", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "Projekt", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "158789bd-7f26-4d88-a27e-6ce11b3d94f9", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "Projekt", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "c96b8b90-df7b-49ea-8ec9-0754c6179561", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "Parzelle", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "cdb610f9-21c6-4e8d-b9b6-d4a44f372ad6", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "Parzelle", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "6d3ff830-ae8f-4447-89a8-eaa8f8c4ecc7", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "Parzelle", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "7791781c-810a-43ac-a5ce-d84a3584e5f4", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "Parzelle", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "f49cd1cb-bdcd-4a9a-92fb-205078a3acba", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "Dokument", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "44d5455e-a17b-4b6d-a426-21565fe1cef7", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "Dokument", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "b2b58648-a555-4135-a038-84218a279437", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "Dokument", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "073195c6-01bc-40f9-9896-f3c10ebce288", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "Dokument", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "ba537ef0-239b-456d-b354-dec2c9d921ed", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "Gemeinde", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "3d66cd04-f4e6-43f8-ab77-c31a87730096", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "Gemeinde", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "bcc52c15-b41c-4a97-8e13-10035dd22202", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "Gemeinde", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "844c7c02-dcc8-43a4-8eb5-f8ec198f50fd", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "Gemeinde", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "15c1c76d-b8f7-40d2-8027-5ffdf6c96e28", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "Kanton", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "b73379ef-3dbf-4118-b6f2-473f3c1c52e7", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "Kanton", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "afc14c03-e953-4186-a923-4a12d3c6a312", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "Kanton", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "c49ee8f3-f295-465d-be92-9bf46ee259e0", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "Kanton", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "fcadb856-46f4-4ff0-85eb-67df3891c25d", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "Land", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "4a4e52ad-4ee3-4044-9e14-e0d797356139", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "Land", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "297ae474-ee2d-42f0-af09-eaa8b48d9684", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "Land", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "a567d373-00be-4c7e-b25e-deb6b10b57a3", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "Land", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "8f961779-1790-4cad-bebc-9b9bc436a29c", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "TrusteeOrganisation", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "81be065a-9ec6-4713-9fca-f5087cb9c3ee", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "TrusteeOrganisation", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "1fe2a920-0f9d-4c33-9288-4381af8c523e", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "TrusteeOrganisation", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "e99b39eb-ed55-4d08-a5d5-c3cf4645c312", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "TrusteeOrganisation", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "a54eed2a-e269-4884-ac2f-c09990f9b3d2", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "TrusteeRole", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "2bd073ca-30c3-43e0-8ea1-d77241053e7c", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "TrusteeRole", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "557ba1d5-2be0-43ee-a842-d0e74b45df41", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "TrusteeRole", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "81b46bcc-6cc3-40e0-9d82-f3a5bcc23b53", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "TrusteeRole", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "f3a58145-8986-42a7-bce4-eab0a1fa0962", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "TrusteeAccess", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "31d2a772-ed6b-447b-aa95-16a160d39601", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "TrusteeAccess", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "8a373342-8b8b-4a64-afd4-9f3ae8071d28", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "TrusteeAccess", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "b7a501e1-793f-47b6-b20c-1bfa61531cee", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "TrusteeAccess", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "0e67e101-5ce6-40fb-a783-104eebe29f92", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "TrusteeContract", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "23005b91-dc46-4bbe-a690-6c4568484858", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "TrusteeContract", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "aec6753b-cd7d-4ec8-8fa6-b9d007eb3657", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "TrusteeContract", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "31bf3c95-1012-4d61-91fc-36e4e3b832ec", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "TrusteeContract", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "17edb067-e62e-489a-842b-adbe4588aec0", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "TrusteeDocument", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "981e57b7-d813-4d67-9cf9-73576cc2affb", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "TrusteeDocument", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "3078980e-e8f2-44f0-b172-4a4c877b1b14", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "TrusteeDocument", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "f25efabc-e861-4cba-ad9c-6c8886f99ae5", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "TrusteeDocument", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "178c1dc4-7879-4a98-bbdd-54c1c55500c2", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "TrusteePosition", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "bbf02493-5ba2-4c0d-83b7-2a1c20e41108", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "TrusteePosition", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "7183b536-9a8a-4c2e-b6f4-4f69cc8a50b4", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "TrusteePosition", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "309130ca-254d-45b0-8629-47fe6a391a34", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "TrusteePosition", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "240fdaa4-75df-47a4-b33e-bce2e09dc741", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "TrusteePositionDocument", - "view": 1, - "read": "a", - "create": "a", - "update": "a", - "delete": "a" - }, - { - "id": "528ba11a-824d-477a-ae2f-aa453fdea2f2", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "TrusteePositionDocument", - "view": 1, - "read": "g", - "create": "g", - "update": "g", - "delete": "g" - }, - { - "id": "e3efeb99-eeb2-4450-85a4-f4261449a9ea", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "TrusteePositionDocument", - "view": 1, - "read": "m", - "create": "m", - "update": "m", - "delete": "m" - }, - { - "id": "ca4bf93c-311c-4d2b-8b6e-9bd879ff5cde", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "TrusteePositionDocument", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "186bc21d-eb17-4d4a-ae4e-20725768befb", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "DATA", - "item": "AuthEvent", - "view": 1, - "read": "a", - "create": "n", - "update": "n", - "delete": "a" - }, - { - "id": "73d6eaa4-c1d1-4bfb-a2d6-a1772f9fd31c", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "DATA", - "item": "AuthEvent", - "view": 1, - "read": "a", - "create": "n", - "update": "n", - "delete": "a" - }, - { - "id": "2dce96a0-9a30-4d83-8544-29b60b7e8199", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "DATA", - "item": "AuthEvent", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "91b2e3ef-7472-41b0-81ef-7e891ce7d183", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "DATA", - "item": "AuthEvent", - "view": 1, - "read": "m", - "create": "n", - "update": "n", - "delete": "n" - }, - { - "id": "5bf4d7af-d8e9-4ca0-a9d1-c4cdd6a8b2a8", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "UI", - "item": null, - "view": 1, - "read": null, - "create": null, - "update": null, - "delete": null - }, - { - "id": "37999b49-c13c-44a1-a94e-41477d2e2e29", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "UI", - "item": null, - "view": 1, - "read": null, - "create": null, - "update": null, - "delete": null - }, - { - "id": "b7af378c-0da9-4554-ab9e-3e4d5130778b", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "UI", - "item": null, - "view": 1, - "read": null, - "create": null, - "update": null, - "delete": null - }, - { - "id": "d0c5bc55-d6e7-40c2-8bab-b7df13836712", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "UI", - "item": null, - "view": 1, - "read": null, - "create": null, - "update": null, - "delete": null - }, - { - "id": "96827d13-bb10-4341-9615-03b940e4eab1", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "context": "RESOURCE", - "item": null, - "view": 1, - "read": null, - "create": null, - "update": null, - "delete": null - }, - { - "id": "c052f46c-07b7-447b-885d-15803f615b6a", - "roleId": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "context": "RESOURCE", - "item": null, - "view": 1, - "read": null, - "create": null, - "update": null, - "delete": null - }, - { - "id": "91213ddd-9490-4f9f-928a-5f7c87bb6e05", - "roleId": "bc22885c-5354-463e-a3fe-480941e016df", - "context": "RESOURCE", - "item": null, - "view": 1, - "read": null, - "create": null, - "update": null, - "delete": null - }, - { - "id": "58abcdc0-c8ba-435c-b01e-7b9c52581251", - "roleId": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "context": "RESOURCE", - "item": null, - "view": 1, - "read": null, - "create": null, - "update": null, - "delete": null - } - ], - "Mandate": [ - { - "id": "e439ce2b-a8c2-4684-8c5f-70df493b82a1", - "name": "Root", - "enabled": 1 - } - ], - "Role": [ - { - "id": "4564beaf-f07d-420f-a8af-d46dff0ba3b3", - "roleLabel": "sysadmin", - "description": { - "en": "System Administrator - Full access to all system resources", - "fr": "Administrateur système - Accès complet à toutes les ressources", - "ge": null, - "it": null - }, - "mandateId": null, - "featureInstanceId": null, - "featureCode": null, - "isSystemRole": 1 - }, - { - "id": "9d7af325-2dc9-451f-88d1-090dc06de3db", - "roleLabel": "admin", - "description": { - "en": "Administrator - Manage users and resources within mandate scope", - "fr": "Administrateur - Gérer les utilisateurs et ressources dans le périmètre du mandat", - "ge": null, - "it": null - }, - "mandateId": null, - "featureInstanceId": null, - "featureCode": null, - "isSystemRole": 1 - }, - { - "id": "bc22885c-5354-463e-a3fe-480941e016df", - "roleLabel": "user", - "description": { - "en": "User - Standard user with access to own records", - "fr": "Utilisateur - Utilisateur standard avec accès à ses propres enregistrements", - "ge": null, - "it": null - }, - "mandateId": null, - "featureInstanceId": null, - "featureCode": null, - "isSystemRole": 1 - }, - { - "id": "95a88cf7-8a2a-42b2-b136-168966ad86b5", - "roleLabel": "viewer", - "description": { - "en": "Viewer - Read-only access to group records", - "fr": "Visualiseur - Accès en lecture seule aux enregistrements du groupe", - "ge": null, - "it": null - }, - "mandateId": null, - "featureInstanceId": null, - "featureCode": null, - "isSystemRole": 1 - } - ], - "UserInDB": [ - { - "id": "3876d530-29d8-451d-a2fc-92af5cb2b817", - "username": "admin", - "email": "admin@example.com", - "fullName": "Administrator", - "language": "en", - "enabled": 1, - "isSysAdmin": 1, - "roleLabels": [ - "sysadmin" - ], - "authenticationAuthority": "local", - "mandateId": "e439ce2b-a8c2-4684-8c5f-70df493b82a1", - "hashedPassword": "$argon2id$v=19$m=65536,t=3,p=4$Sumds1bqvZfyPseYs/YeYw$eiRcnO7J+ebit2oV6Ndqaer2ZIgPErTC9q2riRpiiwA", - "resetToken": null, - "resetTokenExpires": null - }, - { - "id": "805dcd6a-ac87-48c4-a1f0-987d8aa4a64b", - "username": "event", - "email": "event@example.com", - "fullName": "Event", - "language": "en", - "enabled": 1, - "isSysAdmin": 1, - "roleLabels": [ - "sysadmin" - ], - "authenticationAuthority": "local", - "mandateId": "e439ce2b-a8c2-4684-8c5f-70df493b82a1", - "hashedPassword": "$argon2id$v=19$m=65536,t=3,p=4$BoDwnlNq7d3b2ztnrPWecw$ICkAaTjE/R39CJ7MryLmfmeEX5m4N/6S3HaDfOZuOBM", - "resetToken": null, - "resetTokenExpires": null - } - ], - "UserMandate": [ - { - "id": "70f9e733-7297-4afe-8784-9f7c730de3c4", - "userId": "3876d530-29d8-451d-a2fc-92af5cb2b817", - "mandateId": "e439ce2b-a8c2-4684-8c5f-70df493b82a1", - "enabled": 1 - }, - { - "id": "412ba93d-2abe-4916-8a80-bec4672c0baf", - "userId": "805dcd6a-ac87-48c4-a1f0-987d8aa4a64b", - "mandateId": "e439ce2b-a8c2-4684-8c5f-70df493b82a1", - "enabled": 1 - } - ], - "UserMandateRole": [ - { - "id": "cff2dd70-4dd6-4028-a384-7b0e8578f9dc", - "userMandateId": "70f9e733-7297-4afe-8784-9f7c730de3c4", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3" - }, - { - "id": "54232df1-b559-44bb-8a51-adbd82818d94", - "userMandateId": "412ba93d-2abe-4916-8a80-bec4672c0baf", - "roleId": "4564beaf-f07d-420f-a8af-d46dff0ba3b3" - } - ] - }, - "summary": { - "AccessRule": { - "recordCount": 96 - }, - "Mandate": { - "recordCount": 1 - }, - "Role": { - "recordCount": 4 - }, - "UserInDB": { - "recordCount": 2 - }, - "UserMandate": { - "recordCount": 2 - }, - "UserMandateRole": { - "recordCount": 2 - } - } -} \ No newline at end of file diff --git a/tool_db_export_migration.py b/tool_db_export_migration.py index 09aa2f8f..6c93370a 100644 --- a/tool_db_export_migration.py +++ b/tool_db_export_migration.py @@ -5,6 +5,8 @@ Datenbank Export-Tool für Migration. Dieses Script exportiert alle Daten aus ALLEN PowerOn PostgreSQL-Datenbanken in eine JSON-Datei, die als Migrationsdatensatz verwendet werden kann. +Zusätzlich wird eine separate JSON-Datei mit nur den Strukturen (ohne Daten) +erstellt: _structure.json Datenbanken: - poweron_app (User, Mandate, RBAC, Features, etc.) @@ -18,6 +20,7 @@ Verwendung: Optionen: --output, -o Pfad zur Ausgabedatei (Standard: migration_export_.json) + Die Struktur-Datei wird automatisch als _structure.json erstellt --pretty, -p JSON formatiert ausgeben (für bessere Lesbarkeit) --exclude Komma-getrennte Liste von Tabellen, die ausgeschlossen werden sollen --include-meta System-Metadaten (_createdAt, _modifiedAt, etc.) beibehalten @@ -150,6 +153,8 @@ def _getDbConnection(dbDatabase: str): password=dbPassword, cursor_factory=psycopg2.extras.RealDictCursor ) + # Autocommit muss VOR set_client_encoding gesetzt werden, um Transaction-Konflikte zu vermeiden + conn.autocommit = True conn.set_client_encoding('UTF8') return conn except Exception as e: @@ -205,6 +210,222 @@ def _getTableRowCount(conn, tableName: str) -> int: return result["count"] if result else 0 +def _getTableStructure(conn, tableName: str) -> Dict[str, Any]: + """Holt die Struktur einer Tabelle (Spalten, Constraints, Indizes) ohne Daten.""" + structure = { + "columns": [], + "primaryKeys": [], + "foreignKeys": [], + "uniqueConstraints": [], + "indexes": [], + "checkConstraints": [] + } + + # Connection hat bereits autocommit = True, daher keine Transaction-Probleme + with conn.cursor() as cursor: + # Spalten-Informationen + cursor.execute(""" + SELECT + column_name, + data_type, + character_maximum_length, + numeric_precision, + numeric_scale, + is_nullable, + column_default, + udt_name + FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = %s + ORDER BY ordinal_position + """, (tableName,)) + + for row in cursor.fetchall(): + colInfo = { + "name": row["column_name"], + "type": row["data_type"], + "udtName": row["udt_name"], + "nullable": row["is_nullable"] == "YES", + "default": row["column_default"] + } + + if row["character_maximum_length"]: + colInfo["maxLength"] = row["character_maximum_length"] + if row["numeric_precision"]: + colInfo["precision"] = row["numeric_precision"] + if row["numeric_scale"]: + colInfo["scale"] = row["numeric_scale"] + + structure["columns"].append(colInfo) + + # Primary Keys + cursor.execute(""" + SELECT + kcu.column_name + FROM information_schema.table_constraints tc + JOIN information_schema.key_column_usage kcu + ON tc.constraint_name = kcu.constraint_name + WHERE tc.table_schema = 'public' + AND tc.table_name = %s + AND tc.constraint_type = 'PRIMARY KEY' + ORDER BY kcu.ordinal_position + """, (tableName,)) + + structure["primaryKeys"] = [row["column_name"] for row in cursor.fetchall()] + + # Foreign Keys + cursor.execute(""" + SELECT + kcu.column_name, + ccu.table_name AS foreign_table_name, + ccu.column_name AS foreign_column_name, + tc.constraint_name + FROM information_schema.table_constraints AS tc + JOIN information_schema.key_column_usage AS kcu + ON tc.constraint_name = kcu.constraint_name + JOIN information_schema.constraint_column_usage AS ccu + ON ccu.constraint_name = tc.constraint_name + WHERE tc.constraint_type = 'FOREIGN KEY' + AND tc.table_schema = 'public' + AND tc.table_name = %s + """, (tableName,)) + + for row in cursor.fetchall(): + structure["foreignKeys"].append({ + "column": row["column_name"], + "referencesTable": row["foreign_table_name"], + "referencesColumn": row["foreign_column_name"], + "constraintName": row["constraint_name"] + }) + + # Unique Constraints - FIX: Tabellen-Aliase verwenden um ambiguous columns zu vermeiden + cursor.execute(""" + SELECT + kcu.column_name, + tc.constraint_name + FROM information_schema.table_constraints tc + JOIN information_schema.key_column_usage kcu + ON tc.constraint_name = kcu.constraint_name + AND tc.table_schema = kcu.table_schema + AND tc.table_name = kcu.table_name + WHERE tc.table_schema = 'public' + AND tc.table_name = %s + AND tc.constraint_type = 'UNIQUE' + ORDER BY kcu.ordinal_position + """, (tableName,)) + + uniqueGroups = {} + for row in cursor.fetchall(): + constraintName = row["constraint_name"] + if constraintName not in uniqueGroups: + uniqueGroups[constraintName] = [] + uniqueGroups[constraintName].append(row["column_name"]) + + structure["uniqueConstraints"] = [ + {"columns": cols, "constraintName": name} + for name, cols in uniqueGroups.items() + ] + + # Indizes (ohne Primary Key und Unique Constraints) + cursor.execute(""" + SELECT + i.relname AS index_name, + a.attname AS column_name, + ix.indisunique AS is_unique + FROM pg_class t + JOIN pg_index ix ON t.oid = ix.indrelid + JOIN pg_class i ON i.oid = ix.indexrelid + JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(ix.indkey) + WHERE t.relkind = 'r' + AND t.relname = %s + AND NOT ix.indisprimary + ORDER BY i.relname, a.attnum + """, (tableName,)) + + indexGroups = {} + for row in cursor.fetchall(): + indexName = row["index_name"] + if indexName not in indexGroups: + indexGroups[indexName] = { + "name": indexName, + "columns": [], + "unique": row["is_unique"] + } + indexGroups[indexName]["columns"].append(row["column_name"]) + + structure["indexes"] = list(indexGroups.values()) + + # Check Constraints - FIX: Tabellen-Aliase verwenden + cursor.execute(""" + SELECT + cc.constraint_name, + cc.check_clause + FROM information_schema.check_constraints cc + JOIN information_schema.constraint_column_usage ccu + ON cc.constraint_name = ccu.constraint_name + WHERE ccu.table_schema = 'public' + AND ccu.table_name = %s + """, (tableName,)) + + for row in cursor.fetchall(): + structure["checkConstraints"].append({ + "constraintName": row["constraint_name"], + "checkClause": row["check_clause"] + }) + + return structure + + +def _exportSingleDatabaseStructure( + dbDatabase: str, + excludeTables: List[str] +) -> Optional[Dict[str, Any]]: + """Exportiert nur die Struktur einer einzelnen Datenbank (ohne Daten).""" + conn = _getDbConnection(dbDatabase) + + if conn is None: + return None + + try: + allTables = _getTables(conn) + + # System-Tabellen ausschliessen + systemTables = ["_system"] + tablesToExport = [ + t for t in allTables + if t not in systemTables and t not in excludeTables + ] + + dbExport = { + "tables": {}, + "summary": {}, + "tableCount": len(tablesToExport) + } + + for tableName in tablesToExport: + try: + structure = _getTableStructure(conn, tableName) + dbExport["tables"][tableName] = structure + dbExport["summary"][tableName] = { + "columnCount": len(structure["columns"]), + "primaryKeyCount": len(structure["primaryKeys"]), + "foreignKeyCount": len(structure["foreignKeys"]), + "indexCount": len(structure["indexes"]) + } + + logger.info(f" {tableName}: {len(structure['columns'])} Spalten") + + except Exception as e: + logger.error(f" Fehler bei Tabelle {tableName}: {e}") + dbExport["tables"][tableName] = {} + dbExport["summary"][tableName] = {"error": str(e)} + + return dbExport + + finally: + conn.close() + + def _exportSingleDatabase( dbDatabase: str, excludeTables: List[str], @@ -249,6 +470,7 @@ def _exportSingleDatabase( logger.error(f" Fehler bei Tabelle {tableName}: {e}") dbExport["tables"][tableName] = [] dbExport["summary"][tableName] = {"recordCount": 0, "error": str(e)} + # Bei autocommit = True ist kein rollback() notwendig return dbExport @@ -265,6 +487,7 @@ def exportDatabase( ) -> str: """ Exportiert alle Datenbanken in eine JSON-Datei. + Erstellt zusätzlich eine separate JSON-Datei mit nur den Strukturen (ohne Daten). Args: outputPath: Pfad zur Ausgabedatei (optional) @@ -310,12 +533,31 @@ def exportDatabase( "databases": {} } + # Struktur-Export erstellen + structureData = { + "meta": { + "exportedAt": datetime.utcnow().isoformat() + "Z", + "exportedFrom": _getConfigValue("APP_ENV_LABEL", "unknown"), + "version": "1.0", + "databaseCount": 0, + "totalTables": 0, + "excludedTables": excludeTables, + "note": "Nur Strukturen, keine Daten" + }, + "databases": {} + } + # Jede Datenbank exportieren for dbName in databasesToExport: logger.info(f"Exportiere Datenbank: {dbName}") + # Daten exportieren dbExport = _exportSingleDatabase(dbName, excludeTables, includeMeta) + # Struktur exportieren + logger.info(f"Exportiere Struktur für Datenbank: {dbName}") + dbStructure = _exportSingleDatabaseStructure(dbName, excludeTables) + if dbExport is not None: exportData["databases"][dbName] = dbExport exportData["meta"]["databaseCount"] += 1 @@ -324,8 +566,13 @@ def exportDatabase( logger.info(f" -> {dbExport['tableCount']} Tabellen, {dbExport['totalRecords']} Datensätze") else: logger.info(f" -> Übersprungen (existiert nicht)") + + if dbStructure is not None: + structureData["databases"][dbName] = dbStructure + structureData["meta"]["databaseCount"] += 1 + structureData["meta"]["totalTables"] += dbStructure["tableCount"] - # JSON-Datei schreiben + # JSON-Datei mit Daten schreiben logger.info(f"Schreibe Exportdatei: {outputPath}") with open(outputPath, "w", encoding="utf-8") as f: @@ -334,16 +581,29 @@ def exportDatabase( else: json.dump(exportData, f, ensure_ascii=False, default=str) - # Dateigrösse berechnen + # JSON-Datei mit Strukturen schreiben + structurePath = outputPath.replace(".json", "_structure.json") + logger.info(f"Schreibe Struktur-Exportdatei: {structurePath}") + + with open(structurePath, "w", encoding="utf-8") as f: + if prettyPrint: + json.dump(structureData, f, indent=2, ensure_ascii=False, default=str) + else: + json.dump(structureData, f, ensure_ascii=False, default=str) + + # Dateigrössen berechnen fileSize = os.path.getsize(outputPath) fileSizeStr = _formatFileSize(fileSize) + structureFileSize = os.path.getsize(structurePath) + structureFileSizeStr = _formatFileSize(structureFileSize) + logger.info(f"Export abgeschlossen!") logger.info(f" Datenbanken: {exportData['meta']['databaseCount']}") logger.info(f" Tabellen: {exportData['meta']['totalTables']}") logger.info(f" Datensätze: {exportData['meta']['totalRecords']}") - logger.info(f" Dateigrösse: {fileSizeStr}") - logger.info(f" Ausgabedatei: {outputPath}") + logger.info(f" Daten-Export: {fileSizeStr} - {outputPath}") + logger.info(f" Struktur-Export: {structureFileSizeStr} - {structurePath}") return outputPath