diff --git a/dbrepo-analyse-service/Pipfile.lock b/dbrepo-analyse-service/Pipfile.lock
index d1f47348f8d5aa0a9d78d9c8b28ebf7006197766..8a14b2d86f90cf92fb58a7e42d58d520d7d79f0d 100644
--- a/dbrepo-analyse-service/Pipfile.lock
+++ b/dbrepo-analyse-service/Pipfile.lock
@@ -167,27 +167,28 @@
         },
         "boto3": {
             "hashes": [
-                "sha256:009cd143509f2ff4c37582c3f45d50f28c95eed68e8a5c36641206bdb597a9ea",
-                "sha256:7e59f0a848be477a4c98a90e7a18a0e284adfb643f7879d2b303c5f493661b7a"
+                "sha256:4eb8019421cb664a6fcbbee6152aa95a28ce8bbc1c4ee263871c09cdd58bf8ee",
+                "sha256:e9edaf979fbe59737e158f2f0f3f0861ff1d61233f18f6be8ebb483905f24587"
             ],
             "index": "pypi",
-            "version": "==1.34.113"
+            "markers": "python_version >= '3.8'",
+            "version": "==1.34.118"
         },
         "botocore": {
             "hashes": [
-                "sha256:449912ba3c4ded64f21d09d428146dd9c05337b2a112e15511bf2c4888faae79",
-                "sha256:8ca87776450ef41dd25c327eb6e504294230a5756940d68bcfdedc4a7cdeca97"
+                "sha256:0a3d1ec0186f8b516deb39474de3d226d531f77f92a0f56ad79b80219db3ae9e",
+                "sha256:e3f6c5636a4394768e81e33a16f5c6ae7f364f512415d423f9b9dc67fc638df4"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==1.34.113"
+            "version": "==1.34.118"
         },
         "certifi": {
             "hashes": [
-                "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f",
-                "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"
+                "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516",
+                "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"
             ],
             "markers": "python_version >= '3.6'",
-            "version": "==2024.2.2"
+            "version": "==2024.6.2"
         },
         "cffi": {
             "hashes": [
@@ -391,10 +392,15 @@
         },
         "dbrepo": {
             "hashes": [
-                "sha256:ceab260cf76c050e118ce0f0589fec66059396751e03f2ec41fa489cfacc4e7b"
+                "sha256:110db9e4e70f5656a6351409d4b022656abf7de0bd72d5e061a25685f708d9a4"
+            ],
+            "path": "./lib/dbrepo-1.4.4.tar.gz"
+        },
+        "events": {
+            "hashes": [
+                "sha256:a7286af378ba3e46640ac9825156c93bdba7502174dd696090fdfcd4d80a1abd"
             ],
-            "path": "./lib/dbrepo-1.4.4.tar.gz",
-            "version": "==1.4.4"
+            "version": "==0.5"
         },
         "exceptiongroup": {
             "hashes": [
@@ -402,6 +408,7 @@
                 "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.7'",
             "version": "==1.2.1"
         },
         "flasgger": {
@@ -417,6 +424,7 @@
                 "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.8'",
             "version": "==3.0.3"
         },
         "flask-cors": {
@@ -441,6 +449,7 @@
                 "sha256:9215d05a9413d3855764bcd67035e75819d23af2fafb6b55197eb5a3313fdfb2"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.7' and python_version < '4'",
             "version": "==4.6.0"
         },
         "frozenlist": {
@@ -571,6 +580,7 @@
                 "sha256:fbfdce91239fe306772faab57597186710d5699213f4df099d1612da7320d682"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.8'",
             "version": "==24.2.1"
         },
         "greenlet": {
@@ -635,6 +645,7 @@
                 "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.7'",
             "version": "==3.0.3"
         },
         "gunicorn": {
@@ -643,6 +654,7 @@
                 "sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.7'",
             "version": "==22.0.0"
         },
         "idna": {
@@ -698,6 +710,7 @@
                 "sha256:61c9170f92e736b530655e75374681d4fcca9cfa8763ab42be57353b2b203494"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.6'",
             "version": "==1.3.1"
         },
         "markupsafe": {
@@ -918,15 +931,17 @@
                 "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.9'",
             "version": "==1.26.4"
         },
         "opensearch-py": {
             "hashes": [
-                "sha256:0dde4ac7158a717d92a8cd81964cb99705a4b80bcf9258ba195b9a9f23f5226d",
-                "sha256:cf093a40e272b60663f20417fc1264ac724dcf1e03c1a4542a6b44835b1e6c49"
+                "sha256:0b7c27e8ed84c03c99558406927b6161f186a72502ca6d0325413d8e5523ba96",
+                "sha256:b6e78b685dd4e9c016d7a4299cf1de69e299c88322e3f81c716e6e23fe5683c1"
             ],
             "index": "pypi",
-            "version": "==2.5.0"
+            "markers": "python_version >= '3.8' and python_version < '4'",
+            "version": "==2.6.0"
         },
         "packaging": {
             "hashes": [
@@ -969,6 +984,7 @@
                 "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.9'",
             "version": "==2.2.2"
         },
         "pika": {
@@ -1043,96 +1059,97 @@
         },
         "pydantic": {
             "hashes": [
-                "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5",
-                "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"
+                "sha256:c46c76a40bb1296728d7a8b99aa73dd70a48c3510111ff290034f860c99c419e",
+                "sha256:ea91b002777bf643bb20dd717c028ec43216b24a6001a280f83877fd2655d0b4"
             ],
             "index": "pypi",
-            "version": "==2.7.1"
+            "markers": "python_version >= '3.8'",
+            "version": "==2.7.3"
         },
         "pydantic-core": {
             "hashes": [
-                "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b",
-                "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a",
-                "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90",
-                "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d",
-                "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e",
-                "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d",
-                "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027",
-                "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804",
-                "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347",
-                "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400",
-                "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3",
-                "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399",
-                "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349",
-                "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd",
-                "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c",
-                "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e",
-                "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413",
-                "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3",
-                "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e",
-                "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3",
-                "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91",
-                "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce",
-                "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c",
-                "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb",
-                "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664",
-                "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6",
-                "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd",
-                "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3",
-                "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af",
-                "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043",
-                "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350",
-                "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7",
-                "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0",
-                "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563",
-                "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761",
-                "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72",
-                "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3",
-                "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb",
-                "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788",
-                "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b",
-                "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c",
-                "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038",
-                "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250",
-                "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec",
-                "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c",
-                "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74",
-                "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81",
-                "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439",
-                "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75",
-                "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0",
-                "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8",
-                "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150",
-                "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438",
-                "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae",
-                "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857",
-                "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038",
-                "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374",
-                "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f",
-                "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241",
-                "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592",
-                "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4",
-                "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d",
-                "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b",
-                "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b",
-                "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182",
-                "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e",
-                "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641",
-                "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70",
-                "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9",
-                "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a",
-                "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543",
-                "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b",
-                "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f",
-                "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38",
-                "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845",
-                "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2",
-                "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0",
-                "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4",
-                "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"
+                "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3",
+                "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8",
+                "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8",
+                "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30",
+                "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a",
+                "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8",
+                "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d",
+                "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc",
+                "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2",
+                "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab",
+                "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077",
+                "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e",
+                "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9",
+                "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9",
+                "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef",
+                "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1",
+                "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507",
+                "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528",
+                "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558",
+                "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b",
+                "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154",
+                "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724",
+                "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695",
+                "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9",
+                "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851",
+                "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805",
+                "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a",
+                "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5",
+                "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94",
+                "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c",
+                "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d",
+                "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef",
+                "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26",
+                "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2",
+                "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c",
+                "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0",
+                "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2",
+                "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4",
+                "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d",
+                "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2",
+                "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce",
+                "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34",
+                "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f",
+                "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d",
+                "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b",
+                "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07",
+                "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312",
+                "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057",
+                "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d",
+                "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af",
+                "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb",
+                "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd",
+                "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78",
+                "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b",
+                "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223",
+                "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a",
+                "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4",
+                "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5",
+                "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23",
+                "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a",
+                "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4",
+                "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8",
+                "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d",
+                "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443",
+                "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e",
+                "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f",
+                "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e",
+                "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d",
+                "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc",
+                "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443",
+                "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be",
+                "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2",
+                "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee",
+                "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f",
+                "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae",
+                "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864",
+                "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4",
+                "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951",
+                "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==2.18.2"
+            "version": "==2.18.4"
         },
         "pyjwt": {
             "hashes": [
@@ -1224,11 +1241,12 @@
         },
         "requests": {
             "hashes": [
-                "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289",
-                "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"
+                "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760",
+                "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"
             ],
             "index": "pypi",
-            "version": "==2.32.2"
+            "markers": "python_version >= '3.8'",
+            "version": "==2.32.3"
         },
         "rpds-py": {
             "hashes": [
@@ -1377,11 +1395,11 @@
         },
         "typing-extensions": {
             "hashes": [
-                "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8",
-                "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"
+                "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a",
+                "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==4.12.0"
+            "version": "==4.12.1"
         },
         "tzdata": {
             "hashes": [
@@ -1393,11 +1411,11 @@
         },
         "urllib3": {
             "hashes": [
-                "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07",
-                "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"
+                "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d",
+                "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"
             ],
-            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
-            "version": "==1.26.18"
+            "markers": "python_version >= '3.8'",
+            "version": "==2.2.1"
         },
         "werkzeug": {
             "hashes": [
@@ -1592,11 +1610,11 @@
         },
         "certifi": {
             "hashes": [
-                "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f",
-                "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"
+                "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516",
+                "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"
             ],
             "markers": "python_version >= '3.6'",
-            "version": "==2024.2.2"
+            "version": "==2024.6.2"
         },
         "cffi": {
             "hashes": [
@@ -1754,61 +1772,62 @@
         },
         "coverage": {
             "hashes": [
-                "sha256:06d96b9b19bbe7f049c2be3c4f9e06737ec6d8ef8933c7c3a4c557ef07936e46",
-                "sha256:13017a63b0e499c59b5ba94a8542fb62864ba3016127d1e4ef30d354fc2b00e9",
-                "sha256:1acc2e2ef098a1d4bf535758085f508097316d738101a97c3f996bccba963ea5",
-                "sha256:1aef719b6559b521ae913ddeb38f5048c6d1a3d366865e8b320270b7bc4693c2",
-                "sha256:1e4225990a87df898e40ca31c9e830c15c2c53b1d33df592bc8ef314d71f0281",
-                "sha256:1f11f98753800eb1ec872562a398081f6695f91cd01ce39819e36621003ec52a",
-                "sha256:1f29bf497d51a5077994b265e976d78b09d9d0dff6ca5763dbb4804534a5d380",
-                "sha256:1f96aa94739593ae0707eda9813ce363a0a0374a810ae0eced383340fc4a1f73",
-                "sha256:20e611fc36e1a0fc7bbf957ef9c635c8807d71fbe5643e51b2769b3cc0fb0b51",
-                "sha256:23f2f16958b16152b43a39a5ecf4705757ddd284b3b17a77da3a62aef9c057ef",
-                "sha256:24bb4c7859a3f757a116521d4d3a8a82befad56ea1bdacd17d6aafd113b0071e",
-                "sha256:26716a1118c6ce2188283b4b60a898c3be29b480acbd0a91446ced4fe4e780d8",
-                "sha256:29da75ce20cb0a26d60e22658dd3230713c6c05a3465dd8ad040ffc991aea318",
-                "sha256:2b144d142ec9987276aeff1326edbc0df8ba4afbd7232f0ca10ad57a115e95b6",
-                "sha256:2c79f058e7bec26b5295d53b8c39ecb623448c74ccc8378631f5cb5c16a7e02c",
-                "sha256:3bb5b92a0ab3d22dfdbfe845e2fef92717b067bdf41a5b68c7e3e857c0cff1a4",
-                "sha256:3d3f7744b8a8079d69af69d512e5abed4fb473057625588ce126088e50d05493",
-                "sha256:3d9c62cff2ffb4c2a95328488fd7aa96a7a4b34873150650fe76b19c08c9c792",
-                "sha256:3e12536446ad4527ac8ed91d8a607813085683bcce27af69e3b31cd72b3c5960",
-                "sha256:40dbb8e7727560fe8ab65efcddfec1ae25f30ef02e2f2e5d78cfb52a66781ec5",
-                "sha256:431a3917e32223fcdb90b79fe60185864a9109631ebc05f6c5aa03781a00b513",
-                "sha256:448ec61ea9ea7916d5579939362509145caaecf03161f6f13e366aebb692a631",
-                "sha256:482df956b055d3009d10fce81af6ffab28215d7ed6ad4a15e5c8e67cb7c5251c",
-                "sha256:4a00bd5ba8f1a4114720bef283cf31583d6cb1c510ce890a6da6c4268f0070b7",
-                "sha256:51b6cee539168a912b4b3b040e4042b9e2c9a7ad9c8546c09e4eaeff3eacba6b",
-                "sha256:554c7327bf0fd688050348e22db7c8e163fb7219f3ecdd4732d7ed606b417263",
-                "sha256:5662bf0f6fb6757f5c2d6279c541a5af55a39772c2362ed0920b27e3ce0e21f7",
-                "sha256:5997d418c219dcd4dcba64e50671cca849aaf0dac3d7a2eeeb7d651a5bd735b8",
-                "sha256:59a75e6aa5c25b50b5a1499f9718f2edff54257f545718c4fb100f48d570ead4",
-                "sha256:60b66b0363c5a2a79fba3d1cd7430c25bbd92c923d031cae906bdcb6e054d9a2",
-                "sha256:6e34680049eecb30b6498784c9637c1c74277dcb1db75649a152f8004fbd6646",
-                "sha256:74eeaa13e8200ad72fca9c5f37395fb310915cec6f1682b21375e84fd9770e84",
-                "sha256:7c5c5b7ae2763533152880d5b5b451acbc1089ade2336b710a24b2b0f5239d20",
-                "sha256:829fb55ad437d757c70d5b1c51cfda9377f31506a0a3f3ac282bc6a387d6a5f1",
-                "sha256:878243e1206828908a6b4a9ca7b1aa8bee9eb129bf7186fc381d2646f4524ce9",
-                "sha256:8809c0ea0e8454f756e3bd5c36d04dddf222989216788a25bfd6724bfcee342c",
-                "sha256:8941e35a0e991a7a20a1fa3e3182f82abe357211f2c335a9e6007067c3392fcf",
-                "sha256:894b1acded706f1407a662d08e026bfd0ff1e59e9bd32062fea9d862564cfb65",
-                "sha256:900532713115ac58bc3491b9d2b52704a05ed408ba0918d57fd72c94bc47fba1",
-                "sha256:976cd92d9420e6e2aa6ce6a9d61f2b490e07cb468968adf371546b33b829284b",
-                "sha256:97de509043d3f0f2b2cd171bdccf408f175c7f7a99d36d566b1ae4dd84107985",
-                "sha256:9a42970ce74c88bdf144df11c52c5cf4ad610d860de87c0883385a1c9d9fa4ab",
-                "sha256:9e41c94035e5cdb362beed681b58a707e8dc29ea446ea1713d92afeded9d1ddd",
-                "sha256:9f805481d5eff2a96bac4da1570ef662bf970f9a16580dc2c169c8c3183fa02b",
-                "sha256:a35c97af60a5492e9e89f8b7153fe24eadfd61cb3a2fb600df1a25b5dab34b7e",
-                "sha256:a7c6574225f34ce45466f04751d957b5c5e6b69fca9351db017c9249786172ce",
-                "sha256:c7ebf2a37e4f5fea3c1a11e1f47cea7d75d0f2d8ef69635ddbd5c927083211fc",
-                "sha256:d0305e02e40c7cfea5d08d6368576537a74c0eea62b77633179748d3519d6705",
-                "sha256:e1046aab24c48c694f0793f669ac49ea68acde6a0798ac5388abe0a5615b5ec8",
-                "sha256:e5d22eba19273b2069e4efeff88c897a26bdc64633cbe0357a198f92dca94268",
-                "sha256:ec27e93bbf5976f0465e8936f02eb5add99bbe4e4e7b233607e4d7622912d68d",
-                "sha256:fe76d6dee5e4febefa83998b17926df3a04e5089e3d2b1688c74a9157798d7a2"
+                "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523",
+                "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f",
+                "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d",
+                "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb",
+                "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0",
+                "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c",
+                "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98",
+                "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83",
+                "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8",
+                "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7",
+                "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac",
+                "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84",
+                "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb",
+                "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3",
+                "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884",
+                "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614",
+                "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd",
+                "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807",
+                "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd",
+                "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8",
+                "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc",
+                "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db",
+                "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0",
+                "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08",
+                "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232",
+                "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d",
+                "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a",
+                "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1",
+                "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286",
+                "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303",
+                "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341",
+                "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84",
+                "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45",
+                "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc",
+                "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec",
+                "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd",
+                "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155",
+                "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52",
+                "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d",
+                "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485",
+                "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31",
+                "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d",
+                "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d",
+                "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d",
+                "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85",
+                "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce",
+                "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb",
+                "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974",
+                "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24",
+                "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56",
+                "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9",
+                "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"
             ],
             "index": "pypi",
-            "version": "==7.5.2"
+            "markers": "python_version >= '3.8'",
+            "version": "==7.5.3"
         },
         "docker": {
             "hashes": [
@@ -1818,6 +1837,12 @@
             "markers": "python_version >= '3.8'",
             "version": "==7.1.0"
         },
+        "events": {
+            "hashes": [
+                "sha256:a7286af378ba3e46640ac9825156c93bdba7502174dd696090fdfcd4d80a1abd"
+            ],
+            "version": "==0.5"
+        },
         "idna": {
             "hashes": [
                 "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc",
@@ -1844,11 +1869,12 @@
         },
         "opensearch-py": {
             "hashes": [
-                "sha256:0dde4ac7158a717d92a8cd81964cb99705a4b80bcf9258ba195b9a9f23f5226d",
-                "sha256:cf093a40e272b60663f20417fc1264ac724dcf1e03c1a4542a6b44835b1e6c49"
+                "sha256:0b7c27e8ed84c03c99558406927b6161f186a72502ca6d0325413d8e5523ba96",
+                "sha256:b6e78b685dd4e9c016d7a4299cf1de69e299c88322e3f81c716e6e23fe5683c1"
             ],
             "index": "pypi",
-            "version": "==2.5.0"
+            "markers": "python_version >= '3.8' and python_version < '4'",
+            "version": "==2.6.0"
         },
         "packaging": {
             "hashes": [
@@ -1918,6 +1944,7 @@
                 "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.8'",
             "version": "==8.2.1"
         },
         "python-dateutil": {
@@ -1930,11 +1957,12 @@
         },
         "requests": {
             "hashes": [
-                "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289",
-                "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"
+                "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760",
+                "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"
             ],
             "index": "pypi",
-            "version": "==2.32.2"
+            "markers": "python_version >= '3.8'",
+            "version": "==2.32.3"
         },
         "requests-mock": {
             "hashes": [
@@ -1942,6 +1970,7 @@
                 "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.5'",
             "version": "==1.12.1"
         },
         "six": {
@@ -1964,6 +1993,7 @@
                 "sha256:54d330d085c0a11fc5da0b001af87aec4dd3e814104376bf7513e8646c77442a"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.7'",
             "version": "==0.0.1rc1"
         },
         "testcontainers-opensearch": {
@@ -1971,23 +2001,24 @@
                 "sha256:0bdf270b5b7f53915832f7c31dd2bd3ffdc20b534ea6b32231cc7003049bd0e1"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.7'",
             "version": "==0.0.1rc1"
         },
         "typing-extensions": {
             "hashes": [
-                "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8",
-                "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"
+                "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a",
+                "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==4.12.0"
+            "version": "==4.12.1"
         },
         "urllib3": {
             "hashes": [
-                "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07",
-                "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"
+                "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d",
+                "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"
             ],
-            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
-            "version": "==1.26.18"
+            "markers": "python_version >= '3.8'",
+            "version": "==2.2.1"
         },
         "wrapt": {
             "hashes": [
diff --git a/dbrepo-analyse-service/determine_dt.py b/dbrepo-analyse-service/determine_dt.py
index 5aa34240e4fa32be83e2e9626bf04931479b3d98..7c5401a20c3c37c12405c424161a5fb89e585bcd 100644
--- a/dbrepo-analyse-service/determine_dt.py
+++ b/dbrepo-analyse-service/determine_dt.py
@@ -9,7 +9,6 @@ import pandas
 
 from numpy import dtype, max, min
 from flask import current_app
-from pandas._libs.tslibs.parsing import DateParseError
 
 from clients.s3_client import S3Client
 
@@ -65,7 +64,7 @@ def determine_datatypes(filename, enum=False, enum_tol=0.0001, separator=None) -
                     pandas.to_datetime(df[name], format='mixed')
                     r[name] = 'timestamp'
                     continue
-                except DateParseError:
+                except ValueError:
                     pass
                 max_size = max(df[name].astype(str).map(len))
                 if max_size <= 1:
diff --git a/dbrepo-analyse-service/lib/dbrepo-1.4.4-py3-none-any.whl b/dbrepo-analyse-service/lib/dbrepo-1.4.4-py3-none-any.whl
index 4acaa2f242aa1a17081c6b649879afacfa191dad..f58e17a58e747e35bbd37f43efe6b460ba31530f 100644
Binary files a/dbrepo-analyse-service/lib/dbrepo-1.4.4-py3-none-any.whl and b/dbrepo-analyse-service/lib/dbrepo-1.4.4-py3-none-any.whl differ
diff --git a/dbrepo-analyse-service/lib/dbrepo-1.4.4.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.4.4.tar.gz
index e0bdb5adee8536ec4455e215913a6a769237b1e9..5463f6b170c24fff05d29a434562104553292fea 100644
Binary files a/dbrepo-analyse-service/lib/dbrepo-1.4.4.tar.gz and b/dbrepo-analyse-service/lib/dbrepo-1.4.4.tar.gz differ
diff --git a/dbrepo-data-service/Dockerfile b/dbrepo-data-service/Dockerfile
index 0d278d8a016734b9daf3740d54f8d5273b6fe3c7..69edbda3150e0a02b3ce6369052dd189a726d6ea 100644
--- a/dbrepo-data-service/Dockerfile
+++ b/dbrepo-data-service/Dockerfile
@@ -21,7 +21,7 @@ COPY ./services ./services
 RUN mvn clean package -DskipTests
 
 ###### THIRD STAGE ######
-FROM eclipse-temurin:17-jdk as runtime
+FROM amazoncorretto:17-alpine3.19 as runtime
 MAINTAINER Martin Weise <martin.weise@tuwien.ac.at>
 
 WORKDIR /app
diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
index d00089687032e3ae0ccfd84309620b264438c0be..b93ff32264e730c42f9b3c193dfa845d4ec0e4d8 100644
--- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
+++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
@@ -212,7 +212,9 @@ public class TableEndpoint {
     @PostMapping("/{tableId}/data")
     @PreAuthorize("hasAuthority('insert-table-data')")
     @Observed(name = "dbrepo_table_data_create")
-    @Operation(summary = "Create table data", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")})
+    @Operation(summary = "Insert a raw data tuple",
+            description = "Inserts a raw data tuple into a table with at least WRITE_OWN access. Then update the table statistics.",
+            security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")})
     @ApiResponses(value = {
             @ApiResponse(responseCode = "201",
                     description = "Created table data"),
@@ -237,13 +239,13 @@ public class TableEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<Void> createTuple(@NotBlank @PathVariable("databaseId") Long databaseId,
-                                            @NotBlank @PathVariable("tableId") Long tableId,
-                                            @Valid @RequestBody TupleDto data,
-                                            @NotNull Principal principal)
+    public ResponseEntity<Void> insertRawTuple(@NotBlank @PathVariable("databaseId") Long databaseId,
+                                               @NotBlank @PathVariable("tableId") Long tableId,
+                                               @Valid @RequestBody TupleDto data,
+                                               @NotNull Principal principal)
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
             TableMalformedException, QueryMalformedException, NotAllowedException {
-        log.debug("endpoint create table data, databaseId={}, tableId={}", databaseId, tableId);
+        log.debug("endpoint insert raw table data, databaseId={}, tableId={}", databaseId, tableId);
         final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId);
         final DatabaseAccessDto access = metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal));
         endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), UserUtil.getId(principal));
@@ -262,7 +264,9 @@ public class TableEndpoint {
     @PutMapping("/{tableId}/data")
     @PreAuthorize("hasAuthority('insert-table-data')")
     @Observed(name = "dbrepo_table_data_update")
-    @Operation(summary = "Update table data", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")})
+    @Operation(summary = "Update a raw data tuple",
+            description = "Updates a raw data tuple in a table with at least WRITE_OWN access. Then update the table statistics.",
+            security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")})
     @ApiResponses(value = {
             @ApiResponse(responseCode = "202",
                     description = "Updated table data"),
@@ -287,13 +291,13 @@ public class TableEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<Void> updateTuple(@NotBlank @PathVariable("databaseId") Long databaseId,
-                                            @NotBlank @PathVariable("tableId") Long tableId,
-                                            @Valid @RequestBody TupleUpdateDto data,
-                                            @NotNull Principal principal)
+    public ResponseEntity<Void> updateRawTuple(@NotBlank @PathVariable("databaseId") Long databaseId,
+                                               @NotBlank @PathVariable("tableId") Long tableId,
+                                               @Valid @RequestBody TupleUpdateDto data,
+                                               @NotNull Principal principal)
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
             TableMalformedException, QueryMalformedException, NotAllowedException {
-        log.debug("endpoint update table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId,
+        log.debug("endpoint update raw table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId,
                 data.getKeys());
         final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId);
         final DatabaseAccessDto access = metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal));
@@ -313,7 +317,9 @@ public class TableEndpoint {
     @DeleteMapping("/{tableId}/data")
     @PreAuthorize("hasAuthority('delete-table-data')")
     @Observed(name = "dbrepo_table_data_delete")
-    @Operation(summary = "Delete table data", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")})
+    @Operation(summary = "Delete table data",
+            description = "Deletes a raw data tuple in a table with at least WRITE_OWN access. Then update the table statistics.",
+            security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")})
     @ApiResponses(value = {
             @ApiResponse(responseCode = "202",
                     description = "Deleted table data"),
@@ -338,13 +344,13 @@ public class TableEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<Void> deleteTuple(@NotBlank @PathVariable("databaseId") Long databaseId,
-                                            @NotBlank @PathVariable("tableId") Long tableId,
-                                            @Valid @RequestBody TupleDeleteDto data,
-                                            @NotNull Principal principal)
+    public ResponseEntity<Void> deleteRawTuple(@NotBlank @PathVariable("databaseId") Long databaseId,
+                                               @NotBlank @PathVariable("tableId") Long tableId,
+                                               @Valid @RequestBody TupleDeleteDto data,
+                                               @NotNull Principal principal)
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
             TableMalformedException, QueryMalformedException, NotAllowedException {
-        log.debug("endpoint update table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId,
+        log.debug("endpoint delete raw table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId,
                 data.getKeys());
         final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId);
         final DatabaseAccessDto access = metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal));
@@ -524,12 +530,14 @@ public class TableEndpoint {
     @PostMapping("/{tableId}/data/import")
     @Observed(name = "dbrepo_table_data_import")
     @PreAuthorize("hasAuthority('insert-table-data')")
-    @Operation(summary = "Import dataset", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")})
+    @Operation(summary = "Import data from a dataset",
+            description = "Deletes a raw data tuple in a table with at least WRITE_OWN access. Then update the table statistics.",
+            security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")})
     @ApiResponses(value = {
             @ApiResponse(responseCode = "202",
-                    description = "Import dataset successfully"),
+                    description = "Imported dataset successfully"),
             @ApiResponse(responseCode = "400",
-                    description = "Import dataset query is malformed",
+                    description = "Dataset query is malformed",
                     content = {@Content(
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
@@ -549,10 +557,10 @@ public class TableEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<Void> importData(@NotBlank @PathVariable("databaseId") Long databaseId,
-                                           @NotBlank @PathVariable("tableId") Long tableId,
-                                           @Valid @RequestBody ImportCsvDto data,
-                                           @NotNull Principal principal)
+    public ResponseEntity<Void> importDataset(@NotBlank @PathVariable("databaseId") Long databaseId,
+                                              @NotBlank @PathVariable("tableId") Long tableId,
+                                              @Valid @RequestBody ImportCsvDto data,
+                                              @NotNull Principal principal)
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
             QueryMalformedException, StorageNotFoundException, SidecarImportException, NotAllowedException {
         log.debug("endpoint insert table data, databaseId={}, tableId={}, data.location={}", databaseId, tableId, data.getLocation());
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java
index fd93a3ae967be7290776b8d4d910c25a93f12c9a..73760a5a2ab824ff44f550860836c1b79da87bae 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java
@@ -205,7 +205,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO);
 
         /* test */
-        final ResponseEntity<Void> response = tableEndpoint.createTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
+        final ResponseEntity<Void> response = tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
         assertEquals(HttpStatus.CREATED, response.getStatusCode());
     }
 
@@ -221,7 +221,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
-            tableEndpoint.createTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -242,7 +242,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(TableNotFoundException.class, () -> {
-            tableEndpoint.createTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -265,7 +265,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            tableEndpoint.createTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -287,7 +287,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO);
 
         /* test */
-        tableEndpoint.createTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
+        tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
     }
 
     @Test
@@ -309,7 +309,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            tableEndpoint.createTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -331,7 +331,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO);
 
         /* test */
-        tableEndpoint.createTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+        tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
     }
 
     @Test
@@ -363,7 +363,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO);
 
         /* test */
-        final ResponseEntity<Void> response = tableEndpoint.updateTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
+        final ResponseEntity<Void> response = tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
     }
 
@@ -382,7 +382,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
-            tableEndpoint.updateTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -406,7 +406,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(TableNotFoundException.class, () -> {
-            tableEndpoint.updateTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -432,7 +432,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            tableEndpoint.updateTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -466,7 +466,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO);
 
         /* test */
-        final ResponseEntity<Void> response = tableEndpoint.updateTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
+        final ResponseEntity<Void> response = tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
     }
 
@@ -492,7 +492,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            tableEndpoint.updateTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -526,7 +526,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO);
 
         /* test */
-        final ResponseEntity<Void> response = tableEndpoint.updateTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+        final ResponseEntity<Void> response = tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
     }
 
@@ -555,7 +555,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO);
 
         /* test */
-        final ResponseEntity<Void> response = tableEndpoint.deleteTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
+        final ResponseEntity<Void> response = tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
     }
 
@@ -570,7 +570,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
-            tableEndpoint.deleteTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -590,7 +590,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(TableNotFoundException.class, () -> {
-            tableEndpoint.deleteTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -612,7 +612,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            tableEndpoint.deleteTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -642,7 +642,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO);
 
         /* test */
-        final ResponseEntity<Void> response = tableEndpoint.deleteTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
+        final ResponseEntity<Void> response = tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
     }
 
@@ -664,7 +664,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            tableEndpoint.deleteTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -694,7 +694,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO);
 
         /* test */
-        final ResponseEntity<Void> response = tableEndpoint.deleteTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+        final ResponseEntity<Void> response = tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
     }
 
@@ -828,7 +828,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO);
 
         /* test */
-        final ResponseEntity<Void> response = tableEndpoint.importData(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
+        final ResponseEntity<Void> response = tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
     }
 
@@ -843,7 +843,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
-            tableEndpoint.importData(DATABASE_3_ID, TABLE_8_ID, request, USER_4_PRINCIPAL);
+            tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_4_PRINCIPAL);
         });
     }
 
@@ -863,7 +863,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(TableNotFoundException.class, () -> {
-            tableEndpoint.importData(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -885,7 +885,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            tableEndpoint.importData(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -907,7 +907,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO);
 
         /* test */
-        tableEndpoint.importData(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
+        tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
     }
 
     @Test
@@ -928,7 +928,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            tableEndpoint.importData(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
+            tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL);
         });
     }
 
@@ -950,7 +950,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO);
 
         /* test */
-        tableEndpoint.importData(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
+        tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL);
     }
 
 }
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
index 1b51d3072c52398288c68725b6b020d08e66e622..a49b264a03c313bfc68fd05c1e9d4e1ffe359b30 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
@@ -34,7 +34,6 @@ import org.springframework.test.web.servlet.MockMvc;
 
 import java.io.File;
 import java.io.IOException;
-import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.*;
 
@@ -177,17 +176,17 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest {
             /* ignore */
         }
         try {
-            tableEndpoint.createTuple(DATABASE_1_ID, TABLE_1_ID, TupleDto.builder().build(), USER_1_PRINCIPAL);
+            tableEndpoint.insertRawTuple(DATABASE_1_ID, TABLE_1_ID, TupleDto.builder().build(), USER_1_PRINCIPAL);
         } catch (Exception e) {
             /* ignore */
         }
         try {
-            tableEndpoint.updateTuple(DATABASE_1_ID, TABLE_1_ID, TupleUpdateDto.builder().build(), USER_1_PRINCIPAL);
+            tableEndpoint.updateRawTuple(DATABASE_1_ID, TABLE_1_ID, TupleUpdateDto.builder().build(), USER_1_PRINCIPAL);
         } catch (Exception e) {
             /* ignore */
         }
         try {
-            tableEndpoint.deleteTuple(DATABASE_1_ID, TABLE_1_ID, TupleDeleteDto.builder().build(), USER_1_PRINCIPAL);
+            tableEndpoint.deleteRawTuple(DATABASE_1_ID, TABLE_1_ID, TupleDeleteDto.builder().build(), USER_1_PRINCIPAL);
         } catch (Exception e) {
             /* ignore */
         }
@@ -207,7 +206,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest {
             /* ignore */
         }
         try {
-            tableEndpoint.importData(DATABASE_1_ID, TABLE_1_ID, ImportCsvDto.builder().build(), USER_1_PRINCIPAL);
+            tableEndpoint.importDataset(DATABASE_1_ID, TABLE_1_ID, ImportCsvDto.builder().build(), USER_1_PRINCIPAL);
         } catch (Exception e) {
             /* ignore */
         }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java
index b379c01cdff856ab09385a373dfb9173348ad8cb..e28d05929b51ff1376aaceb2ca39a4ff4b6783f8 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java
@@ -8,6 +8,7 @@ import at.tuwien.api.database.query.ImportCsvDto;
 import at.tuwien.api.database.query.QueryDto;
 import at.tuwien.api.database.query.QueryResultDto;
 import at.tuwien.api.database.table.*;
+import at.tuwien.api.database.table.columns.ColumnBriefDto;
 import at.tuwien.api.database.table.columns.ColumnCreateDto;
 import at.tuwien.api.database.table.columns.ColumnDto;
 import at.tuwien.api.database.table.columns.ColumnTypeDto;
@@ -27,6 +28,7 @@ import org.jetbrains.annotations.NotNull;
 import org.mapstruct.Mapper;
 import org.mapstruct.Named;
 
+import javax.swing.table.TableColumn;
 import java.io.*;
 import java.math.BigInteger;
 import java.nio.charset.StandardCharsets;
@@ -583,6 +585,8 @@ public interface MariaDbMapper {
 
     TableBriefDto tableDtoToTableBriefDto(TableDto data);
 
+    ColumnBriefDto columnDtoToColumnBriefDto(ColumnDto data);
+
     default TableDto resultSetToTable(ResultSet resultSet, TableDto table, QueryConfig queryConfig) throws SQLException {
         final ColumnDto column = ColumnDto.builder()
                 .ordinalPosition(resultSet.getInt(1) - 1) /* start at zero */
@@ -601,7 +605,7 @@ public interface MariaDbMapper {
         if (resultSet.getString(9) != null && resultSet.getString(9).equals("PRI")) {
             table.getConstraints().getPrimaryKey().add(PrimaryKeyDto.builder()
                     .table(tableDtoToTableBriefDto(table))
-                    .column(column)
+                    .column(columnDtoToColumnBriefDto(column))
                     .build());
         }
         /* fix boolean and set size for others */
diff --git a/dbrepo-metadata-service/Dockerfile b/dbrepo-metadata-service/Dockerfile
index b66fad27593c18dc7fad89161a7b7807fb4b21d7..5fd1138f24bcf19cd3bd3ad665d154a4d662c8c7 100644
--- a/dbrepo-metadata-service/Dockerfile
+++ b/dbrepo-metadata-service/Dockerfile
@@ -27,7 +27,7 @@ COPY ./test ./test
 RUN mvn clean install -DskipTests
 
 ###### SECOND STAGE ######
-FROM eclipse-temurin:17-jdk as runtime
+FROM amazoncorretto:17-alpine3.19 as runtime
 MAINTAINER Martin Weise <martin.weise@tuwien.ac.at>
 
 WORKDIR /app
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java
index 430bdba2704561274afbeeebcf56679e1ec7a10c..740b2184e72d5f8df4dba6a32cc852f134e58723 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java
@@ -122,7 +122,7 @@ public class ColumnDto {
 
     @ToString.Exclude
     @JsonIgnore
-    private transient TableDto table;
+    private TableDto table;
 
     @ToString.Exclude
     @JsonIgnore
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java
index 68ee2e56da310d8ab6b4ffa8e154ec6906c05135..9fe7c683827f86a95977b9af2d728254dff9974a 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java
@@ -23,9 +23,6 @@ public class ForeignKeyDto {
     @NotNull
     private String name;
 
-    @NotNull
-    private ColumnDto column;
-
     @NotNull
     private List<ForeignKeyReferenceDto> references;
 
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java
index 19c25371b2c67204a48728c705d550c8c8feec9e..25ad3f5d175cc8aeb4d07011c2bc9829da7242a6 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java
@@ -1,7 +1,7 @@
 package at.tuwien.api.database.table.constraints.primary;
 
 import at.tuwien.api.database.table.TableBriefDto;
-import at.tuwien.api.database.table.columns.ColumnDto;
+import at.tuwien.api.database.table.columns.ColumnBriefDto;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
@@ -15,7 +15,7 @@ import lombok.extern.jackson.Jacksonized;
 @ToString
 public class PrimaryKeyDto {
 
-    private Long pkid;
+    private Long id;
 
     @NotNull
     @ToString.Exclude
@@ -23,5 +23,5 @@ public class PrimaryKeyDto {
 
     @NotNull
     @ToString.Exclude
-    private ColumnDto column;
+    private ColumnBriefDto column;
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java
index 10f97e83904a4af1e6bcbba0d24e4e038edec573..05de53784457602248105e8ccd7a6987db53dd51 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java
@@ -21,7 +21,7 @@ import java.util.List;
 public class UniqueDto {
 
     @NotNull
-    private Long uid;
+    private Long id;
 
     @NotNull
     private String name;
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKey.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKey.java
index 83e0d356561c0ea47f1c6278680571e8c27bf17b..e5a58f5d0d37f14ba812f030b70a81a213e8219f 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKey.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKey.java
@@ -6,6 +6,7 @@ import org.hibernate.annotations.GenericGenerator;
 import org.springframework.data.jpa.domain.support.AuditingEntityListener;
 
 import jakarta.persistence.*;
+
 import java.util.List;
 
 @Data
@@ -23,8 +24,8 @@ public class ForeignKey {
     @EqualsAndHashCode.Include
     @GeneratedValue(generator = "foreign-key-sequence")
     @GenericGenerator(name = "foreign-key-sequence", strategy = "increment")
-    @Column(updatable = false, nullable = false)
-    private Long fkid;
+    @Column(name = "fkid", updatable = false, nullable = false)
+    private Long id;
 
     @Column(updatable = false, nullable = false)
     private String name;
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java
index 8a30122286b09361f340b07fb2f4053c9b38a474..c4ccc379c58d88df8bc2ccc0429bd969d0e5c031 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java
@@ -22,8 +22,8 @@ public class PrimaryKey {
     @EqualsAndHashCode.Include
     @GeneratedValue(generator = "foreign-key-sequence")
     @GenericGenerator(name = "foreign-key-sequence", strategy = "increment")
-    @Column(updatable = false, nullable = false)
-    private Long pkid;
+    @Column(name = "pkid", updatable = false, nullable = false)
+    private Long id;
 
     @ToString.Exclude
     @org.springframework.data.annotation.Transient
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java
index 269410a8c88f3197db69c706b933ca2667d62911..25ed2eae5d551896b6836cb6bd5c8bdd36724748 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java
@@ -25,8 +25,8 @@ public class Unique {
     @EqualsAndHashCode.Include
     @GeneratedValue(generator = "constraints-unique-sequence")
     @GenericGenerator(name = "constraints-unique-sequence", strategy = "increment")
-    @Column(updatable = false, nullable = false)
-    private Long uid;
+    @Column(name = "uid", updatable = false, nullable = false)
+    private Long id;
 
     @Column(updatable = false, nullable = false)
     private String name;
diff --git a/dbrepo-metadata-service/pom.xml b/dbrepo-metadata-service/pom.xml
index 2e6651d9cfac0e2e7a20b403886ca18e752da2d6..464cf28ed983e940a7d96736c4fe7807f55a11aa 100644
--- a/dbrepo-metadata-service/pom.xml
+++ b/dbrepo-metadata-service/pom.xml
@@ -34,26 +34,6 @@
             <email>martin.weise@tuwien.ac.at</email>
             <organization>TU Wien</organization>
         </developer>
-        <developer>
-            <name>Moritz Staudinger</name>
-            <email>moritz.staudinger@tuwien.ac.at</email>
-            <organization>TU Wien</organization>
-        </developer>
-        <developer>
-            <name>Tobias Grantner</name>
-            <email>tobias.grantner@tuwien.ac.at</email>
-            <organization>TU Wien</organization>
-        </developer>
-        <developer>
-            <name>Sotirios Tsepelakis</name>
-            <email>sotirios.tsepelakis@tuwien.ac.at</email>
-            <organization>TU Wien</organization>
-        </developer>
-        <developer>
-            <name>Geoffrey Karnbach</name>
-            <email>geoffrey.karnbach@tuwien.ac.at</email>
-            <organization>TU Wien</organization>
-        </developer>
     </developers>
 
     <properties>
@@ -192,6 +172,11 @@
             <artifactId>commons-validator</artifactId>
             <version>${commons-validator.version}</version>
         </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-hibernate6</artifactId>
+            <version>${jackson-datatype.version}</version>
+        </dependency>
         <!-- Authentication -->
         <dependency>
             <groupId>org.keycloak</groupId>
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/AccessMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/AccessMapper.java
deleted file mode 100644
index 9ce8f74cce350ce44fe4dac3247fed74bc3013e8..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/AccessMapper.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.database.AccessTypeDto;
-import at.tuwien.entities.database.AccessType;
-import org.mapstruct.Mapper;
-
-@Mapper(componentModel = "spring")
-public interface AccessMapper {
-
-    AccessTypeDto accessType(AccessType data);
-
-    AccessType accessType(AccessTypeDto data);
-
-}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/AuthenticationMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/AuthenticationMapper.java
deleted file mode 100644
index 9d00f7e159748aa20dcb4cbf4df067c696f18b1a..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/AuthenticationMapper.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package at.tuwien.mapper;
-
-import org.mapstruct.Mapper;
-import org.springframework.http.MediaType;
-import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
-
-import java.util.Collections;
-
-@Mapper(componentModel = "spring", uses = {UserMapper.class})
-public interface AuthenticationMapper {
-
-    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AuthenticationMapper.class);
-
-    default MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
-        final MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
-        mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_FORM_URLENCODED));
-        return mappingJackson2HttpMessageConverter;
-    }
-}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/BannerMessageMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/BannerMessageMapper.java
deleted file mode 100644
index 8fd2b7dc51936768af6e2d9410887c15e6f19c1b..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/BannerMessageMapper.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.maintenance.BannerMessageBriefDto;
-import at.tuwien.api.maintenance.BannerMessageCreateDto;
-import at.tuwien.api.maintenance.BannerMessageDto;
-import at.tuwien.api.maintenance.BannerMessageTypeDto;
-import at.tuwien.entities.maintenance.BannerMessage;
-import at.tuwien.entities.maintenance.BannerMessageType;
-import org.mapstruct.Mapper;
-
-@Mapper(componentModel = "spring")
-public interface BannerMessageMapper {
-
-    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BannerMessageMapper.class);
-
-    BannerMessageDto bannerMessageToBannerMessageDto(BannerMessage data);
-
-    BannerMessageBriefDto bannerMessageToBannerMessageBriefDto(BannerMessage data);
-
-    BannerMessage bannerMessageCreateDtoToBannerMessage(BannerMessageCreateDto data);
-
-    BannerMessageType bannerMessageTypeDtoToBannerMessageType(BannerMessageTypeDto data);
-
-}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ContainerMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ContainerMapper.java
deleted file mode 100644
index 3f6cf3c302488634b02f8ee6999e9f6f5c247258..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ContainerMapper.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.container.ContainerBriefDto;
-import at.tuwien.api.container.ContainerCreateDto;
-import at.tuwien.api.container.ContainerDto;
-import at.tuwien.entities.container.Container;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.Mappings;
-import org.mapstruct.Named;
-
-import java.text.Normalizer;
-import java.util.Locale;
-import java.util.regex.Pattern;
-
-@Mapper(componentModel = "spring", uses = {ImageMapper.class, DatabaseMapper.class, UserMapper.class})
-public interface ContainerMapper {
-
-    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ContainerMapper.class);
-
-    @Mappings({
-            @Mapping(target = "internalName", source = "name", qualifiedByName = "internalNameMapping")
-    })
-    Container containerCreateRequestDtoToContainer(ContainerCreateDto data);
-
-    ContainerDto containerToContainerDto(Container data);
-
-    @Mappings({
-            @Mapping(target = "id", source = "id")
-    })
-    ContainerBriefDto containerToDatabaseContainerBriefDto(Container data);
-
-    // https://stackoverflow.com/questions/1657193/java-code-library-for-generating-slugs-for-use-in-pretty-urls#answer-1657250
-    @Named("internalNameMapping")
-    default String containerToInternalContainerName(String containerName) {
-        final Pattern NONLATIN = Pattern.compile("[^\\w-]");
-        final Pattern WHITESPACE = Pattern.compile("[\\s]");
-        String nowhitespace = WHITESPACE.matcher(containerName).replaceAll("-");
-        String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD);
-        String slug = NONLATIN.matcher(normalized).replaceAll("");
-        final String name = "dbrepo-userdb-" + slug.toLowerCase(Locale.ENGLISH);
-        log.trace("mapped container name {} to internal name {}", containerName, name);
-        return name;
-    }
-}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DataCiteMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DataCiteMapper.java
deleted file mode 100644
index 749f086fcb573290a0c5213d8e33ea3d4819b9d6..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DataCiteMapper.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.datacite.doi.*;
-import at.tuwien.entities.database.License;
-import at.tuwien.entities.identifier.*;
-import at.tuwien.utils.EnumToStringConverter;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.MappingTarget;
-import org.mapstruct.Mappings;
-import org.springframework.context.annotation.Profile;
-
-import java.util.LinkedList;
-import java.util.List;
-
-@Profile("doi")
-@Mapper(componentModel = "spring", uses = EnumToStringConverter.class)
-public interface DataCiteMapper {
-
-    default <T> List<T> list(T t) {
-        if (t == null) return null;
-        return List.of(t);
-    }
-
-    @Mappings({
-            @Mapping(target = "titles", source = "."),
-            @Mapping(target = "publisher", source = "publisher"),
-            @Mapping(target = "publicationYear", source = "publicationYear"),
-            @Mapping(target = "publicationMonth", source = "publicationMonth"),
-            @Mapping(target = "publicationDay", source = "publicationDay"),
-            @Mapping(target = "language", source = "language"),
-            @Mapping(target = "creators", source = "creators"),
-    })
-    DataCiteCreateDoi identifierToDataCiteCreateDoi(Identifier identifier);
-
-    default DataCiteCreateDoi identifierToDataCiteCreateDoi(Identifier identifier, String url, String prefix,
-                                                            DataCiteDoiEvent event) {
-        return addParametersToCreateDoi(
-                identifierToDataCiteCreateDoi(identifier),
-                url,
-                prefix,
-                DataCiteDoiTypes.DATASET,
-                event
-        );
-    }
-
-    DataCiteDoiTitle identifierTitleToDataCiteDoiTitle(IdentifierTitle data);
-
-    default DataCiteDoiTitle.Type titleTypeToDataCiteDoiTitleType(TitleType data) {
-        if (data == null) {
-            return null;
-        }
-        return switch (data) {
-            case OTHER -> DataCiteDoiTitle.Type.OTHER;
-            case TRANSLATED_TITLE -> DataCiteDoiTitle.Type.TRANSLATED_TITLE;
-            case SUBTITLE -> DataCiteDoiTitle.Type.SUBTITLE;
-            case ALTERNATIVE_TITLE -> DataCiteDoiTitle.Type.ALTERNATIVE_TITLE;
-        };
-    }
-
-    default List<DataCiteDoiTitle> identifierToDataCiteDoiTitleList(Identifier data) {
-        if (data.getTitles() == null) {
-            return new LinkedList<>();
-        }
-        return data.getTitles()
-                .stream()
-                .map(this::identifierTitleToDataCiteDoiTitle)
-                .toList();
-    }
-
-    DataCiteCreateDoi addParametersToCreateDoi(@MappingTarget DataCiteCreateDoi target, String url, String prefix,
-                                               DataCiteDoiTypes types, DataCiteDoiEvent event);
-
-    @Mappings({
-            @Mapping(target = "rights", source = "identifier"),
-            @Mapping(target = "rightsUri", source = "uri"),
-    })
-    DataCiteDoiRights licenseToDoiRights(License license);
-
-    @Mappings({
-            @Mapping(target = "name", expression = "java(data.getLastname() + \", \" + data.getFirstname())"),
-            @Mapping(target = "givenName", source = "firstname"),
-            @Mapping(target = "familyName", source = "lastname"),
-            @Mapping(target = "nameType", expression = "java(nameTypeToDataCiteNameType(data.getNameType()))"),
-            @Mapping(target = "affiliation", expression = "java(list(creatorToDoiCreatorAffiliation(data)))"),
-            @Mapping(target = "nameIdentifier", expression = "java(list(creatorToDataCiteDoiCreatorNameIdentifier(data)))"),
-    })
-    DataCiteDoiCreator creatorToDoiCreator(Creator data);
-
-    DataCiteDoiCreatorNameIdentifier creatorToDataCiteDoiCreatorNameIdentifier(Creator data);
-
-    /* keep */
-    default String nameIdentifierSchemeTypeToUri(NameIdentifierSchemeType data) {
-        switch (data) {
-            case ROR -> {
-                return "https://ror.org/";
-            }
-            case ORCID -> {
-                return "https://orcid.org/";
-            }
-            case ISNI -> {
-                return "https://isni.org/isni/";
-            }
-            case GRID -> {
-                return "https://www.grid.ac/";
-            }
-        }
-        return null;
-    }
-
-    /* keep */
-    default DataCiteNameType nameTypeToDataCiteNameType(NameType data) {
-        if (data == null) {
-            return null;
-        }
-        return DataCiteNameType.valueOf(data.toString());
-    }
-
-    @Mappings({
-            @Mapping(target = "name", source = "affiliation"),
-            @Mapping(target = "affiliationIdentifier", source = "affiliationIdentifier"),
-            @Mapping(target = "affiliationScheme", source = "affiliationIdentifierScheme"),
-            @Mapping(target = "schemeUri", source = "affiliationIdentifierSchemeUri"),
-    })
-    DataCiteDoiCreatorAffiliation creatorToDoiCreatorAffiliation(Creator data);
-
-    @Mappings({
-            @Mapping(target = "relatedIdentifier", source = "value"),
-            @Mapping(target = "relatedIdentifierType", source = "type"),
-            @Mapping(target = "relationType", source = "relation"),
-    })
-    DataCiteDoiRelatedIdentifier relatedIdentifierToDoiRelatedIdentifier(RelatedIdentifier relatedIdentifier);
-}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DatabaseMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DatabaseMapper.java
deleted file mode 100644
index c2428f5f2aaa7ffd7eef9f413a6f23e633ed5be2..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DatabaseMapper.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.database.*;
-import at.tuwien.entities.container.image.ContainerImage;
-import at.tuwien.entities.database.*;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.Mappings;
-import org.mapstruct.Named;
-
-import java.text.Normalizer;
-import java.util.Locale;
-import java.util.regex.Pattern;
-
-@Mapper(componentModel = "spring", uses = {ContainerMapper.class, UserMapper.class, ImageMapper.class, UserMapper.class,
-        TableMapper.class, IdentifierMapper.class, ViewMapper.class})
-public interface DatabaseMapper {
-
-    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DatabaseMapper.class);
-
-    /* keep */
-    @Named("internalMapping")
-    default String nameToInternalName(String data) {
-        if (data == null || data.isEmpty()) {
-            return data;
-        }
-        final Pattern NONLATIN = Pattern.compile("[^\\w-]");
-        final Pattern WHITESPACE = Pattern.compile("[\\s]");
-        String nowhitespace = WHITESPACE.matcher(data).replaceAll("_");
-        String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD);
-        String slug = NONLATIN.matcher(normalized).replaceAll("");
-        final String name = slug.toLowerCase(Locale.ENGLISH);
-        log.debug("mapping name {} to internal name {}", data, name);
-        return name;
-    }
-
-    /* keep */
-    @Named("languageMapping")
-    LanguageType languageTypeDtoToLanguageType(LanguageTypeDto data);
-
-    @Named("engineMapping")
-    default String containerImageToEngine(ContainerImage data) {
-        return data.getName() + ":" + data.getVersion();
-    }
-
-    @Mappings({
-            @Mapping(target = "created", source = "created", dateFormat = "dd-MM-yyyy HH:mm"),
-    })
-    DatabaseDto databaseToDatabaseDto(Database data);
-
-    @Mappings({
-            @Mapping(target = "created", source = "created", dateFormat = "dd-MM-yyyy HH:mm"),
-    })
-    DatabaseBriefDto databaseToDatabaseBriefDto(Database data);
-
-    AccessType accessTypeDtoToAccessType(AccessTypeDto data);
-
-    AccessTypeDto accessTypeToAccessTypeDto(AccessType data);
-
-    DatabaseAccessDto databaseAccessToDatabaseAccessDto(DatabaseAccess data);
-
-}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DocumentMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DocumentMapper.java
deleted file mode 100644
index 9a4fc4840def5978ecd19f6ac5e5aceae168a473..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DocumentMapper.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package at.tuwien.mapper;
-
-import org.mapstruct.Mapper;
-
-import java.time.Instant;
-import java.util.Date;
-
-@Mapper(componentModel = "spring")
-public interface DocumentMapper {
-
-    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DocumentMapper.class);
-
-    Date instantToDate(Instant data);
-
-}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ExternalMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ExternalMapper.java
deleted file mode 100644
index 8ab57977706326894c8a152e8b690dd049729fc5..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ExternalMapper.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.crossref.CrossrefDto;
-import at.tuwien.api.orcid.OrcidDto;
-import at.tuwien.api.orcid.activities.employments.affiliation.OrcidAffiliationGroupDto;
-import at.tuwien.api.orcid.activities.employments.affiliation.group.OrcidEmploymentSummaryDto;
-import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedDto;
-import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedSourceTypeDto;
-import at.tuwien.api.ror.RorDto;
-import at.tuwien.api.user.external.ExternalMetadataDto;
-import at.tuwien.api.user.external.ExternalResultType;
-import at.tuwien.api.user.external.affiliation.ExternalAffiliationDto;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.Mappings;
-
-@Mapper(componentModel = "spring", imports = {ExternalResultType.class})
-public interface ExternalMapper {
-
-
-    @Mappings({
-            @Mapping(target = "givenNames", source = "person.name.givenNames.value"),
-            @Mapping(target = "familyName", source = "person.name.familyName.value"),
-            @Mapping(target = "type", expression = "java(ExternalResultType.PERSONAL)"),
-            @Mapping(target = "affiliations", source = "activitiesSummary.employments.affiliationGroup"),
-    })
-    ExternalMetadataDto orcidDtoToExternalMetadataDto(OrcidDto data);
-
-    @Mappings({
-            @Mapping(target = "organizationName", source = "employmentSummary.organization.name"),
-            @Mapping(target = "ringgoldId", expression = "java(disambiguatedOrganizationToRinggoldId(data.getEmploymentSummary().getOrganization().getDisambiguatedOrganization()))"),
-    })
-    ExternalAffiliationDto orcidEmploymentSummaryDtoToExternalAffiliationDto(OrcidEmploymentSummaryDto data);
-
-    default ExternalAffiliationDto orcidAffiliationGroupDtoToExternalAffiliationDto(OrcidAffiliationGroupDto data) {
-        if (data == null || data.getSummaries() == null || data.getSummaries().length == 0) {
-            return null;
-        }
-        return ExternalAffiliationDto.builder()
-                .organizationName(data.getSummaries()[0].getEmploymentSummary().getOrganization().getName())
-                .build();
-    }
-
-    default Long disambiguatedOrganizationToRinggoldId(OrcidDisambiguatedDto data) {
-        if (data.getSource().equals(OrcidDisambiguatedSourceTypeDto.RINGGOLD)) {
-            return Long.parseLong(data.getIdentifier());
-        }
-        return null;
-    }
-
-    default ExternalMetadataDto rorDtoToExternalMetadataDto(RorDto data) {
-        return ExternalMetadataDto.builder()
-                .affiliations(new ExternalAffiliationDto[]{
-                        ExternalAffiliationDto.builder()
-                                .organizationName(data.getName())
-                                .build()})
-                .type(ExternalResultType.ORGANIZATIONAL)
-                .build();
-    }
-
-    default ExternalMetadataDto crossrefDtoToExternalMetadataDto(CrossrefDto data) {
-        return ExternalMetadataDto.builder()
-                .affiliations(new ExternalAffiliationDto[]{
-                        ExternalAffiliationDto.builder()
-                                .crossrefFunderId(data.getId())
-                                .organizationName(data.getPrefLabel().getLabel().getLiteralForm().getContent())
-                                .build()})
-                .type(ExternalResultType.ORGANIZATIONAL)
-                .build();
-    }
-
-    @Mappings({
-            @Mapping(target = "organizationName", source = "name"),
-    })
-    ExternalAffiliationDto rorDtoToExternalAffiliationDto(RorDto data);
-}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/IdentifierMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/IdentifierMapper.java
deleted file mode 100644
index a4b7d28fa334b4ed360818537f9ef64262d56d5e..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/IdentifierMapper.java
+++ /dev/null
@@ -1,157 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.database.LanguageTypeDto;
-import at.tuwien.api.database.LicenseDto;
-import at.tuwien.api.identifier.*;
-import at.tuwien.api.identifier.ld.LdCreatorDto;
-import at.tuwien.api.identifier.ld.LdDatasetDto;
-import at.tuwien.entities.database.LanguageType;
-import at.tuwien.entities.database.License;
-import at.tuwien.entities.identifier.*;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.Mappings;
-import org.mapstruct.Named;
-
-import java.util.List;
-import java.util.Optional;
-
-@Mapper(componentModel = "spring", uses = {DatabaseMapper.class})
-public interface IdentifierMapper {
-
-    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(IdentifierMapper.class);
-
-    Identifier identifierDtoToIdentifier(IdentifierDto data);
-
-    @Mappings({
-            @Mapping(target = "databaseId", source = "database.id"),
-    })
-    IdentifierDto identifierToIdentifierDto(Identifier data);
-
-    IdentifierBriefDto identifierToIdentifierBriefDto(Identifier data);
-
-    default IdentifierTitle identifierToIdentifierTitle(Identifier data, String lang) {
-        final Optional<IdentifierTitle> optional = data.getTitles()
-                .stream()
-                .filter(t -> lang == null || t.getLanguage().getName().equals(lang))
-                .findFirst();
-        if (optional.isEmpty()) {
-            log.warn("no title with language {} found", lang);
-            return identifierToIdentifierTitle(data, "en");
-        }
-        return optional.get();
-    }
-
-    default IdentifierDescription identifierToIdentifierDescription(Identifier data, String lang) {
-        final Optional<IdentifierDescription> optional = data.getDescriptions()
-                .stream()
-                .filter(t -> lang == null || t.getLanguage().getName().equals(lang))
-                .findFirst();
-        if (optional.isEmpty()) {
-            log.warn("no description with language {} found", lang);
-            return identifierToIdentifierDescription(data, "en");
-        }
-        return optional.get();
-    }
-
-    @Mappings({
-            @Mapping(target = "givenName", source = "firstname"),
-            @Mapping(target = "familyName", source = "lastname"),
-            @Mapping(target = "type", expression = "java(data.getNameType().equals(NameType.PERSONAL) ? \"Person\" : \"Organization\")"),
-            @Mapping(target = "sameAs", source = "nameIdentifier"),
-            @Mapping(target = "name", source = "creatorName"),
-    })
-    LdCreatorDto creatorToLdCreatorDto(Creator data);
-
-    default LdDatasetDto identifierToLdDatasetDto(Identifier data, String baseUrl) {
-        return LdDatasetDto.builder()
-                .context("https://schema.org/")
-                .type("Dataset")
-                .name(identifierToIdentifierTitle(data, null)
-                        .getTitle())
-                .description(identifierToIdentifierDescription(data, null)
-                        .getDescription())
-                .url(identifierToLocationUrl(baseUrl, data))
-                .identifier(List.of())
-                .creator(data.getCreators()
-                        .stream()
-                        .map(this::creatorToLdCreatorDto)
-                        .toList())
-                .citation(identifierToLocationUrl(baseUrl, data))
-                .hasPart(List.of())
-                .license(data.getLicenses().isEmpty() ? null : data.getLicenses().get(0).getUri())
-                .temporalCoverage(null)
-                .version(data.getCreated())
-                .build();
-    }
-
-    Identifier identifierCreateDtoToIdentifier(IdentifierCreateDto data);
-
-    Identifier identifierUpdateDtoToIdentifier(IdentifierSaveDto data);
-
-    LanguageType languageTypeDtoToLanguageType(LanguageTypeDto data);
-
-    License licenseDtoToLicense(LicenseDto data);
-
-    IdentifierTitle identifierCreateTitleDtoToIdentifierTitle(IdentifierSaveTitleDto data);
-
-    IdentifierDescription identifierCreateDescriptionDtoToIdentifierDescription(IdentifierSaveDescriptionDto data);
-
-    IdentifierFunder identifierFunderSaveDtoToIdentifierFunder(IdentifierFunderSaveDto data);
-
-    IdentifierSaveDto identifierCreateDtoToIdentifierSaveDto(IdentifierCreateDto data);
-
-    RelatedIdentifierDto relatedIdentifierToRelatedIdentifierDto(RelatedIdentifier data);
-
-    Creator creatorDtoToCreator(CreatorDto data);
-
-    @Mappings({
-            @Mapping(target = "nameIdentifierSchemeUri", source = "nameIdentifierScheme", qualifiedByName = "nameSchemaMapper"),
-            @Mapping(target = "affiliationIdentifierSchemeUri", source = "affiliationIdentifierScheme", qualifiedByName = "affiliationSchemaMapper"),
-    })
-    Creator creatorCreateDtoToCreator(CreatorSaveDto data);
-
-    RelatedIdentifier relatedIdentifierCreateDtoToRelatedIdentifier(RelatedIdentifierSaveDto data);
-
-    IdentifierType identifierTypeDtoToIdentifierType(IdentifierTypeDto data);
-
-    default String identifierToLocationUrl(String baseUrl, Identifier data) {
-        if (data.getType().equals(IdentifierType.SUBSET)) {
-            return baseUrl + "/database/" + data.getDatabase().getId() + "/subset/" + data.getQueryId() + "/info?pid=" + data.getId();
-        } else if (data.getType().equals(IdentifierType.DATABASE)) {
-            return baseUrl + "/database/" + data.getDatabase().getId() + "/info?pid=" + data.getId();
-        } else if (data.getType().equals(IdentifierType.VIEW)) {
-            return baseUrl + "/database/" + data.getDatabase().getId() + "/view/" + data.getViewId() + "/info?pid=" + data.getId();
-        } else if (data.getType().equals(IdentifierType.TABLE)) {
-            return baseUrl + "/database/" + data.getDatabase().getId() + "/table/" + data.getTableId() + "/info?pid=" + data.getId();
-        } else {
-            return null;
-        }
-    }
-
-    @Named("nameSchemaMapper")
-    default String nameIdentifierSchemeToNameIdentifierSchemeUri(NameIdentifierSchemeTypeDto data) {
-        if (data == null) {
-            return null;
-        }
-        return switch (data) {
-            case ROR -> "https://ror.org/";
-            case ORCID -> "https://orcid.org/";
-            case GRID -> "https://grid.ac/";
-            case ISNI -> "https://grid.ac/institutes/";
-        };
-    }
-
-    @Named("affiliationSchemaMapper")
-    default String affiliationIdentifierSchemeTypeToAffiliationIdentifier(AffiliationIdentifierSchemeTypeDto data) {
-        if (data == null) {
-            return null;
-        }
-        return switch (data) {
-            case ROR -> "https://ror.org/";
-            case GRID -> "https://grid.ac/institutes/";
-            case ISNI -> "https://isni.org/";
-        };
-    }
-
-}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ImageMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ImageMapper.java
deleted file mode 100644
index 8ea6609f164127a43bf59647f9612758483ed76d..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ImageMapper.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.container.image.ImageBriefDto;
-import at.tuwien.api.container.image.ImageCreateDto;
-import at.tuwien.api.container.image.ImageDto;
-import at.tuwien.entities.container.image.ContainerImage;
-import org.mapstruct.Mapper;
-
-import java.time.Instant;
-
-@Mapper(componentModel = "spring")
-public interface ImageMapper {
-
-    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ImageMapper.class);
-
-    ContainerImage createImageDtoToContainerImage(ImageCreateDto data);
-
-    ImageBriefDto containerImageToImageBriefDto(ContainerImage data);
-
-    ImageDto containerImageToImageDto(ContainerImage data);
-
-    default Instant dateToInstant(String date) {
-        return Instant.parse(date);
-    }
-
-}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/LicenseMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/LicenseMapper.java
deleted file mode 100644
index 1124c4239eef2acf4657dab94aa30d5109586a8c..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/LicenseMapper.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.database.LicenseDto;
-import at.tuwien.entities.database.License;
-import org.mapstruct.Mapper;
-
-@Mapper(componentModel = "spring")
-public interface LicenseMapper {
-
-    LicenseDto licenseToLicenseDto(License data);
-
-}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
index 2df2d893f79f5de9a6a7cf0de47c85b9a7656d8b..1a41226977ab90f778a3e07e61ac126a83279fc8 100644
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
@@ -1,17 +1,428 @@
 package at.tuwien.mapper;
 
-import org.mapstruct.Mapper;
+import at.tuwien.api.auth.SignupRequestDto;
+import at.tuwien.api.container.ContainerBriefDto;
+import at.tuwien.api.container.ContainerCreateDto;
+import at.tuwien.api.container.ContainerDto;
+import at.tuwien.api.container.image.ImageBriefDto;
+import at.tuwien.api.container.image.ImageCreateDto;
+import at.tuwien.api.container.image.ImageDto;
+import at.tuwien.api.crossref.CrossrefDto;
+import at.tuwien.api.database.*;
+import at.tuwien.api.database.table.TableBriefDto;
+import at.tuwien.api.database.table.TableDto;
+import at.tuwien.api.database.table.columns.ColumnCreateDto;
+import at.tuwien.api.database.table.columns.ColumnDto;
+import at.tuwien.api.database.table.columns.concepts.ConceptDto;
+import at.tuwien.api.database.table.columns.concepts.ConceptSaveDto;
+import at.tuwien.api.database.table.columns.concepts.UnitDto;
+import at.tuwien.api.database.table.columns.concepts.UnitSaveDto;
+import at.tuwien.api.database.table.constraints.ConstraintsCreateDto;
+import at.tuwien.api.database.table.constraints.ConstraintsDto;
+import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto;
+import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto;
+import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto;
+import at.tuwien.api.database.table.constraints.unique.UniqueDto;
+import at.tuwien.api.datacite.doi.*;
+import at.tuwien.api.identifier.*;
+import at.tuwien.api.identifier.ld.LdCreatorDto;
+import at.tuwien.api.identifier.ld.LdDatasetDto;
+import at.tuwien.api.keycloak.CredentialDto;
+import at.tuwien.api.keycloak.CredentialTypeDto;
+import at.tuwien.api.keycloak.UpdateCredentialsDto;
+import at.tuwien.api.keycloak.UserCreateDto;
+import at.tuwien.api.maintenance.BannerMessageBriefDto;
+import at.tuwien.api.maintenance.BannerMessageCreateDto;
+import at.tuwien.api.maintenance.BannerMessageDto;
+import at.tuwien.api.maintenance.BannerMessageTypeDto;
+import at.tuwien.api.orcid.OrcidDto;
+import at.tuwien.api.orcid.activities.employments.affiliation.OrcidAffiliationGroupDto;
+import at.tuwien.api.orcid.activities.employments.affiliation.group.OrcidEmploymentSummaryDto;
+import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedDto;
+import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedSourceTypeDto;
+import at.tuwien.api.ror.RorDto;
+import at.tuwien.api.semantics.EntityDto;
+import at.tuwien.api.semantics.OntologyBriefDto;
+import at.tuwien.api.semantics.OntologyCreateDto;
+import at.tuwien.api.semantics.OntologyDto;
+import at.tuwien.api.user.UserBriefDto;
+import at.tuwien.api.user.UserDetailsDto;
+import at.tuwien.api.user.UserDto;
+import at.tuwien.api.user.external.ExternalMetadataDto;
+import at.tuwien.api.user.external.ExternalResultType;
+import at.tuwien.api.user.external.affiliation.ExternalAffiliationDto;
+import at.tuwien.entities.container.Container;
+import at.tuwien.entities.container.image.ContainerImage;
+import at.tuwien.entities.database.*;
+import at.tuwien.entities.database.table.Table;
+import at.tuwien.entities.database.table.columns.TableColumn;
+import at.tuwien.entities.database.table.columns.TableColumnConcept;
+import at.tuwien.entities.database.table.columns.TableColumnUnit;
+import at.tuwien.entities.database.table.constraints.Constraints;
+import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKey;
+import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKeyReference;
+import at.tuwien.entities.database.table.constraints.foreignKey.ReferenceType;
+import at.tuwien.entities.database.table.constraints.primaryKey.PrimaryKey;
+import at.tuwien.entities.database.table.constraints.unique.Unique;
+import at.tuwien.entities.identifier.*;
+import at.tuwien.entities.maintenance.BannerMessage;
+import at.tuwien.entities.maintenance.BannerMessageType;
+import at.tuwien.entities.semantics.Ontology;
+import at.tuwien.entities.user.User;
+import org.mapstruct.*;
 
+import java.text.Normalizer;
 import java.time.Instant;
 import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
-
-@Mapper(componentModel = "spring")
+@Mapper(componentModel = "spring", imports = {LinkedList.class, ExternalResultType.class})
 public interface MetadataMapper {
 
     org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MetadataMapper.class);
 
+    BannerMessageDto bannerMessageToBannerMessageDto(BannerMessage data);
+
+    BannerMessageBriefDto bannerMessageToBannerMessageBriefDto(BannerMessage data);
+
+    BannerMessage bannerMessageCreateDtoToBannerMessage(BannerMessageCreateDto data);
+
+    BannerMessageType bannerMessageTypeDtoToBannerMessageType(BannerMessageTypeDto data);
+
+    @Mappings({
+            @Mapping(target = "internalName", source = "name", qualifiedByName = "internalMapping")
+    })
+    Container containerCreateRequestDtoToContainer(ContainerCreateDto data);
+
+    ContainerDto containerToContainerDto(Container data);
+
+    @Mappings({
+            @Mapping(target = "id", source = "id")
+    })
+    ContainerBriefDto containerToDatabaseContainerBriefDto(Container data);
+
+    @Mappings({
+            @Mapping(target = "titles", source = "."),
+            @Mapping(target = "publisher", source = "publisher"),
+            @Mapping(target = "publicationYear", source = "publicationYear"),
+            @Mapping(target = "publicationMonth", source = "publicationMonth"),
+            @Mapping(target = "publicationDay", source = "publicationDay"),
+            @Mapping(target = "language", source = "language"),
+            @Mapping(target = "creators", source = "creators"),
+    })
+    DataCiteCreateDoi identifierToDataCiteCreateDoi(Identifier identifier);
+
+    default DataCiteCreateDoi identifierToDataCiteCreateDoi(Identifier identifier, String url, String prefix,
+                                                            DataCiteDoiEvent event) {
+        return addParametersToCreateDoi(
+                identifierToDataCiteCreateDoi(identifier),
+                url,
+                prefix,
+                DataCiteDoiTypes.DATASET,
+                event
+        );
+    }
+
+    DataCiteDoiTitle identifierTitleToDataCiteDoiTitle(IdentifierTitle data);
+
+    default DataCiteDoiTitle.Type titleTypeToDataCiteDoiTitleType(TitleType data) {
+        if (data == null) {
+            return null;
+        }
+        return switch (data) {
+            case OTHER -> DataCiteDoiTitle.Type.OTHER;
+            case TRANSLATED_TITLE -> DataCiteDoiTitle.Type.TRANSLATED_TITLE;
+            case SUBTITLE -> DataCiteDoiTitle.Type.SUBTITLE;
+            case ALTERNATIVE_TITLE -> DataCiteDoiTitle.Type.ALTERNATIVE_TITLE;
+        };
+    }
+
+    default List<DataCiteDoiTitle> identifierToDataCiteDoiTitleList(Identifier data) {
+        if (data.getTitles() == null) {
+            return new LinkedList<>();
+        }
+        return data.getTitles()
+                .stream()
+                .map(this::identifierTitleToDataCiteDoiTitle)
+                .toList();
+    }
+
+    DataCiteCreateDoi addParametersToCreateDoi(@MappingTarget DataCiteCreateDoi target, String url, String prefix,
+                                               DataCiteDoiTypes types, DataCiteDoiEvent event);
+
+    @Mappings({
+            @Mapping(target = "rights", source = "identifier"),
+            @Mapping(target = "rightsUri", source = "uri"),
+    })
+    DataCiteDoiRights licenseToDoiRights(License license);
+
+    default <T> List<T> list(T t) {
+        if (t == null) return null;
+        return List.of(t);
+    }
+
+    @Mappings({
+            @Mapping(target = "name", expression = "java(data.getLastname() + \", \" + data.getFirstname())"),
+            @Mapping(target = "givenName", source = "firstname"),
+            @Mapping(target = "familyName", source = "lastname"),
+            @Mapping(target = "nameType", expression = "java(nameTypeToDataCiteNameType(data.getNameType()))"),
+            @Mapping(target = "affiliation", expression = "java(list(creatorToDoiCreatorAffiliation(data)))"),
+            @Mapping(target = "nameIdentifier", expression = "java(list(creatorToDataCiteDoiCreatorNameIdentifier(data)))"),
+    })
+    DataCiteDoiCreator creatorToDoiCreator(Creator data);
+
+    DataCiteDoiCreatorNameIdentifier creatorToDataCiteDoiCreatorNameIdentifier(Creator data);
+
+    /* keep */
+    default String nameIdentifierSchemeTypeToUri(NameIdentifierSchemeType data) {
+        switch (data) {
+            case ROR -> {
+                return "https://ror.org/";
+            }
+            case ORCID -> {
+                return "https://orcid.org/";
+            }
+            case ISNI -> {
+                return "https://isni.org/isni/";
+            }
+            case GRID -> {
+                return "https://www.grid.ac/";
+            }
+        }
+        return null;
+    }
+
+    /* keep */
+    default DataCiteNameType nameTypeToDataCiteNameType(NameType data) {
+        if (data == null) {
+            return null;
+        }
+        return DataCiteNameType.valueOf(data.toString());
+    }
+
+    @Mappings({
+            @Mapping(target = "name", source = "affiliation"),
+            @Mapping(target = "affiliationIdentifier", source = "affiliationIdentifier"),
+            @Mapping(target = "affiliationScheme", source = "affiliationIdentifierScheme"),
+            @Mapping(target = "schemeUri", source = "affiliationIdentifierSchemeUri"),
+    })
+    DataCiteDoiCreatorAffiliation creatorToDoiCreatorAffiliation(Creator data);
+
+    @Mappings({
+            @Mapping(target = "relatedIdentifier", source = "value"),
+            @Mapping(target = "relatedIdentifierType", source = "type"),
+            @Mapping(target = "relationType", source = "relation"),
+    })
+    DataCiteDoiRelatedIdentifier relatedIdentifierToDoiRelatedIdentifier(RelatedIdentifier relatedIdentifier);
+
+    Date instantToDate(Instant data);
+
+    @Mappings({
+            @Mapping(target = "givenNames", source = "person.name.givenNames.value"),
+            @Mapping(target = "familyName", source = "person.name.familyName.value"),
+            @Mapping(target = "type", expression = "java(ExternalResultType.PERSONAL)"),
+            @Mapping(target = "affiliations", source = "activitiesSummary.employments.affiliationGroup"),
+    })
+    ExternalMetadataDto orcidDtoToExternalMetadataDto(OrcidDto data);
+
+    @Mappings({
+            @Mapping(target = "organizationName", source = "employmentSummary.organization.name"),
+            @Mapping(target = "ringgoldId", expression = "java(disambiguatedOrganizationToRinggoldId(data.getEmploymentSummary().getOrganization().getDisambiguatedOrganization()))"),
+    })
+    ExternalAffiliationDto orcidEmploymentSummaryDtoToExternalAffiliationDto(OrcidEmploymentSummaryDto data);
+
+    default ExternalAffiliationDto orcidAffiliationGroupDtoToExternalAffiliationDto(OrcidAffiliationGroupDto data) {
+        if (data == null || data.getSummaries() == null || data.getSummaries().length == 0) {
+            return null;
+        }
+        return ExternalAffiliationDto.builder()
+                .organizationName(data.getSummaries()[0].getEmploymentSummary().getOrganization().getName())
+                .build();
+    }
+
+    default Long disambiguatedOrganizationToRinggoldId(OrcidDisambiguatedDto data) {
+        if (data.getSource().equals(OrcidDisambiguatedSourceTypeDto.RINGGOLD)) {
+            return Long.parseLong(data.getIdentifier());
+        }
+        return null;
+    }
+
+    default ExternalMetadataDto rorDtoToExternalMetadataDto(RorDto data) {
+        return ExternalMetadataDto.builder()
+                .affiliations(new ExternalAffiliationDto[]{
+                        ExternalAffiliationDto.builder()
+                                .organizationName(data.getName())
+                                .build()})
+                .type(ExternalResultType.ORGANIZATIONAL)
+                .build();
+    }
+
+    default ExternalMetadataDto crossrefDtoToExternalMetadataDto(CrossrefDto data) {
+        return ExternalMetadataDto.builder()
+                .affiliations(new ExternalAffiliationDto[]{
+                        ExternalAffiliationDto.builder()
+                                .crossrefFunderId(data.getId())
+                                .organizationName(data.getPrefLabel().getLabel().getLiteralForm().getContent())
+                                .build()})
+                .type(ExternalResultType.ORGANIZATIONAL)
+                .build();
+    }
+
+    @Mappings({
+            @Mapping(target = "organizationName", source = "name"),
+    })
+    ExternalAffiliationDto rorDtoToExternalAffiliationDto(RorDto data);
+
+    Identifier identifierDtoToIdentifier(IdentifierDto data);
+
+    @Mappings({
+            @Mapping(target = "databaseId", source = "database.id"),
+    })
+    IdentifierDto identifierToIdentifierDto(Identifier data);
+
+    IdentifierBriefDto identifierToIdentifierBriefDto(Identifier data);
+
+    default IdentifierTitle identifierToIdentifierTitle(Identifier data, String lang) {
+        final Optional<IdentifierTitle> optional = data.getTitles()
+                .stream()
+                .filter(t -> lang == null || t.getLanguage().getName().equals(lang))
+                .findFirst();
+        if (optional.isEmpty()) {
+            log.warn("no title with language {} found", lang);
+            return identifierToIdentifierTitle(data, "en");
+        }
+        return optional.get();
+    }
+
+    default IdentifierDescription identifierToIdentifierDescription(Identifier data, String lang) {
+        final Optional<IdentifierDescription> optional = data.getDescriptions()
+                .stream()
+                .filter(t -> lang == null || t.getLanguage().getName().equals(lang))
+                .findFirst();
+        if (optional.isEmpty()) {
+            log.warn("no description with language {} found", lang);
+            return identifierToIdentifierDescription(data, "en");
+        }
+        return optional.get();
+    }
+
+    @Mappings({
+            @Mapping(target = "givenName", source = "firstname"),
+            @Mapping(target = "familyName", source = "lastname"),
+            @Mapping(target = "type", expression = "java(data.getNameType().equals(NameType.PERSONAL) ? \"Person\" : \"Organization\")"),
+            @Mapping(target = "sameAs", source = "nameIdentifier"),
+            @Mapping(target = "name", source = "creatorName"),
+    })
+    LdCreatorDto creatorToLdCreatorDto(Creator data);
+
+    default LdDatasetDto identifierToLdDatasetDto(Identifier data, String baseUrl) {
+        return LdDatasetDto.builder()
+                .context("https://schema.org/")
+                .type("Dataset")
+                .name(identifierToIdentifierTitle(data, null)
+                        .getTitle())
+                .description(identifierToIdentifierDescription(data, null)
+                        .getDescription())
+                .url(identifierToLocationUrl(baseUrl, data))
+                .identifier(List.of())
+                .creator(data.getCreators()
+                        .stream()
+                        .map(this::creatorToLdCreatorDto)
+                        .toList())
+                .citation(identifierToLocationUrl(baseUrl, data))
+                .hasPart(List.of())
+                .license(data.getLicenses().isEmpty() ? null : data.getLicenses().get(0).getUri())
+                .temporalCoverage(null)
+                .version(data.getCreated())
+                .build();
+    }
+
+    Identifier identifierCreateDtoToIdentifier(IdentifierCreateDto data);
+
+    Identifier identifierUpdateDtoToIdentifier(IdentifierSaveDto data);
+
+    License licenseDtoToLicense(LicenseDto data);
+
+    IdentifierTitle identifierCreateTitleDtoToIdentifierTitle(IdentifierSaveTitleDto data);
+
+    IdentifierDescription identifierCreateDescriptionDtoToIdentifierDescription(IdentifierSaveDescriptionDto data);
+
+    IdentifierFunder identifierFunderSaveDtoToIdentifierFunder(IdentifierFunderSaveDto data);
+
+    IdentifierSaveDto identifierCreateDtoToIdentifierSaveDto(IdentifierCreateDto data);
+
+    RelatedIdentifierDto relatedIdentifierToRelatedIdentifierDto(RelatedIdentifier data);
+
+    Creator creatorDtoToCreator(CreatorDto data);
+
+    NameIdentifierSchemeTypeDto nameIdentifierSchemeTypeToNameIdentifierSchemeTypeDto(NameIdentifierSchemeType data);
+
+    CreatorDto creatorToCreatorDto(Creator data);
+
+    @Mappings({
+            @Mapping(target = "nameIdentifierSchemeUri", source = "nameIdentifierScheme", qualifiedByName = "nameSchemaMapper"),
+            @Mapping(target = "affiliationIdentifierSchemeUri", source = "affiliationIdentifierScheme", qualifiedByName = "affiliationSchemaMapper"),
+    })
+    Creator creatorCreateDtoToCreator(CreatorSaveDto data);
+
+    RelatedIdentifier relatedIdentifierCreateDtoToRelatedIdentifier(RelatedIdentifierSaveDto data);
+
+    IdentifierType identifierTypeDtoToIdentifierType(IdentifierTypeDto data);
+
+    default String identifierToLocationUrl(String baseUrl, Identifier data) {
+        if (data.getType().equals(IdentifierType.SUBSET)) {
+            return baseUrl + "/database/" + data.getDatabase().getId() + "/subset/" + data.getQueryId() + "/info?pid=" + data.getId();
+        } else if (data.getType().equals(IdentifierType.DATABASE)) {
+            return baseUrl + "/database/" + data.getDatabase().getId() + "/info?pid=" + data.getId();
+        } else if (data.getType().equals(IdentifierType.VIEW)) {
+            return baseUrl + "/database/" + data.getDatabase().getId() + "/view/" + data.getViewId() + "/info?pid=" + data.getId();
+        } else if (data.getType().equals(IdentifierType.TABLE)) {
+            return baseUrl + "/database/" + data.getDatabase().getId() + "/table/" + data.getTableId() + "/info?pid=" + data.getId();
+        } else {
+            return null;
+        }
+    }
+
+    @Named("nameSchemaMapper")
+    default String nameIdentifierSchemeToNameIdentifierSchemeUri(NameIdentifierSchemeTypeDto data) {
+        if (data == null) {
+            return null;
+        }
+        return switch (data) {
+            case ROR -> "https://ror.org/";
+            case ORCID -> "https://orcid.org/";
+            case GRID -> "https://grid.ac/";
+            case ISNI -> "https://grid.ac/institutes/";
+        };
+    }
+
+    @Named("affiliationSchemaMapper")
+    default String affiliationIdentifierSchemeTypeToAffiliationIdentifier(AffiliationIdentifierSchemeTypeDto data) {
+        if (data == null) {
+            return null;
+        }
+        return switch (data) {
+            case ROR -> "https://ror.org/";
+            case GRID -> "https://grid.ac/institutes/";
+            case ISNI -> "https://isni.org/";
+        };
+    }
+
+    ContainerImage createImageDtoToContainerImage(ImageCreateDto data);
+
+    ImageBriefDto containerImageToImageBriefDto(ContainerImage data);
+
+    ImageDto containerImageToImageDto(ContainerImage data);
+
+    default Instant dateToInstant(String date) {
+        return Instant.parse(date);
+    }
+
+    LicenseDto licenseToLicenseDto(License data);
+
     default String instantToDatestamp(Instant data) {
         final String datestamp = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")
                 .withZone(ZoneId.systemDefault())
@@ -20,4 +431,455 @@ public interface MetadataMapper {
         return datestamp;
     }
 
+    @Mappings({
+            @Mapping(target = "rdf", expression = "java(data.getRdfPath() != null)"),
+            @Mapping(target = "sparql", expression = "java(data.getSparqlEndpoint() != null)")
+    })
+    OntologyDto ontologyToOntologyDto(Ontology data);
+
+    @Mappings({
+            @Mapping(target = "rdf", expression = "java(data.getRdfPath() != null)"),
+            @Mapping(target = "sparql", expression = "java(data.getSparqlEndpoint() != null)")
+    })
+    OntologyBriefDto ontologyToOntologyBriefDto(Ontology data);
+
+    Ontology ontologyCreateDtoToOntology(OntologyCreateDto data);
+
+    ConceptDto tableColumnConceptToConceptDto(TableColumnConcept data);
+
+    UnitDto tableColumnUnitToUnitDto(TableColumnUnit data);
+
+    TableColumnUnit unitSaveDtoToTableColumnUnit(UnitSaveDto data);
+
+    TableColumnUnit entityDtoToTableColumnUnit(EntityDto data);
+
+    TableColumnConcept entityDtoToTableColumnConcept(EntityDto data);
+
+    TableColumnConcept conceptSaveDtoToTableColumnConcept(ConceptSaveDto data);
+
+    @Mappings({
+            @Mapping(source = "id", target = "id"),
+            @Mapping(target = "name", expression = "java(data.getName())"),
+            @Mapping(target = "internalName", expression = "java(data.getInternalName())")
+    })
+    TableBriefDto tableToTableBriefDto(Table data);
+
+    default UniqueDto uniqueToUniqueDto(Unique data) {
+        data.getTable().setOwner(null); /* loop */
+        data.getTable().setCreator(null); /* loop */
+        return UniqueDto.builder()
+                .id(data.getId())
+                .name(data.getName())
+                .columns(data.getColumns()
+                        .stream()
+                        .map(this::tableColumnToColumnDto)
+                        .toList())
+                .table(tableToTableBriefDto(data.getTable()))
+                .build();
+    }
+
+    @Mappings({
+            @Mapping(target = "table.owner", ignore = true),
+            @Mapping(target = "table.creator", ignore = true),
+            @Mapping(target = "table.constraints", ignore = true),
+            @Mapping(target = "referencedTable.owner", ignore = true),
+            @Mapping(target = "referencedTable.creator", ignore = true),
+            @Mapping(target = "referencedTable.constraints", ignore = true),
+    })
+    ForeignKeyDto foreignKeyToForeignKeyDto(ForeignKey data);
+
+    default ConstraintsDto constraintsToConstraintsDto(Constraints data) {
+        if (data == null) {
+            return null;
+        }
+        return ConstraintsDto.builder()
+                .checks(data.getChecks())
+                .uniques(data.getUniques()
+                        .stream()
+                        .map(this::uniqueToUniqueDto)
+                        .toList())
+                .foreignKeys(data.getForeignKeys()
+                        .stream()
+                        .map(this::foreignKeyToForeignKeyDto)
+                        .toList())
+                .primaryKey(data.getPrimaryKey()
+                        .stream()
+                        .map(this::primaryKeyToPrimaryKeyDto)
+                        .collect(Collectors.toSet()))
+                .build();
+    }
+
+    default TableDto customTableToTableDto(Table data) {
+        final TableDto table = TableDto.builder()
+                .id(data.getId())
+                .name(data.getName())
+                .internalName(data.getInternalName())
+                .owner(userToUserDto(data.getOwner()))
+                .createdBy(data.getCreatedBy())
+                .creator(userToUserDto(data.getCreator()))
+                .tdbid(data.getTdbid())
+                .routingKey("dbrepo." + data.getTdbid() + "." + data.getId())
+                .queueName(data.getQueueName())
+                .isPublic(data.getDatabase().getIsPublic())
+                .isVersioned(true)
+                .avgRowLength(data.getAvgRowLength())
+                .maxDataLength(data.getMaxDataLength())
+                .dataLength(data.getDataLength())
+                .numRows(data.getNumRows())
+                .description(data.getDescription())
+                .identifiers(new LinkedList<>())
+                .columns(new LinkedList<>())
+                .created(data.getCreated())
+                .constraints(constraintsToConstraintsDto(data.getConstraints()))
+                .build();
+        table.getConstraints()
+                .getPrimaryKey()
+                .forEach(pk -> {
+                    pk.getTable().setDatabaseId(data.getDatabase().getId());
+                    pk.getColumn().setTableId(data.getId());
+                    pk.getColumn().setDatabaseId(data.getDatabase().getId());
+                });
+        table.getConstraints()
+                .getUniques()
+                .forEach(uk -> {
+                    uk.getTable().setDatabaseId(data.getDatabase().getId());
+                    uk.getColumns()
+                            .forEach(column -> {
+                                column.setTableId(data.getId());
+                                column.setDatabaseId(data.getDatabase().getId());
+                            });
+                });
+        if (data.getIdentifiers() != null) {
+            table.setIdentifiers(new LinkedList<>(data.getIdentifiers()
+                    .stream()
+                    .map(this::identifierToIdentifierDto)
+                    .toList()));
+        }
+        if (data.getColumns() != null) {
+            table.setColumns(new LinkedList<>(data.getColumns()
+                    .stream()
+                    .map(this::tableColumnToColumnDto)
+                    .toList()));
+        }
+        return table;
+    }
+
+    @Mappings({
+            @Mapping(target = "foreignKey", ignore = true),
+    })
+    ForeignKeyReferenceDto foreignKeyReferenceToForeignKeyReferenceDto(ForeignKeyReference foreignKeyReference);
+
+    @Mappings({
+            @Mapping(target = "table", ignore = true)
+    })
+    TableColumn columnDtoToTableColumn(ColumnDto columnDto);
+
+    @Mappings({
+            @Mapping(target = "table", ignore = true)
+    })
+    Unique uniqueDtoToUnique(UniqueDto data);
+
+    @Mappings({
+            @Mapping(target = "ownedBy", source = "owner.id"),
+    })
+    Table tableDtoToTable(TableDto data);
+
+    @Mappings({
+            @Mapping(target = "table.owner", ignore = true),
+            @Mapping(target = "table.columns", ignore = true)
+    })
+    PrimaryKeyDto primaryKeyToPrimaryKeyDto(PrimaryKey data);
+
+    /* keep */
+    default Constraints constraintsCreateDtoToConstraints(ConstraintsCreateDto data, Database database, Table table) {
+        final int[] idx = new int[]{0, 0};
+        final Constraints constrains = Constraints.builder()
+                .checks(data.getChecks())
+                .uniques(data.getUniques()
+                        .stream()
+                        .map(uniqueList -> Unique.builder()
+                                .name("uk_" + table.getInternalName() + "_" + idx[0]++)
+                                .table(table)
+                                .columns(table.getColumns()
+                                        .stream()
+                                        .filter(ukColumn -> uniqueList.stream().map(this::nameToInternalName).toList().contains(nameToInternalName(ukColumn.getInternalName())))
+                                        .toList())
+                                .build())
+                        .toList())
+                .foreignKeys(data.getForeignKeys()
+                        .stream()
+                        .map(fk -> {
+                            final Optional<Table> optional = database.getTables()
+                                    .stream()
+                                    .filter(t -> t.getInternalName().equals(fk.getReferencedTable()))
+                                    .findFirst();
+                            if (optional.isEmpty()) {
+                                log.error("Failed to find foreign key referenced table {} in tables: {}", fk.getReferencedTable(), database.getTables().stream().map(Table::getInternalName).toList());
+                                throw new IllegalArgumentException("Failed to find foreign key referenced table");
+                            }
+                            return ForeignKey.builder()
+                                    .name("fk_" + table.getInternalName() + "_" + idx[1]++)
+                                    .referencedTable(optional.get())
+                                    .references(fk.getReferencedColumns()
+                                            .stream()
+                                            .map(c -> {
+                                                final Optional<TableColumn> column = table.getColumns()
+                                                        .stream()
+                                                        .filter(cc -> cc.getInternalName().equals(c))
+                                                        .findFirst();
+                                                if (column.isEmpty()) {
+                                                    log.error("Failed to find foreign key column {} in columns: {}", c, table.getColumns().stream().map(TableColumn::getInternalName).toList());
+                                                    throw new IllegalArgumentException("Failed to find foreign key column");
+                                                }
+                                                final Optional<TableColumn> referencedColumn = database.getTables()
+                                                        .stream()
+                                                        .filter(t -> t.getInternalName().equals(fk.getReferencedTable()))
+                                                        .map(Table::getColumns)
+                                                        .flatMap(List::stream)
+                                                        .filter(cc -> cc.getInternalName().equals(c))
+                                                        .findFirst();
+                                                if (referencedColumn.isEmpty()) {
+                                                    log.error("Failed to find foreign key referenced column {} in referenced columns: {}", c, database.getTables().stream().filter(t -> t.getInternalName().equals(fk.getReferencedTable())).map(Table::getColumns).flatMap(List::stream).map(TableColumn::getInternalName).toList());
+                                                    throw new IllegalArgumentException("Failed to find foreign key referenced column");
+                                                }
+                                                return ForeignKeyReference.builder()
+                                                        .column(column.get())
+                                                        .referencedColumn(referencedColumn.get())
+                                                        .foreignKey(null) // set later
+                                                        .build();
+                                            })
+                                            .toList())
+                                    .onDelete(ReferenceType.CASCADE)
+                                    .onUpdate(ReferenceType.CASCADE)
+                                    .build();
+                        })
+                        .toList())
+                .primaryKey(data.getPrimaryKey()
+                        .stream()
+                        .map(pk -> {
+                            final Optional<TableColumn> optional = table.getColumns()
+                                    .stream()
+                                    .filter(c -> c.getInternalName().equals(nameToInternalName(pk)))
+                                    .findFirst();
+                            if (optional.isEmpty()) {
+                                log.error("Failed to find primary key column '{}' in columns: {}", pk, table.getColumns().stream().map(TableColumn::getInternalName).toList());
+                                throw new IllegalArgumentException("Failed to find primary key column");
+                            }
+                            return PrimaryKey.builder()
+                                    .table(table)
+                                    .column(optional.get())
+                                    .build();
+                        })
+                        .toList())
+                .build();
+        constrains.getForeignKeys()
+                .forEach(fk -> fk.getReferences()
+                        .forEach(r -> r.setForeignKey(fk)));
+        return constrains;
+    }
+
+    /* keep */
+    @Mappings({
+            @Mapping(target = "tableId", source = "table.id"),
+            @Mapping(target = "databaseId", source = "table.database.id"),
+            @Mapping(target = "isPublic", source = "table.database.isPublic"),
+            @Mapping(target = "description", source = "description"),
+            @Mapping(target = "table", ignore = true),
+            @Mapping(target = "views", ignore = true)
+    })
+    ColumnDto tableColumnToColumnDto(TableColumn data);
+
+    @Mappings({
+            @Mapping(target = "id", expression = "java(null)"),
+            @Mapping(target = "columnType", source = "data.type"),
+            @Mapping(target = "isNullAllowed", source = "data.nullAllowed"),
+            @Mapping(target = "name", source = "data.name"),
+            @Mapping(target = "autoGenerated", expression = "java(false)"),
+            @Mapping(target = "internalName", expression = "java(nameToInternalName(data.getName()))"),
+    })
+    TableColumn columnCreateDtoToTableColumn(ColumnCreateDto data, ContainerImage image);
+
+    default UpdateCredentialsDto passwordToUpdateCredentialsDto(String password) {
+        return UpdateCredentialsDto.builder()
+                .credentials(List.of(CredentialDto.builder()
+                        .temporary(false)
+                        .type(CredentialTypeDto.PASSWORD)
+                        .value(password)
+                        .build()))
+                .build();
+    }
+
+    default UserCreateDto signupRequestDtoToUserCreateDto(SignupRequestDto data) {
+        return UserCreateDto.builder()
+                .username(data.getUsername())
+                .email(data.getEmail())
+                .credentials(List.of(CredentialDto.builder()
+                        .type(CredentialTypeDto.PASSWORD)
+                        .temporary(false)
+                        .value(data.getPassword())
+                        .build()))
+                .enabled(true)
+                .build();
+    }
+
+    /* keep */
+    UserBriefDto keycloakUserDtoToUserBriefDto(at.tuwien.api.keycloak.UserDto data);
+
+    /* keep */
+    @Mappings({
+            @Mapping(target = "id", expression = "java(data.getId().toString())")
+    })
+    UserDetailsDto userDtoToUserDetailsDto(UserDto data);
+
+    /* keep */
+    @Mappings({
+            @Mapping(target = "name", expression = "java(userToFullName(data))"),
+            @Mapping(target = "qualifiedName", expression = "java(userToQualifiedName(data))"),
+    })
+    UserBriefDto userToUserBriefDto(User data);
+
+    UserBriefDto userDtoToUserBriefDto(UserDto data);
+
+    /* keep */
+    @Mappings({
+            @Mapping(target = "attributes.language", source = "language"),
+            @Mapping(target = "attributes.orcid", source = "orcid"),
+            @Mapping(target = "attributes.affiliation", source = "affiliation"),
+            @Mapping(target = "attributes.theme", source = "theme"),
+            @Mapping(target = "name", expression = "java(userToFullName(data))"),
+            @Mapping(target = "qualifiedName", expression = "java(userToQualifiedName(data))"),
+    })
+    UserDto userToUserDto(User data);
+
+    /* keep */
+    User userDtoToUserDto(UserDto data);
+
+    /* keep */
+    @Named("userToFullName")
+    default String userToFullName(User data) {
+        final StringBuilder name = new StringBuilder();
+        if (data.getFirstname() != null) {
+            name.append(data.getFirstname());
+        }
+        if (data.getLastname() != null) {
+            name.append(!name.isEmpty() ? " " : null)
+                    .append(data.getLastname());
+        }
+        return name.isEmpty() ? null : name.toString()
+                .trim();
+    }
+
+    /* keep */
+    @Named("userToQualifiedName")
+    default String userToQualifiedName(User data) {
+        final String fullname = userToFullName(data);
+        final StringBuilder name = new StringBuilder();
+        if (fullname != null) {
+            name.append(fullname);
+        }
+        if (!name.isEmpty()) {
+            name.append(" — ");
+        }
+        name.append("@")
+                .append(data.getUsername());
+        return name.toString()
+                .trim();
+    }
+
+    @Mappings({
+            @Mapping(target = "database.views", ignore = true)
+    })
+    ViewDto viewToViewDto(View data);
+
+    ViewBriefDto viewToViewBriefDto(View data);
+
+    @Mappings({
+            @Mapping(target = "createdBy", source = "creator.id"),
+    })
+    View viewDtoToView(ViewDto data);
+
+    /* keep */
+    @Named("internalMapping")
+    default String nameToInternalName(String data) {
+        if (data == null || data.isEmpty()) {
+            return data;
+        }
+        final Pattern NONLATIN = Pattern.compile("[^\\w-]");
+        final Pattern WHITESPACE = Pattern.compile("[\\s]");
+        String nowhitespace = WHITESPACE.matcher(data).replaceAll("_");
+        String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD);
+        String slug = NONLATIN.matcher(normalized).replaceAll("");
+        final String name = slug.toLowerCase(Locale.ENGLISH);
+        log.debug("mapping name {} to internal name {}", data, name);
+        return name;
+    }
+
+    LanguageType languageTypeDtoToLanguageType(LanguageTypeDto data);
+
+    default DatabaseDto customDatabaseToDatabaseDto(Database data) {
+        if (data == null) {
+            return null;
+        }
+        final DatabaseDto database = DatabaseDto.builder()
+                .id(data.getId())
+                .name(data.getName())
+                .internalName(data.getInternalName())
+                .description(data.getDescription())
+                .exchangeName(data.getExchangeName())
+                .image(data.getImage())
+                .isPublic(data.getIsPublic())
+                .container(containerToContainerDto(data.getContainer()))
+                .creator(userToUserDto(data.getCreator()))
+                .owner(userToUserDto(data.getOwner()))
+                .created(data.getCreated())
+                .contact(userToUserDto(data.getContact()))
+                .subsets(new LinkedList<>())
+                .accesses(new LinkedList<>())
+                .tables(new LinkedList<>())
+                .identifiers(new LinkedList<>())
+                .build();
+        if (data.getSubsets() != null) {
+            database.setSubsets(new LinkedList<>(data.getSubsets()
+                    .stream()
+                    .map(this::identifierToIdentifierDto)
+                    .toList()));
+        }
+        if (data.getTables() != null) {
+            database.setTables(new LinkedList<>(data.getTables()
+                    .stream()
+                    .map(this::customTableToTableDto)
+                    .toList()));
+        }
+        if (data.getViews() != null) {
+            database.setViews(new LinkedList<>(data.getViews()
+                    .stream()
+                    .map(this::viewToViewDto)
+                    .toList()));
+        }
+        if (data.getAccesses() != null) {
+            database.setAccesses(new LinkedList<>(data.getAccesses()
+                    .stream()
+                    .map(this::databaseAccessToDatabaseAccessDto)
+                    .toList()));
+        }
+        if (data.getIdentifiers() != null) {
+            database.setIdentifiers(new LinkedList<>(data.getIdentifiers()
+                    .stream()
+                    .map(this::identifierToIdentifierDto)
+                    .toList()));
+        }
+        return database;
+    }
+
+    @Mappings({
+            @Mapping(target = "created", source = "created", dateFormat = "dd-MM-yyyy HH:mm"),
+    })
+    DatabaseBriefDto databaseToDatabaseBriefDto(Database data);
+
+    AccessType accessTypeDtoToAccessType(AccessTypeDto data);
+
+    AccessTypeDto accessTypeToAccessTypeDto(AccessType data);
+
+    DatabaseAccessDto databaseAccessToDatabaseAccessDto(DatabaseAccess data);
+
 }
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SemanticMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SemanticMapper.java
deleted file mode 100644
index 95c56e0a5c53be6d910b33a637de29ec43da5a32..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SemanticMapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.database.table.columns.concepts.ConceptDto;
-import at.tuwien.api.database.table.columns.concepts.UnitDto;
-import at.tuwien.entities.database.table.columns.TableColumnConcept;
-import at.tuwien.entities.database.table.columns.TableColumnUnit;
-import org.mapstruct.Mapper;
-
-
-@Mapper(componentModel = "spring", uses = {TableMapper.class})
-public interface SemanticMapper {
-
-    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SemanticMapper.class);
-
-    ConceptDto tableColumnConceptToConceptDto(TableColumnConcept data);
-
-    UnitDto tableColumnUnitToUnitDto(TableColumnUnit data);
-}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/OntologyMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SparqlMapper.java
similarity index 66%
rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/OntologyMapper.java
rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SparqlMapper.java
index afb3265fdf58497cd67a102a8aac15dc472d28ec..dff867970fa59c9d0ddd5c0b7ed60750dd508e3b 100644
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/OntologyMapper.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SparqlMapper.java
@@ -1,53 +1,15 @@
 package at.tuwien.mapper;
 
-import at.tuwien.api.database.table.columns.concepts.ConceptDto;
-import at.tuwien.api.database.table.columns.concepts.ConceptSaveDto;
-import at.tuwien.api.database.table.columns.concepts.UnitDto;
-import at.tuwien.api.database.table.columns.concepts.UnitSaveDto;
-import at.tuwien.api.semantics.EntityDto;
-import at.tuwien.api.semantics.OntologyBriefDto;
-import at.tuwien.api.semantics.OntologyCreateDto;
-import at.tuwien.api.semantics.OntologyDto;
-import at.tuwien.entities.database.table.columns.TableColumnConcept;
-import at.tuwien.entities.database.table.columns.TableColumnUnit;
 import at.tuwien.entities.semantics.Ontology;
 import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.Mappings;
 
 import java.util.List;
 
 
 @Mapper(componentModel = "spring")
-public interface OntologyMapper {
+public interface SparqlMapper {
 
-    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(OntologyMapper.class);
-
-    @Mappings({
-            @Mapping(target = "rdf", expression = "java(data.getRdfPath() != null)"),
-            @Mapping(target = "sparql", expression = "java(data.getSparqlEndpoint() != null)")
-    })
-    OntologyDto ontologyToOntologyDto(Ontology data);
-
-    @Mappings({
-            @Mapping(target = "rdf", expression = "java(data.getRdfPath() != null)"),
-            @Mapping(target = "sparql", expression = "java(data.getSparqlEndpoint() != null)")
-    })
-    OntologyBriefDto ontologyToOntologyBriefDto(Ontology data);
-
-    Ontology ontologyCreateDtoToOntology(OntologyCreateDto data);
-
-    ConceptDto tableColumnConceptToConceptDto(TableColumnConcept data);
-
-    UnitDto tableColumnUnitToUnitDto(TableColumnUnit data);
-
-    TableColumnUnit unitSaveDtoToTableColumnUnit(UnitSaveDto data);
-
-    TableColumnUnit entityDtoToTableColumnUnit(EntityDto data);
-
-    TableColumnConcept entityDtoToTableColumnConcept(EntityDto data);
-
-    TableColumnConcept conceptSaveDtoToTableColumnConcept(ConceptSaveDto data);
+    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SparqlMapper.class);
 
     default String defaultNamespaces(List<Ontology> data) {
         return String.join("\n",
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/TableMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/TableMapper.java
deleted file mode 100644
index a63bc5c9459270a0c20df9e57387c91e267d5fb1..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/TableMapper.java
+++ /dev/null
@@ -1,213 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.database.table.TableBriefDto;
-import at.tuwien.api.database.table.TableDto;
-import at.tuwien.api.database.table.columns.ColumnCreateDto;
-import at.tuwien.api.database.table.columns.ColumnDto;
-import at.tuwien.api.database.table.constraints.ConstraintsCreateDto;
-import at.tuwien.api.database.table.constraints.ConstraintsDto;
-import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto;
-import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto;
-import at.tuwien.api.database.table.constraints.unique.UniqueDto;
-import at.tuwien.entities.container.image.ContainerImage;
-import at.tuwien.entities.database.Database;
-import at.tuwien.entities.database.table.Table;
-import at.tuwien.entities.database.table.columns.TableColumn;
-import at.tuwien.entities.database.table.constraints.Constraints;
-import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKey;
-import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKeyReference;
-import at.tuwien.entities.database.table.constraints.foreignKey.ReferenceType;
-import at.tuwien.entities.database.table.constraints.primaryKey.PrimaryKey;
-import at.tuwien.entities.database.table.constraints.unique.Unique;
-import org.mapstruct.*;
-
-import java.text.Normalizer;
-import java.util.*;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-@Mapper(componentModel = "spring", uses = {IdentifierMapper.class, UserMapper.class}, imports = {Collectors.class, LinkedList.class})
-public interface TableMapper {
-
-    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TableMapper.class);
-
-    @Mappings({
-            @Mapping(source = "id", target = "id"),
-            @Mapping(target = "name", expression = "java(data.getName())"),
-            @Mapping(target = "internalName", expression = "java(data.getInternalName())")
-    })
-    TableBriefDto tableToTableBriefDto(Table data);
-
-    TableBriefDto tableDtoToTableBriefDto(TableDto data);
-
-    /* keep */
-    default UniqueDto uniqueToUniqueDto(Unique data) {
-        return UniqueDto.builder()
-                .uid(data.getUid())
-                .name("uk")
-                .columns(data.getColumns().stream().map(this::tableColumnToColumnDto).toList())
-                .table(tableToTableBriefDto(data.getTable()))
-                .build();
-    }
-
-    @Mappings({
-            @Mapping(target = "name", expression = "java(data.getName())"),
-            @Mapping(target = "internalName", expression = "java(data.getInternalName())"),
-            @Mapping(target = "queueName", expression = "java(data.getQueueName())"),
-            @Mapping(target = "routingKey", expression = "java(\"dbrepo.\" + data.getTdbid() + \".\" + data.getId())"),
-            @Mapping(target = "isPublic", source = "database.isPublic"),
-    })
-    TableDto tableToTableDto(Table data);
-
-    @Mappings({
-            @Mapping(target = "table", ignore = true),
-            @Mapping(target = "referencedTable", ignore = true),
-    })
-    ForeignKeyDto foreignKeyToForeignKeyDto(ForeignKey foreignKey);
-
-    @Mappings({
-            @Mapping(target = "foreignKey", ignore = true),
-    })
-    ForeignKeyReferenceDto foreignKeyReferenceToForeignKeyReferenceDto(ForeignKeyReference foreignKeyReference);
-
-    @Mappings({
-            @Mapping(target = "table", ignore = true)
-    })
-    TableColumn columnDtoToTableColumn(ColumnDto columnDto);
-
-    @Mappings({
-            @Mapping(target = "table", ignore = true)
-    })
-    Unique uniqueDtoToUnique(UniqueDto data);
-
-    @Mappings({
-            @Mapping(target = "constraints.primaryKey", expression = "java(new LinkedList<>())"),
-            @Mapping(target = "ownedBy", source = "owner.id"),
-    })
-    Table tableDtoToTable(TableDto data);
-
-    /* keep */
-    default Constraints constraintsCreateDtoToConstraints(ConstraintsCreateDto data, Database database, Table table) {
-        final int[] idx = new int[]{0, 0};
-        final Constraints constrains = Constraints.builder()
-                .checks(data.getChecks())
-                .uniques(data.getUniques()
-                        .stream()
-                        .map(uniqueList -> Unique.builder()
-                                .name("uk_" + table.getInternalName() + "_" + idx[0]++)
-                                .table(table)
-                                .columns(table.getColumns()
-                                        .stream()
-                                        .filter(ukColumn -> uniqueList.stream().map(this::nameToInternalName).toList().contains(nameToInternalName(ukColumn.getInternalName())))
-                                        .toList())
-                                .build())
-                        .toList())
-                .foreignKeys(data.getForeignKeys()
-                        .stream()
-                        .map(fk -> {
-                            final Optional<Table> optional = database.getTables()
-                                    .stream()
-                                    .filter(t -> t.getInternalName().equals(fk.getReferencedTable()))
-                                    .findFirst();
-                            if (optional.isEmpty()) {
-                                log.error("Failed to find foreign key referenced table {} in tables: {}", fk.getReferencedTable(), database.getTables().stream().map(Table::getInternalName).toList());
-                                throw new IllegalArgumentException("Failed to find foreign key referenced table");
-                            }
-                            return ForeignKey.builder()
-                                    .name("fk_" + table.getInternalName() + "_" + idx[1]++)
-                                    .referencedTable(optional.get())
-                                    .references(fk.getReferencedColumns()
-                                            .stream()
-                                            .map(c -> {
-                                                final Optional<TableColumn> column = table.getColumns()
-                                                        .stream()
-                                                        .filter(cc -> cc.getInternalName().equals(c))
-                                                        .findFirst();
-                                                if (column.isEmpty()) {
-                                                    log.error("Failed to find foreign key column {} in columns: {}", c, table.getColumns().stream().map(TableColumn::getInternalName).toList());
-                                                    throw new IllegalArgumentException("Failed to find foreign key column");
-                                                }
-                                                final Optional<TableColumn> referencedColumn = database.getTables()
-                                                        .stream()
-                                                        .filter(t -> t.getInternalName().equals(fk.getReferencedTable()))
-                                                        .map(Table::getColumns)
-                                                        .flatMap(List::stream)
-                                                        .filter(cc -> cc.getInternalName().equals(c))
-                                                        .findFirst();
-                                                if (referencedColumn.isEmpty()) {
-                                                    log.error("Failed to find foreign key referenced column {} in referenced columns: {}", c, database.getTables().stream().filter(t -> t.getInternalName().equals(fk.getReferencedTable())).map(Table::getColumns).flatMap(List::stream).map(TableColumn::getInternalName).toList());
-                                                    throw new IllegalArgumentException("Failed to find foreign key referenced column");
-                                                }
-                                                return ForeignKeyReference.builder()
-                                                        .column(column.get())
-                                                        .referencedColumn(referencedColumn.get())
-                                                        .foreignKey(null) // set later
-                                                        .build();
-                                            })
-                                            .toList())
-                                    .onDelete(ReferenceType.CASCADE)
-                                    .onUpdate(ReferenceType.CASCADE)
-                                    .build();
-                        })
-                        .toList())
-                .primaryKey(data.getPrimaryKey()
-                        .stream()
-                        .map(pk -> {
-                            final Optional<TableColumn> optional = table.getColumns()
-                                    .stream()
-                                    .filter(c -> c.getInternalName().equals(nameToInternalName(pk)))
-                                    .findFirst();
-                            if (optional.isEmpty()) {
-                                log.error("Failed to find primary key column '{}' in columns: {}", pk, table.getColumns().stream().map(TableColumn::getInternalName).toList());
-                                throw new IllegalArgumentException("Failed to find primary key column");
-                            }
-                            return PrimaryKey.builder()
-                                    .table(table)
-                                    .column(optional.get())
-                                    .build();
-                        })
-                        .toList())
-                .build();
-        constrains.getForeignKeys()
-                .forEach(fk -> fk.getReferences()
-                        .forEach(r -> r.setForeignKey(fk)));
-        return constrains;
-    }
-
-    /* keep */
-    @Mappings({
-            @Mapping(target = "tableId", source = "table.id"),
-            @Mapping(target = "databaseId", source = "table.database.id"),
-            @Mapping(target = "isPublic", source = "table.database.isPublic"),
-            @Mapping(target = "description", source = "description"),
-            @Mapping(target = "table.columns", ignore = true),
-            @Mapping(target = "table.constraints", ignore = true),
-            @Mapping(target = "views", ignore = true)
-    })
-    ColumnDto tableColumnToColumnDto(TableColumn data);
-
-    @Named("internalMapping")
-    default String nameToInternalName(String data) {
-        if (data == null || data.isEmpty()) {
-            return data;
-        }
-        final Pattern NONLATIN = Pattern.compile("[^\\w-]");
-        final Pattern WHITESPACE = Pattern.compile("[\\s]");
-        String nowhitespace = WHITESPACE.matcher(data).replaceAll("_");
-        String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD);
-        String slug = NONLATIN.matcher(normalized).replaceAll("_")
-                .replaceAll("-", "_");
-        return slug.toLowerCase(Locale.ENGLISH);
-    }
-
-    @Mappings({
-            @Mapping(target = "id", expression = "java(null)"),
-            @Mapping(target = "columnType", source = "data.type"),
-            @Mapping(target = "isNullAllowed", source = "data.nullAllowed"),
-            @Mapping(target = "name", source = "data.name"),
-            @Mapping(target = "autoGenerated", expression = "java(false)"),
-            @Mapping(target = "internalName", expression = "java(nameToInternalName(data.getName()))"),
-    })
-    TableColumn columnCreateDtoToTableColumn(ColumnCreateDto data, ContainerImage image);
-
-}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/UserMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/UserMapper.java
deleted file mode 100644
index cf1d2d2ac7d2d1abf417daae233ee746e965598c..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/UserMapper.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.auth.SignupRequestDto;
-import at.tuwien.api.keycloak.*;
-import at.tuwien.api.user.*;
-import at.tuwien.api.user.UserDto;
-import at.tuwien.entities.user.User;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.Mappings;
-import org.mapstruct.Named;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Mapper(componentModel = "spring")
-public interface UserMapper {
-
-    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(UserMapper.class);
-
-    default UpdateCredentialsDto passwordToUpdateCredentialsDto(String password) {
-        return UpdateCredentialsDto.builder()
-                .credentials(List.of(CredentialDto.builder()
-                        .temporary(false)
-                        .type(CredentialTypeDto.PASSWORD)
-                        .value(password)
-                        .build()))
-                .build();
-    }
-
-    default UserCreateDto signupRequestDtoToUserCreateDto(SignupRequestDto data) {
-        return UserCreateDto.builder()
-                .username(data.getUsername())
-                .email(data.getEmail())
-                .credentials(List.of(CredentialDto.builder()
-                        .type(CredentialTypeDto.PASSWORD)
-                        .temporary(false)
-                        .value(data.getPassword())
-                        .build()))
-                .enabled(true)
-                .build();
-    }
-
-    /* keep */
-    UserBriefDto keycloakUserDtoToUserBriefDto(at.tuwien.api.keycloak.UserDto data);
-
-    /* keep */
-    @Mappings({
-            @Mapping(target = "id", expression = "java(data.getId().toString())")
-    })
-    UserDetailsDto userDtoToUserDetailsDto(UserDto data);
-
-    /* keep */
-    @Mappings({
-            @Mapping(target = "name", expression = "java(userToFullName(data))"),
-            @Mapping(target = "qualifiedName", expression = "java(userToQualifiedName(data))"),
-    })
-    UserBriefDto userToUserBriefDto(User data);
-
-    UserBriefDto userDtoToUserBriefDto(UserDto data);
-
-    /* keep */
-    @Mappings({
-            @Mapping(target = "attributes.language", source = "language"),
-            @Mapping(target = "attributes.orcid", source = "orcid"),
-            @Mapping(target = "attributes.affiliation", source = "affiliation"),
-            @Mapping(target = "attributes.theme", source = "theme"),
-            @Mapping(target = "name", expression = "java(userToFullName(data))"),
-            @Mapping(target = "qualifiedName", expression = "java(userToQualifiedName(data))"),
-    })
-    UserDto userToUserDto(User data);
-
-    /* keep */
-    User userDtoToUserDto(UserDto data);
-
-    /* keep */
-    @Named("userToFullName")
-    default String userToFullName(User data) {
-        final StringBuilder name = new StringBuilder();
-        if (data.getFirstname() != null) {
-            name.append(data.getFirstname());
-        }
-        if (data.getLastname() != null) {
-            name.append(!name.isEmpty() ? " " : null)
-                    .append(data.getLastname());
-        }
-        return name.isEmpty() ? null : name.toString()
-                .trim();
-    }
-
-    /* keep */
-    @Named("userToQualifiedName")
-    default String userToQualifiedName(User data) {
-        final String fullname = userToFullName(data);
-        final StringBuilder name = new StringBuilder();
-        if (fullname != null) {
-            name.append(fullname);
-        }
-        if (!name.isEmpty()) {
-            name.append(" — ");
-        }
-        name.append("@")
-                .append(data.getUsername());
-        return name.toString()
-                .trim();
-    }
-
-    User signupRequestDtoToUser(SignupRequestDto data);
-
-}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ViewMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ViewMapper.java
deleted file mode 100644
index 7d8f2416b1896cb39cc7641208b75845754108bb..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ViewMapper.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.database.ViewBriefDto;
-import at.tuwien.api.database.ViewDto;
-import at.tuwien.entities.database.View;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.Mappings;
-import org.mapstruct.Named;
-
-import java.text.Normalizer;
-import java.util.Locale;
-import java.util.regex.Pattern;
-
-@Mapper(componentModel = "spring", uses = {ContainerMapper.class, UserMapper.class, TableMapper.class,
-        IdentifierMapper.class})
-public interface ViewMapper {
-
-    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ViewMapper.class);
-
-    @Named("internalNameMapping")
-    default String nameToInternalName(String data) {
-        if (data == null || data.isEmpty()) {
-            return data;
-        }
-        final Pattern NONLATIN = Pattern.compile("[^\\w-]");
-        final Pattern WHITESPACE = Pattern.compile("[\\s]");
-        String nowhitespace = WHITESPACE.matcher(data).replaceAll("_");
-        String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD);
-        String slug = NONLATIN.matcher(normalized).replaceAll("");
-        return slug.toLowerCase(Locale.ENGLISH);
-    }
-
-    @Mappings({
-            @Mapping(target = "database.views", ignore = true),
-            @Mapping(target = "database.tables", ignore = true),
-            @Mapping(target = "database.identifiers", ignore = true),
-    })
-    ViewDto viewToViewDto(View data);
-
-    ViewBriefDto viewToViewBriefDto(View data);
-
-    @Mappings({
-            @Mapping(target = "createdBy", source = "creator.id"),
-    })
-    View viewDtoToView(ViewDto data);
-
-}
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
index ea66257cc19860534fc73d1e72630ddbb71e12f5..17c1e20978453458732be953ed05e478691444d7 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
@@ -7,7 +7,7 @@ import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
-import at.tuwien.mapper.DatabaseMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.AccessService;
 import at.tuwien.service.DatabaseService;
 import at.tuwien.service.UserService;
@@ -40,11 +40,11 @@ public class AccessEndpoint {
 
     private final UserService userService;
     private final AccessService accessService;
-    private final DatabaseMapper databaseMapper;
+    private final MetadataMapper databaseMapper;
     private final DatabaseService databaseService;
 
     @Autowired
-    public AccessEndpoint(UserService userService, AccessService accessService, DatabaseMapper databaseMapper,
+    public AccessEndpoint(UserService userService, AccessService accessService, MetadataMapper databaseMapper,
                           DatabaseService databaseService) {
         this.userService = userService;
         this.accessService = accessService;
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ConceptEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ConceptEndpoint.java
index 2d002e844930f7d249549dd843e8bc987658448e..cb58e62def0c45aebe04519a650d1232b681e9e9 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ConceptEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ConceptEndpoint.java
@@ -1,7 +1,7 @@
 package at.tuwien.endpoints;
 
 import at.tuwien.api.database.table.columns.concepts.ConceptDto;
-import at.tuwien.mapper.SemanticMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.ConceptService;
 import io.micrometer.observation.annotation.Observed;
 import io.swagger.v3.oas.annotations.Operation;
@@ -12,7 +12,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.responses.ApiResponses;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
@@ -26,12 +25,12 @@ import java.util.List;
 public class ConceptEndpoint {
 
     private final ConceptService conceptService;
-    private final SemanticMapper semanticMapper;
+    private final MetadataMapper metadataMapper;
 
     @Autowired
-    public ConceptEndpoint(ConceptService conceptService, SemanticMapper semanticMapper) {
+    public ConceptEndpoint(ConceptService conceptService, MetadataMapper metadataMapper) {
         this.conceptService = conceptService;
-        this.semanticMapper = semanticMapper;
+        this.metadataMapper = metadataMapper;
     }
 
     @GetMapping
@@ -49,7 +48,7 @@ public class ConceptEndpoint {
         log.debug("endpoint list concepts");
         final List<ConceptDto> dtos = conceptService.findAll()
                 .stream()
-                .map(semanticMapper::tableColumnConceptToConceptDto)
+                .map(metadataMapper::tableColumnConceptToConceptDto)
                 .toList();
         log.trace("Find all concepts resulted in dtos {}", dtos);
         return ResponseEntity.ok()
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
index 02f5a00f2bc33a7d73f9518a755fc3b0f5133d89..9d6e24801b453b8f79caf923dcaaa90d44ba2e0b 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
@@ -8,7 +8,7 @@ import at.tuwien.entities.container.Container;
 import at.tuwien.exception.ContainerAlreadyExistsException;
 import at.tuwien.exception.ContainerNotFoundException;
 import at.tuwien.exception.ImageNotFoundException;
-import at.tuwien.mapper.ContainerMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.ContainerService;
 import io.micrometer.observation.annotation.Observed;
 import io.swagger.v3.oas.annotations.Operation;
@@ -42,12 +42,12 @@ import java.util.stream.Collectors;
 @RequestMapping(path = "/api/container")
 public class ContainerEndpoint {
 
-    private final ContainerMapper containerMapper;
+    private final MetadataMapper metadataMapper;
     private final ContainerService containerService;
 
     @Autowired
-    public ContainerEndpoint(ContainerService containerService, ContainerMapper containerMapper) {
-        this.containerMapper = containerMapper;
+    public ContainerEndpoint(ContainerService containerService, MetadataMapper metadataMapper) {
+        this.metadataMapper = metadataMapper;
         this.containerService = containerService;
     }
 
@@ -66,7 +66,7 @@ public class ContainerEndpoint {
         log.debug("endpoint find all containers, limit={}", limit);
         final List<Container> containers = containerService.getAll(limit);
         final List<ContainerBriefDto> dtos = containers.stream()
-                .map(containerMapper::containerToDatabaseContainerBriefDto)
+                .map(metadataMapper::containerToDatabaseContainerBriefDto)
                 .collect(Collectors.toList());
         log.trace("find all containers resulted in containers {}", dtos);
         return ResponseEntity.ok()
@@ -99,7 +99,7 @@ public class ContainerEndpoint {
             throws ImageNotFoundException, ContainerAlreadyExistsException {
         log.debug("endpoint create container, data={}", data);
         final Container container = containerService.create(data);
-        final ContainerBriefDto dto = containerMapper.containerToDatabaseContainerBriefDto(container);
+        final ContainerBriefDto dto = metadataMapper.containerToDatabaseContainerBriefDto(container);
         log.trace("create container resulted in container {}", dto);
         return ResponseEntity.status(HttpStatus.CREATED)
                 .body(dto);
@@ -126,7 +126,7 @@ public class ContainerEndpoint {
             throws ContainerNotFoundException {
         log.debug("endpoint find container, containerId={}", containerId);
         final Container container = containerService.find(containerId);
-        final ContainerDto dto = containerMapper.containerToContainerDto(container);
+        final ContainerDto dto = metadataMapper.containerToContainerDto(container);
         log.trace("find container resulted in container {}", dto);
         final HttpHeaders headers = new HttpHeaders();
         if (principal != null) {
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
index b364e2dcfc6f7abc89ffc7d1a5dc2b1e521836f2..b5248ed23265c67e7a666e4364a0069ff9d5e6de 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
@@ -8,7 +8,7 @@ import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
-import at.tuwien.mapper.DatabaseMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.*;
 import io.micrometer.observation.annotation.Observed;
 import io.swagger.v3.oas.annotations.Operation;
@@ -45,13 +45,13 @@ public class DatabaseEndpoint {
     private final RabbitConfig rabbitConfig;
     private final AccessService accessService;
     private final BrokerService brokerService;
-    private final DatabaseMapper databaseMapper;
+    private final MetadataMapper databaseMapper;
     private final StorageService storageService;
     private final DatabaseService databaseService;
 
     @Autowired
     public DatabaseEndpoint(UserService userService, RabbitConfig rabbitConfig, AccessService accessService,
-                            BrokerService brokerService, DatabaseMapper databaseMapper,
+                            BrokerService brokerService, MetadataMapper databaseMapper,
                             StorageService storageService, DatabaseService databaseService) {
         this.userService = userService;
         this.rabbitConfig = rabbitConfig;
@@ -146,7 +146,7 @@ public class DatabaseEndpoint {
         log.debug("endpoint create database, data.name={}", data.getName());
         final User user = userService.findByUsername(principal.getName());
         final Database database = databaseService.create(data, user);
-        final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(database);
+        final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(database);
         return ResponseEntity.status(HttpStatus.CREATED)
                 .body(dto);
     }
@@ -198,7 +198,7 @@ public class DatabaseEndpoint {
             log.error("Failed to refresh database tables metadata: not owner");
             throw new NotAllowedException("Failed to refresh tables metadata: not owner");
         }
-        final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(databaseService.updateTableMetadata(database));
+        final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.updateTableMetadata(database));
         return ResponseEntity.ok(dto);
     }
 
@@ -244,7 +244,7 @@ public class DatabaseEndpoint {
             log.error("Failed to refresh database views metadata: not owner");
             throw new NotAllowedException("Failed to refresh database views metadata: not owner");
         }
-        final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(databaseService.updateViewMetadata(database));
+        final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.updateViewMetadata(database));
         return ResponseEntity.ok(dto);
     }
 
@@ -290,7 +290,7 @@ public class DatabaseEndpoint {
             log.error("Failed to modify database visibility: not owner");
             throw new NotAllowedException("Failed to modify database visibility: not owner");
         }
-        final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(databaseService.modifyVisibility(database, data));
+        final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.modifyVisibility(database, data));
         return ResponseEntity.accepted()
                 .body(dto);
     }
@@ -340,7 +340,7 @@ public class DatabaseEndpoint {
             log.error("Failed to transfer database: not owner");
             throw new NotAllowedException("Failed to transfer database: not owner");
         }
-        final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(databaseService.modifyOwner(database, newOwner));
+        final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.modifyOwner(database, newOwner));
         return ResponseEntity.accepted()
                 .body(dto);
     }
@@ -399,7 +399,7 @@ public class DatabaseEndpoint {
         if (data.getKey() != null) {
             image = storageService.getBytes(data.getKey());
         }
-        dto = databaseMapper.databaseToDatabaseDto(databaseService.modifyImage(database, image));
+        dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.modifyImage(database, image));
         return ResponseEntity.accepted()
                 .body(dto);
     }
@@ -435,7 +435,7 @@ public class DatabaseEndpoint {
             ServiceConnectionException, DatabaseNotFoundException, ExchangeNotFoundException {
         log.debug("endpoint find database, databaseId={}", databaseId);
         final Database database = databaseService.findById(databaseId);
-        final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(database);
+        final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(database);
         if (database.getOwner().equals(principal)) {
             log.debug("current logged-in user is also the owner: additionally load access list");
             /* only owner sees the access rights */
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java
index 726d118f1302ccb784e6ab440a24b6f0ea19bd1a..c1bf7128400980ce12379ab521407b05dac390fa 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java
@@ -16,7 +16,7 @@ import at.tuwien.entities.identifier.IdentifierType;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.DataServiceGateway;
-import at.tuwien.mapper.IdentifierMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.*;
 import at.tuwien.utils.UserUtil;
 import at.tuwien.validation.EndpointValidator;
@@ -57,27 +57,27 @@ public class IdentifierEndpoint {
     private final TableService tableService;
     private final AccessService accessService;
     private final EndpointConfig endpointConfig;
+    private final MetadataMapper metadataMapper;
     private final DatabaseService databaseService;
     private final MetadataService metadataService;
-    private final IdentifierMapper identifierMapper;
     private final EndpointValidator endpointValidator;
     private final IdentifierService identifierService;
     private final DataServiceGateway dataServiceGateway;
 
     @Autowired
     public IdentifierEndpoint(UserService userService, ViewService viewService, TableService tableService,
-                              AccessService accessService, EndpointConfig endpointConfig,
+                              AccessService accessService, EndpointConfig endpointConfig, MetadataMapper metadataMapper,
                               DatabaseService databaseService, MetadataService metadataService,
-                              IdentifierMapper identifierMapper, EndpointValidator endpointValidator,
-                              IdentifierService identifierService, DataServiceGateway dataServiceGateway) {
+                              EndpointValidator endpointValidator, IdentifierService identifierService,
+                              DataServiceGateway dataServiceGateway) {
         this.userService = userService;
         this.viewService = viewService;
         this.tableService = tableService;
         this.accessService = accessService;
         this.endpointConfig = endpointConfig;
+        this.metadataMapper = metadataMapper;
         this.databaseService = databaseService;
         this.metadataService = metadataService;
-        this.identifierMapper = identifierMapper;
         this.endpointValidator = endpointValidator;
         this.identifierService = identifierService;
         this.dataServiceGateway = dataServiceGateway;
@@ -121,14 +121,14 @@ public class IdentifierEndpoint {
             case "application/json":
                 log.trace("accept header matches json");
                 final List<IdentifierDto> resource1 = identifiers.stream()
-                        .map(identifierMapper::identifierToIdentifierDto)
+                        .map(metadataMapper::identifierToIdentifierDto)
                         .toList();
                 log.debug("find identifier resulted in identifiers {}", resource1);
                 return ResponseEntity.ok(resource1);
             case "application/ld+json":
                 log.trace("accept header matches json-ld");
                 final List<LdDatasetDto> resource2 = identifiers.stream()
-                        .map(i -> identifierMapper.identifierToLdDatasetDto(i, endpointConfig.getWebsiteUrl()))
+                        .map(i -> metadataMapper.identifierToLdDatasetDto(i, endpointConfig.getWebsiteUrl()))
                         .toList();
                 log.debug("find identifier resulted in identifiers {}", resource2);
                 return ResponseEntity.ok(resource2);
@@ -209,12 +209,12 @@ public class IdentifierEndpoint {
             switch (accept) {
                 case "application/json":
                     log.trace("accept header matches json");
-                    final IdentifierDto resource1 = identifierMapper.identifierToIdentifierDto(identifier);
+                    final IdentifierDto resource1 = metadataMapper.identifierToIdentifierDto(identifier);
                     log.debug("find identifier resulted in identifier {}", resource1);
                     return ResponseEntity.ok(resource1);
                 case "application/ld+json":
                     log.trace("accept header matches json-ld");
-                    final LdDatasetDto resource2 = identifierMapper.identifierToLdDatasetDto(identifier, endpointConfig.getWebsiteUrl());
+                    final LdDatasetDto resource2 = metadataMapper.identifierToLdDatasetDto(identifier, endpointConfig.getWebsiteUrl());
                     log.debug("find identifier resulted in identifier {}", resource2);
                     return ResponseEntity.ok(resource2);
                 case "text/csv":
@@ -253,7 +253,7 @@ public class IdentifierEndpoint {
             log.trace("no accept header present");
         }
         final HttpHeaders headers = new HttpHeaders();
-        final String url = identifierMapper.identifierToLocationUrl(endpointConfig.getWebsiteUrl(), identifier);
+        final String url = metadataMapper.identifierToLocationUrl(endpointConfig.getWebsiteUrl(), identifier);
         headers.add("Location", url);
         log.debug("find identifier resulted in http redirect, headers={}, url={}", headers, url);
         return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY)
@@ -353,7 +353,7 @@ public class IdentifierEndpoint {
         log.debug("endpoint publish identifier, identifierId={}", identifierId);
         final Identifier identifier = identifierService.find(identifierId);
         return ResponseEntity.status(HttpStatus.CREATED)
-                .body(identifierMapper.identifierToIdentifierDto(identifierService.publish(identifierId)));
+                .body(metadataMapper.identifierToIdentifierDto(identifierService.publish(identifierId)));
     }
 
     @PutMapping("/{identifierId}")
@@ -478,7 +478,7 @@ public class IdentifierEndpoint {
             }
         }
         return ResponseEntity.accepted()
-                .body(identifierMapper.identifierToIdentifierDto(identifierService.save(database, user, data)));
+                .body(metadataMapper.identifierToIdentifierDto(identifierService.save(database, user, data)));
     }
 
     @PostMapping
@@ -544,7 +544,7 @@ public class IdentifierEndpoint {
         }
         final Identifier identifier = identifierService.create(database, user, data);
         return ResponseEntity.status(HttpStatus.CREATED)
-                .body(identifierMapper.identifierToIdentifierDto(identifier));
+                .body(metadataMapper.identifierToIdentifierDto(identifier));
     }
 
     @GetMapping("/retrieve")
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java
index 44b25250a882d0b094c0ee4a801bf2e8cbd2fb23..d295cc7a11d669dbd149dd0a9ac784dd3d432cb8 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java
@@ -9,7 +9,7 @@ import at.tuwien.entities.container.image.ContainerImage;
 import at.tuwien.exception.ImageAlreadyExistsException;
 import at.tuwien.exception.ImageInvalidException;
 import at.tuwien.exception.ImageNotFoundException;
-import at.tuwien.mapper.ImageMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.impl.ImageServiceImpl;
 import io.micrometer.observation.annotation.Observed;
 import io.swagger.v3.oas.annotations.Operation;
@@ -40,13 +40,13 @@ import java.util.stream.Collectors;
 @RequestMapping(path = "/api/image")
 public class ImageEndpoint {
 
+    private final MetadataMapper metadataMapper;
     private final ImageServiceImpl imageService;
-    private final ImageMapper imageMapper;
 
     @Autowired
-    public ImageEndpoint(ImageServiceImpl imageService, ImageMapper imageMapper) {
+    public ImageEndpoint(ImageServiceImpl imageService, MetadataMapper metadataMapper) {
         this.imageService = imageService;
-        this.imageMapper = imageMapper;
+        this.metadataMapper = metadataMapper;
     }
 
     @GetMapping
@@ -65,7 +65,7 @@ public class ImageEndpoint {
         final List<ContainerImage> containers = imageService.getAll();
         return ResponseEntity.ok()
                 .body(containers.stream()
-                        .map(imageMapper::containerImageToImageBriefDto)
+                        .map(metadataMapper::containerImageToImageBriefDto)
                         .collect(Collectors.toList()));
     }
 
@@ -100,7 +100,7 @@ public class ImageEndpoint {
             throw new ImageInvalidException("Failed to create image, default port is null");
         }
         final ContainerImage image = imageService.create(data, principal);
-        final ImageDto dto = imageMapper.containerImageToImageDto(image);
+        final ImageDto dto = metadataMapper.containerImageToImageDto(image);
         log.trace("create image resulted in image {}", dto);
         return ResponseEntity.status(HttpStatus.CREATED)
                 .body(dto);
@@ -125,7 +125,7 @@ public class ImageEndpoint {
     public ResponseEntity<ImageDto> findById(@NotNull @PathVariable("imageId") Long imageId) throws ImageNotFoundException {
         log.debug("endpoint find image, id={}", imageId);
         final ContainerImage image = imageService.find(imageId);
-        final ImageDto dto = imageMapper.containerImageToImageDto(image);
+        final ImageDto dto = metadataMapper.containerImageToImageDto(image);
         log.trace("find image resulted in image {}", dto);
         return ResponseEntity.ok()
                 .body(dto);
@@ -154,7 +154,7 @@ public class ImageEndpoint {
         log.debug("endpoint update image, id={}, changeDto={}", imageId, changeDto);
         ContainerImage image = imageService.find(imageId);
         image = imageService.update(image, changeDto);
-        final ImageDto dto = imageMapper.containerImageToImageDto(image);
+        final ImageDto dto = metadataMapper.containerImageToImageDto(image);
         log.trace("update image resulted in image {}", dto);
         return ResponseEntity.accepted()
                 .body(dto);
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/LicenseEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/LicenseEndpoint.java
index dd81274a29ffecdab3c7fdbed2dcb023d2a1a6eb..e2b47905c9196431e0545e37c05b86b151a880b7 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/LicenseEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/LicenseEndpoint.java
@@ -1,7 +1,7 @@
 package at.tuwien.endpoints;
 
 import at.tuwien.api.database.LicenseDto;
-import at.tuwien.mapper.LicenseMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.LicenseService;
 import io.micrometer.observation.annotation.Observed;
 import io.swagger.v3.oas.annotations.Operation;
@@ -29,13 +29,13 @@ import java.util.stream.Collectors;
 @RequestMapping(path = "/api/license")
 public class LicenseEndpoint {
 
-    private final LicenseMapper licenseMapper;
     private final LicenseService licenseService;
+    private final MetadataMapper metadataMapper;
 
     @Autowired
-    public LicenseEndpoint(LicenseMapper licenseMapper, LicenseService licenseService) {
-        this.licenseMapper = licenseMapper;
+    public LicenseEndpoint(LicenseService licenseService, MetadataMapper metadataMapper) {
         this.licenseService = licenseService;
+        this.metadataMapper = metadataMapper;
     }
 
     @GetMapping
@@ -53,7 +53,7 @@ public class LicenseEndpoint {
         log.debug("endpoint list licenses");
         final List<LicenseDto> licenses = licenseService.findAll()
                 .stream()
-                .map(licenseMapper::licenseToLicenseDto)
+                .map(metadataMapper::licenseToLicenseDto)
                 .collect(Collectors.toList());
         log.trace("list licenses resulted in licenses {}", licenses);
         return ResponseEntity.status(HttpStatus.OK)
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/MessageEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/MessageEndpoint.java
index bcff92bc49b00e61e9bdbea9fc4aff9435f06189..62677967b01d666ee998f7c9d30fe1019b997fe6 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/MessageEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/MessageEndpoint.java
@@ -7,7 +7,7 @@ import at.tuwien.api.maintenance.BannerMessageDto;
 import at.tuwien.api.maintenance.BannerMessageUpdateDto;
 import at.tuwien.entities.maintenance.BannerMessage;
 import at.tuwien.exception.MessageNotFoundException;
-import at.tuwien.mapper.BannerMessageMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.BannerMessageService;
 import io.micrometer.observation.annotation.Observed;
 import io.swagger.v3.oas.annotations.Operation;
@@ -34,12 +34,12 @@ import java.util.List;
 @RequestMapping(path = "/api/message")
 public class MessageEndpoint {
 
-    private final BannerMessageMapper bannerMessageMapper;
+    private final MetadataMapper metadataMapper;
     private final BannerMessageService bannerMessageService;
 
     @Autowired
-    public MessageEndpoint(BannerMessageMapper bannerMessageMapper, BannerMessageService bannerMessageService) {
-        this.bannerMessageMapper = bannerMessageMapper;
+    public MessageEndpoint(MetadataMapper metadataMapper, BannerMessageService bannerMessageService) {
+        this.metadataMapper = metadataMapper;
         this.bannerMessageService = bannerMessageService;
     }
 
@@ -59,12 +59,12 @@ public class MessageEndpoint {
         if (filter.equals("active")) {
             dtos = bannerMessageService.getActive()
                     .stream()
-                    .map(bannerMessageMapper::bannerMessageToBannerMessageDto)
+                    .map(metadataMapper::bannerMessageToBannerMessageDto)
                     .toList();
         } else {
             dtos = bannerMessageService.findAll()
                     .stream()
-                    .map(bannerMessageMapper::bannerMessageToBannerMessageDto)
+                    .map(metadataMapper::bannerMessageToBannerMessageDto)
                     .toList();
         }
         log.trace("list maintenance messages results in dtos {}", dtos);
@@ -89,7 +89,7 @@ public class MessageEndpoint {
     public ResponseEntity<BannerMessageDto> find(@NotNull @PathVariable("messageId") Long messageId)
             throws MessageNotFoundException {
         log.debug("endpoint find one maintenance messages");
-        final BannerMessageDto dto = bannerMessageMapper.bannerMessageToBannerMessageDto(bannerMessageService.find(messageId));
+        final BannerMessageDto dto = metadataMapper.bannerMessageToBannerMessageDto(bannerMessageService.find(messageId));
         log.trace("find one maintenance message results in dto {}", dto);
         return ResponseEntity.ok(dto);
     }
@@ -107,7 +107,7 @@ public class MessageEndpoint {
     })
     public ResponseEntity<BannerMessageDto> create(@Valid @RequestBody BannerMessageCreateDto data) {
         log.debug("endpoint create maintenance message, data={}", data);
-        final BannerMessageDto dto = bannerMessageMapper.bannerMessageToBannerMessageDto(bannerMessageService.create(data));
+        final BannerMessageDto dto = metadataMapper.bannerMessageToBannerMessageDto(bannerMessageService.create(data));
         log.trace("create maintenance message results in dto {}", dto);
         return ResponseEntity.status(HttpStatus.CREATED)
                 .body(dto);
@@ -134,7 +134,7 @@ public class MessageEndpoint {
             throws MessageNotFoundException {
         log.debug("endpoint update maintenance message, messageId={}, data={}", messageId, data);
         final BannerMessage message = bannerMessageService.find(messageId);
-        final BannerMessageDto dto = bannerMessageMapper.bannerMessageToBannerMessageDto(bannerMessageService.update(message, data));
+        final BannerMessageDto dto = metadataMapper.bannerMessageToBannerMessageDto(bannerMessageService.update(message, data));
         log.trace("update maintenance message results in dto {}", dto);
         return ResponseEntity.status(HttpStatus.ACCEPTED)
                 .body(dto);
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java
index d9a1b2c50b7014b30b581ecf8c5541c2a10892ba..8d626db323ee120704f099059ab4e057e8418525 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java
@@ -4,7 +4,8 @@ import at.tuwien.api.error.ApiErrorDto;
 import at.tuwien.api.semantics.*;
 import at.tuwien.entities.semantics.Ontology;
 import at.tuwien.exception.*;
-import at.tuwien.mapper.OntologyMapper;
+import at.tuwien.mapper.MetadataMapper;
+import at.tuwien.mapper.SparqlMapper;
 import at.tuwien.service.EntityService;
 import at.tuwien.service.OntologyService;
 import io.micrometer.observation.annotation.Observed;
@@ -33,15 +34,16 @@ import java.util.List;
 @RequestMapping(path = "/api/ontology")
 public class OntologyEndpoint {
 
-    private final OntologyMapper ontologyMapper;
-    private final OntologyService ontologyService;
     private final EntityService entityService;
+    private final MetadataMapper metadataMapper;
+    private final OntologyService ontologyService;
 
     @Autowired
-    public OntologyEndpoint(OntologyMapper ontologyMapper, OntologyService ontologyService, EntityService entityService) {
-        this.ontologyMapper = ontologyMapper;
-        this.ontologyService = ontologyService;
+    public OntologyEndpoint(EntityService entityService, MetadataMapper metadataMapper, 
+                            OntologyService ontologyService) {
         this.entityService = entityService;
+        this.metadataMapper = metadataMapper;
+        this.ontologyService = ontologyService;
     }
 
     @GetMapping
@@ -58,7 +60,7 @@ public class OntologyEndpoint {
         log.debug("endpoint find all ontologies");
         final List<OntologyBriefDto> dtos = ontologyService.findAll()
                 .stream()
-                .map(ontologyMapper::ontologyToOntologyBriefDto)
+                .map(metadataMapper::ontologyToOntologyBriefDto)
                 .toList();
         log.trace("create ontology resulted in dtos {}", dtos);
         return ResponseEntity.ok(dtos);
@@ -82,7 +84,7 @@ public class OntologyEndpoint {
     public ResponseEntity<OntologyDto> find(@NotNull @PathVariable("ontologyId") Long ontologyId)
             throws OntologyNotFoundException {
         log.debug("endpoint find all ontologies, ontologyId={}", ontologyId);
-        final OntologyDto dto = ontologyMapper.ontologyToOntologyDto(ontologyService.find(ontologyId));
+        final OntologyDto dto = metadataMapper.ontologyToOntologyDto(ontologyService.find(ontologyId));
         log.trace("create ontology resulted in dto {}", dto);
         return ResponseEntity.ok(dto);
     }
@@ -101,7 +103,7 @@ public class OntologyEndpoint {
     public ResponseEntity<OntologyDto> create(@NotNull @Valid @RequestBody OntologyCreateDto data,
                                               @NotNull Principal principal) {
         log.debug("endpoint create ontology, data={}", data);
-        final OntologyDto dto = ontologyMapper.ontologyToOntologyDto(ontologyService.create(data, principal));
+        final OntologyDto dto = metadataMapper.ontologyToOntologyDto(ontologyService.create(data, principal));
         log.trace("create ontology resulted in dto {}", dto);
         return ResponseEntity.status(HttpStatus.CREATED)
                 .body(dto);
@@ -128,7 +130,7 @@ public class OntologyEndpoint {
             throws OntologyNotFoundException {
         log.debug("endpoint update ontology, data={}", data);
         final Ontology ontology = ontologyService.find(ontologyId);
-        final OntologyDto dto = ontologyMapper.ontologyToOntologyDto(ontologyService.update(ontology, data));
+        final OntologyDto dto = metadataMapper.ontologyToOntologyDto(ontologyService.update(ontology, data));
         log.trace("update ontology resulted in dto {}", dto);
         return ResponseEntity.accepted()
                 .body(dto);
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
index 6e008287baeba357273319a8263a06843f012049..97f7207f0b9bd489b9ede20d0496b2fd84742505 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
@@ -18,7 +18,7 @@ import at.tuwien.entities.database.table.Table;
 import at.tuwien.entities.database.table.columns.TableColumn;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
-import at.tuwien.mapper.TableMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.*;
 import at.tuwien.utils.UserUtil;
 import at.tuwien.validation.EndpointValidator;
@@ -52,25 +52,25 @@ import java.util.stream.Collectors;
 @RequestMapping(path = "/api/database/{databaseId}/table")
 public class TableEndpoint {
 
-    private final TableMapper tableMapper;
     private final UserService userService;
     private final TableService tableService;
     private final RabbitConfig rabbitMqConfig;
     private final EntityService entityService;
     private final BrokerService messageQueueService;
+    private final MetadataMapper metadataMapper;
     private final DatabaseService databaseService;
     private final EndpointValidator endpointValidator;
 
     @Autowired
-    public TableEndpoint(TableMapper tableMapper, UserService userService, TableService tableService,
-                         RabbitConfig rabbitMqConfig, EntityService entityService, BrokerService messageQueueService,
+    public TableEndpoint(UserService userService, TableService tableService, RabbitConfig rabbitMqConfig, 
+                         EntityService entityService, BrokerService messageQueueService, MetadataMapper metadataMapper,
                          DatabaseService databaseService, EndpointValidator endpointValidator) {
-        this.tableMapper = tableMapper;
         this.userService = userService;
         this.tableService = tableService;
         this.rabbitMqConfig = rabbitMqConfig;
         this.entityService = entityService;
         this.messageQueueService = messageQueueService;
+        this.metadataMapper = metadataMapper;
         this.databaseService = databaseService;
         this.endpointValidator = endpointValidator;
     }
@@ -105,7 +105,7 @@ public class TableEndpoint {
         endpointValidator.validateOnlyPrivateHasRole(database, principal, "list-tables");
         final List<TableBriefDto> dto = database.getTables()
                 .stream()
-                .map(tableMapper::tableToTableBriefDto)
+                .map(metadataMapper::tableToTableBriefDto)
                 .collect(Collectors.toList());
         log.trace("list tables resulted in tables {}", dto);
         return ResponseEntity.ok(dto);
@@ -251,7 +251,7 @@ public class TableEndpoint {
         TableColumn column = tableService.findColumnById(table, columnId);
         column = tableService.update(column, updateDto);
         log.info("Updated table semantics of table with id {}", tableId);
-        final ColumnDto columnDto = tableMapper.tableColumnToColumnDto(column);
+        final ColumnDto columnDto = metadataMapper.tableColumnToColumnDto(column);
         log.trace("find table data resulted in column {}", columnDto);
         return ResponseEntity.accepted()
                 .body(columnDto);
@@ -359,7 +359,7 @@ public class TableEndpoint {
             throw new MalformedException("Failed to create table: date column(s) " + failedDateColumns.stream().map(ColumnCreateDto::getName).toList() + " do not contain date format id");
         }
         final Table table = tableService.createTable(database, data, principal);
-        final TableDto dto = tableMapper.tableToTableDto(table);
+        final TableDto dto = metadataMapper.customTableToTableDto(table);
         log.debug("create table resulted in table.id={}", dto.getId());
         return ResponseEntity.status(HttpStatus.CREATED)
                 .body(dto);
@@ -402,7 +402,7 @@ public class TableEndpoint {
             ServiceConnectionException, TableNotFoundException, DatabaseNotFoundException, QueueNotFoundException {
         log.debug("endpoint find table, databaseId={}, tableId={}", databaseId, tableId);
         final Table table = tableService.findById(databaseId, tableId);
-        final TableDto dto = tableMapper.tableToTableDto(table);
+        final TableDto dto = metadataMapper.customTableToTableDto(table);
         final HttpHeaders headers = new HttpHeaders();
         if (principal != null) {
             /* extra effort only when logged-in */
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UnitEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UnitEndpoint.java
index 7808b1b2918eb55a901335f119e14d2dc9deb284..71dfa78ceff621861c1191e84790032dc6924a13 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UnitEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UnitEndpoint.java
@@ -1,7 +1,7 @@
 package at.tuwien.endpoints;
 
 import at.tuwien.api.database.table.columns.concepts.UnitDto;
-import at.tuwien.mapper.SemanticMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.UnitService;
 import io.micrometer.observation.annotation.Observed;
 import io.swagger.v3.oas.annotations.Operation;
@@ -12,7 +12,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.responses.ApiResponses;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
@@ -26,11 +25,11 @@ import java.util.List;
 public class UnitEndpoint {
 
     private final UnitService unitService;
-    private final SemanticMapper semanticMapper;
+    private final MetadataMapper metadataMapper;
 
     @Autowired
-    public UnitEndpoint(SemanticMapper semanticMapper, UnitService unitService) {
-        this.semanticMapper = semanticMapper;
+    public UnitEndpoint(MetadataMapper metadataMapper, UnitService unitService) {
+        this.metadataMapper = metadataMapper;
         this.unitService = unitService;
     }
 
@@ -49,7 +48,7 @@ public class UnitEndpoint {
         log.debug("endpoint list units");
         final List<UnitDto> dtos = unitService.findAll()
                 .stream()
-                .map(semanticMapper::tableColumnUnitToUnitDto)
+                .map(metadataMapper::tableColumnUnitToUnitDto)
                 .toList();
         log.trace("Find all units resulted in dtos {}", dtos);
         return ResponseEntity.ok()
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java
index 4d5ad8164b97934f6d2b511266ca8a78d998614d..fb9ddc0096db6a279011b2d8f0677493c12a22af 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java
@@ -9,7 +9,7 @@ import at.tuwien.api.user.*;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
-import at.tuwien.mapper.UserMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.AuthenticationService;
 import at.tuwien.service.DatabaseService;
 import at.tuwien.service.UserService;
@@ -22,7 +22,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.responses.ApiResponses;
 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
-import jakarta.servlet.http.HttpServletRequest;
 import jakarta.validation.Valid;
 import jakarta.validation.constraints.NotNull;
 import lombok.extern.log4j.Log4j2;
@@ -43,16 +42,16 @@ import java.util.UUID;
 @RequestMapping(path = "/api/user")
 public class UserEndpoint {
 
-    private final UserMapper userMapper;
     private final UserService userService;
+    private final MetadataMapper userMapper;
     private final DatabaseService databaseService;
     private final AuthenticationService authenticationService;
 
     @Autowired
-    public UserEndpoint(UserMapper userMapper, UserService userService, DatabaseService databaseService,
+    public UserEndpoint(UserService userService, MetadataMapper userMapper, DatabaseService databaseService,
                         AuthenticationService authenticationService) {
-        this.userMapper = userMapper;
         this.userService = userService;
+        this.userMapper = userMapper;
         this.databaseService = databaseService;
         this.authenticationService = authenticationService;
     }
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
index a6627689aa3f4c52098b90271b77aa64881bd90b..701e3172fb648af3edc459001c197609c7410633 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
@@ -8,7 +8,7 @@ import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.View;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
-import at.tuwien.mapper.ViewMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.DatabaseService;
 import at.tuwien.service.UserService;
 import at.tuwien.service.ViewService;
@@ -42,17 +42,17 @@ import java.util.stream.Collectors;
 @RequestMapping(path = "/api/database/{databaseId}/view")
 public class ViewEndpoint {
 
-    private final ViewMapper viewMapper;
     private final UserService userService;
     private final ViewService viewService;
+    private final MetadataMapper metadataMapper;
     private final DatabaseService databaseService;
 
     @Autowired
-    public ViewEndpoint(ViewService viewService, DatabaseService databaseService,
-                        ViewMapper viewMapper, UserService userService) {
-        this.viewMapper = viewMapper;
+    public ViewEndpoint(UserService userService, ViewService viewService, MetadataMapper metadataMapper, 
+                        DatabaseService databaseService) {
         this.userService = userService;
         this.viewService = viewService;
+        this.metadataMapper = metadataMapper;
         this.databaseService = databaseService;
     }
 
@@ -81,7 +81,7 @@ public class ViewEndpoint {
         log.trace("find all views for database {}", database);
         final List<ViewBriefDto> views = viewService.findAll(database, user)
                 .stream()
-                .map(viewMapper::viewToViewBriefDto)
+                .map(metadataMapper::viewToViewBriefDto)
                 .collect(Collectors.toList());
         return ResponseEntity.ok(views);
     }
@@ -153,7 +153,7 @@ public class ViewEndpoint {
         log.trace("create view for database {}", database);
         final View view;
         view = viewService.create(database, user, data);
-        final ViewBriefDto dto = viewMapper.viewToViewBriefDto(view);
+        final ViewBriefDto dto = metadataMapper.viewToViewBriefDto(view);
         return ResponseEntity.status(HttpStatus.CREATED)
                 .body(dto);
     }
@@ -201,7 +201,7 @@ public class ViewEndpoint {
         }
         return ResponseEntity.status(HttpStatus.OK)
                 .headers(headers)
-                .body(viewMapper.viewToViewDto(view));
+                .body(metadataMapper.viewToViewDto(view));
     }
 
     @DeleteMapping("/{viewId}")
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java
index 10a9afc94c172f76d977ce1b59e474a176f9651f..0444a766901a3a33ed9cde1b19b874a42fa6ec87 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java
@@ -1,5 +1,6 @@
 package at.tuwien.endpoints;
 
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.test.AbstractUnitTest;
 import at.tuwien.api.database.AccessTypeDto;
 import at.tuwien.api.database.DatabaseAccessDto;
@@ -7,7 +8,6 @@ import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
-import at.tuwien.mapper.AccessMapper;
 import at.tuwien.repository.DatabaseRepository;
 import at.tuwien.repository.UserRepository;
 import at.tuwien.service.AccessService;
@@ -49,7 +49,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
     private AccessEndpoint accessEndpoint;
 
     @Autowired
-    private AccessMapper accessMapper;
+    private MetadataMapper metadataMapper;
 
     @Test
     @WithAnonymousUser
@@ -264,7 +264,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         final DatabaseAccessDto dto = response.getBody();
         assertEquals(userId, dto.getHuserid());
         assertEquals(databaseId, dto.getHdbid());
-        assertEquals(accessMapper.accessType(access.getType()), dto.getType());
+        if (access != null) {
+            assertEquals(metadataMapper.accessTypeToAccessTypeDto(access.getType()), dto.getType());
+        }
     }
 
     protected void generic_update(DatabaseAccess access, String otherUsername, User otherUser, Principal principal,
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/ContainerMapperTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/ContainerMapperTest.java
deleted file mode 100644
index effb6e04a586d16f708195c13abc2acfdcc0154f..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/ContainerMapperTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.test.AbstractUnitTest;
-import at.tuwien.entities.container.Container;
-import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-@Log4j2
-@SpringBootTest
-@ExtendWith(SpringExtension.class)
-public class ContainerMapperTest extends AbstractUnitTest {
-
-    @Test
-    public void equals_fails() {
-
-        /* test */
-        assertNotEquals(CONTAINER_1, CONTAINER_2);
-    }
-
-    @Test
-    public void equals_identity_succeeds() {
-
-        /* test */
-        assertEquals(CONTAINER_1, CONTAINER_1);
-    }
-
-    @Test
-    public void equals_similar_succeeds() {
-        final Container tmp = Container.builder()
-                .id(CONTAINER_1_ID)
-                .build();
-
-        /* test */
-        assertEquals(CONTAINER_1, tmp);
-    }
-
-}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/DatabaseMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/DatabaseMapperUnitTest.java
deleted file mode 100644
index 4dfdadd102f9aca7f0017fdc4e7db35c7a335a37..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/DatabaseMapperUnitTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.database.DatabaseDto;
-import at.tuwien.api.identifier.IdentifierDto;
-import at.tuwien.test.AbstractUnitTest;
-import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-@Log4j2
-@SpringBootTest
-public class DatabaseMapperUnitTest extends AbstractUnitTest {
-
-    @Autowired
-    private DatabaseMapper databaseMapper;
-
-    @BeforeEach
-    public void beforeEach() {
-        genesis();
-    }
-
-    @Test
-    public void databaseToDatabaseDto_succeeds() {
-
-        /* test */
-        final DatabaseDto response = databaseMapper.databaseToDatabaseDto(DATABASE_1);
-        assertEquals(DATABASE_1_ID, response.getId());
-        assertEquals(4, response.getIdentifiers().size());
-        /* identifier 1 */
-        final IdentifierDto identifier1 = response.getIdentifiers().get(0);
-        assertEquals(DATABASE_1_ID, identifier1.getDatabaseId());
-        assertNotNull(identifier1.getCreator());
-        assertEquals(IDENTIFIER_1_CREATED_BY, identifier1.getCreator().getId());
-        assertNotNull(identifier1.getCreated());
-        assertNotNull(identifier1.getLastModified());
-        /* identifier 2 */
-        final IdentifierDto identifier2 = response.getIdentifiers().get(1);
-        assertEquals(DATABASE_1_ID, identifier2.getDatabaseId());
-        assertNotNull(identifier2.getCreator());
-        assertEquals(IDENTIFIER_2_CREATED_BY, identifier2.getCreator().getId());
-        assertNotNull(identifier2.getCreated());
-        assertNotNull(identifier2.getLastModified());
-        /* identifier 3 */
-        final IdentifierDto identifier3 = response.getIdentifiers().get(2);
-        assertEquals(DATABASE_1_ID, identifier3.getDatabaseId());
-        assertNotNull(identifier3.getCreator());
-        assertEquals(IDENTIFIER_3_CREATED_BY, identifier3.getCreator().getId());
-        assertNotNull(identifier3.getCreated());
-        assertNotNull(identifier3.getLastModified());
-        /* identifier 4 */
-        final IdentifierDto identifier4 = response.getIdentifiers().get(3);
-        assertEquals(DATABASE_1_ID, identifier4.getDatabaseId());
-        assertNotNull(identifier4.getCreator());
-        assertEquals(IDENTIFIER_4_CREATED_BY, identifier4.getCreator().getId());
-        assertNotNull(identifier4.getCreated());
-        assertNotNull(identifier4.getLastModified());
-    }
-
-}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/IdentifierMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/IdentifierMapperUnitTest.java
deleted file mode 100644
index 0089ad8a047b1053b5118c949fdbc4877b1c491f..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/IdentifierMapperUnitTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.identifier.IdentifierTypeDto;
-import at.tuwien.entities.identifier.Identifier;
-import at.tuwien.entities.identifier.IdentifierType;
-import at.tuwien.test.AbstractUnitTest;
-import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
-
-@Log4j2
-@SpringBootTest
-public class IdentifierMapperUnitTest extends AbstractUnitTest {
-
-    @Autowired
-    private IdentifierMapper identifierMapper;
-
-    @Test
-    public void identifierTypeDtoToIdentifierType_succeeds() {
-
-        /* test */
-        assertEquals(IdentifierType.VIEW, identifierMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.VIEW));
-        assertEquals(IdentifierType.TABLE, identifierMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.TABLE));
-        assertEquals(IdentifierType.SUBSET, identifierMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.SUBSET));
-        assertEquals(IdentifierType.DATABASE, identifierMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.DATABASE));
-    }
-
-    @Test
-    public void identifierCreateDtoToIdentifier_succeeds() {
-
-        /* test */
-        final Identifier response = identifierMapper.identifierCreateDtoToIdentifier(IDENTIFIER_1_CREATE_DTO);
-        assertNull(response.getDatabase());
-        assertNull(response.getViewId());
-        assertNull(response.getQueryId());
-        assertNull(response.getTableId());
-        assertNull(response.getDoi());
-        assertEquals(IDENTIFIER_1_TYPE, response.getType());
-    }
-
-    @Test
-    public void identifierCreateDtoToIdentifier_withDoi_succeeds() {
-
-        /* test */
-        final Identifier response = identifierMapper.identifierCreateDtoToIdentifier(IDENTIFIER_1_CREATE_WITH_DOI_DTO);
-        assertNull(response.getDatabase());
-        assertNull(response.getViewId());
-        assertNull(response.getQueryId());
-        assertNull(response.getTableId());
-        assertEquals(IDENTIFIER_1_DOI_NOT_NULL, response.getDoi());
-        assertEquals(IDENTIFIER_1_TYPE, response.getType());
-    }
-
-    @Test
-    public void identifierCreateDtoToIdentifier_subset_succeeds() {
-
-        /* test */
-        final Identifier response = identifierMapper.identifierCreateDtoToIdentifier(IDENTIFIER_2_CREATE_DTO);
-        assertNull(response.getDatabase());
-        assertNull(response.getViewId());
-        assertNull(response.getTableId());
-        assertEquals(IDENTIFIER_2_QUERY_ID, response.getQueryId());
-        assertNull(response.getDoi());
-        assertEquals(IDENTIFIER_2_TYPE, response.getType());
-    }
-
-    @Test
-    public void identifierCreateDtoToIdentifier_view_succeeds() {
-
-        /* test */
-        final Identifier response = identifierMapper.identifierCreateDtoToIdentifier(IDENTIFIER_3_CREATE_DTO);
-        assertNull(response.getDatabase());
-        assertNull(response.getQueryId());
-        assertNull(response.getTableId());
-        assertEquals(IDENTIFIER_3_VIEW_ID, response.getViewId());
-        assertNull(response.getDoi());
-        assertEquals(IDENTIFIER_3_TYPE, response.getType());
-    }
-
-}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e253d4f764d73a3aa8890ea9ade0b59cddc46a50
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java
@@ -0,0 +1,475 @@
+package at.tuwien.mapper;
+
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.ViewDto;
+import at.tuwien.api.database.table.TableDto;
+import at.tuwien.api.database.table.columns.ColumnTypeDto;
+import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto;
+import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto;
+import at.tuwien.api.database.table.constraints.foreign.ReferenceTypeDto;
+import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto;
+import at.tuwien.api.database.table.constraints.unique.UniqueDto;
+import at.tuwien.api.identifier.IdentifierDto;
+import at.tuwien.api.identifier.IdentifierTypeDto;
+import at.tuwien.api.user.UserBriefDto;
+import at.tuwien.api.user.UserDto;
+import at.tuwien.entities.container.Container;
+import at.tuwien.entities.database.Database;
+import at.tuwien.entities.database.table.Table;
+import at.tuwien.entities.identifier.Identifier;
+import at.tuwien.entities.identifier.IdentifierType;
+import at.tuwien.test.AbstractUnitTest;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@Log4j2
+@SpringBootTest
+public class MetadataMapperUnitTest extends AbstractUnitTest {
+
+    private final DateTimeFormatter mariaDbFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.SSS]")
+            .withZone(ZoneId.of("UTC"));
+
+    @Autowired
+    private MetadataMapper metadataMapper;
+
+    @BeforeEach
+    public void beforeEach() {
+        genesis();
+    }
+
+    @Test
+    public void mapMariaDbInstant_succeeds() {
+        final String timestamp = "2023-01-08 08:49:29";
+        final Instant compare = Instant.ofEpochSecond(1673167769);
+
+        /* test */
+        final Instant response = LocalDateTime.parse(timestamp, mariaDbFormatter)
+                .atZone(ZoneId.of("UTC"))
+                .toInstant();
+        assertEquals(compare, response);
+    }
+
+    @Test
+    public void containerEquals_fails() {
+
+        /* test */
+        assertNotEquals(CONTAINER_1, CONTAINER_2);
+    }
+
+    @Test
+    public void containerEquals_identity_succeeds() {
+
+        /* test */
+        assertEquals(CONTAINER_1, CONTAINER_1);
+    }
+
+    @Test
+    public void containerEquals_similar_succeeds() {
+        final Container tmp = Container.builder()
+                .id(CONTAINER_1_ID)
+                .build();
+
+        /* test */
+        assertEquals(CONTAINER_1, tmp);
+    }
+
+    @Test
+    public void identifierTypeDtoToIdentifierType_succeeds() {
+
+        /* test */
+        assertEquals(IdentifierType.VIEW, metadataMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.VIEW));
+        assertEquals(IdentifierType.TABLE, metadataMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.TABLE));
+        assertEquals(IdentifierType.SUBSET, metadataMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.SUBSET));
+        assertEquals(IdentifierType.DATABASE, metadataMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.DATABASE));
+    }
+
+    @Test
+    public void identifierCreateDtoToIdentifier_succeeds() {
+
+        /* test */
+        final Identifier response = metadataMapper.identifierCreateDtoToIdentifier(IDENTIFIER_1_CREATE_DTO);
+        assertNull(response.getDatabase());
+        assertNull(response.getViewId());
+        assertNull(response.getQueryId());
+        assertNull(response.getTableId());
+        assertNull(response.getDoi());
+        assertEquals(IDENTIFIER_1_TYPE, response.getType());
+    }
+
+    @Test
+    public void identifierCreateDtoToIdentifier_withDoi_succeeds() {
+
+        /* test */
+        final Identifier response = metadataMapper.identifierCreateDtoToIdentifier(IDENTIFIER_1_CREATE_WITH_DOI_DTO);
+        assertNull(response.getDatabase());
+        assertNull(response.getViewId());
+        assertNull(response.getQueryId());
+        assertNull(response.getTableId());
+        assertEquals(IDENTIFIER_1_DOI_NOT_NULL, response.getDoi());
+        assertEquals(IDENTIFIER_1_TYPE, response.getType());
+    }
+
+    @Test
+    public void identifierCreateDtoToIdentifier_subset_succeeds() {
+
+        /* test */
+        final Identifier response = metadataMapper.identifierCreateDtoToIdentifier(IDENTIFIER_2_CREATE_DTO);
+        assertNull(response.getDatabase());
+        assertNull(response.getViewId());
+        assertNull(response.getTableId());
+        assertEquals(IDENTIFIER_2_QUERY_ID, response.getQueryId());
+        assertNull(response.getDoi());
+        assertEquals(IDENTIFIER_2_TYPE, response.getType());
+    }
+
+    @Test
+    public void identifierCreateDtoToIdentifier_view_succeeds() {
+
+        /* test */
+        final Identifier response = metadataMapper.identifierCreateDtoToIdentifier(IDENTIFIER_3_CREATE_DTO);
+        assertNull(response.getDatabase());
+        assertNull(response.getQueryId());
+        assertNull(response.getTableId());
+        assertEquals(IDENTIFIER_3_VIEW_ID, response.getViewId());
+        assertNull(response.getDoi());
+        assertEquals(IDENTIFIER_3_TYPE, response.getType());
+    }
+
+    @Test
+    public void databaseToDatabaseDto_succeeds() {
+
+        /* test */
+        final DatabaseDto response = metadataMapper.customDatabaseToDatabaseDto(DATABASE_1);
+        assertEquals(DATABASE_1_ID, response.getId());
+        assertNotNull(response.getContact());
+        assertEquals(USER_1_ID, response.getContact().getId());
+        /* identifiers formatted */
+        assertEquals(4, response.getIdentifiers().size());
+        final IdentifierDto identifier1 = response.getIdentifiers().get(0);
+        assertEquals(DATABASE_1_ID, identifier1.getDatabaseId());
+        assertNotNull(identifier1.getCreator());
+        assertEquals(IDENTIFIER_1_CREATED_BY, identifier1.getCreator().getId());
+        assertNotNull(identifier1.getCreated());
+        assertNotNull(identifier1.getLastModified());
+        final IdentifierDto identifier2 = response.getIdentifiers().get(1);
+        assertEquals(DATABASE_1_ID, identifier2.getDatabaseId());
+        assertNotNull(identifier2.getCreator());
+        assertEquals(IDENTIFIER_2_CREATED_BY, identifier2.getCreator().getId());
+        assertNotNull(identifier2.getCreated());
+        assertNotNull(identifier2.getLastModified());
+        final IdentifierDto identifier3 = response.getIdentifiers().get(2);
+        assertEquals(DATABASE_1_ID, identifier3.getDatabaseId());
+        assertNotNull(identifier3.getCreator());
+        assertEquals(IDENTIFIER_3_CREATED_BY, identifier3.getCreator().getId());
+        assertNotNull(identifier3.getCreated());
+        assertNotNull(identifier3.getLastModified());
+        final IdentifierDto identifier4 = response.getIdentifiers().get(3);
+        assertEquals(DATABASE_1_ID, identifier4.getDatabaseId());
+        assertNotNull(identifier4.getCreator());
+        assertEquals(IDENTIFIER_4_CREATED_BY, identifier4.getCreator().getId());
+        assertNotNull(identifier4.getCreated());
+        assertNotNull(identifier4.getLastModified());
+        /* Table 1 formatted */
+        final TableDto table0 = response.getTables().get(0);
+        assertEquals(TABLE_1_ID, table0.getId());
+        assertEquals(TABLE_1_NAME, table0.getName());
+        assertEquals(TABLE_1_INTERNALNAME, table0.getInternalName());
+        assertEquals(TABLE_1_DESCRIPTION, table0.getDescription());
+        assertEquals(DATABASE_1_ID, table0.getTdbid());
+        assertEquals(USER_1_ID, table0.getCreatedBy());
+        assertEquals(USER_1_ID, table0.getOwner().getId());
+        assertEquals(USER_1_ID, table0.getCreator().getId());
+        assertEquals(TABLE_1_AVG_ROW_LENGTH, table0.getAvgRowLength());
+        assertEquals(TABLE_1_NUM_ROWS, table0.getNumRows());
+        assertEquals(TABLE_1_DATA_LENGTH, table0.getDataLength());
+        assertEquals(TABLE_1_MAX_DATA_LENGTH, table0.getMaxDataLength());
+        assertNotNull(table0.getCreated());
+        /* columns formatted */
+        assertEquals(TABLE_1_COLUMNS.size(), table0.getColumns().size());
+        for (int i = 0; i < TABLE_1_COLUMNS.size(); i++) {
+            assertEquals(TABLE_1_COLUMNS.get(i).getId(), table0.getColumns().get(i).getId());
+            assertEquals(TABLE_1_COLUMNS.get(i).getOrdinalPosition(), table0.getColumns().get(i).getOrdinalPosition());
+            assertNotNull(table0.getColumns().get(i).getOrdinalPosition());
+            assertEquals(TABLE_1_COLUMNS.get(i).getTable().getId(), table0.getColumns().get(i).getTableId());
+            assertEquals(TABLE_1_COLUMNS.get(i).getName(), table0.getColumns().get(i).getName());
+            assertEquals(TABLE_1_COLUMNS.get(i).getInternalName(), table0.getColumns().get(i).getInternalName());
+            assertEquals(List.of(ColumnTypeDto.BIGINT, ColumnTypeDto.DATE, ColumnTypeDto.VARCHAR, ColumnTypeDto.DECIMAL, ColumnTypeDto.DECIMAL).get(i), table0.getColumns().get(i).getColumnType());
+            assertEquals(TABLE_1_COLUMNS.get(i).getSize(), table0.getColumns().get(i).getSize());
+            assertEquals(TABLE_1_COLUMNS.get(i).getD(), table0.getColumns().get(i).getD());
+            assertEquals(TABLE_1_COLUMNS.get(i).getIsNullAllowed(), table0.getColumns().get(i).getIsNullAllowed());
+            assertEquals(TABLE_1_COLUMNS.get(i).getAutoGenerated(), table0.getColumns().get(i).getAutoGenerated());
+            assertEquals(TABLE_1_COLUMNS.get(i).getEnums(), table0.getColumns().get(i).getEnums());
+            assertEquals(TABLE_1_COLUMNS.get(i).getSets(), table0.getColumns().get(i).getSets());
+        }
+        /* constraints formatted */
+        assertNotNull(table0.getConstraints());
+        assertEquals(0, table0.getConstraints().getUniques().size());
+        assertEquals(0, table0.getConstraints().getChecks().size());
+        assertEquals(0, table0.getConstraints().getForeignKeys().size());
+        assertEquals(1, table0.getConstraints().getPrimaryKey().size());
+        final PrimaryKeyDto table0pk = new ArrayList<>(table0.getConstraints().getPrimaryKey()).get(0);
+        assertEquals(1L, table0pk.getId());
+        assertEquals(TABLE_1_COLUMNS_BRIEF_0_DTO.getId(), table0pk.getColumn().getId());
+        assertEquals(TABLE_1_COLUMNS_BRIEF_0_DTO.getName(), table0pk.getColumn().getName());
+        assertEquals(TABLE_1_COLUMNS_BRIEF_0_DTO.getId(), table0pk.getColumn().getId());
+        assertEquals(TABLE_1_COLUMNS_BRIEF_0_DTO.getName(), table0pk.getColumn().getName());
+        assertEquals(TABLE_1_COLUMNS_BRIEF_0_DTO.getInternalName(), table0pk.getColumn().getInternalName());
+        assertEquals(TABLE_1_ID, table0pk.getTable().getId());
+        assertEquals(DATABASE_1_ID, table0pk.getTable().getDatabaseId());
+        assertEquals(ColumnTypeDto.BIGINT, table0pk.getColumn().getColumnType());
+        assertNull(table0pk.getColumn().getAlias());
+        assertEquals(TABLE_1_ID, table0pk.getColumn().getTableId());
+        assertEquals(DATABASE_1_ID, table0pk.getColumn().getDatabaseId());
+        /* Table 2 formatted */
+        final TableDto table1 = response.getTables().get(1);
+        assertEquals(TABLE_2_ID, table1.getId());
+        assertEquals(TABLE_2_NAME, table1.getName());
+        assertEquals(TABLE_2_INTERNALNAME, table1.getInternalName());
+        assertEquals(TABLE_2_DESCRIPTION, table1.getDescription());
+        assertEquals(DATABASE_1_ID, table1.getTdbid());
+        assertEquals(USER_2_ID, table1.getCreatedBy());
+        assertEquals(USER_2_ID, table1.getOwner().getId());
+        assertEquals(USER_2_ID, table1.getCreator().getId());
+        assertEquals(TABLE_2_AVG_ROW_LENGTH, table1.getAvgRowLength());
+        assertEquals(TABLE_2_NUM_ROWS, table1.getNumRows());
+        assertEquals(TABLE_2_DATA_LENGTH, table1.getDataLength());
+        assertEquals(TABLE_2_MAX_DATA_LENGTH, table1.getMaxDataLength());
+        assertNotNull(table1.getCreated());
+        /* columns formatted */
+        assertEquals(TABLE_2_COLUMNS.size(), table1.getColumns().size());
+        for (int i = 0; i < TABLE_2_COLUMNS.size(); i++) {
+            assertEquals(TABLE_2_COLUMNS.get(i).getId(), table1.getColumns().get(i).getId());
+            assertEquals(TABLE_2_COLUMNS.get(i).getOrdinalPosition(), table1.getColumns().get(i).getOrdinalPosition());
+            assertNotNull(table1.getColumns().get(i).getOrdinalPosition());
+            assertEquals(TABLE_2_COLUMNS.get(i).getTable().getId(), table1.getColumns().get(i).getTableId());
+            assertEquals(TABLE_2_COLUMNS.get(i).getName(), table1.getColumns().get(i).getName());
+            assertEquals(TABLE_2_COLUMNS.get(i).getInternalName(), table1.getColumns().get(i).getInternalName());
+            assertEquals(List.of(ColumnTypeDto.VARCHAR, ColumnTypeDto.DECIMAL, ColumnTypeDto.DECIMAL).get(i), table1.getColumns().get(i).getColumnType());
+            assertEquals(TABLE_2_COLUMNS.get(i).getSize(), table1.getColumns().get(i).getSize());
+            assertEquals(TABLE_2_COLUMNS.get(i).getD(), table1.getColumns().get(i).getD());
+            assertEquals(TABLE_2_COLUMNS.get(i).getIsNullAllowed(), table1.getColumns().get(i).getIsNullAllowed());
+            assertEquals(TABLE_2_COLUMNS.get(i).getAutoGenerated(), table1.getColumns().get(i).getAutoGenerated());
+            assertEquals(TABLE_2_COLUMNS.get(i).getEnums(), table1.getColumns().get(i).getEnums());
+            assertEquals(TABLE_2_COLUMNS.get(i).getSets(), table1.getColumns().get(i).getSets());
+        }
+        /* constraints formatted */
+        assertNotNull(table1.getConstraints());
+        assertEquals(1, table1.getConstraints().getUniques().size());
+        final UniqueDto table1uk = table1.getConstraints().getUniques().get(0);
+        assertEquals(1L, table1uk.getId());
+        assertEquals(TABLE_2_ID, table1uk.getTable().getId());
+        assertEquals(DATABASE_1_ID, table1uk.getTable().getDatabaseId());
+        assertEquals("uk_1", table1uk.getName());
+        assertEquals(TABLE_2_COLUMNS_DTO.get(1).getId(), table1uk.getColumns().get(0).getId());
+        assertEquals(1, table1.getConstraints().getChecks().size());
+        assertEquals("`mintemp` > 0", new ArrayList<>(table1.getConstraints().getChecks()).get(0));
+        assertEquals(1, table1.getConstraints().getForeignKeys().size());
+        final ForeignKeyDto table1fk = new ArrayList<>(table1.getConstraints().getForeignKeys()).get(0);
+        assertEquals("fk_location", table1fk.getName());
+        assertEquals(ReferenceTypeDto.NO_ACTION, table1fk.getOnDelete());
+        assertEquals(ReferenceTypeDto.NO_ACTION, table1fk.getOnUpdate());
+        assertEquals(TABLE_1_ID, table1fk.getTable().getId());
+        assertEquals(TABLE_2_ID, table1fk.getReferencedTable().getId());
+        final ForeignKeyReferenceDto table1fkr = table1fk.getReferences().get(0);
+        assertEquals(1L, table1fkr.getId());
+        assertEquals(TABLE_2_COLUMNS_DTO.get(2).getId(), table1fkr.getColumn().getId());
+        assertEquals(1, table1.getConstraints().getPrimaryKey().size());
+        final PrimaryKeyDto table1pk = new ArrayList<>(table1.getConstraints().getPrimaryKey()).get(0);
+        assertEquals(2L, table1pk.getId());
+        assertEquals(TABLE_2_COLUMNS_BRIEF_0_DTO.getId(), table1pk.getColumn().getId());
+        assertEquals(TABLE_2_COLUMNS_BRIEF_0_DTO.getName(), table1pk.getColumn().getName());
+        assertEquals(TABLE_2_COLUMNS_BRIEF_0_DTO.getId(), table1pk.getColumn().getId());
+        assertEquals(TABLE_2_COLUMNS_BRIEF_0_DTO.getName(), table1pk.getColumn().getName());
+        assertEquals(TABLE_2_COLUMNS_BRIEF_0_DTO.getInternalName(), table1pk.getColumn().getInternalName());
+        assertEquals(ColumnTypeDto.VARCHAR, table1pk.getColumn().getColumnType());
+        assertNull(table1pk.getColumn().getAlias());
+        assertEquals(TABLE_2_ID, table1pk.getColumn().getTableId());
+        assertEquals(DATABASE_1_ID, table1pk.getColumn().getDatabaseId());
+        /* Table 3 formatted */
+        final TableDto table2 = response.getTables().get(2);
+        assertEquals(TABLE_3_ID, table2.getId());
+        assertEquals(TABLE_3_NAME, table2.getName());
+        assertEquals(TABLE_3_INTERNALNAME, table2.getInternalName());
+        assertEquals(TABLE_3_DESCRIPTION, table2.getDescription());
+        assertEquals(DATABASE_1_ID, table2.getTdbid());
+        assertEquals(USER_3_ID, table2.getCreatedBy());
+        assertEquals(USER_3_ID, table2.getOwner().getId());
+        assertEquals(USER_3_ID, table2.getCreator().getId());
+        assertEquals(TABLE_3_AVG_ROW_LENGTH, table2.getAvgRowLength());
+        assertEquals(TABLE_3_NUM_ROWS, table2.getNumRows());
+        assertEquals(TABLE_3_DATA_LENGTH, table2.getDataLength());
+        assertEquals(TABLE_3_MAX_DATA_LENGTH, table2.getMaxDataLength());
+        assertNotNull(table2.getCreated());
+        /* columns formatted */
+        assertEquals(TABLE_3_COLUMNS.size(), table2.getColumns().size());
+        for (int i = 0; i < TABLE_3_COLUMNS.size(); i++) {
+            assertEquals(TABLE_3_COLUMNS.get(i).getId(), table2.getColumns().get(i).getId());
+            assertEquals(TABLE_3_COLUMNS.get(i).getOrdinalPosition(), table2.getColumns().get(i).getOrdinalPosition());
+            assertNotNull(table2.getColumns().get(i).getOrdinalPosition());
+            assertEquals(TABLE_3_COLUMNS.get(i).getTable().getId(), table2.getColumns().get(i).getTableId());
+            assertEquals(TABLE_3_COLUMNS.get(i).getName(), table2.getColumns().get(i).getName());
+            assertEquals(TABLE_3_COLUMNS.get(i).getInternalName(), table2.getColumns().get(i).getInternalName());
+            assertEquals(List.of(ColumnTypeDto.BIGINT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.DATE, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.DATE, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.DATE, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT).get(i), table2.getColumns().get(i).getColumnType());
+            assertEquals(TABLE_3_COLUMNS.get(i).getSize(), table2.getColumns().get(i).getSize());
+            assertEquals(TABLE_3_COLUMNS.get(i).getD(), table2.getColumns().get(i).getD());
+            assertEquals(TABLE_3_COLUMNS.get(i).getIsNullAllowed(), table2.getColumns().get(i).getIsNullAllowed());
+            assertEquals(TABLE_3_COLUMNS.get(i).getAutoGenerated(), table2.getColumns().get(i).getAutoGenerated());
+            assertEquals(TABLE_3_COLUMNS.get(i).getEnums(), table2.getColumns().get(i).getEnums());
+            assertEquals(TABLE_3_COLUMNS.get(i).getSets(), table2.getColumns().get(i).getSets());
+        }
+        /* constraints formatted */
+        final PrimaryKeyDto table2pk = new ArrayList<>(table2.getConstraints().getPrimaryKey()).get(0);
+        assertEquals(TABLE_3_COLUMNS_BRIEF_0_DTO.getId(), table2pk.getColumn().getId());
+        assertEquals(TABLE_3_COLUMNS_BRIEF_0_DTO.getName(), table2pk.getColumn().getName());
+        assertEquals(TABLE_3_COLUMNS_BRIEF_0_DTO.getId(), table2pk.getColumn().getId());
+        assertEquals(TABLE_3_COLUMNS_BRIEF_0_DTO.getName(), table2pk.getColumn().getName());
+        assertEquals(TABLE_3_COLUMNS_BRIEF_0_DTO.getInternalName(), table2pk.getColumn().getInternalName());
+        assertEquals(ColumnTypeDto.BIGINT, table2pk.getColumn().getColumnType());
+        assertNull(table2pk.getColumn().getAlias());
+        assertEquals(TABLE_3_ID, table2pk.getColumn().getTableId());
+        assertEquals(DATABASE_1_ID, table2pk.getColumn().getDatabaseId());
+        /* Table 4 formatted */
+        final TableDto table3 = response.getTables().get(3);
+        assertEquals(TABLE_4_ID, table3.getId());
+        assertEquals(TABLE_4_NAME, table3.getName());
+        assertEquals(TABLE_4_INTERNALNAME, table3.getInternalName());
+        assertEquals(TABLE_4_DESCRIPTION, table3.getDescription());
+        assertEquals(DATABASE_1_ID, table3.getTdbid());
+        assertEquals(USER_1_ID, table3.getCreatedBy());
+        assertEquals(USER_1_ID, table3.getOwner().getId());
+        assertEquals(USER_1_ID, table3.getCreator().getId());
+        assertEquals(TABLE_4_AVG_ROW_LENGTH, table3.getAvgRowLength());
+        assertEquals(TABLE_4_NUM_ROWS, table3.getNumRows());
+        assertEquals(TABLE_4_DATA_LENGTH, table3.getDataLength());
+        assertEquals(TABLE_4_MAX_DATA_LENGTH, table3.getMaxDataLength());
+        assertNotNull(table3.getCreated());
+        /* columns formatted */
+        assertEquals(TABLE_4_COLUMNS.size(), table3.getColumns().size());
+        for (int i = 0; i < TABLE_4_COLUMNS.size(); i++) {
+            assertEquals(TABLE_4_COLUMNS.get(i).getId(), table3.getColumns().get(i).getId());
+            assertEquals(TABLE_4_COLUMNS.get(i).getOrdinalPosition(), table3.getColumns().get(i).getOrdinalPosition());
+            assertNotNull(table3.getColumns().get(i).getOrdinalPosition());
+            assertEquals(TABLE_4_COLUMNS.get(i).getTable().getId(), table3.getColumns().get(i).getTableId());
+            assertEquals(TABLE_4_COLUMNS.get(i).getName(), table3.getColumns().get(i).getName());
+            assertEquals(TABLE_4_COLUMNS.get(i).getInternalName(), table3.getColumns().get(i).getInternalName());
+            assertEquals(List.of(ColumnTypeDto.TIMESTAMP, ColumnTypeDto.DECIMAL).get(i), table3.getColumns().get(i).getColumnType());
+            assertEquals(TABLE_4_COLUMNS.get(i).getSize(), table3.getColumns().get(i).getSize());
+            assertEquals(TABLE_4_COLUMNS.get(i).getD(), table3.getColumns().get(i).getD());
+            assertEquals(TABLE_4_COLUMNS.get(i).getIsNullAllowed(), table3.getColumns().get(i).getIsNullAllowed());
+            assertEquals(TABLE_4_COLUMNS.get(i).getAutoGenerated(), table3.getColumns().get(i).getAutoGenerated());
+            assertEquals(TABLE_4_COLUMNS.get(i).getEnums(), table3.getColumns().get(i).getEnums());
+            assertEquals(TABLE_4_COLUMNS.get(i).getSets(), table3.getColumns().get(i).getSets());
+        }
+        /* constraints formatted */
+        final PrimaryKeyDto table3pk = new ArrayList<>(table3.getConstraints().getPrimaryKey()).get(0);
+        assertEquals(TABLE_4_COLUMNS_BRIEF_0_DTO.getId(), table3pk.getColumn().getId());
+        assertEquals(TABLE_4_COLUMNS_BRIEF_0_DTO.getName(), table3pk.getColumn().getName());
+        assertEquals(TABLE_4_COLUMNS_BRIEF_0_DTO.getId(), table3pk.getColumn().getId());
+        assertEquals(TABLE_4_COLUMNS_BRIEF_0_DTO.getName(), table3pk.getColumn().getName());
+        assertEquals(TABLE_4_COLUMNS_BRIEF_0_DTO.getInternalName(), table3pk.getColumn().getInternalName());
+        assertEquals(ColumnTypeDto.TIMESTAMP, table3pk.getColumn().getColumnType());
+        assertNull(table3pk.getColumn().getAlias());
+        assertEquals(TABLE_4_ID, table3pk.getColumn().getTableId());
+        assertEquals(DATABASE_1_ID, table3pk.getColumn().getDatabaseId());
+    }
+
+    public static Stream<Arguments> nameToInternalName_parameters() {
+        return Stream.of(
+                Arguments.arguments("dash_minus", "OE/NO-027", "oeno-027"),
+                Arguments.arguments("percent", "OE%NO-027", "oeno-027"),
+                Arguments.arguments("umlaut", "OE/NÖ-027", "oeno-027"),
+                Arguments.arguments("dot", "OE.NO-027", "oeno-027")
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("nameToInternalName_parameters")
+    public void nameToInternalName_succeeds(String name, String request, String compare) {
+
+        /* test */
+        final String response = metadataMapper.nameToInternalName(request);
+        assertEquals(compare, response);
+    }
+
+    @Test
+    public void userEquals_fails() {
+
+        /* test */
+        assertNotEquals(USER_1_DTO, USER_2_DTO);
+    }
+
+    @Test
+    public void userEquals_identity_succeeds() {
+
+        /* test */
+        assertEquals(USER_1_DTO, USER_1_DTO);
+    }
+
+    @Test
+    public void userEquals_similar_succeeds() {
+        final UserDto tmp = UserDto.builder()
+                .id(USER_1_ID)
+                .build();
+
+        /* test */
+        assertEquals(USER_1_DTO, tmp);
+    }
+
+    @Test
+    public void userToUserBriefDto_succeeds() {
+
+        /* test */
+        final UserBriefDto response = metadataMapper.userToUserBriefDto(USER_1);
+        assertEquals(USER_1_NAME, response.getName());
+        assertEquals(USER_1_NAME + " — @" + USER_1_USERNAME, response.getQualifiedName());
+    }
+
+    @Test
+    public void userToUserDto_succeeds() {
+
+        /* test */
+        final UserDto response = metadataMapper.userToUserDto(USER_1);
+        assertEquals(USER_1_NAME, response.getName());
+        assertEquals(USER_1_NAME + " — @" + USER_1_USERNAME, response.getQualifiedName());
+    }
+
+    @Test
+    public void viewToViewDto_succeeds() {
+
+        /* test */
+        final ViewDto response = metadataMapper.viewToViewDto(VIEW_1);
+        assertEquals(VIEW_1_ID, response.getId());
+        assertEquals(VIEW_1_DATABASE_ID, response.getVdbid());
+        assertEquals(VIEW_1_NAME, response.getName());
+        assertEquals(VIEW_1_INTERNAL_NAME, response.getInternalName());
+        assertNotNull(response.getDatabase());
+        assertEquals(VIEW_1_DATABASE_ID, response.getDatabase().getId());
+        assertEquals(VIEW_1_QUERY, response.getQuery());
+        assertEquals(VIEW_1_QUERY_HASH, response.getQueryHash());
+        assertNotNull(response.getIdentifiers());
+        assertEquals(1, response.getIdentifiers().size());
+        final IdentifierDto identifier0 = response.getIdentifiers().get(0);
+        assertEquals(IDENTIFIER_3_ID, identifier0.getId());
+        assertEquals(VIEW_1_DATABASE_ID, identifier0.getDatabaseId());
+        assertEquals(VIEW_1_ID, identifier0.getViewId());
+        assertEquals(VIEW_1_QUERY, identifier0.getQuery());
+        assertEquals(VIEW_1_QUERY_HASH, identifier0.getQueryHash());
+    }
+
+}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/StoreMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/StoreMapperUnitTest.java
deleted file mode 100644
index 202c1cf2240d2684e806feda17e7d0caba47a625..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/StoreMapperUnitTest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.test.AbstractUnitTest;
-import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.Test;
-
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-@Log4j2
-public class StoreMapperUnitTest extends AbstractUnitTest {
-
-    private final DateTimeFormatter mariaDbFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.SSS]")
-            .withZone(ZoneId.of("UTC"));
-
-    @Test
-    public void mapMariaDbInstant_succeeds() {
-        final String timestamp = "2023-01-08 08:49:29";
-        final Instant compare = Instant.ofEpochSecond(1673167769);
-
-        /* test */
-        final Instant response = LocalDateTime.parse(timestamp, mariaDbFormatter)
-                .atZone(ZoneId.of("UTC"))
-                .toInstant();
-        assertEquals(compare, response);
-    }
-
-}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/TableMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/TableMapperUnitTest.java
deleted file mode 100644
index b02d660e0b4948fb20c334ce51d85874b4441fc6..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/TableMapperUnitTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.test.AbstractUnitTest;
-import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-
-import java.util.stream.Stream;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-@Log4j2
-@EnableAutoConfiguration(exclude = RabbitAutoConfiguration.class)
-@SpringBootTest
-@ExtendWith(SpringExtension.class)
-public class TableMapperUnitTest extends AbstractUnitTest {
-
-    @Autowired
-    private TableMapper tableMapper;
-
-    public static Stream<Arguments> nameToInternalName_parameters() {
-        return Stream.of(
-                Arguments.arguments("dash_minus", "OE/NO-027", "oe_no_027"),
-                Arguments.arguments("percent", "OE%NO-027", "oe_no_027"),
-                Arguments.arguments("umlaut", "OE/NÖ-027", "oe_no__027"),
-                Arguments.arguments("dot", "OE.NO-027", "oe_no_027")
-        );
-    }
-
-    @ParameterizedTest
-    @MethodSource("nameToInternalName_parameters")
-    public void nameToInternalName_succeeds(String name, String request, String compare) {
-
-        /* test */
-        final String response = tableMapper.nameToInternalName(request);
-        assertEquals(compare, response);
-    }
-
-}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/UserMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/UserMapperUnitTest.java
deleted file mode 100644
index dab115605f3ff553a611da84fff081cf70ac69c5..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/UserMapperUnitTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.test.AbstractUnitTest;
-import at.tuwien.api.user.UserBriefDto;
-import at.tuwien.api.user.UserDto;
-import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
-
-@Log4j2
-@SpringBootTest
-public class UserMapperUnitTest extends AbstractUnitTest {
-
-    @Autowired
-    private UserMapper userMapper;
-
-    @Test
-    public void equals_fails() {
-
-        /* test */
-        assertNotEquals(USER_1_DTO, USER_2_DTO);
-    }
-
-    @Test
-    public void equals_identity_succeeds() {
-
-        /* test */
-        assertEquals(USER_1_DTO, USER_1_DTO);
-    }
-
-    @Test
-    public void equals_similar_succeeds() {
-        final UserDto tmp = UserDto.builder()
-                .id(USER_1_ID)
-                .build();
-
-        /* test */
-        assertEquals(USER_1_DTO, tmp);
-    }
-
-    @Test
-    public void userToUserBriefDto_succeeds() {
-
-        /* test */
-        final UserBriefDto response = userMapper.userToUserBriefDto(USER_1);
-        assertEquals(USER_1_NAME, response.getName());
-        assertEquals(USER_1_NAME + " — @" + USER_1_USERNAME, response.getQualifiedName());
-    }
-
-    @Test
-    public void userToUserDto_succeeds() {
-
-        /* test */
-        final UserDto response = userMapper.userToUserDto(USER_1);
-        assertEquals(USER_1_NAME, response.getName());
-        assertEquals(USER_1_NAME + " — @" + USER_1_USERNAME, response.getQualifiedName());
-    }
-
-}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/ViewMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/ViewMapperUnitTest.java
deleted file mode 100644
index 07a70982644653a5df5040305f666036f826b6ec..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/ViewMapperUnitTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package at.tuwien.mapper;
-
-import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.identifier.IdentifierDto;
-import at.tuwien.test.AbstractUnitTest;
-import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-@Log4j2
-@SpringBootTest
-public class ViewMapperUnitTest extends AbstractUnitTest {
-
-    @Autowired
-    private ViewMapper viewMapper;
-
-    @BeforeEach
-    public void beforeEach() {
-        genesis();
-    }
-
-    @Test
-    public void viewToViewDto_succeeds() {
-
-        /* test */
-        final ViewDto response = viewMapper.viewToViewDto(VIEW_1);
-        assertEquals(VIEW_1_ID, response.getId());
-        assertEquals(VIEW_1_DATABASE_ID, response.getVdbid());
-        assertEquals(VIEW_1_NAME, response.getName());
-        assertEquals(VIEW_1_INTERNAL_NAME, response.getInternalName());
-        assertNotNull(response.getDatabase());
-        assertEquals(VIEW_1_DATABASE_ID, response.getDatabase().getId());
-        assertEquals(VIEW_1_QUERY, response.getQuery());
-        assertEquals(VIEW_1_QUERY_HASH, response.getQueryHash());
-        assertNotNull(response.getIdentifiers());
-        assertEquals(1, response.getIdentifiers().size());
-        final IdentifierDto identifier0 = response.getIdentifiers().get(0);
-        assertEquals(IDENTIFIER_3_ID, identifier0.getId());
-        assertEquals(VIEW_1_DATABASE_ID, identifier0.getDatabaseId());
-        assertEquals(VIEW_1_ID, identifier0.getViewId());
-        assertEquals(VIEW_1_QUERY, identifier0.getQuery());
-        assertEquals(VIEW_1_QUERY_HASH, identifier0.getQueryHash());
-    }
-
-}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java
index ed5f21281d71961317a4779aa67b38d0d9b9dca1..1d6d1c30e45f04b20f10985ec7ea67e2c8c88a4a 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java
@@ -5,7 +5,6 @@ import at.tuwien.exception.*;
 import at.tuwien.gateway.DataServiceGateway;
 import at.tuwien.gateway.SearchServiceGateway;
 import at.tuwien.repository.*;
-import at.tuwien.service.impl.DatabaseServiceImpl;
 import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
@@ -17,7 +16,6 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
 
@@ -64,7 +62,6 @@ public class DatabaseServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    @Transactional(readOnly = true)
     public void findById_succeeds() throws DatabaseNotFoundException {
 
         /* test */
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java
index 0e74c54947e0693090f43a3a25809473c6c6a609..6dfcb5187ec6237929d5c158ddcd6f21900f7356 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java
@@ -182,7 +182,7 @@ public class TableServiceUnitTest extends AbstractUnitTest {
         assertTrue(column0.getAutoGenerated());
         final TableColumn column1 = response.getColumns().get(1);
         assertEquals("I Am Späshül", column1.getName());
-        assertEquals("i_am_spa_shu_l", column1.getInternalName());
+        assertEquals("i_am_spashul", column1.getInternalName());
         assertEquals(TableColumnType.TEXT, column1.getColumnType());
         assertTrue(column1.getIsNullAllowed());
         assertFalse(column1.getAutoGenerated());
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/JacksonConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/JacksonConfig.java
index c4944a469174ad1962d5c54cc483400dbee12f1d..a451032e9de8d40f04724e44e85eb928dfba2653 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/JacksonConfig.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/JacksonConfig.java
@@ -3,6 +3,7 @@ package at.tuwien.config;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.hibernate6.Hibernate6Module;
 import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 import lombok.extern.slf4j.Slf4j;
@@ -21,6 +22,7 @@ public class JacksonConfig {
         final ObjectMapper objectMapper = new ObjectMapper();
         objectMapper.registerModule(new Jdk8Module());
         objectMapper.registerModule(new JavaTimeModule());
+        objectMapper.registerModule(new Hibernate6Module()); /* lazy load mapping on REST endpoints */
         objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
         objectMapper.setTimeZone(TimeZone.getTimeZone("UTC"));
         log.debug("current time is {}", objectMapper.writeValueAsString(new Date()));
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
index 0e96a47b709040978e9a9ec589218917890af860..1ad9cc46c0bbf9aee9273cc722f266843c951f2c 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
@@ -6,7 +6,7 @@ import at.tuwien.api.user.UserPasswordDto;
 import at.tuwien.config.KeycloakConfig;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.KeycloakGateway;
-import at.tuwien.mapper.UserMapper;
+import at.tuwien.mapper.MetadataMapper;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.http.*;
@@ -24,15 +24,15 @@ import java.util.UUID;
 @Service
 public class KeycloakGatewayImpl implements KeycloakGateway {
 
-    private final UserMapper userMapper;
     private final RestTemplate restTemplate;
     private final KeycloakConfig keycloakConfig;
+    private final MetadataMapper metadataMapper;
 
-    public KeycloakGatewayImpl(UserMapper userMapper, @Qualifier("keycloakRestTemplate") RestTemplate restTemplate,
-                               KeycloakConfig keycloakConfig) {
-        this.userMapper = userMapper;
+    public KeycloakGatewayImpl(@Qualifier("keycloakRestTemplate") RestTemplate restTemplate,
+                               KeycloakConfig keycloakConfig, MetadataMapper metadataMapper) {
         this.restTemplate = restTemplate;
         this.keycloakConfig = keycloakConfig;
+        this.metadataMapper = metadataMapper;
     }
 
     public TokenDto obtainToken() throws ServiceConnectionException, ServiceException {
@@ -192,7 +192,7 @@ public class KeycloakGatewayImpl implements KeycloakGateway {
         /* obtain admin token */
         final HttpHeaders headers = new HttpHeaders();
         headers.set("Authorization", "Bearer " + obtainToken().getAccessToken());
-        final UpdateCredentialsDto payload = userMapper.passwordToUpdateCredentialsDto(data.getPassword());
+        final UpdateCredentialsDto payload = metadataMapper.passwordToUpdateCredentialsDto(data.getPassword());
         final String url = keycloakConfig.getKeycloakEndpoint() + "/admin/realms/dbrepo/users/" + id;
         log.debug("update user credentials at url {}", url);
         final ResponseEntity<Void> response;
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java
index b0aa33888319aa67c5e5e9fa3085d712ffadf20d..49a2a1423ccae657f03f490c5a43cc3b7c057274 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java
@@ -2,13 +2,10 @@ package at.tuwien.gateway.impl;
 
 import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.database.table.constraints.unique.UniqueDto;
 import at.tuwien.entities.database.Database;
-import at.tuwien.entities.database.View;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.SearchServiceGateway;
-import at.tuwien.mapper.DatabaseMapper;
-import at.tuwien.mapper.TableMapper;
+import at.tuwien.mapper.MetadataMapper;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -26,63 +23,27 @@ import java.util.List;
 @Service
 public class SearchServiceGatewayImpl implements SearchServiceGateway {
 
-    private final TableMapper tableMapper;
     private final RestTemplate restTemplate;
-    private final DatabaseMapper databaseMapper;
+    private final MetadataMapper metadataMapper;
 
     @Autowired
-    public SearchServiceGatewayImpl(TableMapper tableMapper,
-                                    @Qualifier("searchServiceRestTemplate") RestTemplate restTemplate,
-                                    DatabaseMapper databaseMapper) {
-        this.tableMapper = tableMapper;
+    public SearchServiceGatewayImpl(@Qualifier("searchServiceRestTemplate") RestTemplate restTemplate,
+                                    MetadataMapper metadataMapper) {
         this.restTemplate = restTemplate;
-        this.databaseMapper = databaseMapper;
+        this.metadataMapper = metadataMapper;
     }
 
     @Override
     public DatabaseDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException {
         final ResponseEntity<DatabaseDto> response;
-        final DatabaseDto payload = databaseMapper.databaseToDatabaseDto(database);
-        payload.getTables()
-                .forEach(table -> {
-                    table.setIsPublic(database.getIsPublic());
-                    table.getColumns()
-                            .forEach(column -> {
-                                column.setTable(table);
-                                column.setTableId(table.getId());
-                                column.setDatabaseId(payload.getId());
-                                column.setIsPublic(payload.getIsPublic());
-                            });
-                    table.getConstraints()
-                            .getUniques()
-                            .forEach(uk -> {
-                                uk.setTable(tableMapper.tableDtoToTableBriefDto(table));
-                                uk.getTable().setDatabaseId(database.getId());
-                                uk.setColumns(new LinkedList<>());
-//                                uk.getColumns()
-//                                        .forEach(column -> {
-//                                            column.setTable(table);
-//                                            column.setTableId(table.getId());
-//                                            column.setDatabaseId(database.getId());
-//                                            column.setIsPublic(database.getIsPublic());
-//                                        });
-                            });
-                });
-        payload.getViews()
-                .stream()
-                .map(ViewDto::getColumns)
-                .flatMap(List::stream)
-                .forEach(columns -> {
-                    columns.setIsPublic(database.getIsPublic());
-                    columns.setDatabaseId(database.getId());
-                });
         final HttpHeaders headers = new HttpHeaders();
         headers.set("Accept", "application/json");
         headers.set("Content-Type", "application/json");
         final String url = "/api/search/database/" + database.getId();
         log.debug("update database in search service");
         try {
-            response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(payload, headers), DatabaseDto.class);
+            response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(
+                    metadataMapper.customDatabaseToDatabaseDto(database), headers), DatabaseDto.class);
         } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable |
                  HttpServerErrorException.InternalServerError e) {
             log.error("Failed to update database: {}", e.getMessage());
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java
index 57bb2c9df730f9796815c2c7eb181858acb39f17..5de1366e9f21b5fb468b38029fc37b98db0323e7 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java
@@ -7,7 +7,7 @@ import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.DataServiceGateway;
 import at.tuwien.gateway.SearchServiceGateway;
-import at.tuwien.mapper.DatabaseMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.repository.DatabaseRepository;
 import at.tuwien.service.AccessService;
 import at.tuwien.service.DatabaseService;
@@ -23,17 +23,17 @@ import java.util.Optional;
 @Service
 public class AccessServiceImpl implements AccessService {
 
-    private final DatabaseMapper databaseMapper;
+    private final MetadataMapper metadataMapper;
     private final DatabaseService databaseService;
     private final DatabaseRepository databaseRepository;
     private final DataServiceGateway dataServiceGateway;
     private final SearchServiceGateway searchServiceGateway;
 
     @Autowired
-    public AccessServiceImpl(DatabaseMapper databaseMapper, DatabaseService databaseService,
+    public AccessServiceImpl(MetadataMapper metadataMapper, DatabaseService databaseService,
                              DatabaseRepository databaseRepository, DataServiceGateway dataServiceGateway,
                              SearchServiceGateway searchServiceGateway) {
-        this.databaseMapper = databaseMapper;
+        this.metadataMapper = metadataMapper;
         this.databaseService = databaseService;
         this.databaseRepository = databaseRepository;
         this.dataServiceGateway = dataServiceGateway;
@@ -73,7 +73,7 @@ public class AccessServiceImpl implements AccessService {
                         .hdbid(database.getId())
                         .database(database)
                         .huserid(user.getId())
-                        .type(databaseMapper.accessTypeDtoToAccessType(access))
+                        .type(metadataMapper.accessTypeDtoToAccessType(access))
                         .build());
         database = databaseRepository.save(database);
         /* create in search service */
@@ -94,7 +94,7 @@ public class AccessServiceImpl implements AccessService {
                 .database(database)
                 .huserid(user.getId())
                 .user(user)
-                .type(databaseMapper.accessTypeDtoToAccessType(access))
+                .type(metadataMapper.accessTypeDtoToAccessType(access))
                 .build();
         final int idx = database.getAccesses().indexOf(entity);
         if (idx == -1) {
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java
index c47c93c86748b935527e7bd86d37950519c1d446..6fa8b250562dd89ade7dcecbe69a1a0d92b9fa66 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java
@@ -8,7 +8,7 @@ import at.tuwien.api.user.UserPasswordDto;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.KeycloakGateway;
-import at.tuwien.mapper.UserMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.AuthenticationService;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -20,19 +20,19 @@ import java.util.UUID;
 @Service
 public class AuthenticationServiceImpl implements AuthenticationService {
 
-    private final UserMapper userMapper;
+    private final MetadataMapper metadataMapper;
     private final KeycloakGateway keycloakGateway;
 
     @Autowired
-    public AuthenticationServiceImpl(UserMapper userMapper, KeycloakGateway keycloakGateway) {
-        this.userMapper = userMapper;
+    public AuthenticationServiceImpl(MetadataMapper metadataMapper, KeycloakGateway keycloakGateway) {
+        this.metadataMapper = metadataMapper;
         this.keycloakGateway = keycloakGateway;
     }
 
     @Override
     public void create(SignupRequestDto data) throws UserExistsException, ServiceException, ServiceConnectionException,
             EmailExistsException {
-        keycloakGateway.createUser(userMapper.signupRequestDtoToUserCreateDto(data));
+        keycloakGateway.createUser(metadataMapper.signupRequestDtoToUserCreateDto(data));
     }
 
     @Override
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BannerMessageServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BannerMessageServiceImpl.java
index 86d28ddde2e3796bb4ec8d01ebf09215383842d6..ac465232503374a1bd3df7d09e46bef00c473673 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BannerMessageServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BannerMessageServiceImpl.java
@@ -4,7 +4,7 @@ import at.tuwien.api.maintenance.BannerMessageCreateDto;
 import at.tuwien.api.maintenance.BannerMessageUpdateDto;
 import at.tuwien.entities.maintenance.BannerMessage;
 import at.tuwien.exception.MessageNotFoundException;
-import at.tuwien.mapper.BannerMessageMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.repository.BannerMessageRepository;
 import at.tuwien.service.BannerMessageService;
 import lombok.extern.log4j.Log4j2;
@@ -18,13 +18,13 @@ import java.util.Optional;
 @Service
 public class BannerMessageServiceImpl implements BannerMessageService {
 
-    private final BannerMessageMapper bannerMessageMapper;
+    private final MetadataMapper metadataMapper;
     private final BannerMessageRepository bannerMessageRepository;
 
     @Autowired
-    public BannerMessageServiceImpl(BannerMessageMapper bannerMessageMapper,
+    public BannerMessageServiceImpl(MetadataMapper metadataMapper,
                                     BannerMessageRepository bannerMessageRepository) {
-        this.bannerMessageMapper = bannerMessageMapper;
+        this.metadataMapper = metadataMapper;
         this.bannerMessageRepository = bannerMessageRepository;
     }
 
@@ -50,7 +50,7 @@ public class BannerMessageServiceImpl implements BannerMessageService {
 
     @Override
     public BannerMessage create(BannerMessageCreateDto data) {
-        final BannerMessage entity = bannerMessageMapper.bannerMessageCreateDtoToBannerMessage(data);
+        final BannerMessage entity = metadataMapper.bannerMessageCreateDtoToBannerMessage(data);
         final BannerMessage message = bannerMessageRepository.save(entity);
         log.info("Created banner message with id {}", message.getId());
         return message;
@@ -61,7 +61,7 @@ public class BannerMessageServiceImpl implements BannerMessageService {
         message.setMessage(data.getMessage());
         message.setDisplayEnd(data.getDisplayEnd());
         message.setDisplayStart(data.getDisplayStart());
-        message.setType(bannerMessageMapper.bannerMessageTypeDtoToBannerMessageType(data.getType()));
+        message.setType(metadataMapper.bannerMessageTypeDtoToBannerMessageType(data.getType()));
         message = bannerMessageRepository.save(message);
         log.info("Updated banner message with id {}", message.getId());
         return message;
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java
index 80c564c989b3538e936e0ecc9becc50b9f420aa4..91db7736db7d9a4a4e931c744a938e78d72308c9 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java
@@ -6,7 +6,7 @@ import at.tuwien.entities.container.image.ContainerImage;
 import at.tuwien.exception.ContainerAlreadyExistsException;
 import at.tuwien.exception.ContainerNotFoundException;
 import at.tuwien.exception.ImageNotFoundException;
-import at.tuwien.mapper.ContainerMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.repository.ContainerRepository;
 import at.tuwien.repository.ImageRepository;
 import at.tuwien.service.ContainerService;
@@ -24,14 +24,14 @@ import java.util.Optional;
 @Service
 public class ContainerServiceImpl implements ContainerService {
 
-    private final ContainerMapper containerMapper;
+    private final MetadataMapper metadataMapper;
     private final ImageRepository imageRepository;
     private final ContainerRepository containerRepository;
 
     @Autowired
-    public ContainerServiceImpl(ContainerMapper containerMapper, ImageRepository imageRepository,
+    public ContainerServiceImpl(MetadataMapper metadataMapper, ImageRepository imageRepository,
                                 ContainerRepository containerRepository) {
-        this.containerMapper = containerMapper;
+        this.metadataMapper = metadataMapper;
         this.imageRepository = imageRepository;
         this.containerRepository = containerRepository;
     }
@@ -40,9 +40,9 @@ public class ContainerServiceImpl implements ContainerService {
     @Transactional
     public Container create(ContainerCreateDto data) throws ImageNotFoundException,
             ContainerAlreadyExistsException {
+        final String containerName = "dbrepo-userdb-" + metadataMapper.nameToInternalName(data.getName());
         /* check */
-        final Optional<Container> optional = containerRepository.findByInternalName(
-                containerMapper.containerToInternalContainerName(data.getName()));
+        final Optional<Container> optional = containerRepository.findByInternalName(containerName);
         if (optional.isPresent()) {
             log.error("Failed to create container with name {}: exists in metadata database", data.getName());
             throw new ContainerAlreadyExistsException("Failed to create container: exists in metadata database");
@@ -56,7 +56,7 @@ public class ContainerServiceImpl implements ContainerService {
         Container container = Container.builder()
                 .image(optional2.get())
                 .name(data.getName())
-                .internalName(containerMapper.containerToInternalContainerName(data.getName()))
+                .internalName(containerName)
                 .host(data.getHost())
                 .port(data.getPort())
                 .privilegedUsername(data.getPrivilegedUsername())
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java
index bb5691514a3b6d6f71d9d247950f932f0b89a270..87f178b1c0d7e0d0bdf4c2be9e883a1a56b26861 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java
@@ -15,8 +15,7 @@ import at.tuwien.entities.database.Database;
 import at.tuwien.entities.identifier.Identifier;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
-import at.tuwien.mapper.DataCiteMapper;
-import at.tuwien.mapper.IdentifierMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.repository.IdentifierRepository;
 import at.tuwien.service.IdentifierService;
 import lombok.extern.slf4j.Slf4j;
@@ -42,7 +41,7 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService {
 
     private final RestTemplate restTemplate;
     private final DataCiteConfig dataCiteConfig;
-    private final DataCiteMapper dataCiteMapper;
+    private final MetadataMapper metadataMapper;
     private final EndpointConfig endpointConfig;
     private final IdentifierService identifierService;
     private final IdentifierRepository identifierRepository;
@@ -51,12 +50,12 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService {
     };
 
     public DataCiteIdentifierServiceImpl(@Qualifier("dataCiteRestTemplate") RestTemplate restTemplate,
-                                         DataCiteConfig dataCiteConfig, DataCiteMapper dataCiteMapper,
+                                         DataCiteConfig dataCiteConfig, MetadataMapper metadataMapper,
                                          EndpointConfig endpointConfig, IdentifierServiceImpl identifierService,
                                          IdentifierRepository identifierRepository) {
         this.restTemplate = restTemplate;
         this.dataCiteConfig = dataCiteConfig;
-        this.dataCiteMapper = dataCiteMapper;
+        this.metadataMapper = metadataMapper;
         this.endpointConfig = endpointConfig;
         this.identifierService = identifierService;
         this.identifierRepository = identifierRepository;
@@ -130,7 +129,7 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService {
                 DataCiteBody.<DataCiteCreateDoi>builder()
                         .data(DataCiteData.<DataCiteCreateDoi>builder()
                                 .type("dois")
-                                .attributes(dataCiteMapper.identifierToDataCiteCreateDoi(identifier,
+                                .attributes(metadataMapper.identifierToDataCiteCreateDoi(identifier,
                                         endpointConfig.getWebsiteUrl() + "/pid/" + identifier.getId(),
                                         dataCiteConfig.getPrefix(), event))
                                 .build())
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
index f695267a4a5c089be5f8235e3cd8abd59d81f826..c4a8187b5255cfea46ec0ebb19b80977014afa46 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
@@ -6,7 +6,6 @@ import at.tuwien.api.database.DatabaseModifyVisibilityDto;
 import at.tuwien.api.database.ViewDto;
 import at.tuwien.api.database.internal.CreateDatabaseDto;
 import at.tuwien.api.database.table.TableDto;
-import at.tuwien.api.database.table.columns.ColumnDto;
 import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto;
 import at.tuwien.api.user.internal.UpdateUserPasswordDto;
 import at.tuwien.entities.container.Container;
@@ -18,9 +17,7 @@ import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.DataServiceGateway;
 import at.tuwien.gateway.SearchServiceGateway;
-import at.tuwien.mapper.DatabaseMapper;
-import at.tuwien.mapper.TableMapper;
-import at.tuwien.mapper.ViewMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.repository.DatabaseRepository;
 import at.tuwien.service.*;
 import lombok.extern.log4j.Log4j2;
@@ -35,21 +32,17 @@ import java.util.*;
 @Service
 public class DatabaseServiceImpl implements DatabaseService {
 
-    private final ViewMapper viewMapper;
-    private final TableMapper tableMapper;
-    private final DatabaseMapper databaseMapper;
+    private final MetadataMapper metadataMapper;
     private final ContainerService containerService;
     private final DatabaseRepository databaseRepository;
     private final DataServiceGateway dataServiceGateway;
     private final SearchServiceGateway searchServiceGateway;
 
     @Autowired
-    public DatabaseServiceImpl(ViewMapper viewMapper, TableMapper tableMapper, DatabaseMapper databaseMapper,
-                               ContainerService containerService, DatabaseRepository databaseRepository,
-                               DataServiceGateway dataServiceGateway, SearchServiceGateway searchServiceGateway) {
-        this.viewMapper = viewMapper;
-        this.tableMapper = tableMapper;
-        this.databaseMapper = databaseMapper;
+    public DatabaseServiceImpl(MetadataMapper metadataMapper, ContainerService containerService,
+                               DatabaseRepository databaseRepository, DataServiceGateway dataServiceGateway, 
+                               SearchServiceGateway searchServiceGateway) {
+        this.metadataMapper = metadataMapper;
         this.containerService = containerService;
         this.databaseRepository = databaseRepository;
         this.dataServiceGateway = dataServiceGateway;
@@ -96,7 +89,7 @@ public class DatabaseServiceImpl implements DatabaseService {
         Database database = Database.builder()
                 .isPublic(data.getIsPublic())
                 .name(data.getName())
-                .internalName(databaseMapper.nameToInternalName(data.getName()) + "_" + RandomStringUtils.randomAlphabetic(4).toLowerCase())
+                .internalName(metadataMapper.nameToInternalName(data.getName()) + "_" + RandomStringUtils.randomAlphabetic(4).toLowerCase())
                 .cid(data.getCid())
                 .container(container)
                 .ownedBy(user.getId())
@@ -206,7 +199,7 @@ public class DatabaseServiceImpl implements DatabaseService {
                 continue;
             }
             log.debug("fetched unknown table from data service: {}.{}", database.getInternalName(), table.getInternalName());
-            final Table tableEntity = tableMapper.tableDtoToTable(table);
+            final Table tableEntity = metadataMapper.tableDtoToTable(table);
             tableEntity.setDatabase(database);
             tableEntity.getColumns()
                     .forEach(column -> {
@@ -267,7 +260,7 @@ public class DatabaseServiceImpl implements DatabaseService {
                 continue;
             }
             log.debug("fetched unknown view from data service: {}.{}", database.getInternalName(), view.getInternalName());
-            final View viewEntity = viewMapper.viewDtoToView(view);
+            final View viewEntity = metadataMapper.viewDtoToView(view);
             viewEntity.setDatabase(database);
             for (ViewColumn column : viewEntity.getColumns()) {
                 column.setView(viewEntity);
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/EntityServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/EntityServiceImpl.java
index 6dee3f7d71364ad733b40af155a51bd7f1781761..dba30481f5c3884ddea7da87930e295df91be37d 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/EntityServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/EntityServiceImpl.java
@@ -7,10 +7,9 @@ import at.tuwien.entities.database.table.Table;
 import at.tuwien.entities.database.table.columns.TableColumn;
 import at.tuwien.entities.semantics.Ontology;
 import at.tuwien.exception.*;
-import at.tuwien.mapper.OntologyMapper;
+import at.tuwien.mapper.SparqlMapper;
 import at.tuwien.service.EntityService;
 import at.tuwien.service.OntologyService;
-import at.tuwien.service.TableService;
 import lombok.extern.log4j.Log4j2;
 import org.apache.jena.query.*;
 import org.apache.jena.rdf.model.RDFNode;
@@ -23,7 +22,6 @@ import org.springframework.transaction.annotation.Transactional;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Optional;
 import java.util.concurrent.TimeUnit;
 
 @Log4j2
@@ -32,11 +30,11 @@ public class EntityServiceImpl implements EntityService {
 
     private final Dataset dataset;
     private final JenaConfig jenaConfig;
-    private final OntologyMapper ontologyMapper;
+    private final SparqlMapper ontologyMapper;
     private final OntologyService ontologyService;
 
     @Autowired
-    public EntityServiceImpl(Dataset dataset, JenaConfig jenaConfig, OntologyMapper ontologyMapper,
+    public EntityServiceImpl(Dataset dataset, JenaConfig jenaConfig, SparqlMapper ontologyMapper,
                              OntologyService ontologyService) {
         this.dataset = dataset;
         this.jenaConfig = jenaConfig;
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java
index a41e36877ae0b4ba7d6f6252381347c0acbe6c43..37215d0787d6532eb03d8bf3ebdd8557f28d83e0 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java
@@ -14,7 +14,6 @@ import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.DataServiceGateway;
 import at.tuwien.gateway.SearchServiceGateway;
-import at.tuwien.mapper.IdentifierMapper;
 import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.repository.IdentifierRepository;
 import at.tuwien.service.*;
@@ -39,21 +38,18 @@ public class IdentifierServiceImpl implements IdentifierService {
     private final MetadataConfig metadataConfig;
     private final MetadataMapper metadataMapper;
     private final TemplateEngine templateEngine;
-    private final IdentifierMapper identifierMapper;
     private final DataServiceGateway dataServiceGateway;
     private final IdentifierRepository identifierRepository;
     private final SearchServiceGateway searchServiceGateway;
 
 
     public IdentifierServiceImpl(ViewService viewService, TemplateEngine templateEngine, MetadataMapper metadataMapper,
-                                 IdentifierMapper identifierMapper, MetadataConfig metadataConfig,
-                                 DataServiceGateway dataServiceGateway, IdentifierRepository identifierRepository,
-                                 SearchServiceGateway searchServiceGateway) {
+                                 MetadataConfig metadataConfig, DataServiceGateway dataServiceGateway,
+                                 IdentifierRepository identifierRepository, SearchServiceGateway searchServiceGateway) {
         this.viewService = viewService;
         this.metadataConfig = metadataConfig;
         this.metadataMapper = metadataMapper;
         this.templateEngine = templateEngine;
-        this.identifierMapper = identifierMapper;
         this.dataServiceGateway = dataServiceGateway;
         this.identifierRepository = identifierRepository;
         this.searchServiceGateway = searchServiceGateway;
@@ -117,7 +113,7 @@ public class IdentifierServiceImpl implements IdentifierService {
         if (type != null) {
             log.trace("filter by type: {}", type);
             stream = stream.filter(i -> Objects.nonNull(i.getType()))
-                    .filter(i -> i.getType().equals(identifierMapper.identifierTypeDtoToIdentifierType(type)));
+                    .filter(i -> i.getType().equals(metadataMapper.identifierTypeDtoToIdentifierType(type)));
         }
         if (databaseId != null) {
             log.trace("filter by database id: {}", databaseId);
@@ -171,20 +167,20 @@ public class IdentifierServiceImpl implements IdentifierService {
         identifier.setQueryId(data.getQueryId());
         identifier.setViewId(data.getViewId());
         identifier.setDoi(data.getDoi());
-        identifier.setLanguage(identifierMapper.languageTypeDtoToLanguageType(data.getLanguage()));
+        identifier.setLanguage(metadataMapper.languageTypeDtoToLanguageType(data.getLanguage()));
         identifier.setLicenses(new LinkedList<>(data.getLicenses()
                 .stream()
-                .map(identifierMapper::licenseDtoToLicense)
+                .map(metadataMapper::licenseDtoToLicense)
                 .toList()));
         identifier.setPublicationDay(data.getPublicationDay());
         identifier.setPublicationMonth(data.getPublicationMonth());
         identifier.setPublicationYear(data.getPublicationYear());
-        identifier.setType(identifierMapper.identifierTypeDtoToIdentifierType(data.getType()));
+        identifier.setType(metadataMapper.identifierTypeDtoToIdentifierType(data.getType()));
         /* create in metadata database */
         if (data.getCreators() != null) {
             identifier.setCreators(new LinkedList<>(data.getCreators()
                     .stream()
-                    .map(identifierMapper::creatorCreateDtoToCreator)
+                    .map(metadataMapper::creatorCreateDtoToCreator)
                     .peek(c -> c.setIdentifier(identifier))
                     .toList()));
             log.debug("set {} creator(s)", identifier.getCreators().size());
@@ -192,7 +188,7 @@ public class IdentifierServiceImpl implements IdentifierService {
         if (data.getRelatedIdentifiers() != null) {
             identifier.setRelatedIdentifiers(new LinkedList<>(data.getRelatedIdentifiers()
                     .stream()
-                    .map(identifierMapper::relatedIdentifierCreateDtoToRelatedIdentifier)
+                    .map(metadataMapper::relatedIdentifierCreateDtoToRelatedIdentifier)
                     .peek(r -> r.setIdentifier(identifier))
                     .toList()));
             log.debug("set {} related identifier(s)", identifier.getRelatedIdentifiers().size());
@@ -200,7 +196,7 @@ public class IdentifierServiceImpl implements IdentifierService {
         if (data.getTitles() != null) {
             identifier.setTitles(new LinkedList<>(data.getTitles()
                     .stream()
-                    .map(identifierMapper::identifierCreateTitleDtoToIdentifierTitle)
+                    .map(metadataMapper::identifierCreateTitleDtoToIdentifierTitle)
                     .peek(t -> t.setIdentifier(identifier))
                     .toList()));
             log.debug("set {} title(s)", identifier.getTitles().size());
@@ -208,7 +204,7 @@ public class IdentifierServiceImpl implements IdentifierService {
         if (data.getDescriptions() != null) {
             identifier.setDescriptions(new LinkedList<>(data.getDescriptions()
                     .stream()
-                    .map(identifierMapper::identifierCreateDescriptionDtoToIdentifierDescription)
+                    .map(metadataMapper::identifierCreateDescriptionDtoToIdentifierDescription)
                     .peek(d -> d.setIdentifier(identifier))
                     .toList()));
             log.debug("set {} description(s)", identifier.getDescriptions().size());
@@ -216,7 +212,7 @@ public class IdentifierServiceImpl implements IdentifierService {
         if (data.getFunders() != null) {
             identifier.setFunders(new LinkedList<>(data.getFunders()
                     .stream()
-                    .map(identifierMapper::identifierFunderSaveDtoToIdentifierFunder)
+                    .map(metadataMapper::identifierFunderSaveDtoToIdentifierFunder)
                     .peek(d -> d.setIdentifier(identifier))
                     .toList()));
             log.debug("set {} funder(s)", identifier.getFunders().size());
@@ -229,7 +225,7 @@ public class IdentifierServiceImpl implements IdentifierService {
     public Identifier create(Database database, User user, IdentifierCreateDto data) throws SearchServiceException,
             ServiceException, QueryNotFoundException, ServiceConnectionException, DatabaseNotFoundException,
             SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException {
-        final Identifier identifier = identifierMapper.identifierCreateDtoToIdentifier(data);
+        final Identifier identifier = metadataMapper.identifierCreateDtoToIdentifier(data);
         identifier.setDatabase(database);
         identifier.setCreatedBy(user.getId());
         identifier.setCreator(user);
@@ -238,7 +234,7 @@ public class IdentifierServiceImpl implements IdentifierService {
         if (data.getCreators() != null) {
             identifier.setCreators(new LinkedList<>(data.getCreators()
                     .stream()
-                    .map(identifierMapper::creatorCreateDtoToCreator)
+                    .map(metadataMapper::creatorCreateDtoToCreator)
                     .peek(c -> c.setIdentifier(identifier))
                     .toList()));
             log.debug("set {} creator(s)", identifier.getCreators().size());
@@ -246,7 +242,7 @@ public class IdentifierServiceImpl implements IdentifierService {
         if (data.getRelatedIdentifiers() != null) {
             identifier.setRelatedIdentifiers(new LinkedList<>(data.getRelatedIdentifiers()
                     .stream()
-                    .map(identifierMapper::relatedIdentifierCreateDtoToRelatedIdentifier)
+                    .map(metadataMapper::relatedIdentifierCreateDtoToRelatedIdentifier)
                     .peek(r -> r.setIdentifier(identifier))
                     .toList()));
             log.debug("set {} related identifier(s)", identifier.getRelatedIdentifiers().size());
@@ -255,7 +251,7 @@ public class IdentifierServiceImpl implements IdentifierService {
             identifier.setTitles(null);
             identifier.setTitles(new LinkedList<>(data.getTitles()
                     .stream()
-                    .map(identifierMapper::identifierCreateTitleDtoToIdentifierTitle)
+                    .map(metadataMapper::identifierCreateTitleDtoToIdentifierTitle)
                     .peek(t -> t.setIdentifier(identifier))
                     .toList()));
             log.debug("set {} title(s)", identifier.getTitles().size());
@@ -263,7 +259,7 @@ public class IdentifierServiceImpl implements IdentifierService {
         if (data.getDescriptions() != null) {
             identifier.setDescriptions(new LinkedList<>(data.getDescriptions()
                     .stream()
-                    .map(identifierMapper::identifierCreateDescriptionDtoToIdentifierDescription)
+                    .map(metadataMapper::identifierCreateDescriptionDtoToIdentifierDescription)
                     .peek(d -> d.setIdentifier(identifier))
                     .toList()));
             log.debug("set {} description(s)", identifier.getDescriptions().size());
@@ -271,7 +267,7 @@ public class IdentifierServiceImpl implements IdentifierService {
         if (data.getFunders() != null) {
             identifier.setFunders(new LinkedList<>(data.getFunders()
                     .stream()
-                    .map(identifierMapper::identifierFunderSaveDtoToIdentifierFunder)
+                    .map(metadataMapper::identifierFunderSaveDtoToIdentifierFunder)
                     .peek(d -> d.setIdentifier(identifier))
                     .toList()));
             log.debug("set {} funder(s)", identifier.getFunders().size());
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java
index f7c9dcec9f5e82810aad6dcdbdb64c7734e96f36..8e4decfc1724a010e4d62f38491ad3404d259b1d 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java
@@ -5,7 +5,7 @@ import at.tuwien.api.container.image.ImageCreateDto;
 import at.tuwien.entities.container.image.ContainerImage;
 import at.tuwien.exception.ImageAlreadyExistsException;
 import at.tuwien.exception.ImageNotFoundException;
-import at.tuwien.mapper.ImageMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.repository.ImageRepository;
 import at.tuwien.service.ImageService;
 import jakarta.validation.ConstraintViolationException;
@@ -23,13 +23,13 @@ import java.util.Optional;
 @Service
 public class ImageServiceImpl implements ImageService {
 
-    private final ImageMapper imageMapper;
+    private final MetadataMapper metadataMapper;
     private final ImageRepository imageRepository;
 
     @Autowired
-    public ImageServiceImpl(ImageRepository imageRepository, ImageMapper imageMapper) {
+    public ImageServiceImpl(ImageRepository imageRepository, MetadataMapper metadataMapper) {
         this.imageRepository = imageRepository;
-        this.imageMapper = imageMapper;
+        this.metadataMapper = metadataMapper;
     }
 
     @Override
@@ -52,7 +52,7 @@ public class ImageServiceImpl implements ImageService {
     @Override
     @Transactional
     public ContainerImage create(ImageCreateDto createDto, Principal principal) throws ImageAlreadyExistsException {
-        final ContainerImage image = imageMapper.createImageDtoToContainerImage(createDto);
+        final ContainerImage image = metadataMapper.createImageDtoToContainerImage(createDto);
         if (imageRepository.findByNameAndVersion(createDto.getName(), createDto.getVersion()).isPresent()) {
             log.error("Failed to create image {}:{}: exists in the metadata database",
                     createDto.getName(), createDto.getVersion());
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java
index a89188c02c418d9574c6b25459f331aebebffeef..9dfefd18cca20a2f6c2e90182c112af147930f18 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java
@@ -10,7 +10,6 @@ import at.tuwien.exception.*;
 import at.tuwien.gateway.CrossrefGateway;
 import at.tuwien.gateway.OrcidGateway;
 import at.tuwien.gateway.RorGateway;
-import at.tuwien.mapper.ExternalMapper;
 import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.oaipmh.OaiErrorType;
 import at.tuwien.oaipmh.OaiListIdentifiersParameters;
@@ -26,18 +25,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
 import org.thymeleaf.TemplateEngine;
 import org.thymeleaf.context.Context;
-import org.w3c.dom.Document;
-import org.xml.sax.InputSource;
 
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.Writer;
 import java.time.Instant;
 import java.util.List;
 import java.util.Optional;
@@ -48,7 +36,6 @@ public class MetadataServiceImpl implements MetadataService {
 
     private final RorGateway rorGateway;
     private final OrcidGateway orcidGateway;
-    private final ExternalMapper externalMapper;
     private final MetadataConfig metadataConfig;
     private final MetadataMapper metadataMapper;
     private final TemplateEngine templateEngine;
@@ -57,13 +44,12 @@ public class MetadataServiceImpl implements MetadataService {
     private final IdentifierRepository identifierRepository;
 
     @Autowired
-    public MetadataServiceImpl(RorGateway rorGateway, OrcidGateway orcidGateway, ExternalMapper externalMapper,
-                               MetadataConfig metadataConfig, MetadataMapper metadataMapper,
-                               TemplateEngine templateEngine, CrossrefGateway crossrefGateway,
-                               IdentifierService identifierService, IdentifierRepository identifierRepository) {
+    public MetadataServiceImpl(RorGateway rorGateway, OrcidGateway orcidGateway, MetadataConfig metadataConfig,
+                               MetadataMapper metadataMapper, TemplateEngine templateEngine,
+                               CrossrefGateway crossrefGateway, IdentifierService identifierService,
+                               IdentifierRepository identifierRepository) {
         this.rorGateway = rorGateway;
         this.orcidGateway = orcidGateway;
-        this.externalMapper = externalMapper;
         this.metadataConfig = metadataConfig;
         this.metadataMapper = metadataMapper;
         this.templateEngine = templateEngine;
@@ -175,7 +161,7 @@ public class MetadataServiceImpl implements MetadataService {
             DoiNotFoundException, IdentifierNotSupportedException {
         if (url.contains("orcid.org")) {
             final OrcidDto orcidDto = orcidGateway.findByUrl(url);
-            return externalMapper.orcidDtoToExternalMetadataDto(orcidDto);
+            return metadataMapper.orcidDtoToExternalMetadataDto(orcidDto);
         } else if (url.contains("ror.org")) {
             final int idx = url.lastIndexOf('/');
             if (idx + 1 >= url.length()) {
@@ -184,7 +170,7 @@ public class MetadataServiceImpl implements MetadataService {
             }
             final String id = url.substring(idx + 1);
             final RorDto rorDto = rorGateway.findById(id);
-            return externalMapper.rorDtoToExternalMetadataDto(rorDto);
+            return metadataMapper.rorDtoToExternalMetadataDto(rorDto);
         } else if (url.contains("doi.org")) {
             final int idx = url.indexOf("doi.org/");
             if (idx + 1 >= url.length()) {
@@ -193,7 +179,7 @@ public class MetadataServiceImpl implements MetadataService {
             }
             final String id = url.substring(idx + 8);
             final CrossrefDto crossrefDto = crossrefGateway.findById(id);
-            return externalMapper.crossrefDtoToExternalMetadataDto(crossrefDto);
+            return metadataMapper.crossrefDtoToExternalMetadataDto(crossrefDto);
         }
         log.error("Failed to find metadata: unsupported identifier {}", url);
         throw new IdentifierNotSupportedException("Failed to find metadata: unsupported identifier " + url);
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java
index 92d1cec924b20e53bf4bc6dd3bc3cb419e46cd0e..3f242914e9ac0f187b7e05258d7fe16edf0715c2 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java
@@ -4,7 +4,8 @@ import at.tuwien.api.semantics.OntologyCreateDto;
 import at.tuwien.api.semantics.OntologyModifyDto;
 import at.tuwien.entities.semantics.Ontology;
 import at.tuwien.exception.OntologyNotFoundException;
-import at.tuwien.mapper.OntologyMapper;
+import at.tuwien.mapper.MetadataMapper;
+import at.tuwien.mapper.SparqlMapper;
 import at.tuwien.repository.OntologyRepository;
 import at.tuwien.service.OntologyService;
 import lombok.extern.log4j.Log4j2;
@@ -21,12 +22,15 @@ import java.util.Optional;
 @Service
 public class OntologyServiceImpl implements OntologyService {
 
-    private final OntologyMapper ontologyMapper;
+    private final SparqlMapper sparqlMapper;
+    private final MetadataMapper metadataMapper;
     private final OntologyRepository ontologyRepository;
 
     @Autowired
-    public OntologyServiceImpl(OntologyMapper ontologyMapper, OntologyRepository ontologyRepository) {
-        this.ontologyMapper = ontologyMapper;
+    public OntologyServiceImpl(SparqlMapper ontologyMapper, MetadataMapper metadataMapper,
+                               OntologyRepository ontologyRepository) {
+        this.sparqlMapper = ontologyMapper;
+        this.metadataMapper = metadataMapper;
         this.ontologyRepository = ontologyRepository;
     }
 
@@ -71,7 +75,7 @@ public class OntologyServiceImpl implements OntologyService {
     @Override
     public Ontology create(OntologyCreateDto data, Principal principal) {
         /* delete in metadata database */
-        final Ontology entity = ontologyMapper.ontologyCreateDtoToOntology(data);
+        final Ontology entity = metadataMapper.ontologyCreateDtoToOntology(data);
         final Ontology ontology = ontologyRepository.save(entity);
         log.info("Created ontology with id {} ", ontology.getId());
         return ontology;
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java
index d53e1c04347a1f94b16857ef27611beac2b3b8ce..bf5ca0a98f13d2233f5fd6b2a896348f9955d732 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java
@@ -18,8 +18,8 @@ import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.DataServiceGateway;
 import at.tuwien.gateway.SearchServiceGateway;
-import at.tuwien.mapper.OntologyMapper;
-import at.tuwien.mapper.TableMapper;
+import at.tuwien.mapper.MetadataMapper;
+import at.tuwien.mapper.SparqlMapper;
 import at.tuwien.repository.DatabaseRepository;
 import at.tuwien.service.*;
 import lombok.extern.log4j.Log4j2;
@@ -34,31 +34,31 @@ import java.util.*;
 @Service
 public class TableServiceImpl implements TableService {
 
-    private final TableMapper tableMapper;
     private final UserService userService;
     private final UnitService unitService;
+    private final SparqlMapper ontologyMapper;
     private final RabbitConfig rabbitConfig;
     private final EntityService entityService;
     private final ConceptService conceptService;
-    private final OntologyMapper ontologyMapper;
+    private final MetadataMapper metadataMapper;
     private final DatabaseService databaseService;
     private final DataServiceGateway dataServiceGateway;
     private final DatabaseRepository databaseRepository;
     private final SearchServiceGateway searchServiceGateway;
 
     @Autowired
-    public TableServiceImpl(TableMapper tableMapper, UserService userService, UnitService unitService,
-                            RabbitConfig rabbitConfig, EntityService entityService, ConceptService conceptService,
-                            OntologyMapper ontologyMapper, DatabaseService databaseService,
-                            DataServiceGateway dataServiceGateway, DatabaseRepository databaseRepository,
+    public TableServiceImpl(UserService userService, UnitService unitService, SparqlMapper ontologyMapper, 
+                            RabbitConfig rabbitConfig, EntityService entityService, ConceptService conceptService, 
+                            MetadataMapper metadataMapper, DatabaseService databaseService, 
+                            DataServiceGateway dataServiceGateway, DatabaseRepository databaseRepository, 
                             SearchServiceGateway searchServiceGateway) {
-        this.tableMapper = tableMapper;
         this.userService = userService;
         this.unitService = unitService;
+        this.ontologyMapper = ontologyMapper;
         this.rabbitConfig = rabbitConfig;
         this.entityService = entityService;
         this.conceptService = conceptService;
-        this.ontologyMapper = ontologyMapper;
+        this.metadataMapper = metadataMapper;
         this.databaseService = databaseService;
         this.dataServiceGateway = dataServiceGateway;
         this.databaseRepository = databaseRepository;
@@ -125,7 +125,7 @@ public class TableServiceImpl implements TableService {
         final Table table = Table.builder()
                 .isVersioned(true)
                 .name(data.getName())
-                .internalName(tableMapper.nameToInternalName(data.getName()))
+                .internalName(metadataMapper.nameToInternalName(data.getName()))
                 .description(data.getDescription())
                 .queueName(rabbitConfig.getQueueName())
                 .tdbid(database.getId())
@@ -143,7 +143,7 @@ public class TableServiceImpl implements TableService {
                     .addAll(data.getColumns()
                             .stream()
                             .map(c -> {
-                                final TableColumn column = tableMapper.columnCreateDtoToTableColumn(c, database.getContainer().getImage());
+                                final TableColumn column = metadataMapper.columnCreateDtoToTableColumn(c, database.getContainer().getImage());
                                 if (data.isNeedSequence() && column.getName().equals("id")) {
                                     column.setAutoGenerated(true);
                                 }
@@ -165,7 +165,7 @@ public class TableServiceImpl implements TableService {
                             })
                             .toList());
             /* set constraints */
-            table.setConstraints(tableMapper.constraintsCreateDtoToConstraints(data.getConstraints(), database, table));
+            table.setConstraints(metadataMapper.constraintsCreateDtoToConstraints(data.getConstraints(), database, table));
         } catch (IllegalArgumentException e) {
             throw new MalformedException(e);
         }
@@ -228,7 +228,7 @@ public class TableServiceImpl implements TableService {
             try {
                 unit = unitService.find(data.getUnitUri());
             } catch (UnitNotFoundException e) {
-                unit = ontologyMapper.entityDtoToTableColumnUnit(entityService.findOneByUri(data.getUnitUri()));
+                unit = metadataMapper.entityDtoToTableColumnUnit(entityService.findOneByUri(data.getUnitUri()));
             }
             column.setUnit(unit);
         } else {
@@ -239,7 +239,7 @@ public class TableServiceImpl implements TableService {
             try {
                 concept = conceptService.find(data.getConceptUri());
             } catch (ConceptNotFoundException e) {
-                concept = ontologyMapper.entityDtoToTableColumnConcept(entityService.findOneByUri(data.getConceptUri()));
+                concept = metadataMapper.entityDtoToTableColumnConcept(entityService.findOneByUri(data.getConceptUri()));
             }
             column.setConcept(concept);
         } else {
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
index ec269391996948f47ad0a3b55c7996eb73a3b9f2..f9d888b5a0bd4117ce56ca2d5be81d8b9751a8c7 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
@@ -8,7 +8,7 @@ import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.DataServiceGateway;
 import at.tuwien.gateway.SearchServiceGateway;
-import at.tuwien.mapper.ViewMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.repository.DatabaseRepository;
 import at.tuwien.service.ViewService;
 import com.google.common.hash.Hashing;
@@ -26,15 +26,15 @@ import java.util.Optional;
 @Service
 public class ViewServiceImpl implements ViewService {
 
-    private final ViewMapper viewMapper;
+    private final MetadataMapper metadataMapper;
     private final DataServiceGateway dataServiceGateway;
     private final DatabaseRepository databaseRepository;
     private final SearchServiceGateway searchServiceGateway;
 
     @Autowired
-    public ViewServiceImpl(ViewMapper viewMapper, DataServiceGateway dataServiceGateway,
+    public ViewServiceImpl(MetadataMapper metadataMapper, DataServiceGateway dataServiceGateway,
                            DatabaseRepository databaseRepository, SearchServiceGateway searchServiceGateway) {
-        this.viewMapper = viewMapper;
+        this.metadataMapper = metadataMapper;
         this.dataServiceGateway = dataServiceGateway;
         this.databaseRepository = databaseRepository;
         this.searchServiceGateway = searchServiceGateway;
@@ -91,7 +91,7 @@ public class ViewServiceImpl implements ViewService {
                 .vdbid(database.getId())
                 .database(database)
                 .name(data.getName())
-                .internalName(viewMapper.nameToInternalName(data.getName()))
+                .internalName(metadataMapper.nameToInternalName(data.getName()))
                 .createdBy(creator.getId())
                 .creator(creator)
                 .identifiers(new LinkedList<>())
diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java
index a7808196311e875f354a997d364e160d510a9f81..3ba5fc9e360d907f68b9fa2a44974e87a8af8054 100644
--- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java
+++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java
@@ -20,6 +20,7 @@ public abstract class AbstractUnitTest extends BaseTest {
         /* USER_4 */
         USER_5.setAccesses(new LinkedList<>());
         /* DATABASE 1 */
+        DATABASE_1.setSubsets(new LinkedList<>());
         DATABASE_1.setAccesses(new LinkedList<>(List.of(DATABASE_1_USER_1_READ_ACCESS, DATABASE_1_USER_2_WRITE_OWN_ACCESS, DATABASE_1_USER_3_WRITE_ALL_ACCESS)));
         DATABASE_1_PRIVILEGED_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_1_USER_1_READ_ACCESS_DTO, DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO, DATABASE_1_USER_3_WRITE_ALL_ACCESS_DTO)));
         TABLE_1.setDatabase(DATABASE_1);
@@ -67,6 +68,7 @@ public abstract class AbstractUnitTest extends BaseTest {
         IDENTIFIER_3.setDatabase(DATABASE_1);
         IDENTIFIER_4.setDatabase(DATABASE_1);
         /* DATABASE 2 */
+        DATABASE_2.setSubsets(new LinkedList<>());
         DATABASE_2.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS, DATABASE_2_USER_3_READ_ACCESS)));
         DATABASE_2.setTables(new LinkedList<>(List.of(TABLE_5, TABLE_6, TABLE_7)));
         DATABASE_2.setViews(new LinkedList<>(List.of(VIEW_4)));
@@ -91,6 +93,7 @@ public abstract class AbstractUnitTest extends BaseTest {
         VIEW_4.setDatabase(DATABASE_2);
         IDENTIFIER_5.setDatabase(DATABASE_2);
         /* DATABASE 3 */
+        DATABASE_3.setSubsets(new LinkedList<>());
         DATABASE_3.setAccesses(new LinkedList<>(List.of(DATABASE_3_USER_1_WRITE_ALL_ACCESS)));
         DATABASE_3.setTables(new LinkedList<>(List.of(TABLE_8)));
         DATABASE_3.setViews(new LinkedList<>(List.of(VIEW_5)));
@@ -106,6 +109,7 @@ public abstract class AbstractUnitTest extends BaseTest {
         VIEW_5.setColumns(VIEW_5_COLUMNS);
         IDENTIFIER_6.setDatabase(DATABASE_3);
         /* DATABASE 4 */
+        DATABASE_4.setSubsets(new LinkedList<>());
         DATABASE_4.setAccesses(new LinkedList<>(List.of(DATABASE_4_USER_1_READ_ACCESS, DATABASE_4_USER_2_WRITE_OWN_ACCESS, DATABASE_4_USER_3_WRITE_ALL_ACCESS)));
         DATABASE_4.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_7)));
         IDENTIFIER_7.setDatabase(DATABASE_4);
diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
index e0275f5d6eb97dd096b8ad4143b1f085c4955c7a..b78619575639f23815785dfb9d50f844b595c455 100644
--- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
+++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
@@ -18,10 +18,7 @@ import at.tuwien.api.database.table.TableBriefDto;
 import at.tuwien.api.database.table.TableCreateDto;
 import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.database.table.TableStatisticDto;
-import at.tuwien.api.database.table.columns.ColumnCreateDto;
-import at.tuwien.api.database.table.columns.ColumnDto;
-import at.tuwien.api.database.table.columns.ColumnStatisticDto;
-import at.tuwien.api.database.table.columns.ColumnTypeDto;
+import at.tuwien.api.database.table.columns.*;
 import at.tuwien.api.database.table.columns.concepts.*;
 import at.tuwien.api.database.table.constraints.ConstraintsCreateDto;
 import at.tuwien.api.database.table.constraints.ConstraintsDto;
@@ -1517,6 +1514,10 @@ public abstract class BaseTest {
     public final static String TABLE_1_QUEUE_NAME = TABLE_1_INTERNALNAME;
     public final static String TABLE_1_ROUTING_KEY = "dbrepo\\." + DATABASE_1_ID + "\\." + TABLE_1_ID;
     public final static Long TABLE_1_DATABASE_ID = DATABASE_1_ID;
+    public final static Long TABLE_1_AVG_ROW_LENGTH = 3L;
+    public final static Long TABLE_1_NUM_ROWS = 3L;
+    public final static Long TABLE_1_DATA_LENGTH = 2000L;
+    public final static Long TABLE_1_MAX_DATA_LENGTH = Long.MAX_VALUE;
     public final static Instant TABLE_1_CREATED = Instant.ofEpochSecond(1677399975L) /* 2023-02-26 08:26:15 (UTC) */;
     public final static Instant TABLE_1_LAST_MODIFIED = Instant.ofEpochSecond(1677399975L) /* 2023-02-26 08:26:15 (UTC) */;
 
@@ -1537,6 +1538,10 @@ public abstract class BaseTest {
             .createdBy(USER_1_ID)
             .owner(USER_1_DTO)
             .isPublic(DATABASE_1_PUBLIC)
+            .avgRowLength(TABLE_1_AVG_ROW_LENGTH)
+            .numRows(TABLE_1_NUM_ROWS)
+            .dataLength(TABLE_1_DATA_LENGTH)
+            .maxDataLength(TABLE_1_MAX_DATA_LENGTH)
             .build();
 
     public final static Table TABLE_1 = Table.builder()
@@ -1557,6 +1562,10 @@ public abstract class BaseTest {
             .ownedBy(USER_1_ID)
             .owner(USER_1)
             .lastModified(TABLE_1_LAST_MODIFIED)
+            .avgRowLength(TABLE_1_AVG_ROW_LENGTH)
+            .numRows(TABLE_1_NUM_ROWS)
+            .dataLength(TABLE_1_DATA_LENGTH)
+            .maxDataLength(TABLE_1_MAX_DATA_LENGTH)
             .build();
 
     public final static TableDto TABLE_1_DTO = TableDto.builder()
@@ -1574,6 +1583,10 @@ public abstract class BaseTest {
             .constraints(null) /* TABLE_1_CONSTRAINT_DTO */
             .createdBy(USER_1_ID)
             .owner(USER_1_DTO)
+            .avgRowLength(TABLE_1_AVG_ROW_LENGTH)
+            .numRows(TABLE_1_NUM_ROWS)
+            .dataLength(TABLE_1_DATA_LENGTH)
+            .maxDataLength(TABLE_1_MAX_DATA_LENGTH)
             .build();
 
     public final static List<ColumnDto> TABLE_1_COLUMNS_DTO = List.of(ColumnDto.builder()
@@ -1665,6 +1678,10 @@ public abstract class BaseTest {
     public final static String TABLE_2_ROUTING_KEY = "dbrepo\\." + DATABASE_1_ID + "\\." + TABLE_2_ID;
     public final static Instant TABLE_2_CREATED = Instant.ofEpochSecond(1677400007L) /* 2023-02-26 08:26:47 (UTC) */;
     public final static Instant TABLE_2_LAST_MODIFIED = Instant.ofEpochSecond(1677400007L) /* 2023-02-26 08:26:47 (UTC) */;
+    public final static Long TABLE_2_AVG_ROW_LENGTH = 3L;
+    public final static Long TABLE_2_NUM_ROWS = 3L;
+    public final static Long TABLE_2_DATA_LENGTH = 2000L;
+    public final static Long TABLE_2_MAX_DATA_LENGTH = Long.MAX_VALUE;
 
     public final static Table TABLE_2 = Table.builder()
             .id(TABLE_2_ID)
@@ -1679,9 +1696,14 @@ public abstract class BaseTest {
             .queueName(TABLE_2_QUEUE_NAME)
             .columns(new LinkedList<>() /* TABLE_2_COLUMNS */)
             .constraints(null) /* TABLE_2_CONSTRAINTS */
+            .creator(USER_2)
             .createdBy(USER_2_ID)
-            .ownedBy(USER_2_ID)
             .owner(USER_2)
+            .ownedBy(USER_2_ID)
+            .avgRowLength(TABLE_2_AVG_ROW_LENGTH)
+            .numRows(TABLE_2_NUM_ROWS)
+            .dataLength(TABLE_2_DATA_LENGTH)
+            .maxDataLength(TABLE_2_MAX_DATA_LENGTH)
             .build();
 
     public final static PrivilegedTableDto TABLE_2_PRIVILEGED_DTO = PrivilegedTableDto.builder()
@@ -1698,8 +1720,13 @@ public abstract class BaseTest {
             .identifiers(new LinkedList<>())
             .columns(new LinkedList<>() /* TABLE_2_COLUMNS_DTO */)
             .constraints(null) /* TABLE_2_CONSTRAINTS_DTO */
-            .createdBy(USER_1_ID)
-            .owner(USER_1_DTO)
+            .creator(USER_2_DTO)
+            .createdBy(USER_2_ID)
+            .owner(USER_2_DTO)
+            .avgRowLength(TABLE_2_AVG_ROW_LENGTH)
+            .numRows(TABLE_2_NUM_ROWS)
+            .dataLength(TABLE_2_DATA_LENGTH)
+            .maxDataLength(TABLE_2_MAX_DATA_LENGTH)
             .build();
 
     public final static TableDto TABLE_2_DTO = TableDto.builder()
@@ -1714,8 +1741,13 @@ public abstract class BaseTest {
             .routingKey(TABLE_2_ROUTING_KEY)
             .columns(new LinkedList<>() /* TABLE_2_COLUMNS_DTO */)
             .constraints(null) /* TABLE_2_CONSTRAINTS_DTO */
+            .creator(USER_2_DTO)
             .createdBy(USER_2_ID)
             .owner(USER_2_DTO)
+            .avgRowLength(TABLE_2_AVG_ROW_LENGTH)
+            .numRows(TABLE_2_NUM_ROWS)
+            .dataLength(TABLE_2_DATA_LENGTH)
+            .maxDataLength(TABLE_2_MAX_DATA_LENGTH)
             .build();
 
     public final static TableBriefDto TABLE_2_BRIEF_DTO = TableBriefDto.builder()
@@ -1738,6 +1770,10 @@ public abstract class BaseTest {
     public final static String TABLE_3_ROUTING_KEY = "dbrepo\\." + DATABASE_1_ID + "\\." + TABLE_3_ID;
     public final static Instant TABLE_3_CREATED = Instant.ofEpochSecond(1677400031L) /* 2023-02-26 08:27:11 (UTC) */;
     public final static Instant TABLE_3_LAST_MODIFIED = Instant.ofEpochSecond(1677400031L) /* 2023-02-26 08:27:11 (UTC) */;
+    public final static Long TABLE_3_AVG_ROW_LENGTH = 6L;
+    public final static Long TABLE_3_NUM_ROWS = 6L;
+    public final static Long TABLE_3_DATA_LENGTH = 1800L;
+    public final static Long TABLE_3_MAX_DATA_LENGTH = Long.MAX_VALUE;
 
     public final static Table TABLE_3 = Table.builder()
             .id(TABLE_3_ID)
@@ -1752,9 +1788,14 @@ public abstract class BaseTest {
             .queueName(TABLE_3_QUEUE_NAME)
             .columns(new LinkedList<>() /* TABLE_3_COLUMNS */)
             .constraints(null) /* TABLE_3_CONSTRAINTS */
+            .creator(USER_3)
             .createdBy(USER_3_ID)
-            .ownedBy(USER_3_ID)
             .owner(USER_3)
+            .ownedBy(USER_3_ID)
+            .avgRowLength(TABLE_3_AVG_ROW_LENGTH)
+            .numRows(TABLE_3_NUM_ROWS)
+            .dataLength(TABLE_3_DATA_LENGTH)
+            .maxDataLength(TABLE_3_MAX_DATA_LENGTH)
             .build();
 
     public final static TableDto TABLE_3_DTO = TableDto.builder()
@@ -1769,8 +1810,13 @@ public abstract class BaseTest {
             .routingKey(TABLE_3_ROUTING_KEY)
             .columns(new LinkedList<>() /* TABLE_3_COLUMNS_DTO */)
             .constraints(null) /* TABLE_3_CONSTRAINTS_DTO */
+            .creator(USER_3_DTO)
             .createdBy(USER_3_ID)
             .owner(USER_3_DTO)
+            .avgRowLength(TABLE_3_AVG_ROW_LENGTH)
+            .numRows(TABLE_3_NUM_ROWS)
+            .dataLength(TABLE_3_DATA_LENGTH)
+            .maxDataLength(TABLE_3_MAX_DATA_LENGTH)
             .build();
 
     public final static TableBriefDto TABLE_3_BRIEF_DTO = TableBriefDto.builder()
@@ -1980,19 +2026,23 @@ public abstract class BaseTest {
 
     public final static Long TABLE_4_ID = 4L;
     public final static String TABLE_4_NAME = "Sensor 2";
-    public final static String TABLE_4_INTERNAL_NAME = "sensor_2";
+    public final static String TABLE_4_INTERNALNAME = "sensor_2";
     public final static Boolean TABLE_4_VERSIONED = true;
     public final static Boolean TABLE_4_PROCESSED_CONSTRAINTS = true;
     public final static String TABLE_4_DESCRIPTION = "Hello sensor";
-    public final static String TABLE_4_QUEUE_NAME = TABLE_4_INTERNAL_NAME;
+    public final static String TABLE_4_QUEUE_NAME = TABLE_4_INTERNALNAME;
     public final static String TABLE_4_ROUTING_KEY = "dbrepo\\." + DATABASE_1_ID + "\\." + TABLE_4_ID;
     public final static Instant TABLE_4_CREATED = Instant.ofEpochSecond(1677400175L) /* 2023-02-26 08:29:35 (UTC) */;
     public final static Instant TABLE_4_LAST_MODIFIED = Instant.ofEpochSecond(1677400175L) /* 2023-02-26 08:29:35 (UTC) */;
+    public final static Long TABLE_4_AVG_ROW_LENGTH = 0L;
+    public final static Long TABLE_4_NUM_ROWS = 0L;
+    public final static Long TABLE_4_DATA_LENGTH = 1000L;
+    public final static Long TABLE_4_MAX_DATA_LENGTH = Long.MAX_VALUE;
 
     public final static Table TABLE_4 = Table.builder()
             .id(TABLE_4_ID)
             .tdbid(DATABASE_1_ID)
-            .internalName(TABLE_4_INTERNAL_NAME)
+            .internalName(TABLE_4_INTERNALNAME)
             .description(TABLE_4_DESCRIPTION)
             .database(null /* DATABASE_1 */)
             .name(TABLE_4_NAME)
@@ -2000,17 +2050,22 @@ public abstract class BaseTest {
             .columns(new LinkedList<>()) /* TABLE_4_COLUMNS */
             .constraints(null) /* TABLE_4_CONSTRAINTS */
             .isVersioned(TABLE_4_VERSIONED)
+            .creator(USER_1)
             .createdBy(USER_1_ID)
-            .ownedBy(USER_1_ID)
             .owner(USER_1)
+            .ownedBy(USER_1_ID)
             .created(TABLE_4_CREATED)
             .lastModified(TABLE_4_LAST_MODIFIED)
+            .avgRowLength(TABLE_4_AVG_ROW_LENGTH)
+            .numRows(TABLE_4_NUM_ROWS)
+            .dataLength(TABLE_4_DATA_LENGTH)
+            .maxDataLength(TABLE_4_MAX_DATA_LENGTH)
             .build();
 
     public final static TableDto TABLE_4_DTO = TableDto.builder()
             .id(TABLE_4_ID)
             .tdbid(DATABASE_1_ID)
-            .internalName(TABLE_4_INTERNAL_NAME)
+            .internalName(TABLE_4_INTERNALNAME)
             .description(TABLE_4_DESCRIPTION)
             .name(TABLE_4_NAME)
             .queueName(TABLE_4_QUEUE_NAME)
@@ -2018,14 +2073,19 @@ public abstract class BaseTest {
             .columns(new LinkedList<>()) /* TABLE_4_COLUMNS_DTO */
             .constraints(null) /* TABLE_4_CONSTRAINTS_DTO */
             .isVersioned(TABLE_4_VERSIONED)
+            .creator(USER_1_DTO)
             .createdBy(USER_1_ID)
             .owner(USER_1_DTO)
             .created(TABLE_4_CREATED)
+            .avgRowLength(TABLE_4_AVG_ROW_LENGTH)
+            .numRows(TABLE_4_NUM_ROWS)
+            .dataLength(TABLE_4_DATA_LENGTH)
+            .maxDataLength(TABLE_4_MAX_DATA_LENGTH)
             .build();
 
     public final static TableBriefDto TABLE_4_BRIEF_DTO = TableBriefDto.builder()
             .id(TABLE_4_ID)
-            .internalName(TABLE_4_INTERNAL_NAME)
+            .internalName(TABLE_4_INTERNALNAME)
             .description(TABLE_4_DESCRIPTION)
             .name(TABLE_4_NAME)
             .columns(new LinkedList<>() /* TABLE_4_COLUMNS */)
@@ -2033,6 +2093,13 @@ public abstract class BaseTest {
             .owner(USER_1_BRIEF_DTO)
             .build();
 
+    public final static ColumnBriefDto TABLE_4_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder()
+            .id(44L)
+            .name("Timestamp")
+            .internalName("timestamp")
+            .columnType(ColumnTypeDto.TIMESTAMP)
+            .build();
+
     public final static List<TableColumn> TABLE_4_COLUMNS = List.of(TableColumn.builder()
                     .id(44L)
                     .ordinalPosition(0)
@@ -2339,6 +2406,13 @@ public abstract class BaseTest {
     public final static List<String> COLUMN_8_2_SET_VALUES = null;
     public final static List<String> COLUMN_8_2_SET_VALUES_DTO = null;
 
+    public final static ColumnBriefDto TABLE_8_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder()
+            .id(COLUMN_8_1_ID)
+            .name(COLUMN_8_1_NAME)
+            .internalName(COLUMN_8_1_INTERNAL_NAME)
+            .columnType(ColumnTypeDto.BIGINT)
+            .build();
+
     public final static List<TableColumn> TABLE_8_COLUMNS = List.of(TableColumn.builder()
                     .id(COLUMN_8_1_ID)
                     .ordinalPosition(COLUMN_8_1_ORDINALPOS)
@@ -2658,6 +2732,13 @@ public abstract class BaseTest {
             .isPersisted(QUERY_6_PERSISTED)
             .build();
 
+    public final static ColumnBriefDto TABLE_1_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder()
+            .id(1L)
+            .name("id")
+            .internalName("id")
+            .columnType(ColumnTypeDto.BIGINT)
+            .build();
+
     public final static List<TableColumn> TABLE_1_COLUMNS = List.of(TableColumn.builder()
                     .id(1L)
                     .ordinalPosition(0)
@@ -2772,6 +2853,13 @@ public abstract class BaseTest {
                     .sets(null)
                     .build());
 
+    public final static ColumnBriefDto TABLE_2_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder()
+            .id(6L)
+            .name("location")
+            .internalName("location")
+            .columnType(ColumnTypeDto.VARCHAR)
+            .build();
+
     public final static List<ColumnDto> TABLE_2_COLUMNS_DTO = List.of(ColumnDto.builder()
                     .id(6L)
                     .table(TABLE_2_DTO)
@@ -2814,6 +2902,13 @@ public abstract class BaseTest {
                     .sets(null)
                     .build());
 
+    public final static ColumnBriefDto TABLE_3_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder()
+            .id(9L)
+            .columnType(ColumnTypeDto.BIGINT)
+            .name("id")
+            .internalName("id")
+            .build();
+
     public final static List<TableColumn> TABLE_3_COLUMNS = List.of(TableColumn.builder()
                     .id(9L)
                     .table(TABLE_3)
@@ -3723,6 +3818,13 @@ public abstract class BaseTest {
                     .sets(new LinkedList<>())
                     .build());
 
+    public final static ColumnBriefDto TABLE_5_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder()
+            .id(45L)
+            .name("id")
+            .internalName("id")
+            .columnType(ColumnTypeDto.BIGINT)
+            .build();
+
     public final static List<TableColumn> TABLE_5_COLUMNS = List.of(TableColumn.builder()
                     .id(45L)
                     .ordinalPosition(0)
@@ -4344,6 +4446,13 @@ public abstract class BaseTest {
                     .autoGenerated(false)
                     .build());
 
+    public final static ColumnBriefDto TABLE_6_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder()
+            .id(66L)
+            .name("id")
+            .internalName("id")
+            .columnType(ColumnTypeDto.BIGINT)
+            .build();
+
     public final static List<ColumnDto> TABLE_6_COLUMNS_DTO = List.of(ColumnDto.builder()
                     .id(66L)
                     .ordinalPosition(0)
@@ -4444,6 +4553,13 @@ public abstract class BaseTest {
             .constraints(TABLE_6_CONSTRAINTS_CREATE)
             .build();
 
+    public final static ColumnBriefDto TABLE_7_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder()
+            .id(26L)
+            .name("name_id")
+            .internalName("name_id")
+            .columnType(ColumnTypeDto.BIGINT)
+            .build();
+
     public final static List<TableColumn> TABLE_7_COLUMNS = List.of(TableColumn.builder()
                     .id(26L)
                     .ordinalPosition(0)
@@ -6745,6 +6861,7 @@ public abstract class BaseTest {
             .owner(USER_1)
             .contactPerson(USER_1_ID)
             .contact(USER_1)
+            .subsets(new LinkedList<>())
             .tables(new LinkedList<>())
             .views(new LinkedList<>())
             .accesses(new LinkedList<>())
@@ -7249,7 +7366,7 @@ public abstract class BaseTest {
             .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder()
                     .table(TABLE_1)
                     .column(TABLE_1_COLUMNS.get(0))
-                    .pkid(1L)
+                    .id(1L)
                     .build())))
             .build();
 
@@ -7259,8 +7376,8 @@ public abstract class BaseTest {
             .uniques(new LinkedList<>())
             .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder()
                     .table(TABLE_1_BRIEF_DTO)
-                    .column(TABLE_1_COLUMNS_DTO.get(0))
-                    .pkid(1L)
+                    .column(TABLE_1_COLUMNS_BRIEF_0_DTO)
+                    .id(1L)
                     .build())))
             .build();
 
@@ -7280,7 +7397,7 @@ public abstract class BaseTest {
                     .onUpdate(ReferenceType.NO_ACTION)
                     .build())))
             .uniques(new LinkedList<>(List.of(Unique.builder()
-                    .uid(1L)
+                    .id(1L)
                     .table(TABLE_2)
                     .name("uk_1")
                     .columns(new LinkedList<>(List.of(TABLE_2_COLUMNS.get(1))))
@@ -7288,7 +7405,7 @@ public abstract class BaseTest {
             .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder()
                     .table(TABLE_2)
                     .column(TABLE_2_COLUMNS.get(0))
-                    .pkid(2L)
+                    .id(2L)
                     .build())))
             .build();
 
@@ -7308,15 +7425,15 @@ public abstract class BaseTest {
                     .onUpdate(ReferenceTypeDto.NO_ACTION)
                     .build())))
             .uniques(new LinkedList<>(List.of(UniqueDto.builder()
-                    .uid(1L)
+                    .id(1L)
                     .table(TABLE_2_BRIEF_DTO)
                     .name("uk_1")
                     .columns(new LinkedList<>(List.of(TABLE_2_COLUMNS_DTO.get(1))))
                     .build())))
             .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder()
                     .table(TABLE_2_BRIEF_DTO)
-                    .column(TABLE_2_COLUMNS_DTO.get(0))
-                    .pkid(2L)
+                    .column(TABLE_2_COLUMNS_BRIEF_0_DTO)
+                    .id(2L)
                     .build())))
             .build();
 
@@ -7327,7 +7444,7 @@ public abstract class BaseTest {
             .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder()
                     .table(TABLE_3)
                     .column(TABLE_3_COLUMNS.get(0))
-                    .pkid(3L)
+                    .id(3L)
                     .build())))
             .build();
 
@@ -7337,8 +7454,8 @@ public abstract class BaseTest {
             .uniques(new LinkedList<>())
             .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder()
                     .table(TABLE_3_BRIEF_DTO)
-                    .column(TABLE_3_COLUMNS_DTO.get(0))
-                    .pkid(3L)
+                    .column(TABLE_3_COLUMNS_BRIEF_0_DTO)
+                    .id(3L)
                     .build())))
             .build();
 
@@ -7349,7 +7466,7 @@ public abstract class BaseTest {
             .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder()
                     .table(TABLE_4)
                     .column(TABLE_4_COLUMNS.get(0))
-                    .pkid(4L)
+                    .id(4L)
                     .build())))
             .build();
 
@@ -7359,8 +7476,8 @@ public abstract class BaseTest {
             .uniques(new LinkedList<>())
             .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder()
                     .table(TABLE_4_BRIEF_DTO)
-                    .column(TABLE_4_COLUMNS_DTO.get(0))
-                    .pkid(4L)
+                    .column(TABLE_4_COLUMNS_BRIEF_0_DTO)
+                    .id(4L)
                     .build())))
             .build();
 
@@ -7371,7 +7488,7 @@ public abstract class BaseTest {
             .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder()
                     .table(TABLE_5)
                     .column(TABLE_5_COLUMNS.get(0))
-                    .pkid(5L)
+                    .id(5L)
                     .build())))
             .build();
 
@@ -7381,8 +7498,8 @@ public abstract class BaseTest {
             .uniques(new LinkedList<>())
             .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder()
                     .table(TABLE_5_BRIEF_DTO)
-                    .column(TABLE_5_COLUMNS_DTO.get(0))
-                    .pkid(5L)
+                    .column(TABLE_5_COLUMNS_BRIEF_0_DTO)
+                    .id(5L)
                     .build())))
             .build();
 
@@ -7393,7 +7510,7 @@ public abstract class BaseTest {
             .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder()
                     .table(TABLE_6)
                     .column(TABLE_6_COLUMNS.get(0))
-                    .pkid(6L)
+                    .id(6L)
                     .build())))
             .build();
 
@@ -7403,8 +7520,8 @@ public abstract class BaseTest {
             .uniques(new LinkedList<>())
             .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder()
                     .table(TABLE_6_BRIEF_DTO)
-                    .column(TABLE_6_COLUMNS_DTO.get(0))
-                    .pkid(6L)
+                    .column(TABLE_6_COLUMNS_BRIEF_0_DTO)
+                    .id(6L)
                     .build())))
             .build();
 
@@ -7440,7 +7557,7 @@ public abstract class BaseTest {
             .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder()
                     .table(TABLE_7)
                     .column(TABLE_7_COLUMNS.get(0))
-                    .pkid(7L)
+                    .id(7L)
                     .build())))
             .build();
 
@@ -7475,8 +7592,8 @@ public abstract class BaseTest {
             .uniques(new LinkedList<>())
             .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder()
                     .table(TABLE_7_BRIEF_DTO)
-                    .column(TABLE_7_COLUMNS_DTO.get(0))
-                    .pkid(7L)
+                    .column(TABLE_7_COLUMNS_BRIEF_0_DTO)
+                    .id(7L)
                     .build())))
             .build();
 
@@ -7487,7 +7604,7 @@ public abstract class BaseTest {
             .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder()
                     .table(TABLE_8)
                     .column(TABLE_8_COLUMNS.get(0))
-                    .pkid(8L)
+                    .id(8L)
                     .build())))
             .build();
 
@@ -7497,8 +7614,8 @@ public abstract class BaseTest {
             .uniques(new LinkedList<>())
             .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder()
                     .table(TABLE_8_BRIEF_DTO)
-                    .column(TABLE_8_COLUMNS_DTO.get(0))
-                    .pkid(8L)
+                    .column(TABLE_8_COLUMNS_BRIEF_0_DTO)
+                    .id(8L)
                     .build())))
             .build();
 
diff --git a/dbrepo-search-service/Pipfile.lock b/dbrepo-search-service/Pipfile.lock
index 1c60362635327df0034e268b2e037d9dd4a73430..c85c4145f461295fa388802c1e6564c8c15c74f7 100644
--- a/dbrepo-search-service/Pipfile.lock
+++ b/dbrepo-search-service/Pipfile.lock
@@ -132,11 +132,11 @@
         },
         "certifi": {
             "hashes": [
-                "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f",
-                "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"
+                "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516",
+                "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"
             ],
             "markers": "python_version >= '3.6'",
-            "version": "==2024.2.2"
+            "version": "==2024.6.2"
         },
         "cffi": {
             "hashes": [
@@ -340,10 +340,9 @@
         },
         "dbrepo": {
             "hashes": [
-                "sha256:ceab260cf76c050e118ce0f0589fec66059396751e03f2ec41fa489cfacc4e7b"
+                "sha256:110db9e4e70f5656a6351409d4b022656abf7de0bd72d5e061a25685f708d9a4"
             ],
-            "path": "./lib/dbrepo-1.4.4.tar.gz",
-            "version": "==1.4.4"
+            "path": "./lib/dbrepo-1.4.4.tar.gz"
         },
         "docker": {
             "hashes": [
@@ -353,6 +352,12 @@
             "markers": "python_version >= '3.8'",
             "version": "==7.1.0"
         },
+        "events": {
+            "hashes": [
+                "sha256:a7286af378ba3e46640ac9825156c93bdba7502174dd696090fdfcd4d80a1abd"
+            ],
+            "version": "==0.5"
+        },
         "flasgger": {
             "hashes": [
                 "sha256:ca098e10bfbb12f047acc6299cc70a33851943a746e550d86e65e60d4df245fb"
@@ -366,6 +371,7 @@
                 "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.8'",
             "version": "==2.3.3"
         },
         "flask-cors": {
@@ -390,6 +396,7 @@
                 "sha256:9215d05a9413d3855764bcd67035e75819d23af2fafb6b55197eb5a3313fdfb2"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.7' and python_version < '4'",
             "version": "==4.6.0"
         },
         "flask-sqlalchemy": {
@@ -398,6 +405,7 @@
                 "sha256:e4b68bb881802dda1a7d878b2fc84c06d1ee57fb40b874d3dc97dabfa36b8312"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.8'",
             "version": "==3.1.1"
         },
         "frozenlist": {
@@ -553,6 +561,7 @@
                 "sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.7'",
             "version": "==22.0.0"
         },
         "idna": {
@@ -615,6 +624,7 @@
                 "sha256:61c9170f92e736b530655e75374681d4fcca9cfa8763ab42be57353b2b203494"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.6'",
             "version": "==1.3.1"
         },
         "markupsafe": {
@@ -831,11 +841,12 @@
         },
         "opensearch-py": {
             "hashes": [
-                "sha256:0dde4ac7158a717d92a8cd81964cb99705a4b80bcf9258ba195b9a9f23f5226d",
-                "sha256:cf093a40e272b60663f20417fc1264ac724dcf1e03c1a4542a6b44835b1e6c49"
+                "sha256:0b7c27e8ed84c03c99558406927b6161f186a72502ca6d0325413d8e5523ba96",
+                "sha256:b6e78b685dd4e9c016d7a4299cf1de69e299c88322e3f81c716e6e23fe5683c1"
             ],
             "index": "pypi",
-            "version": "==2.5.0"
+            "markers": "python_version >= '3.8' and python_version < '4'",
+            "version": "==2.6.0"
         },
         "packaging": {
             "hashes": [
@@ -922,96 +933,96 @@
         },
         "pydantic": {
             "hashes": [
-                "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5",
-                "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"
+                "sha256:c46c76a40bb1296728d7a8b99aa73dd70a48c3510111ff290034f860c99c419e",
+                "sha256:ea91b002777bf643bb20dd717c028ec43216b24a6001a280f83877fd2655d0b4"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==2.7.1"
+            "version": "==2.7.3"
         },
         "pydantic-core": {
             "hashes": [
-                "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b",
-                "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a",
-                "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90",
-                "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d",
-                "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e",
-                "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d",
-                "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027",
-                "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804",
-                "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347",
-                "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400",
-                "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3",
-                "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399",
-                "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349",
-                "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd",
-                "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c",
-                "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e",
-                "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413",
-                "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3",
-                "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e",
-                "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3",
-                "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91",
-                "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce",
-                "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c",
-                "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb",
-                "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664",
-                "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6",
-                "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd",
-                "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3",
-                "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af",
-                "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043",
-                "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350",
-                "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7",
-                "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0",
-                "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563",
-                "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761",
-                "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72",
-                "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3",
-                "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb",
-                "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788",
-                "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b",
-                "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c",
-                "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038",
-                "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250",
-                "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec",
-                "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c",
-                "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74",
-                "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81",
-                "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439",
-                "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75",
-                "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0",
-                "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8",
-                "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150",
-                "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438",
-                "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae",
-                "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857",
-                "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038",
-                "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374",
-                "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f",
-                "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241",
-                "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592",
-                "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4",
-                "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d",
-                "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b",
-                "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b",
-                "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182",
-                "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e",
-                "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641",
-                "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70",
-                "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9",
-                "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a",
-                "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543",
-                "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b",
-                "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f",
-                "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38",
-                "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845",
-                "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2",
-                "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0",
-                "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4",
-                "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"
+                "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3",
+                "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8",
+                "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8",
+                "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30",
+                "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a",
+                "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8",
+                "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d",
+                "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc",
+                "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2",
+                "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab",
+                "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077",
+                "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e",
+                "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9",
+                "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9",
+                "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef",
+                "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1",
+                "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507",
+                "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528",
+                "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558",
+                "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b",
+                "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154",
+                "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724",
+                "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695",
+                "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9",
+                "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851",
+                "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805",
+                "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a",
+                "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5",
+                "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94",
+                "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c",
+                "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d",
+                "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef",
+                "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26",
+                "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2",
+                "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c",
+                "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0",
+                "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2",
+                "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4",
+                "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d",
+                "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2",
+                "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce",
+                "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34",
+                "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f",
+                "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d",
+                "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b",
+                "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07",
+                "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312",
+                "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057",
+                "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d",
+                "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af",
+                "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb",
+                "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd",
+                "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78",
+                "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b",
+                "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223",
+                "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a",
+                "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4",
+                "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5",
+                "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23",
+                "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a",
+                "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4",
+                "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8",
+                "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d",
+                "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443",
+                "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e",
+                "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f",
+                "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e",
+                "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d",
+                "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc",
+                "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443",
+                "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be",
+                "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2",
+                "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee",
+                "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f",
+                "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae",
+                "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864",
+                "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4",
+                "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951",
+                "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==2.18.2"
+            "version": "==2.18.4"
         },
         "pyjwt": {
             "hashes": [
@@ -1035,6 +1046,7 @@
                 "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.8'",
             "version": "==8.2.1"
         },
         "python-dateutil": {
@@ -1051,6 +1063,7 @@
                 "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.8'",
             "version": "==1.0.1"
         },
         "pytz": {
@@ -1123,6 +1136,7 @@
                 "sha256:9995eb8569428059b8c1affd26b25eac510d64f5043d9ce8c84e0d0036e995ae"
             ],
             "index": "pypi",
+            "markers": "python_full_version >= '3.8.1' and python_full_version < '4.0.0'",
             "version": "==7.0.0"
         },
         "referencing": {
@@ -1135,11 +1149,11 @@
         },
         "requests": {
             "hashes": [
-                "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289",
-                "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"
+                "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760",
+                "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==2.32.2"
+            "version": "==2.32.3"
         },
         "rpds-py": {
             "hashes": [
@@ -1315,6 +1329,7 @@
                 "sha256:bc599c8c3b3319e53ce6c5c3c471120bd325d0071fb6f38a10e924e3d07b9990"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.7'",
             "version": "==0.41.2"
         },
         "testcontainers-core": {
@@ -1329,6 +1344,7 @@
                 "sha256:0bdf270b5b7f53915832f7c31dd2bd3ffdc20b534ea6b32231cc7003049bd0e1"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.7'",
             "version": "==0.0.1rc1"
         },
         "tinydb": {
@@ -1349,11 +1365,11 @@
         },
         "typing-extensions": {
             "hashes": [
-                "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8",
-                "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"
+                "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a",
+                "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==4.12.0"
+            "version": "==4.12.1"
         },
         "tzdata": {
             "hashes": [
@@ -1365,11 +1381,11 @@
         },
         "urllib3": {
             "hashes": [
-                "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07",
-                "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"
+                "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d",
+                "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"
             ],
-            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
-            "version": "==1.26.18"
+            "markers": "python_version >= '3.10'",
+            "version": "==2.2.1"
         },
         "werkzeug": {
             "hashes": [
@@ -1555,61 +1571,62 @@
     "develop": {
         "coverage": {
             "hashes": [
-                "sha256:06d96b9b19bbe7f049c2be3c4f9e06737ec6d8ef8933c7c3a4c557ef07936e46",
-                "sha256:13017a63b0e499c59b5ba94a8542fb62864ba3016127d1e4ef30d354fc2b00e9",
-                "sha256:1acc2e2ef098a1d4bf535758085f508097316d738101a97c3f996bccba963ea5",
-                "sha256:1aef719b6559b521ae913ddeb38f5048c6d1a3d366865e8b320270b7bc4693c2",
-                "sha256:1e4225990a87df898e40ca31c9e830c15c2c53b1d33df592bc8ef314d71f0281",
-                "sha256:1f11f98753800eb1ec872562a398081f6695f91cd01ce39819e36621003ec52a",
-                "sha256:1f29bf497d51a5077994b265e976d78b09d9d0dff6ca5763dbb4804534a5d380",
-                "sha256:1f96aa94739593ae0707eda9813ce363a0a0374a810ae0eced383340fc4a1f73",
-                "sha256:20e611fc36e1a0fc7bbf957ef9c635c8807d71fbe5643e51b2769b3cc0fb0b51",
-                "sha256:23f2f16958b16152b43a39a5ecf4705757ddd284b3b17a77da3a62aef9c057ef",
-                "sha256:24bb4c7859a3f757a116521d4d3a8a82befad56ea1bdacd17d6aafd113b0071e",
-                "sha256:26716a1118c6ce2188283b4b60a898c3be29b480acbd0a91446ced4fe4e780d8",
-                "sha256:29da75ce20cb0a26d60e22658dd3230713c6c05a3465dd8ad040ffc991aea318",
-                "sha256:2b144d142ec9987276aeff1326edbc0df8ba4afbd7232f0ca10ad57a115e95b6",
-                "sha256:2c79f058e7bec26b5295d53b8c39ecb623448c74ccc8378631f5cb5c16a7e02c",
-                "sha256:3bb5b92a0ab3d22dfdbfe845e2fef92717b067bdf41a5b68c7e3e857c0cff1a4",
-                "sha256:3d3f7744b8a8079d69af69d512e5abed4fb473057625588ce126088e50d05493",
-                "sha256:3d9c62cff2ffb4c2a95328488fd7aa96a7a4b34873150650fe76b19c08c9c792",
-                "sha256:3e12536446ad4527ac8ed91d8a607813085683bcce27af69e3b31cd72b3c5960",
-                "sha256:40dbb8e7727560fe8ab65efcddfec1ae25f30ef02e2f2e5d78cfb52a66781ec5",
-                "sha256:431a3917e32223fcdb90b79fe60185864a9109631ebc05f6c5aa03781a00b513",
-                "sha256:448ec61ea9ea7916d5579939362509145caaecf03161f6f13e366aebb692a631",
-                "sha256:482df956b055d3009d10fce81af6ffab28215d7ed6ad4a15e5c8e67cb7c5251c",
-                "sha256:4a00bd5ba8f1a4114720bef283cf31583d6cb1c510ce890a6da6c4268f0070b7",
-                "sha256:51b6cee539168a912b4b3b040e4042b9e2c9a7ad9c8546c09e4eaeff3eacba6b",
-                "sha256:554c7327bf0fd688050348e22db7c8e163fb7219f3ecdd4732d7ed606b417263",
-                "sha256:5662bf0f6fb6757f5c2d6279c541a5af55a39772c2362ed0920b27e3ce0e21f7",
-                "sha256:5997d418c219dcd4dcba64e50671cca849aaf0dac3d7a2eeeb7d651a5bd735b8",
-                "sha256:59a75e6aa5c25b50b5a1499f9718f2edff54257f545718c4fb100f48d570ead4",
-                "sha256:60b66b0363c5a2a79fba3d1cd7430c25bbd92c923d031cae906bdcb6e054d9a2",
-                "sha256:6e34680049eecb30b6498784c9637c1c74277dcb1db75649a152f8004fbd6646",
-                "sha256:74eeaa13e8200ad72fca9c5f37395fb310915cec6f1682b21375e84fd9770e84",
-                "sha256:7c5c5b7ae2763533152880d5b5b451acbc1089ade2336b710a24b2b0f5239d20",
-                "sha256:829fb55ad437d757c70d5b1c51cfda9377f31506a0a3f3ac282bc6a387d6a5f1",
-                "sha256:878243e1206828908a6b4a9ca7b1aa8bee9eb129bf7186fc381d2646f4524ce9",
-                "sha256:8809c0ea0e8454f756e3bd5c36d04dddf222989216788a25bfd6724bfcee342c",
-                "sha256:8941e35a0e991a7a20a1fa3e3182f82abe357211f2c335a9e6007067c3392fcf",
-                "sha256:894b1acded706f1407a662d08e026bfd0ff1e59e9bd32062fea9d862564cfb65",
-                "sha256:900532713115ac58bc3491b9d2b52704a05ed408ba0918d57fd72c94bc47fba1",
-                "sha256:976cd92d9420e6e2aa6ce6a9d61f2b490e07cb468968adf371546b33b829284b",
-                "sha256:97de509043d3f0f2b2cd171bdccf408f175c7f7a99d36d566b1ae4dd84107985",
-                "sha256:9a42970ce74c88bdf144df11c52c5cf4ad610d860de87c0883385a1c9d9fa4ab",
-                "sha256:9e41c94035e5cdb362beed681b58a707e8dc29ea446ea1713d92afeded9d1ddd",
-                "sha256:9f805481d5eff2a96bac4da1570ef662bf970f9a16580dc2c169c8c3183fa02b",
-                "sha256:a35c97af60a5492e9e89f8b7153fe24eadfd61cb3a2fb600df1a25b5dab34b7e",
-                "sha256:a7c6574225f34ce45466f04751d957b5c5e6b69fca9351db017c9249786172ce",
-                "sha256:c7ebf2a37e4f5fea3c1a11e1f47cea7d75d0f2d8ef69635ddbd5c927083211fc",
-                "sha256:d0305e02e40c7cfea5d08d6368576537a74c0eea62b77633179748d3519d6705",
-                "sha256:e1046aab24c48c694f0793f669ac49ea68acde6a0798ac5388abe0a5615b5ec8",
-                "sha256:e5d22eba19273b2069e4efeff88c897a26bdc64633cbe0357a198f92dca94268",
-                "sha256:ec27e93bbf5976f0465e8936f02eb5add99bbe4e4e7b233607e4d7622912d68d",
-                "sha256:fe76d6dee5e4febefa83998b17926df3a04e5089e3d2b1688c74a9157798d7a2"
+                "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523",
+                "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f",
+                "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d",
+                "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb",
+                "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0",
+                "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c",
+                "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98",
+                "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83",
+                "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8",
+                "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7",
+                "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac",
+                "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84",
+                "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb",
+                "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3",
+                "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884",
+                "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614",
+                "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd",
+                "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807",
+                "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd",
+                "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8",
+                "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc",
+                "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db",
+                "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0",
+                "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08",
+                "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232",
+                "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d",
+                "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a",
+                "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1",
+                "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286",
+                "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303",
+                "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341",
+                "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84",
+                "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45",
+                "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc",
+                "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec",
+                "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd",
+                "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155",
+                "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52",
+                "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d",
+                "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485",
+                "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31",
+                "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d",
+                "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d",
+                "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d",
+                "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85",
+                "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce",
+                "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb",
+                "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974",
+                "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24",
+                "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56",
+                "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9",
+                "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"
             ],
             "index": "pypi",
-            "version": "==7.5.2"
+            "markers": "python_version >= '3.8'",
+            "version": "==7.5.3"
         },
         "iniconfig": {
             "hashes": [
@@ -1641,6 +1658,7 @@
                 "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.8'",
             "version": "==8.2.1"
         }
     }
diff --git a/dbrepo-search-service/app.py b/dbrepo-search-service/app.py
index be4481cf08ee80a38a666e3db3303f12b8fc6613..844c01709f5b92b00a1daa2922be65ba81f106bb 100644
--- a/dbrepo-search-service/app.py
+++ b/dbrepo-search-service/app.py
@@ -361,8 +361,9 @@ def post_general_search(type):
                description='Time needed to update a database in the search database')
 @auth.login_required(role=['admin'])
 @swag_from("os-yml/update_database.yml")
-def update_database(database_id: int):
+def update_database(database_id: int) -> Database | ApiError:
     logging.debug(f"updating database with id: {database_id}")
+    logging.debug(f"====> {request.json}")
     try:
         payload: Database = Database.model_validate(request.json)
     except ValidationError as e:
diff --git a/dbrepo-search-service/init/database.json b/dbrepo-search-service/init/database.json
index 8e5d443965673d9f9a4ff25b8f42af2e7481401d..4e5200c06a3ea304499a5e21ffaa7fdf9b7734d8 100644
--- a/dbrepo-search-service/init/database.json
+++ b/dbrepo-search-service/init/database.json
@@ -763,7 +763,37 @@
                 "type": "keyword"
               },
               "primary_key": {
-                "type": "keyword"
+                "type": "object",
+                "properties": {
+                  "id": {
+                    "type": "keyword"
+                  },
+                  "table": {
+                    "type": "object",
+                    "properties": {
+                      "id": {
+                        "type": "keyword"
+                      },
+                      "database_id": {
+                        "type": "keyword"
+                      }
+                    }
+                  },
+                  "column": {
+                    "type": "object",
+                    "properties": {
+                      "id": {
+                        "type": "keyword"
+                      },
+                      "table_id": {
+                        "type": "keyword"
+                      },
+                      "database_id": {
+                        "type": "keyword"
+                      }
+                    }
+                  }
+                }
               }
             }
           },
diff --git a/dbrepo-search-service/lib/dbrepo-1.4.4-py3-none-any.whl b/dbrepo-search-service/lib/dbrepo-1.4.4-py3-none-any.whl
index 4acaa2f242aa1a17081c6b649879afacfa191dad..f58e17a58e747e35bbd37f43efe6b460ba31530f 100644
Binary files a/dbrepo-search-service/lib/dbrepo-1.4.4-py3-none-any.whl and b/dbrepo-search-service/lib/dbrepo-1.4.4-py3-none-any.whl differ
diff --git a/dbrepo-search-service/lib/dbrepo-1.4.4.tar.gz b/dbrepo-search-service/lib/dbrepo-1.4.4.tar.gz
index e0bdb5adee8536ec4455e215913a6a769237b1e9..5463f6b170c24fff05d29a434562104553292fea 100644
Binary files a/dbrepo-search-service/lib/dbrepo-1.4.4.tar.gz and b/dbrepo-search-service/lib/dbrepo-1.4.4.tar.gz differ
diff --git a/dbrepo-search-service/test/test_opensearch_client.py b/dbrepo-search-service/test/test_opensearch_client.py
index 51f3a9feaa5ea95b04162a38538f3dc930a758da..906aae0ccc0862703abc740622d793ed8388192b 100644
--- a/dbrepo-search-service/test/test_opensearch_client.py
+++ b/dbrepo-search-service/test/test_opensearch_client.py
@@ -2,7 +2,8 @@ import datetime
 import unittest
 
 import opensearchpy
-from dbrepo.api.dto import Database, User, UserAttributes, Container, Image, Table, Column, ColumnType, Constraints
+from dbrepo.api.dto import Database, User, UserAttributes, Container, Image, Table, Column, ColumnType, Constraints, \
+    PrimaryKey, TableMinimal, ColumnMinimal
 from app import app
 
 from clients.opensearch_client import OpenSearchClient
@@ -56,7 +57,11 @@ class OpenSearchClientTest(unittest.TestCase):
                                 routing_key="dbrepo.test_tuw1.test_table",
                                 is_public=True,
                                 database_id=req.id,
-                                constraints=Constraints(uniques=[], foreign_keys=[], checks=[], primary_key=["id"]),
+                                constraints=Constraints(uniques=[], foreign_keys=[], checks=[],
+                                                        primary_key=[PrimaryKey(id=1,
+                                                                                table=TableMinimal(id=1, database_id=1),
+                                                                                column=ColumnMinimal(id=1, table_id=1,
+                                                                                                     database_id=1))]),
                                 is_versioned=True,
                                 created_by="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
                                 creator=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502",
diff --git a/dbrepo-ui/components/database/DatabaseCreate.vue b/dbrepo-ui/components/database/DatabaseCreate.vue
index a805af0e02d0e83454ae58b4064ba4e901477cd2..f7e2b005974e15afe7aeab285fd006ca5410baf3 100644
--- a/dbrepo-ui/components/database/DatabaseCreate.vue
+++ b/dbrepo-ui/components/database/DatabaseCreate.vue
@@ -113,7 +113,8 @@ export default {
           this.loadingContainers = false
         })
         .catch(({code}) => {
-          this.$toast.error(this.$t(code))
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loadingContainers = false
         })
     },
@@ -127,7 +128,8 @@ export default {
           this.loading = false
         })
         .catch(({code}) => {
-          this.$toast.error(this.$t(code))
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loading = false
         })
     },
diff --git a/dbrepo-ui/components/dialogs/DropTable.vue b/dbrepo-ui/components/dialogs/DropTable.vue
index 9421d1154ba3fd273206cb57ca9a11b91d095ec3..1f62735de5e6ce549386894f525074f53d5cdd5a 100644
--- a/dbrepo-ui/components/dialogs/DropTable.vue
+++ b/dbrepo-ui/components/dialogs/DropTable.vue
@@ -92,7 +92,8 @@ export default {
         .then(() => {
           console.info('Deleted table with id ', this.table.id)
           this.cacheStore.reloadDatabase()
-          this.$toast.success('Successfully deleted table with id ' + this.table.id)
+          const toast = useToastInstance()
+          toast.success('Successfully deleted table with id ' + this.table.id)
           this.$router.push(`/database/${this.$route.params.database_id}/table`)
         })
         .finally(() => {
diff --git a/dbrepo-ui/components/dialogs/EditAccess.vue b/dbrepo-ui/components/dialogs/EditAccess.vue
index 90ac7e3169174d358f83e832feae28e8fd31b1f5..8132adddf5935ae357893f8f91a2c4c597e6cf94 100644
--- a/dbrepo-ui/components/dialogs/EditAccess.vue
+++ b/dbrepo-ui/components/dialogs/EditAccess.vue
@@ -171,7 +171,8 @@ export default {
       const accessService = useAccessService()
       accessService.remove(this.$route.params.database_id, this.userId)
         .then(() => {
-          this.$toast.success(this.$t('notifications.access.revoked'))
+          const toast = useToastInstance()
+          toast.success(this.$t('notifications.access.revoked'))
           this.$emit('close-dialog', { success: true })
         })
         .finally(() => {
@@ -182,7 +183,8 @@ export default {
       const accessService = useAccessService()
       accessService.modify(this.$route.params.database_id, this.userId, this.modify)
         .then(() => {
-          this.$toast.success(this.$t('notifications.access.modified'))
+          const toast = useToastInstance()
+          toast.success(this.$t('notifications.access.modified'))
           this.$emit('close-dialog', { success: true })
         })
         .finally(() => {
@@ -193,7 +195,8 @@ export default {
       const accessService = useAccessService()
       accessService.create(this.$route.params.database_id, this.userId, this.modify)
         .then(() => {
-          this.$toast.success(this.$t('notifications.access.created'))
+          const toast = useToastInstance()
+          toast.success(this.$t('notifications.access.created'))
           this.$emit('close-dialog', { success: true })
         })
         .finally(() => {
diff --git a/dbrepo-ui/components/dialogs/EditTuple.vue b/dbrepo-ui/components/dialogs/EditTuple.vue
index 475e44328f889d637f723f5448e74988703e2f31..3f40a93175b6f3515f9e8b15500ac183cfe95769 100644
--- a/dbrepo-ui/components/dialogs/EditTuple.vue
+++ b/dbrepo-ui/components/dialogs/EditTuple.vue
@@ -280,12 +280,14 @@ export default {
       this.loading = true
       tupleService.update(this.$route.params.database_id, this.$route.params.table_id, { data: this.tuple, keys: constraints })
         .then(() => {
-          this.$toast.success(this.$t('success.data.update'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.data.update'))
           this.$emit('close', { success: true })
           this.loading = false
         })
         .catch(({message}) => {
-          this.$toast.error(message)
+          const toast = useToastInstance()
+          toast.error(message)
           this.loading = false
         })
         .finally(() => {
@@ -308,12 +310,14 @@ export default {
       this.loading = true
       tupleService.create(this.$route.params.database_id, this.$route.params.table_id, { data: this.tuple })
         .then(() => {
-          this.$toast.success(this.$t('success.data.add'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.data.add'))
           this.$emit('close', { success: true })
           this.loading = false
         })
         .catch(({message}) => {
-            this.$toast.error(message)
+          const toast = useToastInstance()
+          toast.error(message)
           this.loading = false
         })
         .finally(() => {
@@ -321,7 +325,8 @@ export default {
         })
     },
     onUpload ({column, s3key}) {
-      this.$toast.success(this.$t('success.upload.blob'))
+      const toast = useToastInstance()
+      toast.success(this.$t('success.upload.blob'))
       this.tuple[column.internal_name] = s3key
     }
   }
diff --git a/dbrepo-ui/components/dialogs/Semantics.vue b/dbrepo-ui/components/dialogs/Semantics.vue
index fd64efa9e702dcbc3f8aa629a599c0a04d270f03..a4a7104788ce1e12460ad693ac543058b60cdf6c 100644
--- a/dbrepo-ui/components/dialogs/Semantics.vue
+++ b/dbrepo-ui/components/dialogs/Semantics.vue
@@ -243,7 +243,8 @@ export default {
           this.recommendations = recommendations
         })
         .catch((error) => {
-          this.$toast.error(this.$t('error.semantics.timeout'))
+          const toast = useToastInstance()
+          toast.error(this.$t('error.semantics.timeout'))
         })
         .finally(() => {
           this.loadingSemantics = false
diff --git a/dbrepo-ui/components/identifier/Creators.vue b/dbrepo-ui/components/identifier/Creators.vue
index 6c5857d978cf8859b58a6987181bdd2b3020b28c..706736b21b155f5dc0265b0993f23b435bd5c345 100644
--- a/dbrepo-ui/components/identifier/Creators.vue
+++ b/dbrepo-ui/components/identifier/Creators.vue
@@ -69,13 +69,16 @@ export default {
         this.creators.push(creator)
         return
       }
+      this.creators.push(creator)
+      if (!(personOrOrg.affiliation || personOrOrg.affiliation_identifier || personOrOrg.affiliation_identifier_scheme)) {
+        return
+      }
       this.affiliations.push({
         name: personOrOrg.affiliation,
         name_identifier: personOrOrg.affiliation_identifier,
         name_identifier_scheme: personOrOrg.affiliation_identifier_scheme
       })
       creator.affiliation_index = this.getIndex(creator) + 1
-      this.creators.push(creator)
     })
   },
   methods: {
diff --git a/dbrepo-ui/components/identifier/Persist.vue b/dbrepo-ui/components/identifier/Persist.vue
index 2af517a68b5f55bc57d5d29e23285c44954ba2d8..3b9321ad3644bcbf9fb55d24cf6725b0dedeb21d 100644
--- a/dbrepo-ui/components/identifier/Persist.vue
+++ b/dbrepo-ui/components/identifier/Persist.vue
@@ -1339,7 +1339,8 @@ export default {
     },
     createOrSave () {
       if (!this.formValid) {
-        this.$toast.info(this.$t('error.identifier.form'))
+        const toast = useToastInstance()
+        toast.info(this.$t('error.identifier.form'))
         return
       }
       if (!this.identifier.id) {
@@ -1355,12 +1356,14 @@ export default {
       identifierService.save(payload)
         .then((identifier) => {
           this.cacheStore.reloadDatabase()
-          this.$toast.success(this.$t('success.pid.saved'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.pid.saved'))
           this.identifier = identifier
           this.loadingSave = false
         })
-        .catch((error) => {
-          this.$toast.error(this.$t(error.code))
+        .catch(({code}) => {
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loadingSave = false
         })
         .finally(() => {
@@ -1374,13 +1377,15 @@ export default {
       identifierService.create(payload)
         .then((identifier) => {
           this.cacheStore.reloadDatabase()
-          this.$toast.success(this.$t('success.pid.created'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.pid.created'))
           this.identifier = identifier
           this.$router.push(this.nextTo)
           this.loadingSave = false
         })
-        .catch((error) => {
-          this.$toast.error(this.$t(error.code))
+        .catch(({code}) => {
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loadingSave = false
         })
         .finally(() => {
@@ -1392,7 +1397,8 @@ export default {
       const identifierService = useIdentifierService()
       identifierService.publish(this.identifier.id)
         .then(() => {
-          this.$toast.success(this.$t('success.pid.published'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.pid.published'))
           this.cacheStore.reloadDatabase()
           this.loadingPublish = false
         })
@@ -1409,7 +1415,8 @@ export default {
       identifierService.remove(this.identifier.id)
         .then(() => {
           this.cacheStore.reloadDatabase()
-          this.$toast.success(this.$t('success.pid.deleted'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.pid.deleted'))
           this.$router.push(this.backTo)
           this.loadingDelete = false
         })
diff --git a/dbrepo-ui/components/subset/Builder.vue b/dbrepo-ui/components/subset/Builder.vue
index f379a59084494cb4cf006068bff1e561222e6c07..e8e60d6559de7a401ac53e9aa769733045145ea7 100644
--- a/dbrepo-ui/components/subset/Builder.vue
+++ b/dbrepo-ui/components/subset/Builder.vue
@@ -503,12 +503,14 @@ export default {
       const queryService = useQueryService()
       queryService.execute(this.$route.params.database_id, { statement: this.sql }, this.timestamp, 0, 1)
         .then(async (subset) => {
-          this.$toast.success(this.$t('success.subset.create'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.subset.create'))
           await this.$router.push(`/database/${this.$route.params.database_id}/subset/${subset.id}/data`)
           this.loadingQuery = false
         })
-        .catch((error) => {
-          this.$toast.error(this.$t(error.message))
+        .catch(({code}) => {
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loadingQuery = false
         })
     },
@@ -520,12 +522,14 @@ export default {
         .then(async (view) => {
           this.resultId = view.id
           this.cacheStore.reloadDatabase()
-          this.$toast.success(this.$t('success.view.create'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.view.create'))
           await this.$router.push(`/database/${this.$route.params.database_id}/view/${view.id}/data`)
           this.loadingQuery = false
         })
-        .catch((error) => {
-          this.$toast.error(this.$t(error.code))
+        .catch(({code}) => {
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loadingQuery = false
         })
     },
@@ -536,7 +540,8 @@ export default {
       const queryService = useQueryService()
       const { error, reason, column, raw, formatted } = queryService.build(this.table.internal_name, this.select, this.clauses)
       if (error) {
-        this.$toast.error(this.$t('error.query.' + reason) + ' ' + column)
+        const toast = useToastInstance()
+        toast.error(this.$t('error.query.' + reason) + ' ' + column)
         return
       }
       this.query.raw = raw
diff --git a/dbrepo-ui/components/subset/Results.vue b/dbrepo-ui/components/subset/Results.vue
index c1e700faef7050b89c6e10e4d711c2dcb2399533..9f0cb366a7a6dfef9198a35ce971f5ec247fc7ae 100644
--- a/dbrepo-ui/components/subset/Results.vue
+++ b/dbrepo-ui/components/subset/Results.vue
@@ -110,7 +110,8 @@ export default {
             this.loadingExecute = false
           })
           .catch(({code}) => {
-            this.$toast.error(this.$t(code))
+            const toast = useToastInstance()
+            toast.error(this.$t(code))
             this.loadingExecute = false
           })
           .finally(() => {
@@ -125,7 +126,8 @@ export default {
             this.loadingExecute = false
           })
           .catch(({code}) => {
-            this.$toast.error(this.$t(code))
+            const toast = useToastInstance()
+            toast.error(this.$t(code))
             this.loadingExecute = false
           })
           .finally(() => {
@@ -146,7 +148,8 @@ export default {
             this.loadingCount = false
           })
           .catch(({code}) => {
-            this.$toast.error(this.$t(code))
+            const toast = useToastInstance()
+            toast.error(this.$t(code))
             this.loadingCount = false
           })
           .finally(() => {
@@ -160,7 +163,8 @@ export default {
             this.loadingCount = false
           })
           .catch(({code}) => {
-            this.$toast.error(this.$t(code))
+            const toast = useToastInstance()
+            toast.error(this.$t(code))
             this.loadingCount = false
           })
           .finally(() => {
diff --git a/dbrepo-ui/components/subset/SubsetList.vue b/dbrepo-ui/components/subset/SubsetList.vue
index 1a0150f4d6ca0817ac773fbd3160f6032ee91c11..94c1bff1e82f0932f86e0aff7ebd3bac9d74a539 100644
--- a/dbrepo-ui/components/subset/SubsetList.vue
+++ b/dbrepo-ui/components/subset/SubsetList.vue
@@ -1,5 +1,10 @@
 <template>
   <div>
+    <v-card
+      v-if="!loadingSubsets && queries.length === 0"
+      variant="flat"
+      rounded="0"
+      :text="$t('pages.database.subpages.subsets.empty')" />
     <v-card
       variant="flat"
       rounded="0">
@@ -8,10 +13,6 @@
         lines="two">
         <Loading />
       </v-list-item>
-      <v-list-item
-        v-if="!loadingSubsets && queries.length === 0"
-        lines="two"
-        :title="$t('pages.database.subpages.subsets.empty')" />
       <div
         v-for="(item, i) in queries"
         :key="`q-${i}`">
@@ -79,8 +80,9 @@ export default {
         .then((queries) => {
           this.queries = queries
         })
-        .catch((error) => {
-          this.$toast.error(this.$t(error.code))
+        .catch(({code}) => {
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loadingSubsets = false
         })
         .finally(() => {
diff --git a/dbrepo-ui/components/table/BlobUpload.vue b/dbrepo-ui/components/table/BlobUpload.vue
index 67d1ffd4d472877c548e374cb7c9c47e72a24045..d0b1ceb49713e01a19c7b6b80f42bf92bbf47467 100644
--- a/dbrepo-ui/components/table/BlobUpload.vue
+++ b/dbrepo-ui/components/table/BlobUpload.vue
@@ -39,8 +39,9 @@ export default {
           this.value = filename
           this.$emit('blob', { column: this.column, s3key: filename })
         })
-        .catch((error) => {
-          this.$toast.error(this.$t(error.code))
+        .catch(({code}) => {
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
         })
     }
   }
diff --git a/dbrepo-ui/components/table/TableImport.vue b/dbrepo-ui/components/table/TableImport.vue
index 92ddba0ecd9973829c8fef238d3b1174b40abcee..3688c4d9e3b4603b3be6929c86ec28b115b31af5 100644
--- a/dbrepo-ui/components/table/TableImport.vue
+++ b/dbrepo-ui/components/table/TableImport.vue
@@ -401,7 +401,8 @@ export default {
       const tableService = useTableService()
       tableService.importCsv(this.$route.params.database_id, this.tableId, this.tableImport)
         .then(() => {
-          this.$toast.success(this.$t('success.import.dataset'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.import.dataset'))
           this.cacheStore.reloadDatabase()
           tableService.getCount(this.$route.params.database_id, this.tableId, null)
             .then((rowCount) => {
@@ -410,9 +411,9 @@ export default {
           this.step = this.stepStart + 2
           this.loading = false
         })
-        .catch((error) => {
-          console.error('Failed to import csv', error)
-          this.$toast.error(this.$t('error.import.dataset'))
+        .catch(() => {
+          const toast = useToastInstance()
+          toast.error(this.$t('error.import.dataset'))
           this.loading = false
         })
         .finally(() => {
@@ -425,11 +426,13 @@ export default {
       const uploadService = useUploadService()
       return uploadService.create(this.previousFile)
         .then((s3key) => {
-          this.$toast.success(this.$t('success.upload.dataset'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.upload.dataset'))
           this.analyse(s3key)
         })
         .catch(() => {
-          this.$toast.error(this.$t('error.upload.dataset'))
+          const toast = useToastInstance()
+          toast.error(this.$t('error.upload.dataset'))
           this.loading = false
         })
     },
@@ -462,12 +465,14 @@ export default {
           this.suggestedAnalyseLineTerminator = line_termination
           this.tableImport.location = filename
           this.step = this.stepStart + 2
-          this.$toast.success(this.$t('success.analyse.dataset'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.analyse.dataset'))
           this.$emit('analyse', {columns: this.columns, filename, line_termination})
           this.loading = false
         })
         .catch(({code}) => {
-          this.$toast.error(this.$t(code))
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loading = false
         })
     }
diff --git a/dbrepo-ui/components/view/ViewToolbar.vue b/dbrepo-ui/components/view/ViewToolbar.vue
index bf415031b767d4688602d9aa3d0f3535c6f4f011..e6cb5e09db3df478b70edc0c189cef179b109c65 100644
--- a/dbrepo-ui/components/view/ViewToolbar.vue
+++ b/dbrepo-ui/components/view/ViewToolbar.vue
@@ -123,12 +123,14 @@ export default {
       const viewService = useViewService()
       viewService.remove(this.$route.params.database_id, this.$route.params.view_id)
         .then(() => {
-          this.$toast.success(this.$t('success.view.delete'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.view.delete'))
           this.cacheStore.reloadDatabase()
           this.$router.push(`/database/${this.$route.params.database_id}/view`)
         })
-        .catch((error) => {
-          this.$toast.error(this.$t(error.code))
+        .catch(({code}) => {
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
         })
         .finally(() => {
           this.loadingDelete = false
diff --git a/dbrepo-ui/composables/database-service.ts b/dbrepo-ui/composables/database-service.ts
index 6a4e283f8d9fb9d04b00c040bb7d769886ee3a70..3890477822cf58a5b0d375b4c45df87931039a52 100644
--- a/dbrepo-ui/composables/database-service.ts
+++ b/dbrepo-ui/composables/database-service.ts
@@ -60,7 +60,7 @@ export const useDatabaseService = (): any => {
           resolve(count);
         })
         .catch((error) => {
-          console.error('Failed to find databases', error);
+          console.error('Failed to find databases count', error);
           reject(axiosErrorToApiError(error));
         });
     });
@@ -72,7 +72,7 @@ export const useDatabaseService = (): any => {
     return new Promise<Date>((resolve, reject) => {
       axios.head<Date>('/api/database')
         .then((response) => {
-          const date: Date = Date(response.headers['Date'])
+          const date: Date = new Date(response.headers['Date'])
           console.info(`Found ${date} server time`);
           resolve(date);
         })
@@ -85,7 +85,7 @@ export const useDatabaseService = (): any => {
 
   async function findOne(id: number): Promise<DatabaseDto | null> {
     const axios = useAxiosInstance();
-    console.debug('find databases with id', id);
+    console.debug('find database with id', id);
     return new Promise((resolve, reject) => {
       axios.get<DatabaseDto>(`/api/database/${id}`)
         .then((response) => {
@@ -93,7 +93,7 @@ export const useDatabaseService = (): any => {
           resolve(response.data);
         })
         .catch((error) => {
-          console.error('Failed to find databases', error);
+          console.error('Failed to find database', error);
           reject(axiosErrorToApiError(error));
         });
     });
diff --git a/dbrepo-ui/composables/toast-instance.ts b/dbrepo-ui/composables/toast-instance.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bac439b1cd6c040a28195d54286131cfa4906ad0
--- /dev/null
+++ b/dbrepo-ui/composables/toast-instance.ts
@@ -0,0 +1,25 @@
+import {type ToastPluginApi, type ToastProps, useToast} from 'vue-toast-notification';
+
+const props: ToastProps = {
+  position: 'top-right',
+  duration: 6000,
+  dismissible: false /* allow copy of error message */
+}
+
+export const useToastInstance = () => {
+  function error(message: string): void {
+    const toast: ToastPluginApi = useToast(props);
+    if (document) {
+      toast.error(message)
+    }
+  }
+
+  function success(message: string): void {
+    const toast: ToastPluginApi = useToast(props);
+    if (document) {
+      toast.success(message)
+    }
+  }
+
+  return {error, success}
+};
diff --git a/dbrepo-ui/locales/de-AT.json b/dbrepo-ui/locales/de-AT.json
index 15c2664f0f67c97852d58596a27cd6084da2c659..2e713bd365e175035cde2f569e4c24564fd0baf3 100644
--- a/dbrepo-ui/locales/de-AT.json
+++ b/dbrepo-ui/locales/de-AT.json
@@ -1212,6 +1212,7 @@
     "database": {
       "upload": "Datenbankbild erfolgreich hochgeladen.",
       "transfer": "Der Datenbankeigentümer wurde erfolgreich übertragen.",
+      "visibility": "Die Datenbanksichtbarkeit wurde erfolgreich aktualisiert.",
       "image": {
         "update": "Datenbankbild erfolgreich aktualisiert.",
         "remove": "Datenbankbild erfolgreich entfernt."
@@ -1226,7 +1227,9 @@
     },
     "user": {
       "info": "Benutzerinformationen erfolgreich aktualisiert.",
-      "theme": "Benutzerthema erfolgreich aktualisiert."
+      "theme": "Benutzerthema erfolgreich aktualisiert.",
+      "password": "Benutzerkennwort erfolgreich aktualisiert.",
+      "login": "Erfolgreich angemeldet."
     },
     "view": {
       "create": "Ansicht erfolgreich erstellt.",
diff --git a/dbrepo-ui/locales/en-US.json b/dbrepo-ui/locales/en-US.json
index 227ae506c244552c0139582bba97f58cdce60188..71d8c09051fe8fad476fa1b11fb23d612755e884 100644
--- a/dbrepo-ui/locales/en-US.json
+++ b/dbrepo-ui/locales/en-US.json
@@ -1212,6 +1212,7 @@
     "database": {
       "upload": "Successfully uploaded database image.",
       "transfer": "Successfully transferred the database owner.",
+      "visibility": "Successfully updated the database visibility.",
       "image": {
         "update": "Successfully updated database image.",
         "remove": "Successfully removed database image."
@@ -1226,7 +1227,9 @@
     },
     "user": {
       "info": "Successfully updated user information.",
-      "theme": "Successfully updated user theme."
+      "theme": "Successfully updated user theme.",
+      "password": "Successfully updated user password.",
+      "login": "Successfully logged in."
     },
     "view": {
       "create": "Successfully created view.",
diff --git a/dbrepo-ui/nuxt.config.ts b/dbrepo-ui/nuxt.config.ts
index f2d9df53a35f8d411378851457ffc139251f2903..7dbf4914d2f76a75282017a38c93fb1e0a6607eb 100644
--- a/dbrepo-ui/nuxt.config.ts
+++ b/dbrepo-ui/nuxt.config.ts
@@ -127,7 +127,7 @@ export default defineNuxtConfig({
     storage: 'localStorage'
   },
   i18n: {
-    lazy: true,
+    lazy: false,
     langDir: 'locales',
     strategy: 'no_prefix',
     defaultLocale: 'de',
diff --git a/dbrepo-ui/pages/database/[database_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/settings.vue
index 296f639caeb813897b1cb1a08906509af4740a14..558f152fef73cdb22eda4c505eb3d7cb3f6ae153 100644
--- a/dbrepo-ui/pages/database/[database_id]/settings.vue
+++ b/dbrepo-ui/pages/database/[database_id]/settings.vue
@@ -418,7 +418,8 @@ export default {
       const databaseService = useDatabaseService()
       databaseService.updateVisibility(this.$route.params.database_id, this.modifyVisibility)
         .then((database) => {
-          this.$toast.success('Successfully updated the database visibility')
+          const toast = useToastInstance()
+          toast.success('success.database.visibility')
           this.cacheStore.setDatabase(database)
         })
         .catch(() => {
@@ -434,7 +435,8 @@ export default {
       uploadService.create(this.fileModel[0])
         .then((s3key) => {
           console.debug('uploaded image', s3key)
-          this.$toast.success(this.$t('success.database.upload'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.database.upload'))
           this.modifyImage.key = s3key
           this.loadingUpload = false
         })
@@ -448,12 +450,14 @@ export default {
       databaseService.updateImage(this.$route.params.database_id, this.modifyImage)
         .then(() => {
           this.cacheStore.reloadDatabase()
-          this.$toast.success(this.$t('success.database.image.update'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.database.image.update'))
           this.modifyImage.key = null
           this.loadingImage = false
         })
         .catch(() => {
-          this.$toast.error('Failed to modify image')
+          const toast = useToastInstance()
+          toast.error('Failed to modify image')
           this.loadingImage = false
         })
         .finally(() => {
@@ -466,11 +470,13 @@ export default {
       databaseService.updateImage(this.$route.params.database_id, { key: null })
         .then(() => {
           this.cacheStore.reloadDatabase()
-          this.$toast.success(this.$t('success.database.image.remove'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.database.image.remove'))
           this.loadingDeleteImage = false
         })
-        .catch(() => {
-          this.$toast.error('Failed to delete image')
+        .catch(({code}) => {
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loadingDeleteImage = false
         })
         .finally(() => {
@@ -482,7 +488,8 @@ export default {
       const databaseService = useDatabaseService()
       databaseService.updateOwner(this.$route.params.database_id, this.modifyOwner.id)
         .then(() => {
-          this.$toast.success(this.$t('success.database.transfer'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.database.transfer'))
           location.reload()
         })
         .catch(() => {
@@ -497,20 +504,24 @@ export default {
       const databaseService = useDatabaseService()
       databaseService.refreshTablesMetadata(this.$route.params.database_id)
         .then(() => {
-          this.$toast.success(this.$t('success.schema.tables'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.schema.tables'))
           databaseService.refreshViewsMetadata(this.$route.params.database_id)
             .then(() => {
-              this.$toast.success(this.$t('success.schema.views'))
+              const toast = useToastInstance()
+              toast.success(this.$t('success.schema.views'))
               this.cacheStore.reloadDatabase()
               this.loadingSchema = false
             })
             .catch(({code}) => {
-              this.$toast.error(this.$t(code))
+              const toast = useToastInstance()
+              toast.error(this.$t(code))
               this.loadingSchema = false
             })
         })
         .catch(({code}) => {
-          this.$toast.error(this.$t(code))
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loadingSchema = false
         })
     },
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue
index 7484989fa34ae4edc38036fe03639b0cfbf46144..3c90c1485819bbd03e267e556e853cbf2c6b0f65 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue
@@ -54,7 +54,9 @@
         @click.stop="pick" />
     </v-toolbar>
     <TimeDrift />
-    <v-card tile>
+    <v-card
+      elevation="0"
+      tile>
       <v-card
         v-if="error"
         variant="flat">
@@ -326,12 +328,14 @@ export default {
         const tupleService = useTupleService()
         wait.push(tupleService.remove(this.$route.params.database_id, this.$route.params.table_id, { keys: constraints })
           .catch(({message}) => {
-            this.$toast.error(message)
+            const toast = useToastInstance()
+            toast.error(message)
           }))
       }
       Promise.all(wait)
         .then(() => {
-          this.$toast.success(`Deleted ${this.selection.length} row(s)`)
+          const toast = useToastInstance()
+          toast.success(`Deleted ${this.selection.length} row(s)`)
           this.$emit('modified', { success: true, action: 'delete' })
           this.selection = []
           this.reload()
@@ -351,8 +355,9 @@ export default {
             document.body.appendChild(link)
             link.click()
           })
-          .catch((error) => {
-            this.$toast.error(this.$t(error.code))
+          .catch(({code}) => {
+            const toast = useToastInstance()
+            toast.error(this.$t(code))
             this.downloadLoading = false
           })
           .finally(() => {
@@ -409,8 +414,9 @@ export default {
         }).forEach(header => this.headers.push(header))
         this.dateColumns = this.table.columns.filter(c => (c.column_type === 'date' || c.column_type === 'timestamp'))
         console.debug('date columns are', this.dateColumns)
-      } catch (error) {
-        this.$toast.error(this.$t(error.code))
+      } catch ({code}) {
+        const toast = useToastInstance()
+        toast.error(this.$t(code))
       }
       this.loading = false
     },
@@ -442,8 +448,9 @@ export default {
           })
           this.loadingData = false
         })
-        .catch((error) => {
-          this.$toast.error(this.$t(error.code))
+        .catch(({code}) => {
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.error = true
           this.loadingData = false
         })
@@ -456,8 +463,9 @@ export default {
           this.total = count
           this.loadingCount = false
         })
-        .catch((error) => {
-          this.$toast.error(this.$t(error.code))
+        .catch(({code}) => {
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loadingCount = false
         })
     },
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue
index 4af6ba09d796889ec81b2a960b0682847fc24f68..0509cc0c2c0dd3edfb711c39fcda15daf5d6993f 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue
@@ -193,7 +193,7 @@ export default {
       return this.userStore.getRoles
     },
     primaryKeysColumns () {
-      return this.table.constraints.primary_key.join(', ')
+      return this.table.constraints.primary_key.map(pk => pk.column.internal_name).join(', ')
     },
     canAssignSemanticInformation () {
       if (!this.user) {
@@ -252,7 +252,8 @@ export default {
       const { success } = event
       console.debug('closed dialog', event)
       if (success) {
-        this.$toast.success(this.$t('success.table.semantics'))
+        const toast = useToastInstance()
+        toast.success(this.$t('success.table.semantics'))
         this.cacheStore.reloadTable()
       }
       this.dialogSemantic = false
diff --git a/dbrepo-ui/pages/database/[database_id]/table/create.vue b/dbrepo-ui/pages/database/[database_id]/table/create.vue
index 496c3ec3cb589e6655e15e0b280f995f5e35f789..34c87d163d5e571b0eaa1f08f161e7d15953db75 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/create.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/create.vue
@@ -260,8 +260,9 @@ export default {
           this.cacheStore.reloadDatabase()
           this.table = table
         })
-        .catch((error) => {
-          this.$toast.error(this.$t(error.code))
+        .catch(({code}) => {
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loading = false
         })
         .finally(() => {
diff --git a/dbrepo-ui/pages/database/[database_id]/table/import.vue b/dbrepo-ui/pages/database/[database_id]/table/import.vue
index 5eb02f7f8ea693e28f232706275612ad1d1a7625..724205c7ba1934dfcbe4c4e3b4a88659e47f77b6 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/import.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/import.vue
@@ -327,7 +327,8 @@ export default {
         })
         .catch((error) => {
           console.error('Failed to create table', error)
-          this.$toast.error(this.$t(error.code))
+          const toast = useToastInstance()
+          toast.error(this.$t(error.code))
           this.loading = false
           reject(error)
         })
@@ -342,12 +343,14 @@ export default {
       tableService.importCsv(this.$route.params.database_id, table.id, this.tableImport)
         .then(() => {
           this.step = 5
-          this.$toast.success(this.$t('success.import.dataset'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.import.dataset'))
           this.cacheStore.reloadDatabase()
         })
-        .catch((error) => {
-          console.error('Failed to import csv', error)
-          this.$toast.error(this.$t(error.code))
+        .catch(({code}) => {
+          console.error('Failed to import csv')
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loading = false
         })
         .finally(() => {
diff --git a/dbrepo-ui/pages/login.vue b/dbrepo-ui/pages/login.vue
index 5ce0c31a81b1ad63be7dbfcdcd3413a40c496bdf..71ea9ec604a39994951a5eb02faf04116d45e77f 100644
--- a/dbrepo-ui/pages/login.vue
+++ b/dbrepo-ui/pages/login.vue
@@ -116,6 +116,8 @@ export default {
           const userId = userService.tokenToUserId(data.access_token)
           userService.findOne(userId)
             .then((user) => {
+              const toast = useToastInstance()
+              toast.info(this.$t('success.user.login'))
               switch (user.attributes.theme) {
                 case 'dark':
                   this.$vuetify.theme.global.name = 'tuwThemeDark'
@@ -133,13 +135,14 @@ export default {
               this.userStore.setUser(user)
               this.$router.push('/database')
             })
-            .catch(error => {
-              this.$toast.error(this.$t(error.code))
+            .catch(({code}) => {
+              const toast = useToastInstance()
+              toast.error(this.$t(code))
             })
         })
-        .catch((error) => {
-          console.error('Failed to login', error)
-          this.$toast.error(this.$t(error.code))
+        .catch(({code}) => {
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loading = false
         })
         .finally(() => {
diff --git a/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue b/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue
index ee1d19d985a3f8b7f7fb56fc6778f5e07c280776..41cfa20426c6d51a12f656ef7cd40bc0dff45405 100644
--- a/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue
+++ b/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue
@@ -182,7 +182,8 @@ export default {
         .then(() => {
           this.loadOntology()
           // this.$store.dispatch('reloadOntologies')
-          this.$toast.success('Successfully update ontology!')
+          const toast = useToastInstance()
+          toast.success('Successfully update ontology!')
         })
         .catch(() => {
           this.loading = false
diff --git a/dbrepo-ui/pages/signup.vue b/dbrepo-ui/pages/signup.vue
index aa944e5d9fa0ab04bdbff72070ea7ab913c777f8..9d84f5c0df8a36b3b56590e42903058895bccb0e 100644
--- a/dbrepo-ui/pages/signup.vue
+++ b/dbrepo-ui/pages/signup.vue
@@ -117,12 +117,14 @@ export default {
       const userService = useUserService()
       userService.create(this.createAccount)
         .then(() => {
-          this.$toast.success(this.$t('success.signup'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.signup'))
           this.$router.push('/login')
           this.loading = false
         })
-        .catch((error) => {
-          this.$toast.error(this.$t(error.code))
+        .catch(({code}) => {
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loading = false
         })
         .finally(() => {
@@ -136,8 +138,9 @@ export default {
         .then((users) => {
           this.usernames = users.map(u => u.username)
         })
-        .catch((error) => {
-          this.$toast.error(this.$t(error.code))
+        .catch(({code}) => {
+          const toast = useToastInstance()
+          toast.error(this.$t(code))
           this.loadingUsers = false
         })
         .finally(() => {
diff --git a/dbrepo-ui/pages/user/authentication.vue b/dbrepo-ui/pages/user/authentication.vue
index 35fec2fa71d9402757ad43076e3c1a88c7e8ad0a..a40fef51e5e8f6b690beffa65d605110384f1c7b 100644
--- a/dbrepo-ui/pages/user/authentication.vue
+++ b/dbrepo-ui/pages/user/authentication.vue
@@ -114,7 +114,8 @@ export default {
       const userService = useUserService()
       userService.updatePassword(this.user.id, this.password)
         .then(() => {
-          this.$toast.success('Successfully changed the password')
+          const toast = useToastInstance()
+          toast.success('success.user.password')
           this.loadingUpdate = false
         })
         .catch(() => {
diff --git a/dbrepo-ui/pages/user/info.vue b/dbrepo-ui/pages/user/info.vue
index 3a085b6008a2362e5dd4c596a7e697fb9cdc3288..3501818ca0408474e81a9038f15a84d61fb662ff 100644
--- a/dbrepo-ui/pages/user/info.vue
+++ b/dbrepo-ui/pages/user/info.vue
@@ -219,7 +219,8 @@ export default {
       userService.update(this.user.id, payload)
         .then((user) => {
           console.info('Updated user information')
-          this.$toast.success(this.$t('success.user.info'))
+          const toast = useToastInstance()
+          toast.success(this.$t('success.user.info'))
           this.userStore.setUser(user)
           /* language */
           this.userStore.setLocale(this.model.language)
@@ -286,7 +287,8 @@ export default {
     },
     copy () {
       navigator.clipboard.writeText(this.model.id)
-      this.$toast.success(this.$t('success.clipboard.user'))
+      const toast = useToastInstance()
+      toast.success(this.$t('success.clipboard.user'))
     }
   }
 }
diff --git a/dbrepo-ui/plugins/backend.ts b/dbrepo-ui/plugins/backend.ts
deleted file mode 100644
index 6d18d9e218a92efa8748e0179f6a51d46184f006..0000000000000000000000000000000000000000
--- a/dbrepo-ui/plugins/backend.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-export default defineNuxtPlugin((nuxtApp) => {
-  const config = useRuntimeConfig();
-  nuxtApp.provide('backendURL', () => {
-    if (process.server && !process.dev) {
-      return config.public.backendURLServer;
-    } else {
-      return config.public.backendURL;
-    }
-  });
-})
diff --git a/dbrepo-ui/stores/cache.js b/dbrepo-ui/stores/cache.js
index bb89295ec5534fb82c3c435737af5baf023994fe..087ae4e9b936330b43d3002b076ea431c95c7420 100644
--- a/dbrepo-ui/stores/cache.js
+++ b/dbrepo-ui/stores/cache.js
@@ -30,25 +30,33 @@ export const useCacheStore = defineStore('cache', {
       const messageService = useMessageService()
       messageService.findAll('active')
         .then(messages => this.messages = messages)
-        .catch(() => {})
+        .catch((error) => {
+          console.error('Failed to reload messages', error)
+        })
     },
     reloadOntologies () {
       const ontologyService = useOntologyService()
       ontologyService.findAll()
         .then(ontologies => this.ontologies = ontologies)
-        .catch(() => {})
+        .catch((error) => {
+          console.error('Failed to reload ontologies', error)
+        })
     },
     reloadDatabase () {
       const databaseService = useDatabaseService()
       databaseService.findOne(this.database.id)
         .then(database => this.database = database)
-        .catch(() => {})
+        .catch((error) => {
+          console.error('Failed to reload database', error)
+        })
     },
     reloadTable () {
       const tableService = useTableService()
       tableService.findOne(this.table.database_id, this.table.id)
         .then(table => this.table = table)
-        .catch(() => {})
+        .catch((error) => {
+          console.error('Failed to reload table', error)
+        })
     },
     setRouteDatabase (databaseId) {
       if (!databaseId) {
@@ -58,7 +66,9 @@ export const useCacheStore = defineStore('cache', {
       const databaseService = useDatabaseService()
       databaseService.findOne(databaseId)
         .then(database => this.database = database)
-        .catch(() => {})
+        .catch((error) => {
+          console.error('Failed to set route database', error)
+        })
     },
     setRouteTable (databaseId, tableId) {
       if (!databaseId || !tableId) {
@@ -68,7 +78,9 @@ export const useCacheStore = defineStore('cache', {
       const tableService = useTableService()
       tableService.findOne(databaseId, tableId)
         .then(table => this.table = table)
-        .catch(() => {})
+        .catch((error) => {
+          console.error('Failed to set route table', error)
+        })
     }
   },
 })
diff --git a/helm/dbrepo/values.prod.yaml b/helm/dbrepo/values.prod.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..93c0bf3d724c5f8a06308b020d0761dd26e27073
--- /dev/null
+++ b/helm/dbrepo/values.prod.yaml
@@ -0,0 +1,514 @@
+namespace: dbrepo
+
+hostname: example.com
+
+metadataDb:
+  fullnameOverride: metadata-db
+  image:
+    debug: false
+  host: metadata-db
+  rootUser:
+    user: root
+    password: dbrepo
+  jdbcExtraArgs: ""
+  db:
+    name: fda
+  metrics:
+    enabled: false
+  galera:
+    mariabackup:
+      user: mariabackup
+      password: mariabackup
+  initdbScriptsConfigMap: metadata-db-setup
+  service:
+    type: ClusterIP
+    annotations: { }
+    loadBalancerIP: ""
+    loadBalancerSourceRanges: [ ]
+  persistence:
+    enabled: true
+  replicaCount: 3 # uneven 3,5,7
+
+authService:
+  fullnameOverride: auth-service
+  image:
+    debug: false
+  auth:
+    adminUser: fda
+    adminPassword: fda
+  postgresql:
+    enabled: false # not needed
+  extraStartupArgs: "--import-realm"
+  tls:
+    enabled: true
+    existingSecret: ingress-cert
+    usePem: true
+  metrics:
+    enabled: true
+  externalDatabase:
+    existingSecret: auth-service-secret
+    existingSecretDatabaseKey: db-name
+    existingSecretHostKey: db-host
+    existingSecretPortKey: db-port
+    existingSecretUserKey: db-username
+    existingSecretPasswordKey: db-password
+  client:
+    id: dbrepo-client
+    secret: MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG
+  extraEnvVarsCM: auth-service-config
+  extraVolumes:
+    - name: config-map
+      configMap:
+        name: auth-service-setup
+  extraVolumeMounts:
+    - name: config-map
+      mountPath: /opt/bitnami/keycloak/data/import
+  replicaCount: 2
+
+authDb:
+  fullnameOverride: auth-db
+  host: auth-db-pgpool
+  port: 5432
+  postgresql:
+    postgresPassword: postgres
+    username: metrics # implicit requirement for metrics container
+    password: metrics # implicit requirement for metrics container
+    repmgrPassword: repmgr # implicit requirement for rolling updates
+    database: keycloak
+    replicaCount: 3
+  pgpool:
+    adminUsername: admin
+    adminPassword: admin
+  metrics:
+    enabled: true
+  service:
+    type: ClusterIP
+    annotations: { }
+    loadBalancerIP: ""
+    loadBalancerSourceRanges: [ ]
+  persistence:
+    enabled: true
+    size: 10Gi
+
+dataDb:
+  fullnameOverride: data-db
+  image:
+    debug: false
+  extraFlags: "--character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci"
+  rootUser:
+    user: root
+    password: dbrepo
+  metrics:
+    enabled: true
+  galera:
+    mariabackup:
+      user: mariabackup
+      password: mariabackup
+  sidecars:
+    - name: sidecar
+      image: s210.dl.hpc.tuwien.ac.at/dbrepo/data-db-sidecar:1.4.2
+      imagePullPolicy: Always
+      securityContext:
+        runAsUser: 1001
+        runAsGroup: 1001
+      ports:
+        - containerPort: 3305
+          protocol: TCP
+      env:
+        - name: S3_STORAGE_ENDPOINT
+          value: http://storageservice-s3:9000
+        - name: S3_ACCESS_KEY_ID
+          value: seaweedfsadmin
+        - name: S3_SECRET_ACCESS_KEY
+          value: seaweedfsadmin
+      volumeMounts:
+        - name: tmp # share between sidecar and galera container
+          mountPath: /tmp
+  service:
+    type: ClusterIP
+    annotations: { }
+    #loadBalancerIP: 1.2.3.4
+    loadBalancerSourceRanges: [ ]
+    extraPorts:
+      - name: "sidecar"
+        port: 3305
+        targetPort: 3305
+        protocol: TCP
+  extraVolumeMounts:
+    - name: tmp
+      mountPath: /tmp
+  extraVolumes:
+    #    - name: tmp
+    #      emptyDir: {}
+    - name: tmp
+      persistentVolumeClaim:
+        claimName: data-db-shared
+  persistence:
+    enabled: true
+    size: 10Gi
+  replicaCount: 3 # uneven 3,5,7
+
+searchdb:
+  fullnameOverride: search-db
+  host: search-db
+  port: 9200
+  protocol: http
+  username: admin
+  password: admin
+  clusterName: search-db
+  masterService: search-db
+  replicas: 3 # uneven 3,5,7
+  image:
+    debug: false
+  sysctlInit:
+    enabled: true
+  persistence:
+    enabled: true
+    size: 10Gi
+  service:
+    type: ClusterIP
+    annotations: { }
+    loadBalancerSourceRanges: [ ]
+  extraEnvs:
+    - name: DISABLE_INSTALL_DEMO_CONFIG
+      value: "true"
+  extraVolumeMounts:
+    - name: node-cert
+      mountPath: /usr/share/opensearch/config/tls
+      readOnly: true
+  extraVolumes:
+    - name: node-cert
+      secret:
+        secretName: search-db-cert
+  config:
+    opensearch.yml: |
+      cluster.name: search-db
+      network.host: 0.0.0.0
+      plugins:
+        security:
+          ssl:
+            transport:
+              pemcert_filepath: tls/tls.crt
+              pemkey_filepath: tls/tls.key
+              pemtrustedcas_filepath: tls/ca.crt
+              enforce_hostname_verification: false
+            http:
+              #enabled: true # uncomment to force ssl connections
+              pemcert_filepath: tls/tls.crt
+              pemkey_filepath: tls/tls.key
+              pemtrustedcas_filepath: tls/ca.crt
+          allow_unsafe_democertificates: false
+          allow_default_init_securityindex: true
+          authcz:
+            admin_dn:
+              - CN=search-db
+          nodes_dn:
+            - CN=search-db
+          audit.type: internal_opensearch
+          enable_snapshot_restore_privilege: true
+          check_snapshot_restore_write_privileges: true
+          restapi:
+            roles_enabled: [ "all_access", "security_rest_api_access" ]
+          system_indices:
+            enabled: true
+            indices:
+              [
+                ".opendistro-alerting-config",
+                ".opendistro-alerting-alert*",
+                ".opendistro-anomaly-results*",
+                ".opendistro-anomaly-detector*",
+                ".opendistro-anomaly-checkpoints",
+                ".opendistro-anomaly-detection-state",
+                ".opendistro-reports-*",
+                ".opendistro-notifications-*",
+                ".opendistro-notebooks",
+                ".opendistro-asynchronous-search-response*",
+              ]
+
+searchDbDashboard:
+  fullnameOverride: search-db-dashboard
+  opensearchHosts: http://search-db:9200
+  extraInitContainers:
+    - name: init
+      image: s210.dl.hpc.tuwien.ac.at/dbrepo/search-db-init:1.4.2
+      imagePullPolicy: Always
+      env:
+        - name: OPENSEARCH_HOST
+          value: http://search-db:9200
+  extraVolumeMounts:
+    - name: tls
+      mountPath: /usr/share/opensearch-dashboards/tls
+      readOnly: true
+    - name: config
+      mountPath: /usr/share/opensearch-dashboards/config/opensearch_dashboards.yml
+      subPath: opensearch_dashboards.yml
+      readOnly: true
+  extraVolumes:
+    - name: tls
+      secret:
+        secretName: ingress-cert
+    - name: config
+      secret:
+        secretName: search-db-dashboard-secret
+  replicaCount: 2
+
+uploadService:
+  enabled: true
+  image:
+    registry: docker.io
+    repository: tusproject/tusd
+    tag: v1.12
+  replicaCount: 2
+
+brokerService:
+  fullnameOverride: broker-service
+  image:
+    debug: true
+  url: http://broker-service:15672
+  host: broker-service
+  port: 5672
+  virtualHost: dbrepo
+  queueName: dbrepo
+  exchangeName: dbrepo
+  routingKey: dbrepo.#
+  connectionTimeout: 60000
+  auth:
+    tls:
+      enabled: false
+      sslOptionsVerify: true
+      failIfNoPeerCert: true
+      existingSecret: ingress-cert
+    username: broker
+    password: broker
+  extraConfiguration: |-
+    default_vhost = dbrepo
+    default_user_tags.administrator = true
+    default_permissions.configure = .*
+    default_permissions.read = .*
+    default_permissions.write = .*
+    load_definitions = /etc/rabbitmq/definitions.json
+    log.console = true
+    listeners.tcp.1 = 0.0.0.0:5672
+    auth_backends.1 = rabbit_auth_backend_oauth2
+    auth_backends.2 = rabbit_auth_backend_internal
+    auth_oauth2.resource_server_id = rabbitmq
+    auth_oauth2.preferred_username_claims.1 = client_id
+    auth_oauth2.default_key = t2OCeCheJ9uwoBbNQjG_nN6WKiLcceTIAZmiTbGODFM
+    auth_oauth2.signing_keys.t2OCeCheJ9uwoBbNQjG_nN6WKiLcceTIAZmiTbGODFM = /etc/rabbitmq/cert.pem
+    auth_oauth2.signing_keys.id2 = /etc/rabbitmq/pubkey.pem
+    auth_oauth2.algorithms.1 = HS256
+    auth_oauth2.algorithms.2 = RS256
+  loadDefinition:
+    enabled: true
+    file: /etc/rabbitmq/definitions.json
+    existingSecret: broker-service-secret
+  extraVolumeMounts:
+    - name: secret-map
+      mountPath: /etc/rabbitmq/definitions.json
+      subPath: definitions.json
+      readOnly: true
+    - name: secret-map
+      mountPath: /etc/rabbitmq/pubkey.pem
+      subPath: pubkey.pem
+      readOnly: true
+    - name: secret-map
+      mountPath: /etc/rabbitmq/cert.pem
+      subPath: cert.pem
+      readOnly: true
+  extraVolumes:
+    - name: secret-map
+      secret:
+        secretName: broker-service-secret
+  extraPlugins: rabbitmq_prometheus rabbitmq_auth_backend_oauth2 rabbitmq_auth_mechanism_ssl
+  persistence:
+    enabled: false
+    size: 5Gi
+  service:
+    type: ClusterIP
+    # loadBalancerIP:
+  replicaCount: 2
+
+analyseService:
+  enabled: true
+  image:
+    name: s210.dl.hpc.tuwien.ac.at/dbrepo/analyse-service:1.4.2
+    pullPolicy: Always
+    debug: false
+  replicaCount: 2
+
+metadataService:
+  enabled: true
+  image:
+    name: s210.dl.hpc.tuwien.ac.at/dbrepo/metadata-service:1.4.2
+    pullPolicy: Always
+    debug: false
+  adminEmail: noreply@example.com
+  authService:
+    url: http://auth-service
+  website: http://example.com
+  repositoryName: Database Repository
+  datacite:
+    enabled: false
+    url: https://api.datacite.org
+    prefix: ""
+    username: ""
+    password: ""
+  rates:
+    deleteStaleFiles: 60
+    mirror: 60
+    obtainMetadata: 60
+    deleteStaleQueries: 60
+  replicaCount: 2
+
+dataService:
+  enabled: true
+  image:
+    name: s210.dl.hpc.tuwien.ac.at/dbrepo/data-service:1.4.2
+    pullPolicy: Always
+    debug: false
+  jwt:
+    pubkey: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB"
+  consumerConcurrentMin: 1
+  consumerConcurrentMax: 5
+  requeueRejected: false
+  replicaCount: 2
+
+searchService:
+  enabled: true
+  image:
+    name: s210.dl.hpc.tuwien.ac.at/dbrepo/search-service:1.4.2
+    pullPolicy: Always
+    debug: false
+  replicaCount: 2
+
+storageservice:
+  master:
+    enabled: true
+  filer:
+    enabled: true
+    replicas: 2
+    enablePVC: false
+    storage: 25Gi
+    s3:
+      enabled: true
+      allowEmptyFolder: true
+      port: 9000
+      enableAuth: true
+      skipAuthSecretCreation: true
+      existingConfigSecret: seaweedfs-s3-secret
+  volume:
+    enabled: true
+    replicas: 2
+  s3:
+    enabled: true
+    replicas: 2
+    port: 9000
+    metricsPort: 9091
+    enableAuth: true
+    skipAuthSecretCreation: true
+    existingConfigSecret: seaweedfs-s3-secret
+    auth:
+      username: seaweedfsadmin
+      password: seaweedfsadmin
+
+logservice:
+  fullnameOverride: log-service
+  config:
+    outputs: |
+      [OUTPUT]
+          Name               opensearch
+          Match              kube.*
+          Host               search-db
+          Port               9200
+          HTTP_User          admin
+          HTTP_Passwd        admin
+          Logstash_Format    On
+          Replace_Dots       On
+          Type               _doc
+          Retry_Limit        False
+          Suppress_Type_Name On
+      
+      [OUTPUT]
+          Name               opensearch
+          Match              host.*
+          Host               search-db
+          Port               9200
+          HTTP_User          admin
+          HTTP_Passwd        admin
+          Logstash_Format    On
+          Logstash_Prefix    node
+          Replace_Dots       On
+          Type               _doc
+          Retry_Limit        False
+          Suppress_Type_Name On
+#          Replace_Dots        On
+#          Suppress_Type_Name  On
+
+ui:
+  enabled: true
+  image:
+    name: s210.dl.hpc.tuwien.ac.at/dbrepo/ui:1.4.2
+    pullPolicy: Always
+    debug: false
+  public:
+    api:
+      client: {}
+      server: {}
+    title: "Database Repository"
+    logo: "/logo.svg"
+    icon: "/favicon.ico"
+    touch: "/apple-touch-icon.png"
+    broker:
+      host: example.com
+      port:
+        5671: true
+        5672: false
+      extra: "128.130.0.0/15"
+    database:
+      extra: "128.130.0.0/15"
+    pid:
+      default:
+        publisher: "Example University"
+    doi:
+      enabled: false
+      endpoint: https://doi.org
+  replicaCount: 2
+  extraVolumes: [ ]
+  #  - name: images-map
+  #    configMap:
+  #      name: ui-config
+  extraVolumeMounts: [ ]
+  #  - name: images-map
+  #    mountPath: /static/logo.svg
+  #    subPath: logo.svg
+
+ingress:
+  enabled: true
+  className: nginx
+  tls:
+    enabled: true
+    secretName: ingress-cert
+  annotations:
+    basic: {}
+#      cert-manager.io/cluster-issuer: letsencrypt-cluster-issuer
+    secure:
+#      cert-manager.io/cluster-issuer: letsencrypt-cluster-issuer
+      nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
+      nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
+    upload:
+#      cert-manager.io/cluster-issuer: letsencrypt-cluster-issuer
+      nginx.ingress.kubernetes.io/proxy-body-size: 2G
+    rewriteApi:
+#      cert-manager.io/cluster-issuer: letsencrypt-cluster-issuer
+      nginx.ingress.kubernetes.io/use-regex: "true"
+      nginx.ingress.kubernetes.io/rewrite-target: /api/$1
+    rewriteRoot:
+#      cert-manager.io/cluster-issuer: letsencrypt-cluster-issuer
+      nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
+      nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
+      nginx.ingress.kubernetes.io/use-regex: "true"
+      nginx.ingress.kubernetes.io/rewrite-target: /$1
+    rewritePid:
+#      cert-manager.io/cluster-issuer: letsencrypt-cluster-issuer
+      nginx.ingress.kubernetes.io/use-regex: "true"
+      nginx.ingress.kubernetes.io/rewrite-target: /api/pid/$1
diff --git a/lib/python/Makefile b/lib/python/Makefile
index 31371ee1da71daa24e663344df62a860e674c04e..7c79a178bfd875327542c07e6bbdd0353a068b19 100644
--- a/lib/python/Makefile
+++ b/lib/python/Makefile
@@ -1,11 +1,8 @@
-all: build
+all: build install
 
 clean:
 	rm -rf ./python/dist/* ./docs/build/* ./dist/*
 
-install:
-	pipenv install
-
 docs: clean
 	sphinx-apidoc -o ./docs/source ./dbrepo
 	sphinx-build -M html ./docs/ ./docs/build/
@@ -16,8 +13,14 @@ check:
 build: clean
 	python3 -m build --sdist .
 	python3 -m build --wheel .
+
+install:
 	cp ./dist/dbrepo-* ../../dbrepo-analyse-service/lib/
+	(cd ../../dbrepo-analyse-service && pipenv lock)
 	cp ./dist/dbrepo-* ../../dbrepo-search-service/lib/
+	(cd ../../dbrepo-search-service && pipenv lock)
+	cp ./dist/dbrepo-* ../../../dpm2024/lib/
+	(cd ../../../dpm2024 && pipenv lock)
 
 deploy: build
 	python3 -m twine upload --config-file ~/.pypirc --verbose --repository pypi ./dist/dbrepo-*
diff --git a/lib/python/dbrepo/RestClient.py b/lib/python/dbrepo/RestClient.py
index 453a7d4315439b60e00638273291175f38f15e63..79e6fd1181b73b80f6ed74824cb7981ee914a5c7 100644
--- a/lib/python/dbrepo/RestClient.py
+++ b/lib/python/dbrepo/RestClient.py
@@ -62,11 +62,12 @@ class RestClient:
             logging.debug(f'headers: {headers}')
         if payload is not None:
             logging.debug(f'payload: {payload.model_dump()}')
+            payload = payload.model_dump()
         if self.username is not None and self.password is not None:
             logging.debug(f'username: {self.username}, password: (hidden)')
             return requests.request(method=method, url=url, auth=(self.username, self.password), verify=self.secure,
-                                    json=payload.model_dump(), headers=headers, params=params, stream=stream)
-        return requests.request(method=method, url=url, verify=self.secure, json=payload.model_dump(),
+                                    json=payload, headers=headers, params=params, stream=stream)
+        return requests.request(method=method, url=url, verify=self.secure, json=payload,
                                 headers=headers, params=params, stream=stream)
 
     def upload(self, file_path: str) -> str:
diff --git a/lib/python/dbrepo/api/dto.py b/lib/python/dbrepo/api/dto.py
index 0a27cb664d7e4b5c1f4ed71dfa64328d2f52dcf8..db84bbbdbc3b886fcabcf840cfbbbba692bd1f43 100644
--- a/lib/python/dbrepo/api/dto.py
+++ b/lib/python/dbrepo/api/dto.py
@@ -511,6 +511,7 @@ class CreateTableColumn(BaseModel):
 class CreateTableConstraints(BaseModel):
     uniques: List[List[str]] = field(default_factory=list)
     checks: List[str] = field(default_factory=list)
+    primary_key: List[str] = field(default_factory=list)
     foreign_keys: List[CreateForeignKey] = field(default_factory=list)
 
 
@@ -945,7 +946,12 @@ class Table(BaseModel):
 class TableMinimal(BaseModel):
     id: int
     database_id: int
-    name: str
+
+
+class ColumnMinimal(BaseModel):
+    id: int
+    table_id: int
+    database_id: int
 
 
 class Database(BaseModel):
@@ -970,16 +976,17 @@ class Database(BaseModel):
 
 
 class Unique(BaseModel):
-    uid: int
+    id: int
     table: TableMinimal
-    columns: List[Column]
+    columns: List[ColumnMinimal]
 
 
 class ForeignKey(BaseModel):
+    id: int
     name: str
-    columns: List[Column]
+    columns: List[ColumnMinimal]
     referenced_table: TableMinimal
-    referenced_columns: List[Column]
+    referenced_columns: List[ColumnMinimal]
     on_update: Optional[str] = None
     on_delete: Optional[str] = None
 
@@ -993,7 +1000,9 @@ class CreateForeignKey(BaseModel):
 
 
 class PrimaryKey(BaseModel):
-    pkid: int
+    id: int
+    table: TableMinimal
+    column: ColumnMinimal
 
 
 class Constraints(BaseModel):
diff --git a/lib/python/tests/test_database.py b/lib/python/tests/test_database.py
index 017a17445ab4a7e4eb0e56002f1a444da0208118..1ac768690c5ac6e1ad5bececc35755b666583d5b 100644
--- a/lib/python/tests/test_database.py
+++ b/lib/python/tests/test_database.py
@@ -531,8 +531,7 @@ class DatabaseTest(unittest.TestCase):
             mock.delete('/api/database/1/access/abdbf897-e599-4e5a-a3f0-7529884ea011', status_code=202)
             # test
             client = RestClient(username="a", password="b")
-            response = client.delete_database_access(database_id=1,
-                                                     user_id='abdbf897-e599-4e5a-a3f0-7529884ea011')
+            client.delete_database_access(database_id=1, user_id='abdbf897-e599-4e5a-a3f0-7529884ea011')
 
     def test_delete_database_access_malformed_fails(self):
         with requests_mock.Mocker() as mock:
@@ -541,8 +540,7 @@ class DatabaseTest(unittest.TestCase):
             # test
             try:
                 client = RestClient(username="a", password="b")
-                response = client.delete_database_access(database_id=1,
-                                                         user_id='abdbf897-e599-4e5a-a3f0-7529884ea011')
+                client.delete_database_access(database_id=1, user_id='abdbf897-e599-4e5a-a3f0-7529884ea011')
             except MalformedError:
                 pass
 
@@ -553,8 +551,7 @@ class DatabaseTest(unittest.TestCase):
             # test
             try:
                 client = RestClient(username="a", password="b")
-                response = client.delete_database_access(database_id=1,
-                                                         user_id='abdbf897-e599-4e5a-a3f0-7529884ea011')
+                client.delete_database_access(database_id=1, user_id='abdbf897-e599-4e5a-a3f0-7529884ea011')
             except ForbiddenError:
                 pass
 
@@ -565,8 +562,7 @@ class DatabaseTest(unittest.TestCase):
             # test
             try:
                 client = RestClient(username="a", password="b")
-                response = client.delete_database_access(database_id=1,
-                                                         user_id='abdbf897-e599-4e5a-a3f0-7529884ea011')
+                client.delete_database_access(database_id=1, user_id='abdbf897-e599-4e5a-a3f0-7529884ea011')
             except NotExistsError:
                 pass
 
@@ -576,8 +572,7 @@ class DatabaseTest(unittest.TestCase):
             mock.delete('/api/database/1/access/abdbf897-e599-4e5a-a3f0-7529884ea011', status_code=404)
             # test
             try:
-                response = RestClient().delete_database_access(database_id=1,
-                                                               user_id='abdbf897-e599-4e5a-a3f0-7529884ea011')
+                RestClient().delete_database_access(database_id=1, user_id='abdbf897-e599-4e5a-a3f0-7529884ea011')
             except AuthenticationError:
                 pass