persona-harness 0.3.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.persona/harness.jsonc +9 -0
- package/.persona/rules/backend/gradle-bootstrap.md +27 -0
- package/.persona/rules/backend/java-backend-bootstrap.md +28 -0
- package/.persona/rules/backend/java-common.md +22 -0
- package/.persona/rules/backend/layered-architecture.md +19 -0
- package/.persona/rules/backend/package-structure.md +21 -0
- package/.persona/rules/backend/spring-controller.md +19 -0
- package/.persona/rules/backend/spring-dto.md +21 -0
- package/.persona/rules/backend/spring-entity.md +22 -0
- package/.persona/rules/backend/spring-repository.md +22 -0
- package/.persona/rules/backend/spring-service.md +23 -0
- package/.persona/rules/backend/spring-test.md +32 -0
- package/.persona/rules/backend/step1-api-contract.md +29 -0
- package/.persona/rules/backend/step2-3-api-contract.md +24 -0
- package/.persona/rules/backend/validation-exception.md +18 -0
- package/.persona/rules/clean-code/abstraction.md +18 -0
- package/.persona/rules/clean-code/common.md +21 -0
- package/.persona/rules/clean-code/method-design.md +20 -0
- package/.persona/rules/clean-code/naming.md +19 -0
- package/.persona/rules/clean-code/oop.md +18 -0
- package/.persona/rules/clean-code/testability.md +19 -0
- package/CHANGELOG.md +40 -0
- package/LICENSE +201 -0
- package/README.ja.md +95 -0
- package/README.ko.md +95 -0
- package/README.md +125 -0
- package/README.zh-cn.md +95 -0
- package/dist/cli/bearshell.d.ts +12 -0
- package/dist/cli/bearshell.js +189 -0
- package/dist/cli/bearshell.js.map +1 -0
- package/dist/cli/history.d.ts +15 -0
- package/dist/cli/history.js +156 -0
- package/dist/cli/history.js.map +1 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.js +117 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +21 -0
- package/dist/cli/init.js +194 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/intake-profile.d.ts +52 -0
- package/dist/cli/intake-profile.js +167 -0
- package/dist/cli/intake-profile.js.map +1 -0
- package/dist/cli/intake.d.ts +14 -0
- package/dist/cli/intake.js +209 -0
- package/dist/cli/intake.js.map +1 -0
- package/dist/cli/plan-command.d.ts +4 -0
- package/dist/cli/plan-command.js +130 -0
- package/dist/cli/plan-command.js.map +1 -0
- package/dist/cli/plan-status.d.ts +11 -0
- package/dist/cli/plan-status.js +41 -0
- package/dist/cli/plan-status.js.map +1 -0
- package/dist/cli/plan.d.ts +10 -0
- package/dist/cli/plan.js +199 -0
- package/dist/cli/plan.js.map +1 -0
- package/dist/cli/policy.d.ts +7 -0
- package/dist/cli/policy.js +139 -0
- package/dist/cli/policy.js.map +1 -0
- package/dist/cli/report-status.d.ts +13 -0
- package/dist/cli/report-status.js +40 -0
- package/dist/cli/report-status.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/phase0/drift-detector.d.ts +24 -0
- package/dist/phase0/drift-detector.js +334 -0
- package/dist/phase0/drift-detector.js.map +1 -0
- package/dist/phase0/evidence.d.ts +9 -0
- package/dist/phase0/evidence.js +36 -0
- package/dist/phase0/evidence.js.map +1 -0
- package/dist/phase0/file-role.d.ts +5 -0
- package/dist/phase0/file-role.js +55 -0
- package/dist/phase0/file-role.js.map +1 -0
- package/dist/phase0/harness-config.d.ts +12 -0
- package/dist/phase0/harness-config.js +115 -0
- package/dist/phase0/harness-config.js.map +1 -0
- package/dist/phase0/hooks.d.ts +8 -0
- package/dist/phase0/hooks.js +127 -0
- package/dist/phase0/hooks.js.map +1 -0
- package/dist/phase0/injection.d.ts +2 -0
- package/dist/phase0/injection.js +77 -0
- package/dist/phase0/injection.js.map +1 -0
- package/dist/phase0/java-role-discovery.d.ts +6 -0
- package/dist/phase0/java-role-discovery.js +90 -0
- package/dist/phase0/java-role-discovery.js.map +1 -0
- package/dist/phase0/messages.d.ts +2 -0
- package/dist/phase0/messages.js +30 -0
- package/dist/phase0/messages.js.map +1 -0
- package/dist/phase0/policy-overlay.d.ts +12 -0
- package/dist/phase0/policy-overlay.js +171 -0
- package/dist/phase0/policy-overlay.js.map +1 -0
- package/dist/phase0/project-profile.d.ts +1 -0
- package/dist/phase0/project-profile.js +148 -0
- package/dist/phase0/project-profile.js.map +1 -0
- package/dist/phase0/rule-catalog.d.ts +14 -0
- package/dist/phase0/rule-catalog.js +77 -0
- package/dist/phase0/rule-catalog.js.map +1 -0
- package/dist/phase0/rule-diagnostics-report.d.ts +17 -0
- package/dist/phase0/rule-diagnostics-report.js +51 -0
- package/dist/phase0/rule-diagnostics-report.js.map +1 -0
- package/dist/phase0/rule-frontmatter-diagnostics.d.ts +19 -0
- package/dist/phase0/rule-frontmatter-diagnostics.js +65 -0
- package/dist/phase0/rule-frontmatter-diagnostics.js.map +1 -0
- package/dist/phase0/rule-frontmatter.d.ts +23 -0
- package/dist/phase0/rule-frontmatter.js +172 -0
- package/dist/phase0/rule-frontmatter.js.map +1 -0
- package/dist/phase0/rule-glob.d.ts +2 -0
- package/dist/phase0/rule-glob.js +38 -0
- package/dist/phase0/rule-glob.js.map +1 -0
- package/dist/phase0/rule-loader.d.ts +13 -0
- package/dist/phase0/rule-loader.js +143 -0
- package/dist/phase0/rule-loader.js.map +1 -0
- package/dist/phase0/shared-skill-router.d.ts +14 -0
- package/dist/phase0/shared-skill-router.js +85 -0
- package/dist/phase0/shared-skill-router.js.map +1 -0
- package/dist/phase0/store.d.ts +6 -0
- package/dist/phase0/store.js +14 -0
- package/dist/phase0/store.js.map +1 -0
- package/dist/phase0/target-file.d.ts +2 -0
- package/dist/phase0/target-file.js +41 -0
- package/dist/phase0/target-file.js.map +1 -0
- package/dist/phase0/types.d.ts +38 -0
- package/dist/phase0/types.js +2 -0
- package/dist/phase0/types.js.map +1 -0
- package/dist/phase1/observer/controller-repository-observer.d.ts +17 -0
- package/dist/phase1/observer/controller-repository-observer.js +210 -0
- package/dist/phase1/observer/controller-repository-observer.js.map +1 -0
- package/dist/phase1/observer/controller-sql-observer.d.ts +20 -0
- package/dist/phase1/observer/controller-sql-observer.js +148 -0
- package/dist/phase1/observer/controller-sql-observer.js.map +1 -0
- package/dist/phase1/observer/java-source.d.ts +9 -0
- package/dist/phase1/observer/java-source.js +88 -0
- package/dist/phase1/observer/java-source.js.map +1 -0
- package/dist/phase1/observer/report.d.ts +52 -0
- package/dist/phase1/observer/report.js +173 -0
- package/dist/phase1/observer/report.js.map +1 -0
- package/dist/phase1/observer/service-storage-observer.d.ts +20 -0
- package/dist/phase1/observer/service-storage-observer.js +155 -0
- package/dist/phase1/observer/service-storage-observer.js.map +1 -0
- package/dist/phase1/observer/test-contract-anchor-matchers.d.ts +10 -0
- package/dist/phase1/observer/test-contract-anchor-matchers.js +198 -0
- package/dist/phase1/observer/test-contract-anchor-matchers.js.map +1 -0
- package/dist/phase1/observer/test-contract-observer.d.ts +21 -0
- package/dist/phase1/observer/test-contract-observer.js +70 -0
- package/dist/phase1/observer/test-contract-observer.js.map +1 -0
- package/docs/README.md +34 -0
- package/docs/current/README.md +35 -0
- package/docs/current/java-backend-mvp-install-guide.md +160 -0
- package/docs/current/persona-harness-detailed-usage.md +782 -0
- package/docs/current/release/README.md +6 -0
- package/docs/current/release/release-checklist.md +113 -0
- package/docs/current/release/release-notes-template.md +68 -0
- package/docs/current/v0.3.0-alpha-publish-readiness.md +185 -0
- package/docs/current/v0.3.0-external-tester-feedback-template.md +214 -0
- package/docs/current/v0.3.0-external-tester-guide.md +217 -0
- package/docs/current/v0.3.0-gradle-spring-build-guidance.md +100 -0
- package/package.json +87 -0
- package/packages/shared-skills/skills/programming/SKILL.md +490 -0
- package/packages/shared-skills/skills/programming/references/java/README.md +193 -0
- package/packages/shared-skills/skills/programming/references/java/anti-patterns.md +85 -0
- package/packages/shared-skills/skills/programming/references/java/application-layer.md +200 -0
- package/packages/shared-skills/skills/programming/references/java/architecture.md +152 -0
- package/packages/shared-skills/skills/programming/references/java/backend.md +152 -0
- package/packages/shared-skills/skills/programming/references/java/code-quality-refactoring.md +146 -0
- package/packages/shared-skills/skills/programming/references/java/concurrency-discipline.md +98 -0
- package/packages/shared-skills/skills/programming/references/java/domain-model.md +214 -0
- package/packages/shared-skills/skills/programming/references/java/error-handling.md +179 -0
- package/packages/shared-skills/skills/programming/references/java/foundations.md +49 -0
- package/packages/shared-skills/skills/programming/references/java/java-idioms.md +108 -0
- package/packages/shared-skills/skills/programming/references/java/language-core.md +96 -0
- package/packages/shared-skills/skills/programming/references/java/method-and-naming.md +164 -0
- package/packages/shared-skills/skills/programming/references/java/object-collaboration.md +140 -0
- package/packages/shared-skills/skills/programming/references/java/performance-discipline.md +115 -0
- package/packages/shared-skills/skills/programming/references/java/repository-pattern.md +181 -0
- package/packages/shared-skills/skills/programming/references/java/technology-seams.md +92 -0
- package/packages/shared-skills/skills/programming/references/java/test-design.md +149 -0
- package/packages/shared-skills/skills/programming/references/java/testing.md +188 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: backend.gradle-bootstrap
|
|
3
|
+
source: backend-policy
|
|
4
|
+
domain: backend
|
|
5
|
+
topic: gradle-bootstrap
|
|
6
|
+
globs:
|
|
7
|
+
- "build.gradle"
|
|
8
|
+
- "settings.gradle"
|
|
9
|
+
- "**/build.gradle"
|
|
10
|
+
- "**/settings.gradle"
|
|
11
|
+
- "build.gradle.kts"
|
|
12
|
+
- "settings.gradle.kts"
|
|
13
|
+
- "**/build.gradle.kts"
|
|
14
|
+
- "**/settings.gradle.kts"
|
|
15
|
+
severity: must
|
|
16
|
+
enforcement: inject_only
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Gradle Bootstrap
|
|
20
|
+
|
|
21
|
+
- Gradle build file에서는 Java/Spring Boot backend 기준을 유지하고 Maven `pom.xml`을 생성하지 않는다.
|
|
22
|
+
- `settings.gradle` 또는 `settings.gradle.kts`는 하나의 Spring Boot application root project 이름을 명확히 둔다.
|
|
23
|
+
- `build.gradle` 또는 `build.gradle.kts`는 Spring Boot backend를 만들기 위한 최소 plugin/dependency/source compatibility만 다루며, 호환되는 Spring Boot plugin / Gradle launcher or wrapper / JDK toolchain 조합을 먼저 선택하고 그 선택을 build file에 명시한다. JUnit Platform 실행에는 `testRuntimeOnly "org.junit.platform:junit-platform-launcher"` 또는 동등한 runtime launcher를 포함한다.
|
|
24
|
+
- 실행 가능한 Spring Boot app에서는 `bootJar`를 끄지 않는다. `tasks.named("bootJar") { enabled = false }` 또는 동등한 설정은 plain Java library로 명시된 프로젝트가 아니면 사용하지 않는다. `bootJar`가 `CopyProcessingSpec.getDirMode()` 같은 호환성 오류로 실패하면, `bootJar`를 비활성화하지 말고 Spring Boot plugin을 현재 Gradle과 호환되는 line으로 올리거나 Gradle wrapper를 해당 plugin이 지원하는 line으로 고정한다.
|
|
25
|
+
- 로컬 launcher가 Gradle 9.x이면 Spring Boot 3.3.x 같은 오래된 plugin line을 기본으로 섞지 않는다. 호환 여부가 불명확하면 executable app 기준으로 `gradle test`, `gradle build`, `gradle bootRun`이 모두 통과하는 line을 선택한다.
|
|
26
|
+
- build 설정은 presentation/application/domain/infrastructure package 구조를 대신하지 않는다.
|
|
27
|
+
- build file target에서는 frontend/infra/multi-domain productization으로 확장하지 않는다.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: backend.java-backend-bootstrap
|
|
3
|
+
source: backend-policy
|
|
4
|
+
domain: backend
|
|
5
|
+
topic: backend-bootstrap
|
|
6
|
+
globs:
|
|
7
|
+
- "README.md"
|
|
8
|
+
- "**/README.md"
|
|
9
|
+
- "requirements.md"
|
|
10
|
+
- "**/requirements.md"
|
|
11
|
+
severity: must
|
|
12
|
+
enforcement: inject_only
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Java Backend Bootstrap
|
|
16
|
+
|
|
17
|
+
- 0-start 요구사항을 먼저 backend product code shape 계획으로 변환하고 Gradle 기반 Spring Boot backend project로 구현한다. Maven 파일은 생성하지 않는다.
|
|
18
|
+
- 구현 전에 package structure plan을 작성한다. root package 바로 아래에 `global`과 `root/<domain>`을 같은 depth로 두고, `feature/features/module/modules` 같은 wrapper package를 추가하지 않는다.
|
|
19
|
+
- 도메인 package 내부는 presentation/application/domain/infrastructure 흐름을 기본으로 두고 `root/<domain>/presentation`, `root/<domain>/application`, `root/<domain>/domain`, `root/<domain>/infrastructure`로 배치한다.
|
|
20
|
+
- DTO는 파일 경계로 둔다. Presentation DTO는 `root/<domain>/presentation/dto/request`와 `root/<domain>/presentation/dto/response`, Application DTO는 `root/<domain>/application/dto/command`와 `root/<domain>/application/dto/result`에 둔다.
|
|
21
|
+
- 구현 중에는 package structure plan을 기준으로 Domain, Repository, Service, DTO, Controller 역할 파일을 만들고 주요 Java 파일을 다시 읽고 다음 역할로 넘어간다.
|
|
22
|
+
- presentation은 HTTP 요청/응답과 request/response DTO boundary를 담당하고, application service에 위임한다.
|
|
23
|
+
- Application Service는 use-case 흐름 조율만 담당하며 Service는 Map/List/AtomicLong/nextId/idCounter 같은 저장소 상태나 id sequence를 직접 소유하지 않는다.
|
|
24
|
+
- 저장소 상태와 id generation은 Repository/Store 같은 persistence/storage component 뒤로 위임한다.
|
|
25
|
+
- Repository interface는 domain 경계에 `root/<domain>/domain/<Domain>Repository`로 두고 구현체는 infrastructure 경계에 `Jdbc<Domain>Repository` 또는 `InMemory<Domain>Repository`로 둔다.
|
|
26
|
+
- Domain은 Spring, HTTP, DB, infrastructure 세부사항에 의존하지 않는다.
|
|
27
|
+
- Domain entity/aggregate는 record 데이터 홀더로 만들지 않는다. 자신의 필드로 판단할 수 있는 규칙은 `isOwner(name)`, `isReturned()`, `canLoan()` 같은 의미 있는 메서드로 Domain 객체가 직접 판단하고, Application Service가 getter/accessor로 필드를 꺼내 판단하지 않는다.
|
|
28
|
+
- frontend, infra, test-quality, generated app product-quality 보증은 현재 bootstrap injection 범위 밖이다.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: backend.java.common
|
|
3
|
+
source: backend-policy
|
|
4
|
+
domain: backend
|
|
5
|
+
topic: backend-boundary
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*.java"
|
|
8
|
+
severity: must
|
|
9
|
+
enforcement: inject_only
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Java/Spring Backend Baseline
|
|
13
|
+
|
|
14
|
+
- Java/Spring 프로젝트는 Gradle을 기본 빌드 도구로 사용하고 Maven 파일을 생성하지 않으며, Spring Boot main application class는 root package에 하나만 두고 feature/domain package 아래에 추가 `*Application.java`를 만들지 않는다.
|
|
15
|
+
- 구현 전에 package structure plan을 먼저 작성한다. root package는 Spring Boot Application class가 위치한 최상위 앱 패키지이며, global은 root package 바로 아래에 두고 도메인 패키지는 global과 같은 depth에 둔다. `feature/features/module/modules` 같은 wrapper package를 추가하지 않는다. 명시적 기본 구조는 root/global/exception·root/global/response·root/global/config와 root/<domain>/application·root/<domain>/application/dto/command·root/<domain>/application/dto/result·root/<domain>/domain·root/<domain>/domain/<Domain>Repository interface·root/<domain>/infrastructure·root/<domain>/infrastructure/Jdbc<Domain>Repository 또는 InMemory<Domain>Repository·root/<domain>/presentation·root/<domain>/presentation/dto/request·root/<domain>/presentation/dto/response이다. 기존 Application class가 com.example.library에 있으면 library를 도메인 패키지로 보고 library 아래에 loan 같은 추가 도메인 패키지를 만들지 않는다. global은 공통 관심사만, Repository interface는 domain, 구현체는 infrastructure에 두며 infrastructure class 이름을 <Domain>Repository로 끝내지 않는다.
|
|
16
|
+
- presentation → application → domain 흐름을 기본으로 두고, infrastructure는 domain을 사용할 수 있지만 domain은 infrastructure를 알지 않는다.
|
|
17
|
+
- API 외부 계약은 DTO로 표현하고 Entity를 직접 노출하지 않는다.
|
|
18
|
+
- 도메인 규칙은 Spring, HTTP, DB 세부사항에 의존하지 않게 둔다.
|
|
19
|
+
- Domain entity/aggregate는 record 데이터 홀더가 아니라 class로 두고, 자신이 가진 필드로 판단 가능한 규칙은 스스로 판단한다. 예: `isOwner(name)`, `isReturned()`, `canLoan()` 같은 메서드가 Domain 안에 있어야 하며, Application Service가 accessor로 필드를 꺼내 동일한 판단을 대신하지 않는다.
|
|
20
|
+
- RuntimeException을 직접 던지는 방식으로 정책을 숨기지 않는다.
|
|
21
|
+
- 요구사항의 요청/응답 필드 이름을 임의로 바꾸지 않는다.
|
|
22
|
+
- Spring annotation은 역할이 분명한 타입에만 붙인다.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: backend.layered-architecture
|
|
3
|
+
source: backend-policy
|
|
4
|
+
domain: backend
|
|
5
|
+
topic: layered-architecture
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*.java"
|
|
8
|
+
severity: must
|
|
9
|
+
enforcement: inject_only
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Layered Architecture Policy
|
|
13
|
+
|
|
14
|
+
- Presentation은 HTTP 요청/응답, 상태 코드, 외부 DTO 변환을 담당한다.
|
|
15
|
+
- Application은 하나의 유스케이스 흐름, 트랜잭션 경계, 필요한 협력 객체 호출을 조율한다.
|
|
16
|
+
- Domain은 비즈니스 규칙과 상태 전이를 담당하고 Spring, HTTP, DB 세부사항을 알지 않는다.
|
|
17
|
+
- Infrastructure는 저장소, 외부 API, 프레임워크 연동 같은 기술 세부사항을 담당한다.
|
|
18
|
+
- 상위 계층은 하위 계층을 알 수 있지만, presentation이 domain/infrastructure를 직접 호출하는 식으로 계층 경계를 건너뛰지 않는다.
|
|
19
|
+
- Domain은 Application Service와 Infrastructure 양쪽에서 사용할 수 있는 독립 계층이며, Application이나 Infrastructure를 알지 않는다.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: backend.package-structure
|
|
3
|
+
source: backend-policy
|
|
4
|
+
domain: backend
|
|
5
|
+
topic: package-structure
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*.java"
|
|
8
|
+
severity: should
|
|
9
|
+
enforcement: inject_only
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Package Structure Policy
|
|
13
|
+
|
|
14
|
+
- 패키지는 기능과 책임을 찾기 쉽게 구성한다.
|
|
15
|
+
- Spring Boot main application class는 root package에 하나만 두고, feature/domain package 아래에 추가 `*Application.java`를 만들지 않는다.
|
|
16
|
+
- root package 바로 아래에 `global`과 도메인 package를 같은 depth로 두고, `feature/features/module/modules` 같은 wrapper package를 추가하지 않는다.
|
|
17
|
+
- 도메인 package 내부는 presentation/application/domain/infrastructure와 presentation/application DTO 파일 경계를 드러낸다.
|
|
18
|
+
- 프로젝트가 커지면 `controller`, `service`, `repository` 같은 기술 계층 중심보다 도메인 기능 중심 구성을 우선 검토한다.
|
|
19
|
+
- `global`이나 `common`은 예외 처리, 설정, 공통 인프라처럼 실제로 여러 기능이 공유하는 것만 둔다.
|
|
20
|
+
- 테스트 패키지는 가능하면 production 패키지 구조를 따라가서 대상 코드를 찾기 쉽게 한다.
|
|
21
|
+
- 단순한 초기 단계에서는 과한 패키지 분리보다 역할이 드러나는 이름과 작은 책임을 우선한다.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: backend.spring.controller
|
|
3
|
+
source: backend-policy
|
|
4
|
+
domain: backend
|
|
5
|
+
topic: controller-responsibility
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*Controller.java"
|
|
8
|
+
severity: must
|
|
9
|
+
enforcement: inject_only
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Spring Controller Policy
|
|
13
|
+
|
|
14
|
+
- Controller는 HTTP 요청/응답 변환만 담당하고, API 경로, 메서드, status code, request body, response body는 요구사항의 외부 계약을 그대로 따르며, 유스케이스 실행은 Service public 메서드에 위임한다.
|
|
15
|
+
- Controller에는 Repository 의존성, Map/List 저장 상태, id sequence, 저장소 구현 세부사항을 넣지 않는다.
|
|
16
|
+
- Request/Response DTO를 명시적으로 사용한다.
|
|
17
|
+
- Entity를 API 응답으로 직접 반환하지 않는다.
|
|
18
|
+
- 특정 미션 fixture의 200 OK/201 Created/204 No Content 판단을 일반 clean project에 재사용하지 않는다.
|
|
19
|
+
- Controller에서 트랜잭션 경계나 저장소 구현 세부사항을 결정하지 않는다.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: backend.spring.dto
|
|
3
|
+
source: backend-policy
|
|
4
|
+
domain: backend
|
|
5
|
+
topic: dto-boundary
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*Request.java"
|
|
8
|
+
- "**/*Response.java"
|
|
9
|
+
- "**/*Controller.java"
|
|
10
|
+
severity: must
|
|
11
|
+
enforcement: inject_only
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# DTO Boundary Policy
|
|
15
|
+
|
|
16
|
+
- Request DTO는 외부 입력 계약과 검증 경계를 표현한다. Controller 내부 중첩 request/response record/class 대신 `presentation/dto/request`와 `presentation/dto/response` 파일 경계에 DTO를 둔다.
|
|
17
|
+
- Controller/Service response path는 domain entity를 직접 외부 응답으로 노출하지 않고 Response DTO boundary를 둔다. Controller는 Request DTO를 Command/Query로 변환해 Application Service에 넘기고, Application Result를 Response DTO로 변환해 반환한다. Service 내부 중첩 response/result record/class 대신 `application/dto/command`와 `application/dto/result` 파일 경계를 사용한다.
|
|
18
|
+
- 요구사항의 필드 이름을 임의로 합치거나 바꾸지 않는다.
|
|
19
|
+
- DTO가 Entity 변환 세부사항을 과도하게 소유하면 책임이 섞였는지 의심한다.
|
|
20
|
+
- Service 입력이 HTTP 요청 구조와 달라지면 Request DTO와 Command/Query를 분리한다.
|
|
21
|
+
- Response DTO는 도메인 내부 구조를 그대로 노출하기보다 외부 계약에 맞춘다.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: backend.spring.entity
|
|
3
|
+
source: backend-policy
|
|
4
|
+
domain: backend
|
|
5
|
+
topic: domain-entity
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*Entity.java"
|
|
8
|
+
- "**/domain/**/*.java"
|
|
9
|
+
severity: must
|
|
10
|
+
enforcement: inject_only
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Entity Policy
|
|
14
|
+
|
|
15
|
+
- Entity/Aggregate는 record 데이터 홀더로 만들지 않고 class로 둔다. record는 Request/Response DTO, Command/Result DTO, 값 자체가 의미인 Value Object에만 제한한다.
|
|
16
|
+
- Entity는 setter를 열지 않는다.
|
|
17
|
+
- 상태 변경은 의미 있는 메서드로만 한다.
|
|
18
|
+
- 도메인 불변식은 Entity나 Domain 객체 안에서 지킨다.
|
|
19
|
+
- 자신의 필드만으로 판단할 수 있는 규칙은 Entity/Domain 객체가 직접 판단한다. 예: `isOwner(name)`, `isReturned()`, `canLoan()` 같은 메서드를 두고, Service가 `entity.name()`/getter/accessor를 꺼내 같은 판단을 대신하지 않는다.
|
|
20
|
+
- 외부 API 요청 DTO가 Entity 생성 세부사항을 직접 소유하지 않게 한다.
|
|
21
|
+
- getter는 응답 변환이나 직렬화처럼 필요한 경계에서만 사용하고, 외부 판단을 유도하는 기본 수단으로 삼지 않는다.
|
|
22
|
+
- equals/hashCode 기준은 식별자와 생명주기 요구가 분명할 때 명시적으로 정한다.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: backend.spring.repository
|
|
3
|
+
source: backend-policy
|
|
4
|
+
domain: backend
|
|
5
|
+
topic: repository-boundary
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*Repository.java"
|
|
8
|
+
severity: should
|
|
9
|
+
enforcement: inject_only
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Repository Policy
|
|
13
|
+
|
|
14
|
+
- Repository contract는 domain package의 BookRepository 같은 interface로 두고, 저장소 구현은 infrastructure의 JdbcBookRepository 또는 InMemoryBookRepository 같은 class로 둔다. Repository는 저장소 접근, Map/List 상태, id sequence, 테스트 reset을 담당하고, HTTP Request/Response DTO를 저장소 API나 저장 상태로 삼지 않는다.
|
|
15
|
+
- Repository 구현체가 다른 Repository 구현체를 주입받아 aggregate를 조립하거나 N+1 조회 흐름을 숨기지 않는다. 여러 aggregate 조립은 application orchestration, 전용 query/read model, 또는 명시적 infrastructure query 책임으로 분리한다.
|
|
16
|
+
- 메모리 CRUD나 작은 프로젝트에서도 Repository를 생략하지 않는다. `ReservationRepository` 같은 Repository 이름은 저장소 계약 interface로 두고, Map/List 저장 상태와 id sequence는 `InMemoryReservationRepository` 같은 `@Repository` 구현체에 둔다.
|
|
17
|
+
- 비즈니스 판단을 Repository query 조건이나 map 조작 안에 숨기지 않는다.
|
|
18
|
+
- 메모리 저장소 단계에서는 id 발급, 저장 상태 변화, 테스트 초기화가 가능해야 한다.
|
|
19
|
+
- in-memory Repository는 테스트에서 호출할 수 있는 `clear()` 또는 동등한 초기화 메서드로 저장 상태와 id sequence를 함께 초기화한다.
|
|
20
|
+
- find/save/delete 메서드는 호출자가 기대하는 저장소 의미를 명확히 드러낸다.
|
|
21
|
+
- SQL, JPA, Map 같은 저장 방식 세부사항은 호출 계층의 비즈니스 흐름에 새지 않게 한다.
|
|
22
|
+
- Repository 메서드 이름은 저장소 기술보다 도메인 관점의 조회 의미를 드러낸다.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: backend.spring.service
|
|
3
|
+
source: backend-policy
|
|
4
|
+
domain: backend
|
|
5
|
+
topic: service-transaction
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*Service.java"
|
|
8
|
+
severity: must
|
|
9
|
+
enforcement: inject_only
|
|
10
|
+
max_bullets: 3
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Spring Service Policy
|
|
14
|
+
|
|
15
|
+
- Application Service는 비즈니스/use-case 흐름을 조율하고 저장소 구현 세부사항을 직접 소유하지 않는다.
|
|
16
|
+
- Service는 List, Map, AtomicLong, nextId, idCounter, sequence 같은 저장소 상태나 id sequence를 직접 소유하지 않는다.
|
|
17
|
+
- 저장 상태와 id 발급은 Repository 또는 명시적인 persistence boundary 책임이다. Service response path는 저장 결과를 domain entity 그대로 노출하지 않고 Response DTO로 변환한다. Service 내부 중첩 `*Response/*Item/*View` record/class나 presentation Response DTO 반환을 피하고, Service 내부 표현은 `application/dto/result` 같은 application result로 둔다.
|
|
18
|
+
- Controller가 아니라 Service가 Repository를 호출하고, 생성/조회/삭제 흐름을 조율한다.
|
|
19
|
+
- @Transactional 경계가 필요해지면 Service public 메서드 기준으로 둔다.
|
|
20
|
+
- Controller의 HTTP 세부사항이나 Repository의 저장 방식 세부사항을 Service에 새기지 않는다.
|
|
21
|
+
- Service는 흐름을 조율하고, 검증과 정책 판단은 가능한 Domain, Validator, Policy 같은 이름 있는 책임에 맡긴다.
|
|
22
|
+
- 도메인 상태 변경은 의미 있는 도메인 메서드나 명확한 유스케이스 메서드로 표현한다.
|
|
23
|
+
- 조회 전용 유스케이스는 읽기 전용 트랜잭션을 검토한다.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: backend.spring.test
|
|
3
|
+
source: backend-policy
|
|
4
|
+
domain: backend
|
|
5
|
+
topic: test-policy
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*Test.java"
|
|
8
|
+
severity: must
|
|
9
|
+
enforcement: inject_only
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Backend Test Policy
|
|
13
|
+
|
|
14
|
+
## 메모리 저장소 테스트 격리
|
|
15
|
+
|
|
16
|
+
- 메모리 저장소, static Map/List, sequence/id generator를 사용하는 테스트는 `@BeforeEach`에서 Repository `clear()`/`reset()`을 직접 호출해 저장 데이터와 id sequence를 함께 초기화한다. HTTP DELETE 요청으로 지우는 방식은 id sequence를 초기화하지 못하므로 쓰지 않는다.
|
|
17
|
+
- 각 테스트는 독립적으로 실행되어야 하며, 이전 테스트의 저장 데이터나 id sequence에 의존하지 않는다.
|
|
18
|
+
- Repository가 in-memory 구현이면 `@BeforeEach`에서 `clear()` 또는 동등한 초기화 메서드를 호출해 저장 데이터와 id sequence를 함께 초기화한다.
|
|
19
|
+
- 첫 생성 `id=1`을 여러 테스트에서 검증한다면 매 테스트 전에 id sequence도 1로 되돌아가야 한다.
|
|
20
|
+
- 테스트가 단독 실행될 때만 통과하고 전체 실행에서 실패하면 상태 공유를 1순위 원인으로 의심한다.
|
|
21
|
+
- `@DirtiesContext`는 마지막 수단이며, 먼저 저장소 초기화 API를 명시적으로 제공하는 방식을 우선한다.
|
|
22
|
+
|
|
23
|
+
## HTTP Contract Test
|
|
24
|
+
|
|
25
|
+
- 테스트는 요구사항의 HTTP method, path, status, response body를 직접 검증한다.
|
|
26
|
+
- 테스트는 구현이 선택한 REST 관습을 따라가지 말고, 요구사항에 적힌 status/body 계약을 고정한다.
|
|
27
|
+
- 1단계 Controller 테스트는 첫 생성 응답의 `id`가 1인지, 생성 후 목록 크기가 1인지, 삭제 후 목록 크기가 0인지 검증한다.
|
|
28
|
+
- 생성 전 조회, 생성 후 조회, 삭제 후 조회처럼 상태 변화를 한 흐름으로 확인한다.
|
|
29
|
+
- 테스트가 컴파일되는지 확인하지 않고 완료했다고 말하지 않는다.
|
|
30
|
+
- 테스트 helper보다 요구사항의 입력과 기대값이 먼저 읽혀야 한다.
|
|
31
|
+
- Controller 테스트는 HTTP 계약을, Service/Domain 테스트는 유스케이스와 규칙을 검증한다.
|
|
32
|
+
- 테스트는 구현 클래스의 private 흐름보다 사용자에게 보이는 결과를 기준으로 실패해야 한다.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: backend.step1.api-contract
|
|
3
|
+
source: backend-policy
|
|
4
|
+
domain: backend
|
|
5
|
+
topic: external-contract
|
|
6
|
+
globs:
|
|
7
|
+
- "**/roomescape/**/*Controller.java"
|
|
8
|
+
- "**/roomescape/**/*Request.java"
|
|
9
|
+
- "**/roomescape/**/*Response.java"
|
|
10
|
+
- "**/roomescape/**/*Test.java"
|
|
11
|
+
- "**/roomescape/**/*Tests.java"
|
|
12
|
+
- "**/roomescape/**/*IntegrationTest.java"
|
|
13
|
+
severity: must
|
|
14
|
+
enforcement: inject_only
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Step 1 API Contract
|
|
18
|
+
|
|
19
|
+
Roomescape step fixture 전용 외부 계약이다. 일반 Java/Spring clean project의 HTTP status, request body, response body는 해당 프로젝트 README와 intake/profile 요구사항을 따른다.
|
|
20
|
+
|
|
21
|
+
- `GET /reservations`는 200 OK와 예약 목록을 반환하고, 생성 전 목록 크기는 0이어야 한다.
|
|
22
|
+
- `POST /reservations`는 200 OK를 반환한다. 201 Created는 이 단계에서 오답이며, 요청 본문은 `name`, `date`, `time`, 응답은 `id`, `name`, `date`, `time`, 첫 `id`는 1, 생성 후 목록 크기는 1이어야 한다.
|
|
23
|
+
- `DELETE /reservations/{id}`는 200 OK를 반환한다. 204 No Content는 이 단계에서 오답이며, 삭제 후 목록 크기는 0이어야 한다.
|
|
24
|
+
- 1단계 예약 추가 요청 본문은 반드시 `name`, `date`, `time`이다.
|
|
25
|
+
- 예약 추가 응답은 `id`, `name`, `date`, `time`을 반환한다.
|
|
26
|
+
- `GET /reservations`는 예약 목록을 반환하고, 처음 목록 크기는 0이어야 한다.
|
|
27
|
+
- 첫 예약 추가 응답의 `id`는 1이어야 한다.
|
|
28
|
+
- `POST /reservations` 이후 목록 크기는 1이고, `DELETE /reservations/{id}` 이후 목록 크기는 0이어야 한다.
|
|
29
|
+
- 화면, 데이터베이스, H2, 시간 관리 기능은 1단계 범위가 아니다.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: backend.step2-3.api-contract
|
|
3
|
+
source: backend-policy
|
|
4
|
+
domain: backend
|
|
5
|
+
topic: external-contract
|
|
6
|
+
globs:
|
|
7
|
+
- "**/roomescape/**/*Controller.java"
|
|
8
|
+
- "**/roomescape/**/*Request.java"
|
|
9
|
+
- "**/roomescape/**/*Response.java"
|
|
10
|
+
- "**/roomescape/**/*Test.java"
|
|
11
|
+
- "**/roomescape/**/*Tests.java"
|
|
12
|
+
- "**/roomescape/**/*IntegrationTest.java"
|
|
13
|
+
severity: must
|
|
14
|
+
enforcement: inject_only
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Step 2-3 API Contract
|
|
18
|
+
|
|
19
|
+
Roomescape step fixture 전용 외부 계약이다. 일반 Java/Spring clean project의 HTTP status, request body, response body는 해당 프로젝트 README와 intake/profile 요구사항을 따른다.
|
|
20
|
+
|
|
21
|
+
- `GET /reservations`는 200 OK를 반환하고, `POST /reservations`는 request body로 `name`, `date`, `timeId`를 받으며 200 OK와 DB가 생성한 `id`를 반환하고, `DELETE /reservations/{id}`는 200 OK를 반환한다.
|
|
22
|
+
- 예약 조회 응답의 `time`은 문자열이 아니라 `{ id, startAt }` 객체이며, 예약 생성 request body는 `time`이 아니라 `timeId`를 사용한다.
|
|
23
|
+
- `POST /times`는 request body로 `startAt`을 받으며 200 OK를 반환하고, `GET /times`는 200 OK와 시간 목록을 반환하고, `DELETE /times/{id}`는 200 OK를 반환한다.
|
|
24
|
+
- 원문에 없는 실패 케이스, validation 응답, DELETE response body는 단정하지 않는다.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: backend.validation-exception
|
|
3
|
+
source: backend-policy
|
|
4
|
+
domain: backend
|
|
5
|
+
topic: validation-exception
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*.java"
|
|
8
|
+
severity: should
|
|
9
|
+
enforcement: inject_only
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Validation And Exception Policy
|
|
13
|
+
|
|
14
|
+
- 검증 책임은 그 규칙을 가장 잘 아는 계층에 둔다. 형식 검증은 입력 경계에, 도메인 규칙은 도메인에 둔다.
|
|
15
|
+
- 예외는 일반적인 분기 처리를 대신하는 수단으로 쓰지 않는다.
|
|
16
|
+
- 예외 메시지와 타입은 호출자가 이해할 수 있는 도메인 의미를 드러낸다.
|
|
17
|
+
- Spring 애플리케이션에서는 예외 응답 변환을 Controller마다 흩뿌리지 않고 일관된 처리 지점에 모은다.
|
|
18
|
+
- 구체적인 ErrorCode 체계는 프로젝트 규모와 API 요구가 충분할 때 도입한다.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: clean-code.abstraction
|
|
3
|
+
source: clean-code
|
|
4
|
+
domain: common
|
|
5
|
+
topic: abstraction
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*.java"
|
|
8
|
+
severity: should
|
|
9
|
+
enforcement: inject_only
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Abstraction Policy
|
|
13
|
+
|
|
14
|
+
- 추상화는 미리 만들지 않고, 반복되는 변경 비용이나 책임 혼재가 실제로 보일 때 도입한다.
|
|
15
|
+
- 패턴 적용 자체를 목표로 삼지 않는다. 현재 요구사항을 더 읽기 쉽고 테스트 가능하게 만들 때만 사용한다.
|
|
16
|
+
- 상속이나 generic base class보다 명시적인 조합과 작은 타입 분리를 먼저 검토한다.
|
|
17
|
+
- 공통 코드가 생겨도 도메인 의미가 다르면 성급하게 합치지 않는다.
|
|
18
|
+
- 구조 변경은 public behavior를 유지한 채 작게 진행한다.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: clean-code.common
|
|
3
|
+
source: clean-code
|
|
4
|
+
domain: common
|
|
5
|
+
topic: readability
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*.java"
|
|
8
|
+
severity: must
|
|
9
|
+
enforcement: inject_only
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Clean Code Baseline
|
|
13
|
+
|
|
14
|
+
- 코드는 짧게보다 명확하게 작성한다.
|
|
15
|
+
- 한 파일과 한 타입은 읽는 사람이 예측할 수 있는 하나의 중심 책임을 가져야 한다.
|
|
16
|
+
- 구현 편의를 위해 API 계약, 도메인 규칙, 영속성 세부사항을 한 곳에 섞지 않는다.
|
|
17
|
+
- 흐름을 진행하는 코드와 판단을 내리는 코드를 구분한다.
|
|
18
|
+
- 중복 제거보다 의도 보존을 우선한다. 의미가 다른 코드를 같은 모양이라는 이유만으로 합치지 않는다.
|
|
19
|
+
- null을 정상 흐름의 신호로 반환하지 않는다.
|
|
20
|
+
- 숨은 전역 상태와 암묵적 부작용을 만들지 않는다.
|
|
21
|
+
- 공통화가 필요하면 먼저 이름 있는 책임을 찾고, `Util`, `Helper`, `Manager` 같은 범용 이름을 기본 선택으로 쓰지 않는다.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: clean-code.method-design
|
|
3
|
+
source: clean-code
|
|
4
|
+
domain: common
|
|
5
|
+
topic: method-design
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*.java"
|
|
8
|
+
severity: must
|
|
9
|
+
enforcement: inject_only
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Method Design
|
|
13
|
+
|
|
14
|
+
- 메서드는 하나의 의도를 가진다.
|
|
15
|
+
- 메서드 이름은 내부 절차가 아니라 호출자가 얻는 결과를 표현한다.
|
|
16
|
+
- 정상 흐름을 읽기 쉽게 만들기 위해 실패 조건은 early return이나 early throw로 먼저 정리한다.
|
|
17
|
+
- boolean 파라미터로 두 흐름을 한 메서드에 숨기지 않는다.
|
|
18
|
+
- 복잡한 조건식은 도메인 의미가 드러나는 메서드나 변수로 추출한다.
|
|
19
|
+
- 조건 분기가 늘어나면 도메인 메서드, 정책 객체, 별도 타입으로 책임을 분리할 수 있는지 먼저 본다.
|
|
20
|
+
- 지역 변수는 사용하는 곳 가까이에 선언하고, 임시 변수 이름도 도메인 의미를 드러내게 한다.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: clean-code.naming
|
|
3
|
+
source: clean-code
|
|
4
|
+
domain: common
|
|
5
|
+
topic: naming
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*.java"
|
|
8
|
+
severity: should
|
|
9
|
+
enforcement: inject_only
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Naming
|
|
13
|
+
|
|
14
|
+
- 이름은 구현 방식보다 도메인 의도와 유스케이스를 드러낸다.
|
|
15
|
+
- 축약어와 모호한 접미사(`data`, `info`, `manager`, `helper`, `util`)를 기본 선택으로 쓰지 않는다.
|
|
16
|
+
- DTO 이름은 외부 계약이면 `Request`/`Response`, 내부 유스케이스 입력이면 `Command`/`Query`처럼 역할을 드러낸다.
|
|
17
|
+
- 컬렉션 이름은 단수형보다 복수형이나 의미 있는 집합 이름을 사용한다.
|
|
18
|
+
- boolean 이름은 참/거짓 의미가 문장처럼 읽히게 한다.
|
|
19
|
+
- 테스트 이름은 조건과 기대 결과를 함께 드러낸다.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: clean-code.oop
|
|
3
|
+
source: clean-code
|
|
4
|
+
domain: common
|
|
5
|
+
topic: object-responsibility
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*.java"
|
|
8
|
+
severity: should
|
|
9
|
+
enforcement: inject_only
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Object Responsibility
|
|
13
|
+
|
|
14
|
+
- 객체는 자신의 상태와 규칙을 스스로 지키게 한다.
|
|
15
|
+
- 외부에서 getter로 상태를 꺼내 판단한 뒤 다시 객체를 조작하는 흐름을 기본 선택으로 삼지 않는다.
|
|
16
|
+
- 상태 변경은 의미 있는 행위 메서드로 표현한다.
|
|
17
|
+
- 불변으로 만들 수 있는 값은 불변으로 두고, setter는 기본으로 열지 않는다.
|
|
18
|
+
- 복잡한 정책 판단은 도메인 객체나 이름 있는 정책 타입으로 옮겨 호출자의 흐름 코드를 단순하게 둔다.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: clean-code.testability
|
|
3
|
+
source: clean-code
|
|
4
|
+
domain: common
|
|
5
|
+
topic: testability
|
|
6
|
+
globs:
|
|
7
|
+
- "**/*.java"
|
|
8
|
+
severity: should
|
|
9
|
+
enforcement: inject_only
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Testability
|
|
13
|
+
|
|
14
|
+
- 외부 입출력, 시간, 저장소 같은 변하는 요소는 테스트에서 통제할 수 있게 분리한다.
|
|
15
|
+
- 테스트는 public behavior를 검증하고 내부 구현 순서에 과하게 결합하지 않는다.
|
|
16
|
+
- 성공 경로만 확인하지 말고 비어 있음, 삭제 후 상태, 잘못된 입력 같은 경계 조건을 확인한다.
|
|
17
|
+
- 테스트 데이터는 읽는 사람이 요청과 응답을 바로 이해할 수 있게 명시한다.
|
|
18
|
+
- 테스트는 빠르고 독립적으로 실행되어야 하며, 실행 순서나 이전 테스트의 상태에 기대지 않는다.
|
|
19
|
+
- Mock은 상호작용 자체가 요구사항일 때 사용하고, 단순 상태 검증은 가짜 구현이나 실제 객체를 우선 검토한다.
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable Persona Harness changes are recorded here.
|
|
4
|
+
|
|
5
|
+
This project uses npm prerelease versions for tester-facing alpha builds. Stable `latest` releases are deferred until the Java/Spring backend MVP has enough external tester feedback.
|
|
6
|
+
|
|
7
|
+
## [0.3.0-alpha.0] - Unreleased
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Java/Spring backend alpha package posture for external tester installation.
|
|
12
|
+
- `ph init`, `ph intake`, `ph policy`, `ph plan`, `ph history`, and `ph bearshell` as the current CLI workflow surface.
|
|
13
|
+
- Backend project profile, policy overlay, planning artifact, report lifecycle, and workflow history docs.
|
|
14
|
+
- Apache-2.0 license file and alpha publish readiness record.
|
|
15
|
+
- User-facing README plus language-specific README files for Korean, Japanese, and Simplified Chinese.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Root README is now user-facing, while previous detailed usage notes moved to `docs/current/persona-harness-detailed-usage.md`.
|
|
20
|
+
- npm package contents are trimmed to the Java backend MVP surface.
|
|
21
|
+
- The alpha package includes only the Java programming shared-skill reference subset, not the full vendored shared-skills tree.
|
|
22
|
+
|
|
23
|
+
### Removed From Package
|
|
24
|
+
|
|
25
|
+
- Inactive OMO reference skills such as `ast-grep`, `frontend`, `debugging`, and `review-work`.
|
|
26
|
+
- Java no-excuse fixture files from the public alpha tarball.
|
|
27
|
+
- Repo maintenance scripts that are not required by installed package users.
|
|
28
|
+
|
|
29
|
+
### Known Gaps
|
|
30
|
+
|
|
31
|
+
- npm public publish has not been completed yet.
|
|
32
|
+
- `latest` dist-tag is intentionally deferred.
|
|
33
|
+
- Generated app product quality is not certified.
|
|
34
|
+
- Rule compliance is not enforced by AST, linter, or build failure gates.
|
|
35
|
+
- Frontend, infra, desktop, and full TDD workflows remain future tracks.
|
|
36
|
+
|
|
37
|
+
## Links
|
|
38
|
+
|
|
39
|
+
- Release checklist: [docs/current/release/release-checklist.md](docs/current/release/release-checklist.md)
|
|
40
|
+
- Release notes template: [docs/current/release/release-notes-template.md](docs/current/release/release-notes-template.md)
|