--- title: error / sample-ticket-oauth2-resource-server-dependency-2026-05-27 source_type: error-note status: raw related_branches: [feature-skeleton-package-blueprint-contract] related_projects: [ca-skeleton] tags: [error, ca-skeleton, architecture, spring-boot, testing] created: 2026-05-27 status_label: resolved --- # error: sample-ticket-oauth2-resource-server-dependency-2026-05-27 > Layer: `raw/errors/` — 작업 중 마주친 단일 실패·트러블슈팅 기록. 원본은 raw에 영구 보관한다. ## Parent / 부모 - [[raw/branch-notes/feature-skeleton-package-blueprint-contract]] — reference code를 production module에서 `sample-ticket`으로 격리하는 중 sample module compile classpath가 부족했다. - [[raw/project-notes/ca-skeleton-operational-contract]] — ca-tmpl sample fixture 격리 정책과 연결된다. ## 증상 / Symptom - 에러 메시지 (원문 그대로): ```text package org.springframework.security.oauth2.server.resource does not exist cannot find symbol: class InvalidBearerTokenException ``` - 발생 컨텍스트: `cd src && ./gradlew test` 실행 중 `:sample-ticket:compileJava` 실패. - 발생 시점: 2026-05-27 - 발생 환경: local ca-tmpl repository. - 재현 가능 여부: `always` — sample-ticket 내부 `GlobalExceptionHandler`가 `InvalidBearerTokenException`을 import하지만 sample module에 resource-server starter가 없으면 재현. ## 재현 절차 / Reproduction 1. 기존 web error handler를 `sample-ticket` 내부 `adapter/web/error`로 이동한다. 2. `sample-ticket/build.gradle`에 web/security/validation/jpa starter만 둔다. 3. `cd src && ./gradlew test` 실행. 4. 기대 결과: sample-ticket이 production module과 별개로 자가 컴파일된다. 5. 실제 결과: OAuth2 resource-server 예외 type을 찾지 못해 compile 실패. ## 조사 단계 / Investigation log - 2026-05-27 — full test 재실행 → `:sample-ticket:compileJava` 실패. - 2026-05-27 — `GlobalExceptionHandler` import 확인 → `InvalidBearerTokenException`이 resource-server starter에서 제공되는 type임을 확인. - 2026-05-27 — `sample-ticket/build.gradle`에 `spring-boot-starter-oauth2-resource-server` 추가. - 2026-05-27 — full `./gradlew test` 재실행 → 성공. ## 근본 원인 / Root cause - 직접 원인: `sample-ticket`의 compile classpath에 `spring-boot-starter-oauth2-resource-server`가 없었다. - 근본 원인: 기존 production `adapter-web` module이 갖고 있던 external dependency를 sample module 이동 후에도 명시해야 했는데, project dependency만으로 external implementation dependency가 전파된다고 잘못 기대할 수 있었다. - 트리거 조건: sample code를 별도 Gradle module로 격리하면서 compile dependency를 module-local로 재선언하지 않음. ## Sources / 근거 - [[raw/branch-notes/feature-skeleton-package-blueprint-contract]] — `sample-ticket`을 production과 분리된 fixture/sample consumer로 둔 결정. - [[wiki/projects/ca-tmpl/clean-architecture-package-layout]] — sample-ticket 격리 적용 사실. ## 해결 / Resolution - 적용한 조치: `sample-ticket/build.gradle`에 `org.springframework.boot:spring-boot-starter-oauth2-resource-server`를 추가했다. - 검증 방법: - `cd src && ./gradlew test` 성공. - `cd src && ./gradlew verifyCleanArchitectureDependencies` 성공. - 잔여 위험 / 후속 작업: sample-ticket이 production runtime classpath에 들어가지 않도록 Gradle dependency rule과 ArchUnit sample 역의존 금지를 계속 유지해야 한다. ## 회고 / Lessons - 빨리 감지하는 신호: sample module로 이동한 Spring component가 기존 module의 external starter type을 import하면 sample module에도 명시 dependency가 필요하다. - 예방 체크리스트 항목 후보: production code를 sample module로 격리할 때 project dependency와 external dependency를 분리해서 점검한다. - wiki로 끌어올릴 가치가 있는 일반화된 교훈: sample/fixture module도 "실행되지 않는 코드"가 아니라 독립 compile 대상이므로 dependency contract가 필요하다. ## Related / 관련 - 트리거된 daily note: [[raw/daily-notes/2026-05-27]] - 관련 branch note: [[raw/branch-notes/feature-skeleton-package-blueprint-contract]] - 관련 wiki 개념: [[wiki/concepts/clean-architecture-package-layout]]