산모 예약 계약 동의·서명 Gap Mining
이 페이지는 P04-mother-reservation-chat의 계약 동의·서명 source truth다.
ADR-032가
결정 권위를 소유하고, 이 페이지는 구버전에서 확인한 사실과 아직 승인되지 않은 정책을
분리한다. 아래 레거시 문구와 파일은 마이그레이션 근거이지 운영 정책 seed가 아니다.
구버전 A→Z
Section titled “구버전 A→Z”| 순서 | 실제 동작 | Source |
|---|---|---|
| 1 | 결제 직전 화면이 서비스 유형에 따라 서명이 적용될 문서 목록을 다르게 보여준다. 바우처는 6종, 일반은 3종이다. | source-refs/sanmopia_web/application/views/service/reservation_payment.php:44-61 |
| 2 | 산모가 개인정보 처리, 고유식별정보 처리, 민감정보 처리, 제3자 제공 네 항목을 각각 체크한다. | reservation_payment.php:63-115 |
| 3 | 첫 세 항목의 보기는 모두 같은 agree.png, 제3자 제공은 3rd.png를 연다. 체크박스와 상세 문서가 일대일이 아니다. | source-refs/sanmopia_web/static/js/reservation_payment.js:15-34 |
| 4 | JavaScript가 네 항목 전체 동의와 canvas 서명을 모두 요구한다. | reservation_payment.js:40-49, reservation_payment.js:92-112 |
| 5 | 브라우저가 PNG data URL 전체를 sign_image form field로 먼저 업로드한다. 이 성공 뒤에만 0원 처리 또는 KCP 결제로 진행한다. | reservation_payment.js:51-89 |
| 6 | API는 path의 숫자 예약 id로 현재 SIGN_IMG_URL을 읽고 새 random PNG를 쓴 뒤 DB 경로를 교체한다. | source-refs/sanmopia_web/application/controllers/api/Service.php:869-882, source-refs/sanmopia_web/application/models/Payment_model.php:12-37 |
| 7 | 이전 서명 파일은 즉시 삭제된다. 동의 item, 문구 revision, 문서 digest, 개별 선택, 서명 checksum·object version·보존 정책은 저장하지 않는다. | Payment_model.php:38-42 |
상세 이미지 source fingerprint:
| Source asset | SHA-256 | 레거시 사용 |
|---|---|---|
static/image/service/payment_agree/agree.png | 7b5210e81d0db23e696598e1f2451e680b9d7ccc79a410c11c12128379bdc09f | 개인정보·고유식별정보·민감정보 세 항목이 공유 |
static/image/service/payment_agree/3rd.png | 3eee35cf8ac7781d5f1c1e455cd31c5126c662a2268b9f15afef9bfb4686bba5 | 제3자 제공 |
원본 bytes는 source manifest와 함께 문서 증거 폴더에 고정했다. 아래 이미지는 현대 정책 승인이 아니라 구버전 동작을 감사하기 위한 byte-identical snapshot이다.
Manifest classification은 historical_source_only다. source drift gate가 이미지 bytes뿐
아니라 화면, JavaScript, API, mutable 저장 model의 전체 SHA-256과 핵심 marker를 검증한다.
upload/sign/**의 실제 구버전 서명은 개인 식별 가능 정보라 복사·공개하지 않는다.
개인정보·고유식별정보·민감정보가 공유한 구버전 상세 이미지

제3자 제공 구버전 상세 이미지

확인된 결함
Section titled “확인된 결함”- 체크박스 네 개는 DOM 상태일 뿐 서버 acceptance evidence가 아니다.
- 세 항목이 같은 이미지에 연결돼 어떤 세부 문구를 각각 수락했는지 분리해 증명할 수 없다.
- 이미지 파일명에는 효력 기간, 승인자, 문서 revision, wording revision이 없다.
- 서명 업로드와 결제·예약 확정은 하나의 원자적 transaction이 아니다.
- API 경계에서 path 예약 id와 로그인 산모의 소유권을 명시적으로 대조하지 않는다.
- 새 서명이 mutable
SIGN_IMG_URL을 덮고 이전 파일을 삭제하므로 역사 문서가 drift한다. - base64 원문이 browser request에 실리고 서버는 크기, digest, object version, expiry를 동의 evidence와 함께 고정하지 않는다.
- 바우처와 일반의 적용 문서 집합이 다른데도 현대 bundle을 하나의 전역 current row로 선택하면 잘못된 계약을 표시할 수 있다.
현대화 SSOT
Section titled “현대화 SSOT”document_reporting domain policy → reservation_operations consumer-owned query/evaluator ports → Supabase immutable bundle revision + ordered items + source evidence → server final-review projection → browser item intent + opaque signature reference → exact bundle reload + owner-bound signature verification → reservation confirmation과 같은 primary-data transaction각 item은 최소한 다음 사실을 가져야 한다.
- stable
acceptanceItemCode; - document code, document version, document content digest;
- 승인된 표시문구, wording revision key, wording content digest;
- required 여부와 source order.
Bundle은 effective window, 적용 조건, signature-policy revision, retention-policy revision, source evidence, supersession과 canonical fingerprint를 가진다. 여러 item이 같은 legacy document digest를 공유하는 것은 허용하되 item code와 wording revision은 각각 명시한다.
서명 bytes는 public command, 로그, screenshot, WebP, 공개 bucket에 포함하지 않는다. 브라우저는 contract-first upload로 opaque reference만 받고, backend가 owner, ready 상태, 정책 revision, content type, digest, immutable object version, capture/expiry를 다시 확인한다. Evidence는 추가로 owner, draft, review projection, reviewed fingerprint, bundle revision에 결합하고 같은 confirmation transaction에서 정확히 한 번 소비한다. 다른 예약이나 변경된 문구에 같은 서명을 재사용하는 의미론은 승인하지 않았다.
Publication은 HQ actor와 별도 승인 decision이 exact payload에 결합된 경우만 허용한다. Confirmation은 caller 시간을 법적 시각으로 신뢰하지 않고 DB command time으로 정규화하며, publication과 같은 advisory authority lock 아래에서 current bundle을 다시 선택한다.
2026-07-19 구현·검증 현황
Section titled “2026-07-19 구현·검증 현황”Backend 731f321d0564cdee752fd86b8a7b926fec09ac92는 법률 값을 seed하지 않은 채
immutable bundle revision, ordered item, source evidence, exact approval payload, current/exact
조회와 confirmation-time 재검증을 구현했다. Publication은 exclusive authority lock,
confirmation은 shared lock을 사용한다. DB가 저장 draft와 review projection을 다시 잠그고
canonical command time으로 acceptance, booking handoff, waiting payment obligation, outbox를
한 transaction에 기록한다. Signature evidence는 owner/draft/review revision/fingerprint,
bundle revision/content digest와 bundle 순서의 선택 item에 결합되고 같은 transaction에서
append-only READY → CONSUMED로 한 번만 전이된다. 동일 idempotency replay는 승자 row를 반환하고 다른
fingerprint·wording·document·bundle·payment lineage는 전체 무변경으로 거절한다.
service_role의 command direct INSERT/UPDATE/DELETE도 제거했다.
새 capture 경계는 raw image/png body만 최대 1 MiB로 받는다. PNG
signature/chunk/CRC/IEND를 검사하고 APNG, trailing polyglot, blank 또는 너무 작은 ink,
64..2048 × 32..1024 밖 dimension을 거절한다. Pillow가 전체 decode한 뒤 alpha를 흰 배경에
합성하고 metadata 없는 RGB PNG로 다시 인코딩하며 canonical digest를 계산한다. Backend만
private customer-reservation-signatures bucket에 upsert=false로 저장하고, DB가 만든
opaque evidence reference와 random object key만 사용한다. 동일 digest 응답 유실은
reconcile하고 다른 digest collision은 거절한다. PENDING orphan과 expired unconsumed READY는
fenced cleaner가 삭제하며 READY tombstone을 보존하고, CONSUMED object만 승인된 retention과
legal-hold 정책을 따른다.
검증 결과는 다음과 같다.
| Gate | 실제 결과 | 판정 경계 |
|---|---|---|
| Supabase full replay | CLI 2.109.1, migration 320/320, latest 20260719120000, DB lint/auth schema/storage migrations, catalog smoke 7, exact-26, contract/signature smoke PASS | local disposable DB 증거. stage/production 적용 아님 |
| Actual Storage lifecycle | pinned Storage API canonical PNG POST→GET SHA-256 일치→immutable collision→anonymous existence hiding→DELETE→missing; production adapter roundtrip, PENDING orphan cleanup, READY consume-vs-cleaner 2-session race, disposable cleanup PASS | 실제 private Storage/backend gate. owner browser confirm 증거 아님 |
| Backend regression | Python 7,250 passed, existing Starlette warning 1; Ruff PASS, Tach all/exact diagnostic 0 | 계약·예약 권위 code/DB gate |
| Vulture 100 | changed P04 slice candidate 0 | 정적 분석 보조 근거 |
| Contract/frontend | contract ba6df817, frontend e833eb15; canonical raw image/png upload, server wording/revision/digest 표시, 필수·선택 item, canvas·binding invalidation·pixel cleanup | UI와 transport 계약 gate |
브라우저 증거는
manifest에
고정했다. 실제 Chromium desktop/mobile이 열 카드를 하나씩 열고 계약 item을 표시하며,
pointer/touch/keyboard canvas에서 서명한다. 등록 뒤 Blob과 canvas pixel을 제거하고,
item/review binding 변경은 이전 opaque reference를 폐기한 뒤 redraw를 요구한다. Desktop과
390px mobile은 raw PNG upload를 각각 3회 수행하고 mock confirm까지 완료했다. 다만 API는
stateful mock, 법률 값과 stroke는 synthetic_test_only이므로 실제 승인·backend
confirm·영속화 증거가 아니다.



2026-07-20 통합 실행 근거
Section titled “2026-07-20 통합 실행 근거”동일 full replay의 terminal 관찰은 Supabase CLI 2.109.1, migration 321/321, latest
20260719123000과 fixture/runtime cleanup PASS를 기록했다. Backend 85f127ef 재실행은
cleanup-source-receipt.json과
cleanup-manifest.json을
추가해 browser manifest/run-summary SHA, 네 repository pin, 잔여 resource 0을 고정했다.
통합 manifest은
네 repository pin, 실제 GoTrue/Astro/FastAPI/PostgREST/Storage runtime과 desktop/mobile
confirmation 관찰값을 고정한다. 각 viewport는 서로 다른 test-owned draft에서 raw PNG를
canonicalize해 private bucket에 저장하고 READY evidence를 등록한 뒤 같은 transaction으로
READY → CONSUMED, accepted evidence, booking/payment handoff와 outbox를 기록했다. 첫
confirm과 exact replay는 모두 HTTP 201, evidence/consumption/command cardinality는
1/1/1이다.
시각 asset 53개는 수동 개인정보 검수를 마쳤고 raw signature bytes, bearer token,
idempotency key, UUID와 실제 인물 정보는 공개 artifact에 없다. Bundle publisher, approval,
wording, signature/retention policy는 화면과 manifest에 synthetic_test_only로 표시했다.
따라서 이 run은 architecture와 구현 연결을 증명하지만 실제 법률 문구 승인이나 운영 publication
결정을 대신하지 않는다. legalApprovalProof=false, productionContractAuthorityProof=false,
completionClaim=false다.
2026-07-20 산모 화면 문구 정합성
Section titled “2026-07-20 산모 화면 문구 정합성”Frontend 2ca15a8은 표시명·열람 URL·보존 안내가 없는 현재 server bundle을 문서 열람
기능처럼 설명하던 문구를 제거했다. 화면은 server-owned displayWording 확인과 항목 선택만
안내한다. Legacy PNG를 운영 문서로 승격하거나 기술 식별자를 노출하지 않는다. View/store/
signature/client focused 61, full Vitest 642, ESLint, Astro 7.1 check와 production build가
통과했다. 새 screenshot·WebP나 실제 actor run은 만들지 않았으므로 기존 P04 증거 pin과
RED 판정은 바뀌지 않는다.
운영 publication 전 미해결 정책
Section titled “운영 publication 전 미해결 정책”아래 값은 source code에서 추측해 seed하지 않는다.
- 네 legacy label을 대체하는 canonical item code와 각 항목의 정확한 표시문구.
agree.png내부 내용을 개별 item 문구로 분리할지, 하나의 versioned document로 유지할지.- 바우처·일반·연장·상담·사전예약별 적용 bundle selector.
- drawn signature가 항상 필수인지와 허용 capture/content type.
- 서명·동의 evidence 보존기간, 폐기·legal hold·열람 정책.
- 과거 이미지 두 개를 승인된 현대 문서로 가져올지, 새 법무 문서를 발행할지.
승인용 source-derived 초안
Section titled “승인용 source-derived 초안”결정 속도를 늦추지 않도록 구버전에서 기계적으로 옮길 수 있는 후보를 별도로 적는다. 이는 publication payload나 운영 seed가 아니며 법무·상품 승인 전에는 사용할 수 없다.
| 순서 | Candidate item code | 구버전 표시문구 | 상세 source |
|---|---|---|---|
| 1 | personal_information_processing | 개인정보 처리에 동의하십니까? | agree.png |
| 2 | unique_identifying_information_processing | 고유식별정보 처리에 동의하십니까? | agree.png |
| 3 | sensitive_information_processing | 민감정보 처리에 동의하십니까? | agree.png |
| 4 | third_party_information_provision | 제3자 제공에 동의하십니까? | 3rd.png |
구버전 동작만 기준으로 하면 네 항목과 canvas 서명은 모두 필수다. agree.png에 적힌
전자이용권 이용자격 종료 후 5년까지는 바우처 개인정보의 legacy 보유 문구이지,
현대 계약 동의·서명 evidence 전체의 retention 결정으로 자동 승격할 수 없다.
- 무시드 DB에서는 current bundle 조회가 정확히
none이고 final review가 fail-closed다. - 승인 publication은 exact replay만 허용하고 같은 key의 다른 사실은 conflict다.
- current 조회는 적용 조건과 효력 시간이 정확히 하나일 때만 성공한다.
- exact historical 조회는 supersession 뒤에도 동일 payload와 fingerprint를 반환한다.
- 변경된 wording/document/signature/retention revision은 이전 browser intent를 거절한다.
- 필수 item 누락, unknown item, 다른 owner 서명, pending/expired evidence, digest/content-type drift는 reservation·payment·outbox를 하나도 만들지 않는다.
- desktop/mobile은 서버 표시문구를 그대로 보여주고 기술 키를 주 문구로 대신하지 않는다.
- 실제 actor browser, primary DB, exact replay/conflict, cleanup, screenshot, animated WebP가 같은 네 repository pin으로 수집된 뒤에만 P04 legal gate를 GREEN으로 올린다.