feat: establish iteration 1 platform foundation

This commit is contained in:
sechmachine
2026-08-14 23:31:39 +07:00
parent 5967f7f70d
commit 4b37f8fd05
13 changed files with 1349 additions and 0 deletions
@@ -0,0 +1,7 @@
package com.lab.labtimesheet.accounts;
/** Accounts and security module boundary. */
public final class ModuleBoundary {
private ModuleBoundary() {
}
}
@@ -0,0 +1,7 @@
package com.lab.labtimesheet.attendance;
/** Attendance, leave, and corrections module boundary. */
public final class ModuleBoundary {
private ModuleBoundary() {
}
}
@@ -0,0 +1,7 @@
package com.lab.labtimesheet.configuration;
/** Configuration, integrations, and calendar module boundary. */
public final class ModuleBoundary {
private ModuleBoundary() {
}
}
@@ -0,0 +1,15 @@
package com.lab.labtimesheet.configuration;
import java.time.Clock;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
class TimeConfiguration {
@Bean
Clock applicationClock() {
return Clock.systemUTC();
}
}
@@ -0,0 +1,7 @@
package com.lab.labtimesheet.notifications;
/** Notifications module boundary. */
public final class ModuleBoundary {
private ModuleBoundary() {
}
}
@@ -0,0 +1,7 @@
package com.lab.labtimesheet.projects;
/** Projects and tasks module boundary. */
public final class ModuleBoundary {
private ModuleBoundary() {
}
}
@@ -0,0 +1,7 @@
package com.lab.labtimesheet.reporting;
/** Reporting module boundary. */
public final class ModuleBoundary {
private ModuleBoundary() {
}
}
+2
View File
@@ -7,4 +7,6 @@ spring:
compose:
enabled: false
jpa:
hibernate:
ddl-auto: validate
open-in-view: false
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,75 @@
package com.lab.labtimesheet;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ActiveProfiles;
@Import(TestcontainersConfiguration.class)
@SpringBootTest
@ActiveProfiles("test")
class PlatformFoundationTest {
@Autowired
private ApplicationContext applicationContext;
@Autowired
private DataSource dataSource;
@Autowired
private Clock clock;
@Test
void applicationExposesRequiredModulePackages() throws ClassNotFoundException {
assertThat(applicationContext).isNotNull();
assertThat(Class.forName("com.lab.labtimesheet.accounts.ModuleBoundary")).isNotNull();
assertThat(Class.forName("com.lab.labtimesheet.configuration.ModuleBoundary")).isNotNull();
assertThat(Class.forName("com.lab.labtimesheet.projects.ModuleBoundary")).isNotNull();
assertThat(Class.forName("com.lab.labtimesheet.attendance.ModuleBoundary")).isNotNull();
assertThat(Class.forName("com.lab.labtimesheet.notifications.ModuleBoundary")).isNotNull();
assertThat(Class.forName("com.lab.labtimesheet.reporting.ModuleBoundary")).isNotNull();
}
@Test
void flywayCreatesApprovedPostgresCatalog() {
JdbcTemplate jdbc = new JdbcTemplate(dataSource);
Integer tables = jdbc.queryForObject("""
select count(*)
from information_schema.tables
where table_schema = 'public'
and table_type = 'BASE TABLE'
and table_name <> 'flyway_schema_history'
""", Integer.class);
Integer foreignKeys = jdbc.queryForObject("""
select count(*)
from pg_constraint c
join pg_namespace n on n.oid = c.connamespace
where n.nspname = 'public' and c.contype = 'f'
""", Integer.class);
assertThat(tables).isEqualTo(23);
assertThat(foreignKeys).isEqualTo(56);
assertThat(jdbc.queryForObject(
"select checkout_grace_minutes from attendance_policy_versions where effective_from = date '1970-01-01'",
Integer.class)).isEqualTo(30);
assertThat(jdbc.queryForObject("select count(*) from attendance_policy_workdays", Integer.class)).isEqualTo(5);
}
@Test
void testClockIsDeterministic() {
assertThat(clock.instant()).isEqualTo(Instant.parse("2026-08-14T00:00:00Z"));
assertThat(clock.getZone()).isEqualTo(ZoneId.of("Asia/Ho_Chi_Minh"));
}
}
@@ -1,8 +1,13 @@
package com.lab.labtimesheet;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.testcontainers.postgresql.PostgreSQLContainer;
import org.testcontainers.utility.DockerImageName;
@@ -15,4 +20,10 @@ class TestcontainersConfiguration {
return new PostgreSQLContainer(DockerImageName.parse("postgres:18.4"));
}
@Bean
@Primary
Clock testClock() {
return Clock.fixed(Instant.parse("2026-08-14T00:00:00Z"), ZoneId.of("Asia/Ho_Chi_Minh"));
}
}
+3
View File
@@ -2,3 +2,6 @@ spring:
docker:
compose:
enabled: false
lab:
security:
master-key: AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=