feat: 프로젝트 게시와 홈 focus, 그리고 기록 사이 연결을 실제로 가능하게 한다
계약에 선언만 되어 있고 구현이 없던 네 오퍼레이션과, 의도된 스텁으로 남아 있던 catalog 두 종류가 공개 화면 다섯 곳을 조용히 비워 두고 있었다. 프로젝트 게시 — 프로젝트는 `RecordKind` 에 없어 문서 게시 파이프라인을 타지 못하는데, 공개 조회들(프로젝트 목록·상세·프로필의 "현재 프로젝트"·홈 focus)은 전부 `public_resource_projection` 의 PROJECT 행을 가시성 관문으로 쓴다. 그 행을 세우는 경로가 없었으므로 프로젝트는 만들 수는 있어도 공개될 수는 없었다. 릴리스가 자체 경로를 갖는 것과 같은 이유로, 문서 파이프라인에 끼워 넣지 않고 원본 상태·투영·canonical route 세 곳을 한 트랜잭션에서 함께 세운다. 홈 focus — `home_focus_config` 는 마이그레이션이 빈 행 하나만 넣어 두었고 그 값을 읽고 쓸 use case 가 없었다. 지목한 대상이 실제로 있는지는 여기서 확인한다. 테이블에 FK 가 없어(설정이 대상보다 오래 살아남는 것을 허용하는 설계다) 없는 id 도 저장되고, 그러면 공개 화면은 조용히 빈 focus 를 그린다 — 저장은 성공했는데 아무것도 안 나오는, 이유를 알 수 없는 실패가 된다. 대상이 공개인지는 확인하지 않는다: 미리 지목해 두고 게시와 동시에 뜨게 하는 것이 정상적인 순서다. catalog RELATION/EVIDENCE — 「슬라이스 2·5에서 채운다」는 주석과 함께 `List.of()` 로 남아 있었다. 그래서 어떤 기록도 연결 대상 목록을 채울 수 없었다. RELATION 은 작성 중에 고르는 것이라 작업본까지 포함하고(두 문서를 같이 쓰면서 서로 잇는 것이 정상적인 순서다), EVIDENCE 는 읽는 사람이 따라갈 수 있어야 하므로 공개된 것만 포함한다. 계약은 이 네 오퍼레이션을 ProblemDetails 모양으로 두고 있었다. 백엔드가 모든 JSON 응답을 envelope 으로 감싸므로 구현하는 순간 어긋난다 — 나머지와 같은 모양으로 옮겼다. `/home-focus` 는 케밥 세그먼트라 D19(AIP-122)를 위반해 `/home/focus` 로 나눴다. 함께 고친 것들 (모두 이 작업 전부터 빨간 상태였다): - `error-codes.yaml` 의 DOCUMENT_NOT_FOUND 가 표면마다 하나씩 두 행이었다. 이 레지스트리의 식별자는 code 하나뿐이라 로딩 자체가 깨졌고, 그 여파로 거버넌스 테스트 네 개와 outbox 계약 테스트가 함께 넘어졌다. 같은 코드는 같은 말을 해야 한다. - 벤더된 계약 세 개의 MANIFEST.sha256 이 실제 파일과 어긋나 있었다. - ActuatorSecurityHttpTest 는 "DB·Redis 없는 슬라이스"라고 적어 두고 Redis 자동설정을 막지 않아, localhost:6379 연결 실패가 /actuator/health 를 503 으로 만들었다. 보안 태세와 무관한 이유로 빨개지던 테스트다. - 테스트 JVM 힙이 Gradle 기본 512m 이라 Spring context 캐시 + ArchUnit + Testcontainers 조합에서 OOM 이 났다. 증상이 테스트 실패가 아니라 "Executor 를 완료할 수 없음"이어서 원인을 가리켰다. - APP_SESSION_TIMEOUT 이 env-keys 레지스트리에 없었다. 새 SQL 은 실제 PostgreSQL 위에서 돌린다 — 컴파일도 단위 테스트도 컬럼 이름을 검증하지 못한다는 것이 이 파일이 존재하는 이유다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XEHXspz4rv5pB5wiiSsVDu
This commit is contained in:
co-authored by
Claude Opus 5
parent
23d82bd250
commit
561d02ae3a
@@ -112,6 +112,22 @@ env_keys:
|
||||
compatibility_impact: behavior-change
|
||||
required_test: env-contract:server-shutdown-timeout-aligned
|
||||
|
||||
- name: APP_SESSION_TIMEOUT
|
||||
# source: Studio 작성 세션. Spring 기본 30분 유휴 만료는 한 기록을 여러 번 저장하며
|
||||
# 오래 머무는 작성 리듬보다 짧아, 저장하지 않은 편집을 잃는 원인이 되었다.
|
||||
# 늘릴수록 훔친 session cookie 가 유효한 창도 같이 늘어나므로 Keycloak realm 의
|
||||
# SSO idle 과 함께 맞춘다.
|
||||
type: duration
|
||||
default: 8h
|
||||
allowed_values: null
|
||||
classification: public-config
|
||||
required: false
|
||||
reload_policy: restart-only
|
||||
owner_branch: feature-env-driven-runtime-configuration
|
||||
validation: spring_duration_shorthand
|
||||
compatibility_impact: behavior-change
|
||||
required_test: env-contract:session-timeout
|
||||
|
||||
- name: APP_SERVER_FORWARD_HEADERS_STRATEGY
|
||||
# source: feature-env-driven-runtime-configuration D2 (2026-06-05) — APP_ unification
|
||||
# (trust X-Forwarded-* when behind LB/proxy)
|
||||
|
||||
Reference in New Issue
Block a user