Merge commit 'c3f92d4e310d625d95d374e974c478444331f6d7' into work/tasks

This commit is contained in:
sechmachine
2026-08-15 01:06:20 +07:00
15 changed files with 454 additions and 22 deletions
@@ -0,0 +1,75 @@
# Test Evidence: Locked Project context for Task mutations
- **Test type:** Unit
- **Requirement IDs:** `AUTH-001`, `AUTH-011`, `PRJ-012`
- **Scenario IDs:** `AC-AUTH-001`, `AC-AUTH-010`, `AC-PRJ-006`
- **Test class/method:** `com.lab.labtimesheet.feature.project.service.ProjectTaskMutationContextTest#loadsTheProjectForUpdateBeforeBuildingTheTaskMutationContext`
- **Implementation commit:** `19a3518`
## Protected behavior
Task mutations obtain their Project authorization and current lifecycle, Leader, owning-Mentor, and active-member facts from a DTO-only Project service boundary after the Project row has been locked for update. Missing and unauthorized Projects retain the same non-disclosing denial behavior.
## Test method
The isolated service test invokes `ProjectService.taskMutationContext(actorUserId, projectId)`, verifies that `ProjectRepository.findLockedById` is used and the ordinary `findById` path is not used, and verifies that only the locked entity is passed to the existing Project-owned authorization and DTO mapper. The PostgreSQL integration test additionally exercises the public API with authorized, unauthorized, current-member, and former-member data.
## Hand-derived expected result
Exactly one pessimistic Project lookup occurs before context evaluation. The returned `ProjectTaskContext` exposes scalar/DTO facts only; no Project repository or entity crosses the feature boundary. When called from Task's active transaction, Spring's default `REQUIRED` propagation keeps the row lock in that transaction through its commit or rollback.
## RED
**Command**
```text
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
export PATH="$JAVA_HOME/bin:$PATH"
./mvnw -Dtest=ProjectTaskMutationContextTest test
```
**Observed result**
```text
[ERROR] constructor ProjectService ... cannot be applied to given types
[ERROR] incompatible types: ProjectEntity cannot be converted to long
[INFO] BUILD FAILURE
```
The test failed to compile because Project had no mutation-context API and its context mapper accepted only an unlocked Project ID lookup.
## GREEN
**Command**
```text
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
export PATH="$JAVA_HOME/bin:$PATH"
./mvnw -Dtest=ProjectTaskMutationContextTest test
```
**Observed result**
```text
[INFO] Running com.lab.labtimesheet.feature.project.service.ProjectTaskMutationContextTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
```
## 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='Project*Test' test
[INFO] Tests run: 20, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
```
## External-test boundaries
The unit test proves the locked repository path and DTO-only handoff, while the integration coverage proves current Project authorization/member mapping against PostgreSQL 18.4. It does not orchestrate two concurrent database transactions; the lock-retention guarantee relies on the public method's `@Transactional` default `REQUIRED` propagation and the Task caller retaining its outer transaction.
+5 -5
View File
@@ -3,8 +3,8 @@
- **Test type:** Unit
- **Requirement IDs:** `PRJ-001``PRJ-007`, `PRJ-012`, `PRJ-017`, `AUTH-001``AUTH-004`
- **Scenario IDs:** `AC-PRJ-001`, `AC-PRJ-003`, `AC-PRJ-006`, `AC-PRJ-009`
- **Test class/method:** `com.lab.labtimesheet.projects.domain.ProjectTest`
- **Implementation commit:** `3483347`
- **Test class/method:** `com.lab.labtimesheet.feature.project.model.entity.ProjectEntityTest`
- **Implementation commit:** `25a855e`
## Protected behavior
@@ -43,13 +43,13 @@ export PATH="$JAVA_HOME/bin:$PATH"
```text
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
export PATH="$JAVA_HOME/bin:$PATH"
./mvnw -Dtest=ProjectTest test
./mvnw -Dtest=ProjectEntityTest test
```
**Observed result**
```text
[INFO] Running com.lab.labtimesheet.projects.domain.ProjectTest
[INFO] Running com.lab.labtimesheet.feature.project.model.entity.ProjectEntityTest
[INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
```
@@ -61,7 +61,7 @@ export PATH="$JAVA_HOME/bin:$PATH"
```text
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
export PATH="$JAVA_HOME/bin:$PATH"
./mvnw -Dtest=ProjectTest test
./mvnw -Dtest=ProjectEntityTest test
[INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
@@ -0,0 +1,75 @@
# Test Evidence: Project layer and JPA structure
- **Test type:** Unit
- **Requirement IDs:** `ARC-002`, `ARC-005``ARC-007`, `OPS-018``OPS-020`, `TST-001``TST-010`
- **Scenario IDs:** `I1-PRJ-01``I1-PRJ-05`
- **Test class/method:** `com.lab.labtimesheet.feature.project.repository.ProjectPersistenceStructureTest#projectPersistenceUsesTheRequiredLayerPackagesAndSpringDataJpa`
- **Implementation commit:** `25a855e`
## Protected behavior
Project-owned production code follows the authoritative feature-first package layout, persists aggregate entities through Spring Data JPA, keeps JDBC operations out of Project business services, and does not shadow Account or Task persistence.
## Test method
Plain JUnit inspects the public Project entity, repository, and service types. It verifies their exact feature/layer packages, the entity's JPA mapping, the repository's `JpaRepository` contract, the absence of JDBC service dependencies, and the absence of foreign-table Account/Task shadow entities.
## Hand-derived expected result
The Project aggregate is under `feature.project.model.entity`, persistence under `feature.project.repository`, business logic under `feature.project.service`, the service has zero JDBC collaborators, and Account/Task persistence remains owned by those features.
## RED
**Command**
```text
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
export PATH="$JAVA_HOME/bin:$PATH"
./mvnw -Dtest=ProjectPersistenceStructureTest test
```
**Observed result**
```text
[ERROR] cannot find symbol: class ProjectUserRepository
[ERROR] cannot find symbol: class ProjectInternProfileRepository
[ERROR] cannot find symbol: class ProjectTaskRepository
[INFO] BUILD FAILURE
```
The RED was observed after removing Project-owned shadow mappings of Account and Task tables. It proves the service still required cross-feature dependencies and could not be made green by retaining forbidden repositories.
## GREEN
**Command**
```text
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
export PATH="$JAVA_HOME/bin:$PATH"
./mvnw -Dtest=ProjectPersistenceStructureTest test
```
**Observed result**
```text
[INFO] Running com.lab.labtimesheet.feature.project.repository.ProjectPersistenceStructureTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
```
## Affected suite
**Command and result**
```text
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
export PATH="$JAVA_HOME/bin:$PATH"
./mvnw -Dtest=LayerStructureTest,ProjectPersistenceStructureTest,ProjectEntityTest test
[INFO] Tests run: 8, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
```
## External-test boundaries
This check does not prove database mappings, transaction behavior, MVC routing, or runtime authorization; those remain covered by PostgreSQL and MockMvc tests.