콘텐츠로 이동

Task: Canonical 데이터·API 호환·RAG 전달

상태: Active · Task 1/5 임상 검토 gate 최종 갱신: 2026-09-03 역할: 이 작업 묶음의 실행 상태, 완료 gate, 최소 테스트, blocker와 증거를 소유하는 단일 원장

1. 이 문서의 책임

이 문서는 컨텍스트가 요약되거나 작업자가 바뀌어도 아래 내용을 한 곳에서 복구하기 위한 실행 원장이다.

  • 현재 진행 중인 Task와 다음 Task
  • 변경할 수 없는 제품·API 결정
  • Task별 완료 기준과 최소 테스트
  • 임상 검수가 필요한 blocker
  • 실제 검증 명령과 결과 링크
  • 작업 중 새로 확정된 결정

상세 설계를 복제하지 않는다. 설계의 source of truth는 다음 문서다.

2. 고정 결정

2.1 기존 API 계약은 변경하지 않는다

DB·도메인 객체·내부 DTO는 바꿀 수 있지만 이미 노출된 API의 다음 항목은 변경하지 않는다.

  • URL과 HTTP method
  • request body와 query parameter
  • status code와 오류 응답 구조
  • response 필드명, alias, 중첩, 타입, nullability
  • enum 값과 필드의 의미

값 자체는 승인된 content release를 통해 갱신될 수 있다. 구조나 의미를 바꿔야 한다면 기존 API를 수정하지 않고 별도 version 또는 endpoint를 먼저 제안하고 승인을 받는다.

예외로, STG·PRD에 아직 배포하지 않은 /knowledge/retrieve는 호출 서비스별 payload를 줄이기 위한 additive fields 요청 필드를 승인했다. fields를 생략하면 기존 전체 응답을 그대로 반환하고, 지정한 경우에만 선택 섹션을 생략한다. 공통 추적 필드는 항상 유지한다.

Canonical DB / Domain
        ↓
Typed Internal DTO
        ↓
Compatibility Presenter
        ↓
기존 Response Schema

2.2 새 코드와 실제로 수정하는 코드는 현재 설계 규칙을 따른다

  • Router는 Request 수신과 Response 변환을 소유한다.
  • Service는 use case, 호출 순서, transaction을 소유하고 Internal DTO를 반환한다.
  • Repository는 aggregate 또는 typed projection의 조회·저장을 소유하며 commit하지 않는다.
  • Domain은 SQLAlchemy, FastAPI, Pydantic을 import하지 않는다.
  • 행동은 기존 명사의 메서드로 배치하고 역할 없는 Handler·Facade를 만들지 않는다.
  • 공개 메서드는 명시적 return type과 필요한 keyword-only parameter를 사용한다.
  • 동작 중인 legacy 구조의 일괄 정리 작업은 만들지 않는다. 새 코드가 legacy에 의존하지 않게 하고, 기존 코드는 실제 변경과 직접 충돌할 때만 함께 정리한다.

2.3 완료와 구현을 구분한다

상태 의미
PLANNED 범위와 완료 기준만 확정됨
IN_PROGRESS 구현 또는 검증이 진행 중임
IMPLEMENTED 코드가 존재하지만 전체 증명이나 선행 승인이 남음
VERIFIED 코드·자동 검증·검토 증거·blocker 해소가 모두 완료됨
BLOCKED 사람의 판단이나 외부 조건 없이는 다음 gate로 이동할 수 없음
DEFERRED 현재 release를 막지 않는 후순위 작업

이 문서에서 VERIFIED만 완료를 뜻한다.

2.4 화면은 조회하고, 쓰기는 BE 경계 안에서만 수행한다

화면의 기본 역할은 조회와 판단 지원이다. 화면, BFF, 배포된 JSON 파일은 데이터 정합성과 publication 상태를 직접 변경하지 않는다. 모든 쓰기는 BE Application Service를 통과하고, Domain 규칙과 transaction, audit를 한 경계에서 적용한다.

일반 화면 ────────────────> Read API ───────────────> Projection / Repository

운영 UI·자동화 ──인증·인가──> Admin/Internal API ─┐
                                                   ├─> Application Service
저빈도 운영 작업 ──────────> CLI ─────────────────┘        ↓
                                                Domain → Repository → DB

HTTP write API는 실제 반복 호출자가 있을 때만 만든다. 검수 반영, release 생성·발행, rollback처럼 저빈도이면서 영향이 큰 작업은 우선 CLI로 제공하되 동일한 Application Service와 Domain 메서드를 사용한다. 이후 운영 UI가 필요해지면 그 Service 앞에 인증·인가된 Admin/Internal API를 추가한다. CLI와 API 어느 쪽도 Repository나 DB를 우회하지 않는다.

새 Canonical write surface의 필수 조건은 다음과 같다.

  • 일반 공개 API와 사용자 화면에는 persistence write를 노출하지 않는다.
  • Admin/Internal API에는 인증·인가, actor, audit trail, idempotency 또는 version guard를 둔다.
  • published revision은 직접 수정하지 않고 새 revision과 release로 교정한다.
  • POST /knowledge/retrieve처럼 HTTP method가 POST여도 상태를 바꾸지 않는 질의는 semantic read로 분류한다.
  • 호출자가 없는 write use case를 미래 대비 명목으로 HTTP endpoint화하지 않는다.

현행에는 이 목표 경계와 다른 legacy surface가 있다. 기존 소비자를 확인하기 전 제거하거나 응답 계약을 바꾸지 않고 Task 0에서 호출자와 보호 경계를 먼저 확정한다.

현행 surface 실제 동작 현재 확인된 경계 처리 원칙
제거된 Next PUT /api/taxonomy 과거 JSON 파일 직접 저장 C2에서 route·화면 caller 제거 완료 BE Application Service 없이는 재도입 금지
BE glossary upload/rollback DB 반영·버전 생성·복원 화면 프록시가 호출, BE는 Gateway admin gating을 전제로 하나 저장소에서 실재 여부는 확인 불가 STG 전 Gateway 또는 BE 보호를 증명하고 기존 계약 유지
BE terminology PUT/DELETE 번역 셀 upsert/delete BE route 자체 인증 없음, 현행 FE 호출자는 정적 검색에서 확인되지 않음 실제 소비자 확인 후 Admin/Internal surface로 분류
Canonical publish/rollback revision/release 상태 전이 운영 CLI가 Application Service 호출 UI 요구 전까지 CLI 유지

2.5 Runtime 임상·업무 데이터는 JSON을 읽거나 쓰지 않는다

Canonical 전환의 목적은 JSON 파일을 또 다른 운영 저장소로 유지하는 것이 아니다. 운영 요청을 처리하는 화면, Next BFF, BE Service와 배포 부트스트랩은 임상·업무 JSON을 source of truth로 읽거나 수정하지 않는다.

허용 범위:

  • 환경 최초 구성 시 운영자가 수동 복원하는 PostgreSQL data snapshot
  • 운영 요청과 분리된 일회성 분석 보고서
  • 임상·업무 사실이 아닌 build-time 설정

금지 범위:

  • Request handler 또는 화면 코드의 임상·업무 JSON 직접 import/read/write
  • BE Service가 요청마다 원본 JSON을 읽어 응답을 만드는 경로
  • 화면/BFF가 파일을 덮어써 persistence 상태를 변경하는 경로
  • Canonical 전환 후 컨테이너 시작마다 JSON을 DB에 재seed하여 파일을 사실상 운영 원본으로 유지하는 경로
  • UI 번역 리소스에 임상 용어·분류·안전 규칙의 원본을 함께 두는 구조

외부 API의 URL과 응답 계약은 유지한다. Next /api/*가 필요한 경우 파일 서버가 아니라 기존 계약을 보존하는 얇은 BE compatibility proxy로 남긴다.

2.6 작업 단위마다 검증된 commit을 기준점으로 남긴다

  • 한 commit은 독립적으로 설명하고 검증할 수 있는 하나의 완료 단위만 포함한다.
  • 최소 테스트와 정적 gate를 통과하기 전에는 해당 단위를 완료 commit으로 기록하지 않는다.
  • 실행 원장의 상태·검증 증거를 해당 코드와 같은 commit에 갱신한다.
  • 여러 commit이 필요한 Task는 각 commit의 하위 gate와 결과를 증거 원장에 남긴다.
  • 생성물인 graphify-out/과 현재 Task에 무관한 사용자 변경은 commit하지 않는다.
  • STG migration·배포처럼 별도 승인이 필요한 변경은 로컬 구현 commit과 분리한다.

3. 테스트 원칙: 적게 만들고 강하게 판정한다

테스트 수나 coverage 비율을 목표로 삼지 않는다. 테스트가 실패했을 때 다음 중 하나의 판단이 달라지는 경우에만 추가한다.

  1. 외부 API 소비자가 깨지는가
  2. 임상 안전·추천·근거 판단이 달라지는가
  3. DB 제약·transaction·release 원자성이 깨지는가
  4. 빈 DB baseline과 data snapshot 복원이 깨지는가
  5. 기존 공개 API 응답 계약이 달라지는가
  6. Retrieval이 잘못된 entity·rule·citation을 반환하거나 근거 없이 답하는가
  7. 실제로 재현된 결함이 다시 발생하는가

테스트를 추가하지 않는 경우

  • private helper의 구현 자체를 고정하는 테스트
  • 단순 getter, dataclass 필드 저장, framework 기본 동작 테스트
  • 같은 규칙을 Domain·Service·Router에서 반복하는 테스트
  • coverage 숫자를 올리기 위한 branch 나열
  • 이미 상위 contract 또는 integration test가 동일 실패를 검출하는 경우
  • 테스트마다 거의 같은 fixture를 복제하는 경우

테스트 선택 순서

  1. 기존 테스트가 같은 위험을 막는지 먼저 확인한다.
  2. 가장 낮고 책임이 명확한 계층 하나에서 규칙을 검증한다.
  3. 여러 사례는 table-driven 또는 parameterized case로 합친다.
  4. 경계 테스트는 대표 happy path와 의미가 다른 실패 path만 둔다.
  5. 전체 suite는 작은 수정마다 반복하지 않고 Task gate와 release gate에서 실행한다.

새 테스트 파일을 만들기 전 이 문서의 해당 Task에 “최소 테스트”를 먼저 적는다. 기존 테스트와 의미가 겹치면 새로 만들지 않고 기존 테스트를 확장하거나 중복을 제거한다.

4. 현재 상태

Task 이름 상태 다음 gate
0 외부 API 계약·write surface 동결 VERIFIED C1 기준선 유지
1 Canonical 데이터 검수 BLOCKED 피부과 의사의 claim·revision 승인
2 최초 Canonical Release IMPLEMENTED Task 1 완료 후 최초 release 발행
3 Compatibility Read Model VERIFIED C1 공개 계약과 exact parity 기준선 유지
4 Legacy–Canonical Shadow와 전환 IMPLEMENTED STG에서 runtime image rollback 실행 증명
5 Retrieval·RAG IMPLEMENTED 로컬 사용자 검토 후 임상 fixture·최초 release
6 STG 배포 검증 IN_PROGRESS 핵심 화면 회귀와 실제 rollback 실행 증명
7 기존 구조 정리 DEFERRED 별도 청소 작업 없음; 수정 대상과 충돌할 때만 정리

5. Task와 완료 gate

Task 0. 외부 API 계약·write surface 동결

목표: 현재 공개 API의 실제 구조와 의미를 변경 불가능한 기준선으로 고정하고, 모든 write surface의 호출자와 노출 수준, 보호 책임을 확정한다.

예상 결과:

  • 등록된 공개 endpoint 전부가 contract ledger에 포함됨
  • 미분류 endpoint가 0개임
  • endpoint별 semantic read/write와 public/admin/internal/CLI 분류가 존재함
  • write surface별 실제 호출자와 인증·인가 책임이 확정됨
  • 성공·빈 결과·대표 오류 응답 fixture가 존재함
  • OpenAPI와 실제 HTTP 응답의 비승인 contract diff가 0임

최소 테스트:

  • 기존 공개 API contract test를 재사용한다.
  • 전체 공개 endpoint 누락과 OpenAPI breaking diff를 잡는 table-driven contract gate 하나를 둔다.
  • HTTP write API를 유지하거나 새로 추가할 때만 대표 허용·거부를 묶은 authorization matrix test 하나를 둔다. CLI만 유지하면 이 테스트를 만들지 않는다.
  • endpoint별로 새 schema test를 복제하지 않는다.

완료 gate:

  • path, method, request, status, response 구조, enum 의미 중 미고정 항목이 0개다.
  • 호출자나 보호 책임이 불명확한 write endpoint가 0개다.
  • 새 Canonical write 중 일반 공개 surface에 노출된 endpoint가 0개다.
  • 공개 operation 구조 gate와 대표 response contract test가 통과한다. JSON↔DB content 값 parity는 Task 3에서 별도로 판정한다.
  • contract baseline과 소비자 목록을 사람이 읽을 수 있다.

Runtime JSON inventory — 2026-09-03 기준

경로 실측 판정 전환 위치
Next /api/*의 src/data 직접 read/import C0 기준 22 routes → 현재 0 route 제거 완료 C3~C7에서 전부 DB compatibility proxy로 전환
Next taxonomy PUT 파일 저장 0 route / 0 UI caller 제거 완료 C2에서 read-only UI로 전환. 향후 BE Application Service 없이는 재도입 금지
Page·component의 임상 JSON 직접 import 0 active paths 제거 완료 C7에서 evidence taxonomy·integrity를 DB API로 전환
사용되지 않는 src/data/i18n/index.ts 정적 bundle 0 path 제거 완료 C7에서 dead bundle 제거, 언어 Provider는 선택 상태만 소유
BE 임상 query 원본 read 0 files 제거 완료 C6에서 immutable ContentRevision.snapshot adapter로 교체했고 U0에서 범용 Knowledge Retrieval로 통합
BE ExtractedCatalog 원본 read 0 files 제거 완료 C5에서 immutable ContentRevision.snapshot DB projection으로 교체
Docker의 JSON 복사와 startup seed runtime corpus·seed 호출 0 제거 완료 runtime은 Alembic+서버만 기동
seed/import/bootstrap 도구 active path 0 제거 완료 새 환경은 PostgreSQL data snapshot을 수동 복원
PostgreSQL data snapshot DB-native custom format 1개 허용 최초 환경 구성용 수동 입력, runtime 자동 실행 금지

src/data와 애플리케이션 seed/importer는 0개다. 22개 Next read route는 모두 FastAPI의 DB-backed endpoint를 호출하는 compatibility proxy이며, i18n domain data와 fallback도 DB가 소유한다.

실행 checkpoint 순서

Checkpoint 완료 단위 최소 gate 상태
C0 runtime JSON read/write 전수 inventory와 원칙 고정 정적 검색 재현, 과거 상충 결론 폐기 표시, 문서 diff 검사 VERIFIED
C1 공개 API contract baseline과 write caller·보호 경계 동결 endpoint 누락 0, 대표 contract fixture, 미분류 write 0 VERIFIED
C2 taxonomy 파일 write 제거 UI 기능 의미 유지, 파일 write 0, 허용·거부 또는 read-only 회귀 검증 VERIFIED
C3 DB endpoint가 이미 있는 11개 Next route를 compatibility proxy로 전환 동일 fixture response parity, 해당 JSON read 0 VERIFIED
C4 없는 9개 임상 compatibility read 구현 후 proxy 전환 Repository→Service→Presenter 경계, 기존 response parity VERIFIED
C5 extracted를 Canonical DB projection으로 전환 17개 file read 0, 기존 response parity VERIFIED
C6 임상 query를 Canonical adapter로 전환 3개 file read 0, 전환 시점 query response와 Safety 의미 보존 VERIFIED
C7 UI-only i18n 분리와 page/component 직접 임상 import 제거 domain label JSON import 0, UI locale 회귀 없음 VERIFIED
C8 Docker copy·반복 startup seed 의존 제거 단일 baseline + 수동 snapshot 복원, image runtime JSON 의존 0 VERIFIED
C9 전체 shadow·contract·STG gate 비승인 diff 0, rollback 증거, 핵심 smoke failure 0 IN_PROGRESS

C4의 9개는 i18n을 제외한 anatomy-danger-zones, consent-checklist, market-pricing, patient-education, pih-risk, post-procedure-timeline, procedure-comparison, treatment-optimization, treatment-sequence다. C0는 준비 기준점이며, 실제 구현은 C1에서 계약을 먼저 얼린 뒤 한 checkpoint씩 진행한다.

Task 1. Canonical 데이터 검수

목표: mapping과 임상 근거 문제를 모두 판정해 release 후보를 확정한다.

예상 결과:

  • 기술 mapping 118건이 모두 canonical identity로 확정됨
  • 기존 evidence/taxonomy blocking issue 78건이 교정 또는 제외 상태를 가짐
  • release 후보의 identifier·taxonomy blocking validation이 0건임
  • 결정마다 원문, 출처, 판단자, 판단 사유가 존재함
  • release 후보에 포함된 blocking issue가 0건임

최소 테스트:

  • unresolved validation이 release publish를 차단하는 기존 Domain/Application test를 재사용한다.
  • 항목마다 test case를 만들지 않는다.
  • 검수 결과는 DB audit 한 번으로 누락과 blocking count를 판정한다.

완료 gate:

  • 판단 없는 issue가 0개다.
  • 미확정 항목이 자동 승인되거나 release에 포함된 사례가 0개다.
  • release 후보 validation의 blocking count가 0이다.
  • claim 검수는 Domain 정책을 거쳐 append-only verification과 reviewer audit을 함께 남긴다.

Task 1 실행 checkpoint

Checkpoint 완료 단위 최소 gate 상태
1-A legacy reference를 canonical identity로 확정 118건 importable, pending mapping 0 VERIFIED
1-B evidence identifier·taxonomy source 교정안 NCBI identity와 임상 claim 지지 판단을 분리, 미확정 자동 승인 0 VERIFIED
1-C claim 검수 Application Service·로컬 CLI 현재 statement만 append-only 검수, usable source 없는 승인 차단, audit 보존 VERIFIED
1-D 교정 source successor import와 임상 승인 blocking validation 0, 승인 claim만 retrieval 대상 BLOCKED

1-B의 교정 정책과 source import, 1-C의 검수 경계까지 로컬 기술 구현으로 완료했다. 1-D에서 남은 claim·revision 승인과 fixture 확정은 피부과 의사의 판단 없이는 진행하지 않는다. 첫 migration 이후 운영 write는 JSON을 직접 고치지 않고 같은 Application Service를 호출하는 보호된 BE API로 확장한다.

Task 2. 최초 Canonical Release

목표: 승인된 revision만 포함한 최초 운영 release를 발행한다.

예상 결과:

  • 포함 revision 전부가 approved 상태임
  • current published release가 정확히 하나임
  • 동일 source 재import가 no_change=true임
  • rollback이 과거 revision 집합으로 새 release를 생성함

최소 테스트:

  • Publication 상태 전이와 publish guard를 parameterized domain test로 검증한다.
  • application transaction은 publish 성공과 rollback 한 사례만 PostgreSQL에서 검증한다.
  • aggregate 메서드마다 별도 test class를 만들지 않는다.

완료 gate:

  • 미승인 revision publish가 차단된다.
  • 발행 전 Retrieval은 fail-closed이고 발행 후에는 동일 release만 반환한다.
  • release에서 revision, source checksum, reviewer를 역추적할 수 있다.
  • rollback 후 audit history가 보존된다.

Task 3. Compatibility Read Model

목표: canonical DB를 읽으면서 기존 API 응답을 그대로 반환한다.

예상 결과:

  • Repository가 typed projection을 반환함
  • Service가 Internal DTO를 반환함
  • Router 또는 Presenter가 기존 Response schema로 변환함
  • 기존 응답 구조와 의미의 비승인 diff가 0임

최소 테스트:

  • 동일 fixture를 legacy와 canonical 양쪽에 넣는 parameterized parity test를 사용한다.
  • DTO 필드별 단위 테스트는 만들지 않고 최종 presenter snapshot으로 판정한다.
  • Domain에서 이미 검증한 규칙을 Service test에서 반복하지 않는다.

완료 gate:

  • path, status code, response 구조의 diff가 0이다.
  • 값 차이는 승인된 content 변경 또는 결함으로 전부 분류된다.
  • 신규·수정 Service가 API Response DTO를 직접 반환하지 않는다.

Task 4. Legacy–Canonical Shadow와 전환

목표: 동일 입력의 legacy와 canonical 결과를 비교하고 안전하게 read source를 전환한다.

예상 결과:

  • 대상 endpoint와 대표 상태가 모두 shadow matrix에 포함됨
  • 비승인 구조·의미 diff가 0건임
  • canonical 장애 시 직전 immutable runtime image 복귀 경로가 존재함
  • 전환 전후 외부 API contract가 동일함
  • 운영 요청 경로의 임상·업무 JSON 직접 read/write가 0건임
  • 배포 image와 startup이 JSON corpus를 운영 source of truth로 요구하지 않음

최소 테스트:

  • endpoint와 scenario를 데이터로 가진 shadow runner 하나를 사용한다.
  • endpoint마다 별도 shadow test 파일을 만들지 않는다.
  • Safety 27개 pair 전수 비교는 기존 test를 유지한다.

완료 gate:

  • shadow matrix 전체가 통과한다.
  • 승인되지 않은 allowlist 항목이 0개다.
  • 현재 read source로의 전환과 직전 immutable runtime image 복귀가 모두 증명된다. 운영 runtime에 JSON legacy source를 다시 포함시키는 feature flag는 만들지 않는다.
  • src/app, src/components, backend/app의 runtime 임상·업무 JSON read/write가 0건이다.
  • taxonomy 파일 write, InsightQueryService JSON read, ExtractedCatalog JSON read가 모두 제거되거나 DB-backed compatibility path로 교체됐다.

Task 5. Retrieval·RAG

목표: 자연어 query 하나만으로 분야·화면·분류를 미리 지정하지 않고 Procedure Hub의 모든 searchable domain에서 관련 정보를 찾아, 검증된 canonical 데이터와 출처로 구성한 범용 Context Pack을 제공한다. 상세 API·index·검색 설계는 범용 Retrieval API 설계를 따른다.

예상 결과:

  • intent나 화면 분류에 관계없이 모든 searchable domain이 검색됨
  • 서로 다른 domain의 관련 정보가 공통 Knowledge Item으로 손실 없이 반환됨
  • 승인된 평가 fixture에서 expected entity·domain·safety item 누락이 0건임
  • 미검증 citation 반환이 0건임
  • 서로 다른 release의 데이터 혼합이 0건임
  • 결과가 잘리거나 source가 unavailable인 사실이 응답에서 숨겨지지 않음
  • 이미 사용 중인 기존 API 응답 contract가 유지됨

최소 테스트:

  • searchable domain registry coverage test 하나를 둔다.
  • index build의 release/source/entity link와 멱등성을 integration test 하나로 검증한다.
  • 피부과 의사가 검수한 query fixture를 evaluation runner 하나에서 실행한다.
  • query나 domain마다 pytest 함수를 만들지 않는다.
  • Safety 우선순위와 Evidence publication gate만 독립 domain test로 유지한다.
  • public contract는 대표 response snapshot 하나로 고정한다.
  • fields 선택 응답은 기존 public contract test에 전체 응답과 대표 projection 한 사례만 추가해 기본 호환과 선택 생략을 함께 판정한다.

완료 gate:

  • registry에 등록되지 않은 published domain이 0개다.
  • 평가 fixture의 expected entity·domain·item/source가 모두 충족된다.
  • Safety를 누락하거나 unknown을 safe로 바꾼 사례가 0개다.
  • 다른 release 또는 미검증 claim/citation 반환이 0건이다.
  • 응답 budget 밖의 결과는 truncated와 cursor로 확인할 수 있다.
  • 이미 사용 중인 기존 공개 API의 필드·enum·nullability·의미 diff가 0이다.

기존 5-A~5-G는 고정 intent·section 기반 1차 구현과 optional answer 생성의 증거다. 해당 코드는 범용 Retrieval의 완료 증거가 아니며, 새 경로에 억지로 보존하지 않는다. 기존 Insight endpoint·probe·answer generator는 범용 Retrieval과 책임이 중복되고 외부 caller가 없음을 확인했으므로 제거한다. 신규 공개 경로는 /knowledge/retrieve로 단일화한다.

Task 5 범용 Retrieval checkpoint

Checkpoint 완료 단위 최소 gate 상태
U0 Insight 제거·Knowledge 명칭 단일화 Insight runtime caller·route·probe·generator 0 VERIFIED
U1 Public contract와 domain registry OpenAPI·포함/제외 domain 확정, 기존 caller 영향 0 VERIFIED
U2 Knowledge index projection published release 전체 unit과 source/entity link, 재실행 멱등 VERIFIED
U3 Release retrieval exact+sparse+relation expansion, 검색 가능한 전체 domain 후보화 VERIFIED
U4 Safety·Context assembly safety recall 100%, dedupe·budget·coverage 동작 VERIFIED
U5 /knowledge/retrieve HTTP adapter 새 HTTP contract 일치, 기존 API diff 0 VERIFIED
U6 Retrieval Inspector 화면에서 query→관련 item→source 추적 가능 VERIFIED
U7 임상 fixture·최초 release 평가 expected entity·domain·item/source 및 safety 100% BLOCKED

U1~U6는 로컬에서 구현·검증한다. U7은 피부과 의사가 claim·fixture를 승인하고 최초 canonical release를 발행해야 완료할 수 있다. Task 5 결과를 사용자와 검토한 뒤에만 Task 6 STG 배포 검증으로 이동한다.

Task 6. STG 배포 검증

목표: 로컬에서 검증한 baseline, release, API 동작을 STG에 동일하게 재현한다.

상세 구현 순서와 환경 계약은 ADR 0004: STG runtime 설정과 Canonical DB 전환이 소유한다. ADR 승인 전에는 클라우드 설정·DB·배포 workflow를 변경하지 않는다.

예상 결과:

  • 단일 baseline migration과 canonical import가 성공함
  • 로컬과 STG의 manifest 및 주요 row count가 일치함
  • 기존 API와 화면의 회귀가 없음
  • canonical 대표 질의와 rollback이 STG에서 동작함

최소 테스트:

  • 기존 backend contract/regression suite를 그대로 실행한다.
  • STG 전용으로 같은 unit test를 복제하지 않는다.
  • 브라우저 smoke는 핵심 사용자 흐름과 외부 소비 API만 확인한다.

완료 gate:

  • 기존 공개 API contract diff가 0이다.
  • 핵심 화면과 알려진 외부 소비자의 smoke failure가 0이다.
  • 치명·높음 등급 미해결 결함이 0이다.
  • 실제 rollback 절차와 결과가 기록돼 있다.
  • 배포 image와 시작 명령이 runtime 임상·업무 JSON corpus에 의존하지 않는다.

Task 7. 기존 구조 정리

목표: legacy를 유지하기 위한 새 코드도, 사용 여부를 증명하기 위한 별도 청소 작업도 만들지 않는다. 기존 구조는 현재 작업과 직접 충돌하거나 같은 파일을 수정할 때만 최소 범위에서 정리한다.

예상 결과:

  • 신규 canonical 기능이 legacy read/write 경로에 의존하지 않음
  • legacy 보존만을 위한 신규 adapter·shadow·이중 쓰기가 추가되지 않음
  • 수정 대상과 직접 충돌한 legacy 코드만 같은 변경에서 최소 정리됨

최소 테스트:

  • legacy 정리만을 위한 테스트나 전수 검사는 추가하지 않는다.
  • 실제 기능 변경이 있을 때 그 기능의 기존 최소 gate만 사용한다.

완료 gate:

  • 독립 실행 Task로 완료 판정하지 않는다.
  • 새 작업에서 legacy 운영 비용을 추가하지 않았는지만 해당 Task review에 포함한다.

6. 전체 완료 판정

Task 0~5 VERIFIED = 로컬 기능 완성
Task 0~6 VERIFIED = STG 반영 완료
Task 7 DEFERRED   = 별도 구조 정리는 완료 조건에서 제외

Task 7의 일반 구조 정리는 STG 반영과 최종 완료를 막지 않는다. 단, runtime 임상·업무 JSON read/write 제거는 Task 4·6의 cutover gate이므로 Task 7로 미룰 수 없다. Task 0~6 중 하나라도 gate를 통과하지 못하면 “거의 완료”가 아니라 해당 Task를 현재 상태로 유지한다.

7. 검증 증거 원장

Task를 진행할 때 아래 표에 실제 명령, 날짜, 결과 또는 문서 링크를 추가한다. 실행하지 않은 검증을 예상 결과로 기록하지 않는다.

Task 검증일 증거 결과
0 2026-09-03 Router·Next Route·FE 호출부·BE service·Docker/bootstrap 정적 조사 Next JSON read 22 routes, file write 1 route, BE runtime read 20 files 확인
0 2026-09-03 uv run pytest tests/test_public_api_contract.py -q C4 additive read 반영 후 41 operations(read 31/write 9/conditional 1) 분류·OpenAPI 구조 fingerprint PASS
0 2026-09-03 router·terminology·glossary contract 묶음 75 tests 최초 실행 74 passed/1 content parity failed; 분류 후 -k 'not test_problem_combos_snapshot' 재실행 74 passed/1 deselected. 실패는 Task 3 blocker로 유지
0/C2 2026-09-03 taxonomy Next route·화면 caller 정적 검사, npm run lint, npm run build PUT·writeFile·화면 저장 caller 0, read-only 조회 유지, lint·Next 16 production build PASS
3/C3 2026-09-03 11개 DB-backed router snapshot 묶음 로컬 DB source 재동기화 후 45 passed; 기존 JSON과 의도된 projection 정규화 parity PASS
4/C3 2026-09-03 로컬 FastAPI:8005·Next:3001 실기동 표 기반 smoke 11/11 BFF가 Backend status·JSON body 동일 전달, 연결 실패는 502+고정 JSON, 대상 route의 runtime JSON read 0
3/C4 2026-09-03 uv run pytest -q tests/test_reference_read_router.py tests/test_public_api_contract.py 9개 임상 relational projection과 기존 JSON 응답 exact parity, 전체 공개 API 구조 gate PASS (2 passed)
3/C4 2026-09-03 uv run alembic check 응답 메타 3종과 optimization safety caveat 모델 포함 schema drift 0
4/C4 2026-09-03 로컬 FastAPI:8005·Next:3001 실기동 표 기반 smoke와 Next route 정적 검색 9/9 BFF status·JSON exact 전달, 대상 file read 0, 전체 Next runtime JSON route 2개만 잔존
3·4/C4 2026-09-03 9개 모델·응답·공개 계약 관련 묶음, npm run lint, npm run build Backend 91 passed, Ruff·ESLint·TypeScript·Next 16 production build PASS
3/C5 2026-09-03 canonical import 후 uv run pytest -q tests/test_data_router.py tests/test_public_api_contract.py SourceArtifact·ContentRevision 48개 적재, extracted 17개 DB map과 기존 파일 fixture exact parity, 공개 계약 PASS (6 passed)
4/C5 2026-09-03 로컬 FastAPI:8005·Next:3001 실기동 shape/parity smoke BE map 17개·Next array 17개 기존 이중 계약 유지, Next 배열이 BE map values와 exact match, runtime extracted file read 0
3·4/C5 2026-09-03 Ruff·Alembic check, npm run lint, npm run build schema drift 0, Python·ESLint·TypeScript·Next 16 production build PASS
3·4/C6 2026-09-03 uv run pytest -q tests/test_insight_query_service.py tests/test_insight_query_router.py tests/test_public_api_contract.py 10 passed. DB snapshot 3종으로 계산한 HTTP 전체 응답이 기존 JSON evaluator 응답과 exact match, Safety·필수 확인·selector 의미 보존
4/C6 2026-09-03 runtime 정적 검색과 로컬 FastAPI:8005·Next:3001 실기동 smoke Insight request 경로의 file read 0. 대표 safe/restricted 2개 질의에서 생성 문장 본문을 제외한 BFF·BE 응답 exact match; 생성 문장은 기존 OpenAI 비결정성으로 별도 분류
3·4/C7 2026-09-03 uv run pytest -q tests/test_reference_read_router.py tests/test_literature_evidence_router.py tests/test_taxonomy_router.py tests/test_public_api_contract.py 11 passed. Evidence integrity·i18n DB snapshot이 기존 JSON과 exact match, 미지원 locale의 한국어 fallback 유지, 공개 API 43 operations(read 33/write 9/conditional 1) PASS
4/C7 2026-09-03 runtime 정적 검색, npm run lint, npm run build, 로컬 FastAPI:8005·Next:3001 smoke page/component/BFF/BE runtime 임상·업무 JSON read/write 0. Evidence 의존 API 3개·화면 200, integrity/i18n BFF↔BE exact, invalid locale 400 유지
4/C8 2026-09-03 격리된 신규 DB에 sh scripts/provision_database.sh, canonical import 재실행, Alembic 재실행 최초 import 48 artifacts/revisions, 재실행 no_change=true; modality/revision/glossary 카운트 [17,48,158] 무변경. 생성한 검증 DB만 제거
4/C8 2026-09-03 Docker runtime·data-init target build와 container filesystem/CMD 검사 기본 runtime에 /app/data, /app/import-data, importer·bootstrap·임상 JSON 0; data-init에만 입력 corpus와 one-off provision 명령 존재
3·4/C9 2026-09-03 uv run pytest -q, npm run lint, npm run build, Ruff, Alembic check Backend 513 passed, 공개 43 operations 구조 기준선 PASS, Frontend lint·Next 16 production build PASS, schema drift 0
4/C9 2026-09-03 수정된 scripts/shadow_compare_insight.py와 현재 canonical candidate DB C6 service 생성자 변경으로 깨진 runner를 explicit legacy fixture evaluator로 복구; safety 27/27, mismatch 0
2·5/C9 2026-09-03 publication·rollback·retrieval·shadow·공개 계약 집중 묶음 17 passed. 과거 revision 집합을 새 published release로 복구하는 원자적 rollback, 미발행 row 격리, release-scoped verified evidence gate PASS
3·4·5/C9 2026-09-03 로컬 production BE·Next 실기동 표 기반 HTTP smoke BFF/BE 30개 데이터 계약, 21개 화면, locale fallback·invalid 400 모두 PASS. 미발행 retrieval은 unavailable, data_revision=null로 fail-closed
2·3·4/C9 2026-09-03 미배포 0045~0047 migration consolidation과 격리 DB 왕복 compatibility metadata·safety caveat DDL까지 최종 0045 하나로 합침. 신규 DB upgrade·drift 0, 0045→0044→0045 재구성, 48 revisions·612 procedures·774 claims 복원, 반복 import no_change=true
6/C9 2026-09-03 Azure CD workflow·Docker target·운영 CLI 검증 CD가 runtime과 ${env}-data-init을 함께 push하되 runtime만 자동 배포하도록 분리. 3개 운영 CLI의 container .env load, 두 target build, actionlint PASS
5/C9 2026-09-03 scripts/evaluate_canonical_retrieval.py, 단일 fail-closed 평가 test 공개 retrieval API 기준 entity·safety rule·claim/source·verified evidence·abstention·release 일관성·latency를 한 runner에서 판정. 임상 미승인 fixture는 HTTP 호출 전 종료 코드 2로 차단; 집중 회귀 14 passed
1/C9 2026-09-03 manage_canonical_release.py review-queue를 현재 canonical DB에 실행 read-only 검수 queue가 mapping 3건과 validation 78건(pmid_not_found 2, pmid_unverified 72, taxonomy_mismatch 4)을 누락 없이 반환하고 모든 validation에 source revision을 제공; release_ready=false 유지
1/C9 2026-09-03 legacy prefix와 다른 정확 시술명 3건을 canonical mapping registry에서 기술 확정 후 fresh DB import mapping issue 0, ProcedureSynergy 115건, blocking validation 78건; 임상 근거 gate는 그대로 fail-closed
1/C9 2026-09-03 ClinicalClaimReviewApplication·review_clinical_claim.py, 집중 transaction test와 실제 local DB inspect DI Application 경계에서 inspect·verify·reject 제공. usable source 없는 승인 rollback, verification·reviewer audit 각 2건 보존. 교차 순서 집중 회귀 17 passed, 전체 backend 522 passed. 실제 CLM-M1-MOA-001 claim/source 조회 성공
5/C9 2026-09-03 Canonical Retrieval API adapter 경계 교정, 전체 backend regression·Alembic check Router가 Pydantic↔internal command/result 변환을 소유하고 Service의 app.schema 의존을 제거. 공개 request/response model 유지, 514 passed, schema drift 0
5/C9 2026-09-03 Canonical Retrieval 로컬 CLI DI Container에서 API와 동일한 CanonicalRetrievalService를 직접 실행하도록 연결. 집중 회귀 7 passed, 공개 contract diff 0, 미발행 DB에서 의도한 unavailable fail-closed 확인
5/C9 2026-09-03 OPENAI_API_KEY 등 OpenAI 환경 변수를 제거한 격리 directory에서 codex exec --ephemeral --ignore-user-config --sandbox read-only 실행 codex login status가 ChatGPT 로그인을 확인했고 비대화형 smoke가 exit 0과 LOCAL_CODEX_AUTH_OK를 반환. 로컬 생성기의 별도 프로젝트 API key 불필요 조건 증명
5/C9 2026-09-03 RagQueryApplication 집중 contract test와 실제 Codex CLI synthetic Context Pack smoke 6개 경계 case 포함 집중 회귀 13 passed. 유효 답변은 procedure:M1과 고정 safety 문구를 반환했고, 현재 미발행 DB의 실제 CLI는 generator를 호출하지 않고 skipped로 fail-closed
5/C9 2026-09-03 배포용 OpenAIResponsesAnswerGenerator request/response contract test 공식 Responses structured output 형태, strict=true, store=false, 동일 GeneratedAnswer 검증을 credential 없는 fake transport로 확인. Retrieval·공개 계약 집중 회귀 14 passed
5/C9 2026-09-03 synthetic published release DB에서 실제 retrieve_canonical.py --generate-answer end-to-end 실행 최초 출력에서 단일 citation으로 근거 부재를 추론한 결함 발견. Context를 원자적 source fact로 축소하고 문장당 ref 1개로 제한한 뒤 재실행하여 5개 문장 모두 정확한 procedure·safety·claim·policy ref와 고정 safety 문구를 반환
5/C9 2026-09-03 /insights/query compatibility 연결과 공개 contract·전체 backend 회귀 legacy entity·safety·source ref는 그대로 두고 생성 성공 시 answer만 canonical RAG 결과로 교체. /insights/retrieve 불변, OpenAPI fingerprint 불변. 집중 회귀 18 passed, 전체 backend 523 passed
4·6/C9 2026-09-03 Canonical 0045 upgrade 정적 검사와 Azure CD rollback 경로 upgrade가 기존 table alter/drop 없이 additive create만 수행함을 확인. CD가 직전 runtime을 ${env}-rollback으로 보존하고 runtime/data-init을 commit SHA로 immutable tagging하도록 준비; 실제 복구 실행은 STG gate에 유지
1/C9 2026-09-03 주간 문헌 수집기 NCBI identity gate와 taxonomy mapping 교정 새 citation은 공식 NCBI title·year exact match를 통과해야 병합되고 불일치/미조회/식별자 없음은 제거. M11↔M12와 M13·M14 수집 정의를 canonical taxonomy에 맞춤; Node gate 1 passed, ESLint·actionlint PASS. 기존 78건은 자동 변경 없이 검수 차단 유지
1/C9 2026-09-03 기존 citation enrichment의 NCBI identity gate --enrich-only와 수집 후 enrichment도 모든 PMID의 공식 title·year를 재검증하고 일치한 citation에만 DOI·PMC·OA URL을 추가함. 불일치 citation이 메타데이터로 강화되지 않는 회귀 gate와 ESLint PASS
1/C9 2026-09-03 NCBI metadata 기반 literature-evidence v2.0 교정과 개발·테스트 DB 재적재 A군은 PMID만 바꾸지 않고 전체 citation metadata를 교체하고 B/C·식별자 없는 citation은 제외. M11/M12는 canonical taxonomy로 교환하고 M13/M14의 오매칭 claim은 제외해 25 verified source·119 claim/citation, mapping 0·blocking validation 0을 확인. 5434 빈 DB provision과 전체 backend 523 tests PASS, 반복 import no_change=true, 빈 review queue, release_ready=true
2/C9 2026-09-03 Canonical 최초 적재 write 경계와 기존 DI Container import·publication Repository를 기존 dependency-injector Container가 주입하고 CLI가 Application의 transaction을 사용하도록 교정. 집중 회귀 6 passed, 전체 backend 514 passed, Alembic drift 0, PostgreSQL 재실행 no_change=true·48 revisions·612 procedures 확인
1 2026-09-03 로컬 DB 적재·회귀 검증 기록 (git show b9aae70:docs/local-db-load-proof.md) mapping 0건·blocking validation 0건. 식별자·taxonomy 교정 완료, claim·revision 임상 승인 HOLD
2 2026-09-03 로컬 DB 적재·회귀 검증 기록 (git show b9aae70:docs/local-db-load-proof.md) 구현 PASS·최초 publish HOLD
3 2026-09-03 C3~C7 endpoint별 기존 fixture exact parity와 C9 전체 회귀 DB Repository→Service→Router presenter로 전환한 30개 BFF/BE 데이터 계약의 비승인 구조·의미 diff 0; VERIFIED
4 2026-09-03 로컬 DB 적재·회귀 검증 기록 (git show b9aae70:docs/local-db-load-proof.md), C3~C9 cutover 증거 runtime 임상 JSON read/write 0, safety 27/27, 로컬 핵심 smoke 0 failure. immutable image rollback 구현 완료·STG 실행 대기
5/U1 2026-09-03 범용 Retrieval API 설계와 실제 Service/caller 대조 기존 구현이 6개 intent·고정 section·exact entity 조회에 한정됨을 확인. 전체 published domain을 검색하는 Knowledge Item contract와 U1~U7 gate로 Task 5 범위를 교정; 구현은 IN_PROGRESS
5/U1~U5 2026-09-03 전체 backend 정적 검사·회귀 및 로컬 PostgreSQL baseline 검증 전체 48개 data domain 분류(검색 36·해석 전용 9·제외 2·mapping 1), 검색 unit 4,178개 projection 증명, 미분류 0. ruff 통과, pytest 498 passed. 게시 릴리스가 없는 실제 HTTP는 status=unavailable로 fail-closed 확인
5/U6 2026-09-03 /knowledge-retrieval Inspector와 Next BFF 실제 렌더·상호작용 검증 실제 로컬 API의 publication gate, 일회성 응답을 사용한 결과 목록→상세 선택→출처·안전·coverage 추적을 Orca 브라우저에서 확인. console error 0, Next lint·typecheck·production build 통과
2·5/U6 2026-09-03 격리 procedure_hub_preview DB에서 미검수 표시 local release 발행 후 FastAPI·Next BFF·Orca 브라우저 실기동 배열형 revision snapshot의 publication 변환 결함을 교정. API·BFF status=ok, 10건 반환, 서버 200·browser console error 0 확인. 운영 snapshot과 Task 1 임상 승인 상태는 변경하지 않음
5/U5 2026-09-03 fields 선택 응답 public contract·실제 local preview HTTP 검증 fields 생략 시 기존 11개 최상위 필드 유지, items+safety 선택 시 공통 5개와 선택 2개만 반환, 빈 배열은 공통 필드만 반환, 미지원 값 422. 집중 회귀 6 passed
4/C8 2026-09-03 단일 Alembic baseline + PostgreSQL data snapshot을 빈 로컬 DB에 복원 b202609030001 upgrade와 data-only restore PASS. 166개 앱 table row count mismatch 0, 전체 backend 420 passed, runtime image legacy path 0. 로컬 main DB는 데이터 변경 없이 새 head로 stamp·drift 0
6/6-1 2026-09-03 Next server Backend origin 단일화와 Vercel STG env 교정 PROCEDURE_API_BASE 직접 참조 1곳, production 누락·path 포함 값 fail-closed, lint·Next build PASS. local BFF taxonomy·glossary body exact, knowledge items+safety 200
6/6-2 2026-09-04 Runtime image·CD workflow·중앙 Bastion deploy script 검증과 INFRA PR #21·#22·#23 반영 image filesystem·history의 .env 0, Backend 421 passed·Alembic drift 0, actionlint·Docker runtime build PASS. build context를 Backend로 제한하고 lockfile frozen install 적용. CD의 env bundle 전달을 제거하고 VM 로컬 mode 600 env-file을 Procedure Hub container에만 연결하는 경계로 교정. 빈 파일 또는 DATABASE_URL 누락 시 기존 container 정리 전에 실패하도록 보강. INFRA Bastion sync success
6/6-3 2026-09-04 Azure VM·DB·Gateway read-only STG preflight 현재 runtime health 200과 과거 revision b0c1d2e10042 확인. VM env owner/mode azureuser:azureuser 600, 필수 key 존재, DB owner·CREATE 권한 true, pg_trgm 미설치 확인. full rollback DB backup 883,341 bytes, cutover snapshot 1,591,517 bytes·SHA256 6f7cca1146fd925b6e457a7e8be4774810a6269a8551a8fdd703728cba854c9a 확인. Gateway needsAuth:false write 노출 결정과 실제 destructive cutover는 대기
6/6-4 2026-09-04 CI/CD를 거치지 않은 STG VM 수동 canonical cutover 전환 직전 full backup pre-manual-cutover-20260904T005629Z.dump 생성·목록 검증 후 DB를 b202609030001 baseline과 canonical snapshot으로 교체. immutable amd64 image stg-81060b4d…(sha256:a49d9dd6…) 직접 기동. pg_trgm은 Procedure Hub DB에만 설치되고 공유 DB 4개는 0임을 확인. Gateway health·config·OpenAPI·taxonomy·Knowledge endpoint 모두 200, publication gate는 release 미발행으로 unavailable 정상 동작. 이전 중지 container는 smoke 후 제거하고 full backup과 ACR image를 rollback 단위로 유지
6/6-5 2026-09-04 Vercel 수동 STG 배포와 검색용 test release 발행 commit b89164b를 preview deployment dpl_5mF5mcyvyKK5BLyLo9kAvbv9hAJC로 빌드하고 stg-procedure-hub.medisolveai.com alias를 연결. mapping·validation issue 0을 확인한 뒤 STG smoke actor로 48개 revision을 승인하고 test release stg-2026.09.04.1(d75d8f4e-51f0-47eb-b8c7-26b4b08038e7) 발행. FE BFF와 BE direct retrieval 모두 status=ok, item 18·safety 4·limitations 0, taxonomy modality 17·problem 14 확인. 이 test 승인은 피부과 의사의 PROD 임상 승인 근거로 사용하지 않음
6 2026-09-04 위 6-4·6-5의 수동 STG 배포·test release 기록 수동 검증 완료. PROD 임상 승인과 자동 CD 검증 완료를 뜻하지 않음
7 — 의도적 후순위 대기

8. 컨텍스트 복구 절차

새 세션이나 요약된 컨텍스트에서 이 작업을 이어갈 때 다음 순서만 따른다.

  1. 이 문서의 고정 결정, 현재 상태, 검증 증거 원장을 읽는다.
  2. 현재 Task가 참조하는 상세 설계 문서만 추가로 읽는다.
  3. git status와 최근 commit을 확인하되 사용자 변경을 되돌리지 않는다.
  4. 문서의 상태를 믿고 완료로 가정하지 않고 실제 코드와 마지막 검증을 대조한다.
  5. 구현 전에 해당 Task의 최소 테스트가 과도하거나 중복되지 않는지 확인한다.
  6. 작업 종료 전에 상태, blocker, 실제 검증 결과와 다음 gate를 이 문서에 갱신한다.

채팅 전문이나 일시적인 추측은 기록하지 않는다. 이후 작업자가 판단과 검증을 재현하는 데 필요한 결정, 상태, blocker, 증거만 남긴다.

9. 결정 기록

날짜 결정 이유
2026-09-03 기존 공개 API의 응답 구조와 의미를 변경하지 않는다. 다른 서비스가 이미 소비하고 있어 내부 전환이 외부 계약을 깨면 안 된다.
2026-09-03 legacy의 선제 제거·전수 검증·병행 운용에 추가 리소스를 쓰지 않는다. 신규 경로는 canonical DB만 사용하고 기존 코드는 직접 충돌할 때만 정리한다. 짧은 점검 중단을 허용하므로 무중단 strangler와 이중 경로의 비용이 제품 가치보다 크다.
2026-09-03 Canonical Application과 Repository는 기존 dependency-injector Container에서 조립하며 생성자 내부 fallback 생성을 두지 않는다. 프로젝트의 thready 계열 DI 규칙을 따르고 CLI·HTTP 어디서든 같은 의존성 경계를 사용하기 위함이다.
2026-09-03 Retrieval은 배포 전 로컬 CLI와 배포 후 API가 동일한 DI Service를 사용한다. STG 배포는 Task 0~5 기능과 검수가 모두 완료된 뒤에만 시작한다. 로컬 검증용 로직 복제를 막고 미완성 기능을 STG에 먼저 올리지 않기 위함이다.
2026-09-03 기존 /insights/query의 optional 답변 생성은 RagQueryApplication과 환경별 generator DI를 유지하되, 범용 /insights/retrieve는 Context Pack 조회만 소유한다. 관련 정보 검색과 최종 문장 생성을 분리하고, 범용 Retrieval이 특정 LLM provider나 생성 성공 여부에 의존하지 않게 하기 위함이다.
2026-09-03 새 코드와 실제 수정하는 코드는 현재 Domain·Service·Repository 경계를 따른다. 신규 부채를 만들지 않되 기존 동작 코드의 일괄 정리는 뒤로 미룬다.
2026-09-03 테스트 수나 coverage를 목표로 하지 않는다. 제품 판단을 보호하는 최소 테스트만 유지하고 중복 test code를 피한다.
2026-09-03 이 문서가 Task 0~7의 실행 상태와 증거를 단독 소유한다. 컨텍스트 요약 후에도 한 문서에서 작업을 재개하기 위함이다.
2026-09-03 화면은 조회 중심으로 두고 모든 persistence write는 BE Application Service 경계 안에서 수행한다. Domain 규칙·transaction·audit·publication을 우회하는 화면/JSON/DB 직접 수정을 막기 위함이다.
2026-09-03 실제 반복 호출자가 없는 고위험 write는 HTTP API 대신 CLI로 유지한다. 불필요한 공개 surface와 인증 코드를 만들지 않으면서 동일한 Domain 경계를 재사용하기 위함이다.
2026-09-03 runtime 임상·업무 데이터의 JSON 직접 read/write 제거를 Task 4·6의 cutover gate로 둔다. DB 전환 뒤에도 파일을 운영 원본으로 읽거나 덮어쓰면 정합성·transaction·audit 경계를 우회하기 때문이다.
2026-09-03 Docker runtime은 migration과 API만 포함하고 seed/importer/data-init을 두지 않는다. 재현 도구를 운영 코드로 유지하는 비용 없이 DB를 단일 source of truth로 만들기 위해서다.
2026-09-03 STG 미반영 migration 전체를 b202609030001 단일 schema baseline으로 합친다. 로컬 중간 migration 이력을 운영에 노출하지 않고 최초 물리 DB 반영 단위를 하나로 유지하기 위해서다.
2026-09-03 초기 데이터는 PostgreSQL custom-format snapshot 하나를 운영자가 수동 복원한다. 자동 seed와 legacy importer를 제거하면서 현재 DB 상태를 그대로 전달하기 위해서다.
2026-09-03 자연어 retrieval 평가는 피부과 의사가 승인한 단일 fixture만 허용하고 미승인 상태에서는 fail-closed한다. 잘못된 PMID·mapping을 개발자가 expected 결과로 고정해 자기검증하는 것을 막고, 공개 API·release 단위의 품질을 재현 가능하게 판정하기 위함이다.
2026-09-03 Canonical Retrieval의 Pydantic 변환은 Router에만 두고 Service는 immutable internal command/result를 사용한다. 신규 코드의 Router/Application/Domain 경계를 지키면서 이미 동결한 공개 API 구조와 의미를 그대로 보존하기 위함이다.
2026-09-03 JSON legacy feature flag 대신 additive DB migration과 immutable runtime image rollback을 사용한다. runtime JSON 의존 0이라는 cutover 조건을 되돌리지 않으면서 애플리케이션 결함과 content release 결함을 서로 독립적으로 복구하기 위함이다.
2026-09-03 문헌 수집·enrichment 단계에서 모든 PMID를 공식 NCBI title·year와 exact 검증하고 실패 citation은 병합하거나 DOI·PMC·OA URL로 보강하지 않는다. 존재하는 다른 논문의 PMID가 잘못된 citation을 새로 만들거나 기존 오염 citation을 더 신뢰할 수 있어 보이게 만드는 경로를 source에서 차단하기 위함이다. 기존 자료는 자동 교정하지 않는다.
2026-09-03 각 완료 단위를 검증 후 별도 commit으로 고정한다. 변경 범위와 완료 기준을 추적하고 문제 발생 시 독립적으로 판단·복구하기 위함이다.
2026-09-03 FastAPI 공개 operation 기준선을 C7의 evidence integrity·i18n read까지 포함한 43개(read 33, write 9, conditional-write 1)로 갱신한다. Next 임상 route의 파일 read를 제거하면서 기존 URL·응답은 유지하고 새 BE read surface를 누락 없이 동결하기 위함이다.
2026-09-03 9개 임상 compatibility read는 공통 Repository·Service와 endpoint별 명시 메서드를 사용하고, 전체 leaf 계약은 단일 exact parity test로 보호한다. 역할 없는 클래스 9세트를 만들지 않으면서 persistence/application/presenter 경계를 지키고 테스트 중복을 피하기 위함이다.
2026-09-03 treatment-optimization.caveats를 안전 정보 자식 엔티티로 보존한다. 기존 모델 누락으로 안전·근거 주의사항이 응답에서 유실되는 것을 exact parity 검사에서 발견했기 때문이다.
2026-09-03 /api/v1/extracted는 최신 immutable legacy ContentRevision을 읽고, Next /api/extracted는 map을 기존 array로 변환한다. FastAPI를 쓰는 Linky의 map 계약과 기존 Procedure Hub 화면의 array 계약이 달라 단순 프록시하면 소비자가 깨지며, 두 계약 모두 runtime 파일 read 없이 보존해야 하기 때문이다.
2026-09-03 legacy /insights/query는 published-release 전용 retrieval로 합치지 않고 최신 imported ContentRevision 3종을 읽는 compatibility adapter를 사용한다. 최초 release가 임상 검수 blocker로 보류된 상태에서도 기존 query 기능을 유지해야 하며, resolver·Safety·contraindications.json#rules[index] selector의 구조와 의미를 바꾸면 기존 소비자가 깨지기 때문이다. DB transaction은 source load 직후 종료해 OpenAI 호출을 포함하지 않는다.
2026-09-03 문헌 화면의 taxonomy·PMID integrity와 legacy /api/i18n/{lang} 응답은 최신 imported ContentRevision에서 읽는다. 언어 Provider는 선택 상태만 소유한다. 정적 i18n bundle은 실제 UI에서 소비되지 않았고, 환자 언어 전환은 DB 문헌 응답의 patient 표현을 선택하는 데만 사용됐다. 기존 locale endpoint와 fallback 계약을 유지하면서 runtime JSON 의존을 제거하기 위함이다.
2026-09-03 기존 BE admin write 인증 책임은 Gateway에 두고 실제 차단은 STG에서 증명한다. 저장소 규칙은 BE 직접 인증을 금지하며 현재 코드만으로 외부 Gateway 실재를 증명할 수 없기 때문이다.
2026-09-03 /insights/retrieve는 query 하나로 모든 searchable PHub domain을 검색하는 범용 Context Pack API로 교체한다. intent는 ranking에만 쓰고 검색 domain을 제외하지 않는다. 호출자가 PHub의 메뉴·테이블·분류를 알아야 하는 구조는 “어떤 query든 관련 정보를 모두 전달한다”는 API 목적과 맞지 않기 때문이다. 현재 endpoint는 STG·PRD 미배포이고 repository 내부 runtime caller가 없어 별도 v2·호환 계층을 만들지 않는다.
2026-09-03 /knowledge/retrieve는 optional fields로 interpretation, items, sources, safety, coverage, retrieval을 선택 반환한다. 서비스별로 쓰지 않는 대용량 섹션까지 전송하지 않되, 생략 시 전체 응답을 유지하고 request/status/query/limitations/data revision 추적성은 항상 보존하기 위함이다.