feat(S15P11A705-41): member 엔티티 + BaseEntity(created_at·soft delete) (도메인 스캐폴딩 3/3) - #25
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…arting per class Every test class extending PostgresContainerSupport redeclared its shared static container behind its own @container field, so JUnit5's Testcontainers extension stopped and restarted it in that class's own afterAll. A later class with an identical @SpringBootTest config then reused a cached Spring context whose DataSource still pointed at the now-dead port, failing every DB call in MemberSoftDeleteTests with a 30s connection timeout (14 tests completed, 3 failed, reproduced twice under `clean check`). Switch to the Testcontainers singleton-container pattern: start the container once in a static initializer in PostgresContainerSupport, with no @container annotation anywhere, so nothing stops it mid-suite. Remove the now-redundant @Testcontainers/@container redeclarations from the six subclasses. `clean check` now passes twice in a row (14/14 tests). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…roubleshooting Document Tasks 1-4 of this branch per CLAUDE.md rule 10: BD-02 (BaseEntity common-column decision and rejected alternatives), BI-02 (what was built and how it was verified), BT-01 (the shared-Testcontainers container lifecycle bug, its fix, and the follow-up it leaves). Register all three in their zone README index tables and add one WORKLOG line per task (Tasks 1-5). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Task 3 (`d1204bf`, `02fcaa7`) only added and strengthened the soft-delete tests; it completed cleanly. The Testcontainers singleton-container fix (`6c61272`, see BT-01) surfaced only when Task 4 first ran the full `clean check` gate, so move it onto the Task 4 line and drop it from Task 3. Add commit SHAs to every task line per the authoritative task-to-commit mapping. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Final whole-branch review surfaced four documentation gaps: BaseEntity's @EntityListeners is not inherited, so place must declare it explicitly or created_at INSERTs null; @SQLDelete never covers bulk delete methods, so deleteAllInBatch()/deleteAllByIdInBatch()/bulk JPQL delete stay documented as physical deletes on soft-delete tables; BT-01's follow-up wrongly recommended @transactional on the member tests, which would defeat the soft-delete exclusion assertions via first-level cache; and package-structure.md's member "공개 프로필·소개" claim contradicts the product spec and the shipped entity, now recorded as an open conflict per CLAUDE.md rule 9 instead of silently rewritten. Also documents which soft-delete write path is canonical (DB clock vs. app clock) and that a deleted in-memory entity still reports isDeleted() == false until reloaded. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MemberSoftDeleteTests.deletedMemberIsExcludedFromQueries discarded the result of memberRepository.findAll(), so BI-02's claim that findAll exclusion was verified had no test backing it. Replace the dead call with a real assertion that the deleted member id is absent from findAll(), covering collection-query filtering without weakening the existing findById assertion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
cherry-go-round
approved these changes
Jul 27, 2026
5 tasks
This was referenced Jul 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
요약
다른 도메인이 복붙할 기준 구현을 만듭니다. Flyway V2로
core.member를 만들고,created_at(감사)과deleted_at(soft delete)만 공유하는BaseEntity, 첫 엔티티Member, 리포지토리, Testcontainers 검증을 추가합니다. 엔티티·영속 계층까지만이며 service·controller·DTO는 다음 PR입니다.Jira (필수)
변경 사항
core.member(id, created_at, deleted_at)— 제품 명세06_데이터모델_및_무결성.md§2.1 그대로.updated_at·status없음, 개인정보 컬럼 없음(익명 서비스). 부분 인덱스ix_member_active.global/common/BaseEntity—@MappedSuperclass+@EntityListeners(AuditingEntityListener),@CreatedDate created_at,deleted_at,isDeleted(),softDelete(). 시간 타입은Instant(TIMESTAMPTZ ↔ UTC).global/config/JpaAuditingConfig—@EnableJpaAuditing. 없으면created_at이 null로 INSERT되어 NOT NULL 위반.domain/member—Member(@Table(schema="core"), 엔티티별@SQLDelete/@SQLRestriction),MemberRepository.deleted_at기록 +findById·findAll제외, raw SQL로 영속 상태 검증).application-local.yml추가,configuration.md로컬 값 정합(15432/pinlog-local/16379, 없던dev/경로 정정).database-conventions.md— 공통 컬럼 매트릭스 + BaseEntity 사용 규약.BD-02(결정),BI-02(구현 리포트),BT-01(트러블슈팅), WORKLOG 5줄.설계 결정:
BaseEntity에updated_at을 두지 않음core테이블 8개의 공통 컬럼 조합이 다릅니다 —created_at8/8,deleted_at7/8(place제외),updated_at3/8(place·record·collection).ddl-auto=validate이므로updated_at을 베이스에 넣으면 member·context 등에서 기동 실패합니다. 따라서updated_at은 필요한 엔티티가 각자 선언하고,place는BaseEntity를 상속하지 않습니다.restore()도 넣지 않았습니다 —@SQLRestriction때문에 삭제된 행을 다시 로드할 수 없어 동작 불가입니다. 근거·대안 비교는BD-02참고.테스트 / 검증
./gradlew clean check --no-daemonBUILD SUCCESSFUL (14/14, 연속 2회 확인)리뷰 포인트
@SQLRestriction의 파급 — 엔티티 단위 필터라 향후record/collection이@ManyToOne Member를 가지면, 소프트 삭제된 회원을 참조하는 연관 로딩에서EntityNotFoundException이나 null이 될 수 있습니다. 다음 도메인 설계 시 확인이 필요합니다.deleteAllInBatch()등). 규약 문서에 금지로 명시했고, 리포지토리에 오버라이드로 막을지는 다음 PR에서 판단.6c61272) — 6개 테스트 클래스가 같은 컨테이너를@Container로 재선언해 클래스마다 정지·재시작되고, 캐시된 컨텍스트가 죽은 포트를 잡아 게이트가 깨졌습니다. 표준 싱글톤 패턴으로 고쳤고 단정 약화·스킵은 없습니다. 상세는BT-01.발견된 문서 충돌 (CLAUDE.md 9 — 기록만)
package-structure.md의 member 행 "공개 프로필·소개를 포함합니다"는 명세 §2.1(익명 서비스, 개인정보 저장 없음)과 실제Member(필드 없음)에 반합니다. 임의로 고치지 않고 해당 위치에> 검토 필요로 기록했습니다. 팀 확인 후 정리가 필요합니다.미결 / 후속
FlywayMigrationTests의 "빈 DB" 전제가 컨테이너 공유로 실행 순서에 의존(현재 단정은 스키마 수준이라 영향 없음) —BT-01에 후속 과제로 기록ExceptionInInitializerError가 5건의NoClassDefFoundError로 번져 진단성 저하spring-boot-docker-compose가local프로파일에서도 우선하므로application-local.yml은 컨테이너를 직접 띄우는 경우에 유효place추가 시created_at만 가진 상위 클래스 분리 검토