Merge commit '01b8095e9459417e2cf5bd1079c796d4f01ec549' into work/reports-ui

# Conflicts:
#	src/main/resources/templates/attendance/history.html
This commit is contained in:
sechmachine
2026-08-15 03:35:04 +07:00
46 changed files with 1270 additions and 63 deletions
@@ -0,0 +1,92 @@
# Test Evidence: Checkout eligibility and stable conflict outcomes
- **Test type:** Unit
- **Requirement IDs:** `ATT-007`, `ATT-008`, `ATT-010`, `ATT-012`
- **Scenario IDs:** `AC-ATT-003`, `AC-ATT-004`
- **Test class/method:** `com.lab.labtimesheet.feature.attendance.service.AttendanceApplicationServiceTest#rejectsCheckoutWhenInternIsNoLongerEligibleForPersistedWorkDate`, `#translatesConcurrentCheckInUniqueConflictToStableDuplicateRejection`, `#translatesConcurrentCheckoutVersionConflictToStableDuplicateRejection`
- **Implementation commit:** `4c39df70e1f901e232669e9090ff5d21393519f0`
## Protected behavior
Checkout revalidates active internship eligibility for the attendance row's
persisted work date. A terminal Intern cannot checkout after checking in.
Database uniqueness and optimistic-lock races are translated to stable duplicate
punch rejection codes instead of leaking persistence exceptions.
## Test method
Plain JUnit and Mockito drive the production transactional application service
with a fixed Clock, attached policy, persisted row, AccountService eligibility,
and repository exceptions. Account state remains behind its public service API.
## Hand-derived expected result
False date-aware eligibility returns `INACTIVE_INTERN` before raw checkout is
saved. A check-in uniqueness race returns `ALREADY_CHECKED_IN`; a checkout
version race returns `ALREADY_CHECKED_OUT`.
## RED
**Command**
```text
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
export PATH="$JAVA_HOME/bin:$PATH"
./mvnw -Dtest=AttendanceApplicationServiceTest#rejectsCheckoutWhenInternIsNoLongerEligibleForPersistedWorkDate test
```
**Observed result**
```text
Expected AttendanceException(INACTIVE_INTERN) but was NullPointerException after
the service continued to save checkout without calling AccountService eligibility.
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
BUILD FAILURE
Process exited 1.
```
The conflict regressions were also observed RED in the combined focused run:
```text
DataIntegrityViolationException: concurrent unique conflict
ObjectOptimisticLockingFailureException: optimistic locking failed
Both escaped AttendanceApplicationService instead of stable AttendanceException values.
```
## GREEN
**Command**
```text
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
export PATH="$JAVA_HOME/bin:$PATH"
./mvnw -Dtest=AttendanceApplicationServiceTest test
```
**Observed result**
```text
Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
Process exited 0.
```
## Affected suite
**Command and result**
```text
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
export PATH="$JAVA_HOME/bin:$PATH"
export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock
./mvnw -Dtest='*Attendance*Test' test
Tests run: 32, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
Process exited 0.
```
## External-test boundaries
The account platform has no Iteration 1 terminal-state mutation API, so the
completed/withdrawn state is represented through its public date-aware eligibility
result. The companion PostgreSQL concurrency test proves the real unique conflict.
+2 -2
View File
@@ -4,7 +4,7 @@
- **Requirement IDs:** `ATT-005`, `I1-UI-03`
- **Scenario IDs:** `I1-ATT-03`, `I1-ATT-04`
- **Test class/method:** `com.lab.labtimesheet.feature.attendance.service.AttendanceApplicationServiceTest`
- **Implementation commit:** `pending (committed with this evidence)`
- **Implementation commit:** `8b48e281f7e860af435ae35b16c4edeb139286dc`
## Protected behavior
@@ -70,7 +70,7 @@ export JAVA_HOME=/opt/homebrew/opt/openjdk@25
export PATH="$JAVA_HOME/bin:$PATH"
export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock
./mvnw -Dtest='*Attendance*Test' test
Tests run: 26, Failures: 0, Errors: 0, Skipped: 0
Tests run: 32, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
Process exited 0.
```
@@ -4,7 +4,7 @@
- **Requirement IDs:** `ARC-005`, `OPS-020`
- **Scenario IDs:** `I1-ATT-01` through `I1-ATT-05` structural gate
- **Test class/method:** `com.lab.labtimesheet.architecture.AttendanceLayerStructureTest`
- **Implementation commit:** `pending (committed with this evidence)`
- **Implementation commit:** `8b48e281f7e860af435ae35b16c4edeb139286dc`
## Protected behavior
@@ -90,7 +90,7 @@ export JAVA_HOME=/opt/homebrew/opt/openjdk@25
export PATH="$JAVA_HOME/bin:$PATH"
export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock
./mvnw -Dtest='*Attendance*Test' test
Tests run: 26, Failures: 0, Errors: 0, Skipped: 0
Tests run: 32, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
Process exited 0.
```
+2 -2
View File
@@ -4,7 +4,7 @@
- **Requirement IDs:** `ATT-001`, `ATT-002`, `ATT-003`, `ATT-004`
- **Scenario IDs:** `AC-ATT-001`
- **Test class/method:** `com.lab.labtimesheet.feature.attendance.model.AttendancePolicyTest`
- **Implementation commit:** `pending (committed with this evidence)`
- **Implementation commit:** `71901d1670f633a1b594bdce3348efebe73fc175`
## Protected behavior
@@ -66,7 +66,7 @@ Process exited 0.
```text
./mvnw -Dtest='*Attendance*Test' test
Tests run: 26, Failures: 0, Errors: 0, Skipped: 0
Tests run: 32, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
Process exited 0.
```
@@ -4,7 +4,7 @@
- **Requirement IDs:** `GOV-011`, `GOV-012`, `ATT-005`, `ATT-007`, `ATT-008`, `ATT-009`, `ATT-010`, `ATT-011`, `ATT-012`, `ATT-016`
- **Scenario IDs:** `AC-ATT-002`, `AC-ATT-003`, `AC-ATT-004`, `AC-ATT-005`
- **Test class/method:** `com.lab.labtimesheet.feature.attendance.service.AttendanceServiceTest`
- **Implementation commit:** `pending (committed with this evidence)`
- **Implementation commit:** `71901d1670f633a1b594bdce3348efebe73fc175`
## Protected behavior
@@ -71,7 +71,7 @@ Process exited 0.
```text
./mvnw -Dtest='*Attendance*Test' test
Tests run: 26, Failures: 0, Errors: 0, Skipped: 0
Tests run: 32, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
Process exited 0.
```