diff --git a/dbrepo-metadata-service/pom.xml b/dbrepo-metadata-service/pom.xml
index 8cd08e853640a0b6c810c36b65a5c46d4cc425c0..c76bc5517788001521cf01d551573d0db6b044f5 100644
--- a/dbrepo-metadata-service/pom.xml
+++ b/dbrepo-metadata-service/pom.xml
@@ -151,10 +151,20 @@
             <version>${c3p0-hibernate.version}</version>
         </dependency>
         <!-- Monitoring -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
         <dependency>
             <groupId>io.micrometer</groupId>
             <artifactId>micrometer-registry-prometheus</artifactId>
-            <scope>runtime</scope>
+            <version>${micrometer.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.micrometer</groupId>
+            <artifactId>micrometer-observation-test</artifactId>
+            <version>${micrometer.version}</version>
+            <scope>test</scope>
         </dependency>
         <!-- Authentication -->
         <dependency>
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 cd0bc94d5865a493538444a88a9bbb74333c30ab..d3c26da5659dd1f6c84141a74854c76972c69c79 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
@@ -10,6 +10,7 @@ import at.tuwien.mapper.DatabaseMapper;
 import at.tuwien.service.AccessService;
 import at.tuwien.utils.PrincipalUtil;
 import at.tuwien.utils.UserUtil;
+import io.micrometer.observation.annotation.Observed;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -46,6 +47,7 @@ public class AccessEndpoint {
 
     @PostMapping("/{userId}")
     @Transactional
+    @Observed(name = "dbr_access_give")
     @PreAuthorize("hasAuthority('create-database-access')")
     @Operation(summary = "Give access to some database", security = @SecurityRequirement(name = "bearerAuth"))
     @ApiResponses(value = {
@@ -89,6 +91,7 @@ public class AccessEndpoint {
 
     @PutMapping("/{userId}")
     @Transactional
+    @Observed(name = "dbr_access_modify")
     @PreAuthorize("hasAuthority('update-database-access')")
     @Operation(summary = "Modify access to some database", security = @SecurityRequirement(name = "bearerAuth"))
     @ApiResponses(value = {
@@ -126,6 +129,7 @@ public class AccessEndpoint {
 
     @GetMapping
     @Transactional
+    @Observed(name = "dbr_access_check")
     @PreAuthorize("hasAuthority('check-database-access')")
     @Operation(summary = "Check access to some database", security = @SecurityRequirement(name = "bearerAuth"))
     @ApiResponses(value = {
@@ -157,6 +161,7 @@ public class AccessEndpoint {
 
     @DeleteMapping("/{userId}")
     @Transactional
+    @Observed(name = "dbr_access_delete")
     @PreAuthorize("hasAuthority('delete-database-access')")
     @Operation(summary = "Revoke access to some database", security = @SecurityRequirement(name = "bearerAuth"))
     @ApiResponses(value = {
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java
index 6169e677d4ae1b2b3120262bc91235cb3c084380..3176f6327d630e022e1baa489effc539b61119d2 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java
@@ -92,17 +92,37 @@ public class EndpointValidator {
                 .filter(c -> needSize.contains(c.getType()))
                 .findFirst();
         if (optional0.isPresent()) {
+            log.error("Validation failed: column {} needs size parameter", optional0.get().getName() );
             throw new TableMalformedException("Validation failed: column " + optional0.get().getName() + " needs size parameter");
         }
         /* check size and d */
         final Optional<ColumnCreateDto> optional1 = data.getColumns()
                 .stream()
-                .filter(c -> Objects.isNull(c.getSize()) || Objects.isNull(c.getD()))
                 .filter(c -> needSizeAndD.contains(c.getType()))
+                .filter(c -> Objects.isNull(c.getSize()) || Objects.isNull(c.getD()))
                 .findFirst();
         if (optional1.isPresent()) {
+            log.error("Validation failed: column {} needs size and d parameter", optional1.get().getName());
             throw new TableMalformedException("Validation failed: column " + optional1.get().getName() + " needs size and d parameter");
         }
+        final Optional<ColumnCreateDto> optional1a = data.getColumns()
+                .stream()
+                .filter(c -> needSizeAndD.contains(c.getType()))
+                .filter(c -> c.getSize() > 65 || c.getD() > 38)
+                .findFirst();
+        if (optional1a.isPresent()) {
+            log.error("Validation failed: column {} needs size (max 65) and d (max 30)", optional1a.get().getName());
+            throw new TableMalformedException("Validation failed: column " + optional1a.get().getName() + " needs size (max 65) and d (max 30)");
+        }
+        final Optional<ColumnCreateDto> optional1b = data.getColumns()
+                .stream()
+                .filter(c -> needSizeAndD.contains(c.getType()))
+                .filter(c -> c.getSize() < c.getD())
+                .findFirst();
+        if (optional1b.isPresent()) {
+            log.error("Validation failed: column {} needs size >= d", optional1b.get().getName());
+            throw new TableMalformedException("Validation failed: column " + optional1b.get().getName() + " needs size >= d");
+        }
         /* check enum */
         final Optional<ColumnCreateDto> optional2 = data.getColumns()
                 .stream()
@@ -110,6 +130,7 @@ public class EndpointValidator {
                 .filter(c -> c.getEnums() == null || c.getEnums().isEmpty())
                 .findFirst();
         if (optional2.isPresent()) {
+            log.error("Validation failed: column {} needs at least 1 allowed enum value", optional2.get().getName());
             throw new TableMalformedException("Validation failed: column " + optional2.get().getName() + " needs at least 1 allowed enum value");
         }
         /* check set */
@@ -119,6 +140,7 @@ public class EndpointValidator {
                 .filter(c -> c.getEnums() == null || c.getSets().isEmpty())
                 .findFirst();
         if (optional3.isPresent()) {
+            log.error("Validation failed: column {} needs at least 1 allowed set value", optional3.get().getName());
             throw new TableMalformedException("Validation failed: column " + optional3.get().getName() + " needs at least 1 allowed set value");
         }
         /* check date */
@@ -128,6 +150,7 @@ public class EndpointValidator {
                 .filter(c -> Objects.isNull(c.getDfid()))
                 .findFirst();
         if (optional4.isPresent()) {
+            log.error("Validation failed: column {} needs a format", optional4.get().getName());
             throw new TableMalformedException("Validation failed: column " + optional4.get().getName() + " needs a format");
         }
     }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java
index 9005b65ff7911f7669d98056a899d36d3fe698fa..5ee6b057a2cb95b3d968e48d6c39fdc9144e8ec7 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java
@@ -6,6 +6,8 @@ import at.tuwien.annotations.MockOpensearch;
 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.columns.ColumnCreateDto;
+import at.tuwien.api.database.table.columns.ColumnTypeDto;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
 import at.tuwien.entities.database.table.Table;
@@ -155,6 +157,109 @@ public class TableEndpointUnitTest extends BaseUnitTest {
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
+    public void create_publicDecimalColumnSizeMissing_fails() {
+        final TableCreateDto request = TableCreateDto.builder()
+                .name("Some Table")
+                .description("Some Description")
+                .columns(List.of(ColumnCreateDto.builder()
+                        .name("ID")
+                        .type(ColumnTypeDto.DECIMAL)
+                        .build()))
+                .constraints(null)
+                .build();
+
+        /* test */
+        assertThrows(TableMalformedException.class, () -> {
+            generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_ID, USER_1_PRINCIPAL, DATABASE_3_USER_1_WRITE_OWN_ACCESS);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
+    public void create_publicDecimalColumnSizeTooSmall_fails() {
+        final TableCreateDto request = TableCreateDto.builder()
+                .name("Some Table")
+                .description("Some Description")
+                .columns(List.of(ColumnCreateDto.builder()
+                        .name("ID")
+                        .type(ColumnTypeDto.DECIMAL)
+                        .size(-1)
+                        .d(0)
+                        .build()))
+                .constraints(null)
+                .build();
+
+        /* test */
+        assertThrows(TableMalformedException.class, () -> {
+            generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_ID, USER_1_PRINCIPAL, DATABASE_3_USER_1_WRITE_OWN_ACCESS);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
+    public void create_publicDecimalColumnSizeTooBig_fails() {
+        final TableCreateDto request = TableCreateDto.builder()
+                .name("Some Table")
+                .description("Some Description")
+                .columns(List.of(ColumnCreateDto.builder()
+                        .name("ID")
+                        .type(ColumnTypeDto.DECIMAL)
+                        .size(66)
+                        .d(0)
+                        .build()))
+                .constraints(null)
+                .build();
+
+        /* test */
+        assertThrows(TableMalformedException.class, () -> {
+            generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_ID, USER_1_PRINCIPAL, DATABASE_3_USER_1_WRITE_OWN_ACCESS);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
+    public void create_publicDecimalColumnDTooBig_fails() {
+        final TableCreateDto request = TableCreateDto.builder()
+                .name("Some Table")
+                .description("Some Description")
+                .columns(List.of(ColumnCreateDto.builder()
+                        .name("ID")
+                        .type(ColumnTypeDto.DECIMAL)
+                        .size(0)
+                        .d(39)
+                        .build()))
+                .constraints(null)
+                .build();
+
+        /* test */
+        assertThrows(TableMalformedException.class, () -> {
+            generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_ID, USER_1_PRINCIPAL, DATABASE_3_USER_1_WRITE_OWN_ACCESS);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
+    public void create_publicDecimalColumnDBiggerSize_fails() {
+        final TableCreateDto request = TableCreateDto.builder()
+                .name("Some Table")
+                .description("Some Description")
+                .columns(List.of(ColumnCreateDto.builder()
+                        .name("ID")
+                        .type(ColumnTypeDto.DECIMAL)
+                        .size(9)
+                        .d(10)
+                        .build()))
+                .constraints(null)
+                .build();
+
+        /* test */
+        assertThrows(TableMalformedException.class, () -> {
+            generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_ID, USER_1_PRINCIPAL, DATABASE_3_USER_1_WRITE_OWN_ACCESS);
+        });
+    }
+
     @Test
     @WithAnonymousUser
     public void findById_publicAnonymous_succeeds() throws DatabaseNotFoundException, TableNotFoundException,
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/ActuatorEndpointMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/ActuatorEndpointMvcTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..11d52c79efd91d66aec071b20d9b7f409d507dd0
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/ActuatorEndpointMvcTest.java
@@ -0,0 +1,50 @@
+package at.tuwien.mvc;
+
+import at.tuwien.BaseUnitTest;
+import at.tuwien.annotations.MockAmqp;
+import at.tuwien.annotations.MockOpensearch;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@Log4j2
+@ExtendWith(SpringExtension.class)
+@AutoConfigureMockMvc
+@SpringBootTest
+@AutoConfigureObservability
+@MockAmqp
+@MockOpensearch
+public class ActuatorEndpointMvcTest extends BaseUnitTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @Test
+    public void actuatorInfo_succeeds() throws Exception {
+
+        /* test */
+        this.mockMvc.perform(get("/actuator/info"))
+                .andDo(print())
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    public void actuatorPrometheus_succeeds() throws Exception {
+
+        /* test */
+        this.mockMvc.perform(get("/actuator/prometheus"))
+                .andDo(print())
+                .andExpect(status().isOk());
+    }
+
+}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..efbe24aa944480ea5e7b2e715ff3da1c6255e1e8
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
@@ -0,0 +1,108 @@
+package at.tuwien.mvc;
+
+import at.tuwien.BaseUnitTest;
+import at.tuwien.annotations.MockAmqp;
+import at.tuwien.annotations.MockOpensearch;
+import at.tuwien.api.database.AccessTypeDto;
+import at.tuwien.api.database.DatabaseGiveAccessDto;
+import at.tuwien.api.database.DatabaseModifyAccessDto;
+import at.tuwien.config.MetricsConfig;
+import at.tuwien.endpoints.AccessEndpoint;
+import io.micrometer.observation.tck.TestObservationRegistry;
+import lombok.SneakyThrows;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Import;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.util.List;
+
+import static io.micrometer.observation.tck.TestObservationRegistryAssert.assertThat;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@Log4j2
+@ExtendWith(SpringExtension.class)
+@AutoConfigureMockMvc
+@SpringBootTest
+@Import(MetricsConfig.class)
+@AutoConfigureObservability
+@MockAmqp
+@MockOpensearch
+public class PrometheusEndpointMvcTest extends BaseUnitTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @Autowired
+    private TestObservationRegistry registry;
+
+    @Autowired
+    private AccessEndpoint accessEndpoint;
+
+    @TestConfiguration
+    static class ObservationTestConfiguration {
+
+        @Bean
+        public TestObservationRegistry observationRegistry() {
+            return TestObservationRegistry.create();
+        }
+    }
+
+    @Test
+    public void prometheus_succeeds() throws Exception {
+
+        /* test */
+        this.mockMvc.perform(get("/actuator/prometheus"))
+                .andDo(print())
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"create-database-access", "update-database-access", "check-database-access", "delete-database-access"})
+    public void prometheusAccessEndpoint_succeeds() throws Exception {
+
+        /* mock */
+        try {
+            accessEndpoint.create(DATABASE_1_ID, USER_1_ID, DatabaseGiveAccessDto.builder().type(AccessTypeDto.READ).build(), USER_1_PRINCIPAL);
+        } catch (Exception e) {
+            /* ignore */
+        }
+        try {
+            accessEndpoint.update(DATABASE_1_ID, USER_1_ID, DatabaseModifyAccessDto.builder().type(AccessTypeDto.READ).build(), USER_1_PRINCIPAL);
+        } catch (Exception e) {
+            /* ignore */
+        }
+        try {
+            accessEndpoint.find(DATABASE_1_ID, USER_1_PRINCIPAL);
+        } catch (Exception e) {
+            /* ignore */
+        }
+        try {
+            accessEndpoint.revoke(DATABASE_1_ID, USER_1_ID, USER_1_PRINCIPAL);
+        } catch (Exception e) {
+            /* ignore */
+        }
+
+
+        this.mockMvc.perform(get("/actuator/prometheus"))
+                .andDo(print())
+                .andExpect(status().isOk());
+        /* test */
+        for (String metric : List.of("dbr_access_give", "dbr_access_modify", "dbr_access_check", "dbr_access_delete")) {
+            assertThat(registry)
+                    .hasObservationWithNameEqualTo(metric);
+        }
+    }
+
+}
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/MetricsConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/MetricsConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..450be2f7df8b52fe493dd498dc0422350bb3ff39
--- /dev/null
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/MetricsConfig.java
@@ -0,0 +1,15 @@
+package at.tuwien.config;
+
+import io.micrometer.observation.ObservationRegistry;
+import io.micrometer.observation.aop.ObservedAspect;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class MetricsConfig {
+
+    @Bean
+    public ObservedAspect observedAspect(ObservationRegistry observationRegistry) {
+        return new ObservedAspect(observationRegistry);
+    }
+}