## 2026-11-12 배포 인계
[개발·배포 가이드](docs/DEPLOYMENT_GUIDE.md) · [아키텍처](docs/ARCHITECTURE.md) · [외부 연동](docs/EXTERNAL_INTEGRATIONS.md)
# BLOCKSIGN v0.13
배포 서버 전자계약: `contracts.html` · 전체 시연: `platform-demo.html` · 인계: `docs/HOSTED_SIGNING.md`.
아래 이전 버전 기록보다 최신 인계 문서가 우선합니다.
# 블록싸인 v0.12 — 원격 공증 · 전체 플랫폼
전체 시연 `platform-demo.html`, 전체 개발 `platform-development.html`. 모든 서비스 메뉴를 공통 표시. 신분증 진위·원격 의사 확인·비동기 시연·공식 서식 기반 샘플 추가. `docs/REMOTE_NOTARY.md`를 먼저 읽으세요.
# 블록싸인 v0.11 — 공증 역견적 및 CLI 인계
계약서 제출부터 리포트·공증사 비교·선택·결제·일정·면담·발급·수령까지 고객 순서로 진행합니다. 별도 시연과 개발 소스를 제공합니다. [변경점](docs/REVERSE_QUOTES.md), [Codex CLI 인계](docs/CODEX_CLI.md). 실제 AI 분석·PG 실결제·공증기관 운영은 연결 및 검증이 남아 있습니다.
# BLOCKSIGN 0.10 — 실제 신청자료 관리 / 개발 버전 / 별도 시연 버전
0.10: 고객 공증 화면을 7단계 단일 폼으로 교체했습니다. 화면 하나에 현재 작업만 표시하고, 고객이 업무 역할을 전환하지 않습니다. 업무 관리는 `/notary-workspace.html`로 분리했습니다. 상세는 `docs/NOTARY_WIZARD.md`.
0.9: 다음 할 일 안내·당사자별 확인·일정 응답·면담 기록·수령 확인·원본 ZIP/합본 PDF·파트너 입점 시연을 추가했습니다. `docs/NOTARY_MARKET.md` 참고.
0.8: 공증인 선택·자격 심사·견적·분리 결제·진행 위탁·공증인 결과 등록·자동 전달을 추가했습니다. 실제 진행 `/notary-market.html`, 독립 시연 `/notary-market-demo.html`. `docs/NOTARY_MARKET.md`를 읽으세요.
`/notary-live.html`에 로그인 계정별 실제 공증 신청자료 저장·공식 신청용 ZIP·접수/발급 근거 PDF 보관 기능을 추가했습니다. `docs/NOTARY_LIVE.md`에서 실제 동작 범위와 미연동 단계를 확인하세요. 자체 공증 발급/공식 시스템 자동 접수 기능은 아닙니다.
블록싸인은 글로벌 전자계약을 기본으로 하고, 문서 증명을 블록체인에 연결하며 필요한 계약에만 에스크로를 적용합니다. 예제 당사자는 블록오디세이와 데이톤, 예제 계약은 ERP 개발 컨설팅 계약입니다.
## 두 버전
- `dist/demo.html`: 브라우저만으로 실행하는 독립 시연. 실제 이메일, 신원 인증, 체인 기록, 자금 이동 없음. 시연 전용 IndexedDB/프로필 키를 사용합니다.
- `dist/development.html`: 서버 API와 연결하는 개발 워크스페이스. 실제 SQLite 저장, 사용자·테넌트 권한, 순차 서명, 서버 PDF 생성, 지갑 소유 검증, 감사 체인 검증을 수행합니다. **지급 엔진의 execute는 개발 정책 시뮬레이션**입니다.
- `dist/index.html`: 독립 서비스 랜딩. 앱 초기화나 자동 화면 전환이 없으며, 시연 시작 링크를 클릭해야 `demo.html`에 진입합니다. 기존 시연은 `blocksign.html`, 별도 시연은 `demo.html`에 유지합니다.
- `development/contracts`: 실제 EVM에서 실행·테스트한 개발용 Solidity 소스. 배포·감사된 운영 컨트랙트가 아닙니다.
## 바로 실행
Node.js 24 이상, Python 3 필요.
```bash
cd development
npm ci
npm test
npm run typecheck
npm start
```
브라우저에서 `http://127.0.0.1:8787`을 여세요. 최초 실행 시 `development/data/actors.json`에 무작위 사용자 토큰을 생성합니다. 이 파일의 token을 개발 화면에 입력하세요. 관리자/블록오디세이/데이톤/중재 담당자 네 계정이 있으며 토큰을 바꾸면 서버 권한도 바뀝니다. 토큰은 화면 메모리에만 보관됩니다. data 폴더는 Git·배포·소스 ZIP에 포함하지 않습니다. 재시작해도 SQLite 데이터는 유지됩니다.
## ERP 계약 검증 순서
1. 관리자 연결 → 내 기본 서명인 등록 → 새 계약 → 수신인 등록·서명 순서 설정. 현재 수신인을 서버 주소록에 저장하고 다음 계약에서 선택할 수 있습니다.
2. ERP 샘플 또는 원본 PDF 선택. 서명자를 선택해 투명 서명란 추가·드래그 이동·크기 조절. 저장 후 발송.
3. 블록오디세이 사용자로 다시 연결 → 목록에서 계약 → 문서 확인·직접 서명·동의 후 제출.
4. 데이톤 사용자로 연결 → 서명. 서명 순서가 아직 아니면 서버가 거절합니다.
5. 서명본+증명 다운로드 → 합본 PDF, 서명본 단독 PDF, JSON 증명 저장 링크 생성.
6. 관리자 감사 이력 검사. 지갑 확장 프로그램이 있으면 각 계정에서 지갑 소유 인증 가능.
7. 에스크로 개발 명령으로 금고 규칙 설정 → 가상 예치 → 검수 → 지급 요청 → 서로 다른 두 지갑 승인 → 가상 실행. 취소·기한 만료·분쟁으로 재사용 차단 확인.
UI에서 서버 재연결은 사용자 전환을 위한 개발 도구입니다. 운영 서비스의 본인인증을 대신하지 않습니다. 개발 화면은 핵심 API 검증용이며, 기존 시연의 모든 편의 옵션을 서버와 연결한 상용 프런트엔드는 아닙니다.
## 재빌드
```bash
python3 scripts/build.py
node tests/workflow.cjs
```
빌드는 `development/node_modules` 또는 런타임 지정 의존성을 사용합니다. HTML은 PDF 라이브러리를 내장하여 외부 CDN 없이 동작합니다. 개발 소스 ZIP과 별도 시연 HTML도 재생성합니다.
## 운영 연결 전 남은 범위
실제 메일 초대·보안 링크, OIDC/KYC 및 회사 대표권 검증, 접근코드·패스키 서버 검증, 운영 스토리지와 백업·암호화·보존정책, PDF 악성 파일 검사, 서버 알림 작업자, 온체인 배포/릴레이/재구성 모니터링, Solidity 외부 감사, 환불·중재 판정 정책, 다국어 전문·국가별 계약 성립 규칙은 별도 구현 범위입니다. 이 릴리스는 실자금 운영 준비 완료판으로 표시하지 않습니다.
Claude로 이어갈 때는 **CLAUDE.md부터 읽으세요.** 데이터·해시·권한 계약을 보존한 TypeScript 전환 순서를 적었습니다.
최신 서비스 흐름은 docs/SERVICES_V6.md 참고. 랜딩의 에스크로/공증 시연 링크에서 각 전용 화면으로 진입할 수 있습니다.
@AGENTS.md
# 기능 연결 릴리스 2026-11-02
먼저 `docs/RELEASE_2026_11_02.md`를 읽으세요. v12 시연·포털 기준을 유지하며 실제 서버 서명과 별도 시연을 연결합니다. 수신인 재정렬 시 서명란 연결을 보존하는 `src/contract-editor.js` 테스트를 유지하세요.
# 최신 인계: v0.13
먼저 `docs/HOSTED_SIGNING.md`를 읽으세요. 실제 계정 기반 계약은 `contracts.html`과 `worker/esign-api.mjs`, 타입 SDK는 `development/client/esign.ts`입니다. 시연과 실제 데이터를 섞거나 미연동 외부 서비스를 성공 처리하지 마세요.
# 최신: v0.12
`docs/REMOTE_NOTARY.md` 우선. protocol3는 예약 없이 신분증/원격 연결 상태를 사용한다. v2와 감사기록 호환 보존. 전체 시연과 개발 포털을 각각 유지한다. 실제 신분증 이미지를 시연에 수집하지 않는다.
# 최신: v0.11 역견적
`docs/REVERSE_QUOTES.md`, `docs/CODEX_CLI.md`를 먼저 읽는다. AI 미연결 상태를 실제 분석으로 표시하지 않는다. 기존 전자계약·Safe·증명 기능과 정적 랜딩을 보존한다.
# Claude 개발 인수인계 — BLOCKSIGN
0.10 UI 재구성: `docs/NOTARY_WIZARD.md`부터 읽으세요. 고객용 `src/notary-app.js`는 단일 submit/click 경로와 단계별 화면을 사용합니다. `src/notary-flow.js`가 실제 주문 상태를 단계로 투영하고 `src/notary-files.js`는 PDF/ZIP만 처리합니다. 기존 n9 렌더 오버라이드를 고객 화면에 다시 붙이지 마세요. 운영·공증인 UI는 `src/notary-workspace.html`로 분리했습니다.
0.9 전체 과정: `src/notary-complete.js`를 공용 UI 템플릿에 주입합니다. 신규/기존 미완료 주문은 서버 protocolVersion 2로 당사자별 확인·일정 동의·면담을 집행합니다. `worker/archive.mjs`는 원본 바이트·해시를 보존하는 스트리밍 ZIP과 플랫폼 기록 PDF를 생성합니다. 합본은 열람용이며 전자서명 검증은 ZIP 원본으로 합니다.
0.8 공증인 참여 플랫폼: `docs/NOTARY_MARKET.md`를 먼저 읽으세요. `worker/agency-domain.mjs` 상태 전이, `worker/market-api.mjs` D1/R2 API, `worker/toss-payments.mjs` 실제 PG 어댑터, `src/notary-market.html` 운영/시연 공용 UI입니다. 공증 업무는 자격 사업자가 수행하며 정부 API 연동·자동 법적 발급으로 표시하지 마세요.
0.7 실제 공증 신청자료 관리 추가: `docs/NOTARY_LIVE.md`를 먼저 읽으세요. hosted Worker + D1/R2를 사용하며 기존 시연은 유지합니다. 신청자료 관리와 실제 법적 공증 발급을 구분하세요. 플랫폼에 공식 접수 API/제휴 권한이 없으므로 현재는 사용자가 공식 시스템에서 신청하고 실제 증빙을 연결합니다. 미검증 파일·사용자 보고를 공증기관 확인으로 표시하지 마세요.
최신 변경: `docs/SERVICES_V6.md`를 함께 읽으세요. 에스크로 전체 시연·공증 신청 모델·계약별 증명 옵션을 추가했습니다. 시연 금고는 `envelope.settlement`, 실제 지갑 검증 기반 개발 엔진은 기존 `envelope.escrow`에 있습니다. 두 상태를 혼동하지 말고 통합 어댑터를 구현하세요.
## 사용자 확정 요구사항
- 브랜드: 블록싸인/BLOCKSIGN. 제품 화면에서 HANDY·Pentasquare 명칭 제거.
- 예제: 블록오디세이 ↔ 데이톤 ERP 개발 컨설팅 계약, 48,000 USDC, 단계별 30/40/30%.
- 글로벌 전자계약이 주 서비스. 블록체인은 증명 계층, 멀티시그는 선택형 에스크로의 백그라운드 계층.
- 흰색·차콜·블루, 그라데이션·장식적인 AI 느낌 지양. 반응형 모바일·웹.
- 기본 서명인 먼저 등록 → 수신인 선택·역할·순서 → 실제 PDF → 투명 서명 컴포넌트 드래그·리사이즈 → 검토·발송 → 수신인 직접 서명.
- 서명자/검토자/참조, 같은 순서 동시 진행, 순차 요청, 이름·이메일 혼동 방지.
- 완료 계약서와 근거문서를 함께 PDF로 다운로드. JSON만 다운로드시키면 안 됨.
- **개발 버전과 독립 시연 버전을 반드시 함께 유지.** 시연은 외부 키·서버 없이 실행 가능해야 함.
- 첫 주소는 독립 랜딩(src/landing.html). 랜딩에서 자동으로 앱을 초기화·전환하지 말 것. 시연 진입은 명시적인 링크 클릭으로만 처리. legacy base의 첫 render()로 구 화면을 잠깐 노출하지 말 것.
## 현재 소스 지도
| 위치 | 역할 |
| --- | --- |
| src/base.html | 기존 시연 골격 및 구 UI. legacy와 override 공존 |
| src/platform.js | 실제 PDF 읽기/표시/서명 합성/다운로드·IndexedDB·기존 에스크로 시연 |
| src/workflow.js | v4 서명인 디렉터리, 4단계 준비, 순서/역할, 투명 PDF 필드 포인터 드래그, 수신 서명 |
| src/trust.js | v5 지급 요청 라운드·취소·만료·분쟁 무효화와 보관 PDF 지문 검사 |
| development/server/core.mjs | 서버 명령 엔진, 접근 제어, 계약/에스크로 상태 전이, 문서/배치/증명 해시 |
| development/server/store.mjs | SQLite 테넌트 JSON aggregate, 낙관적 버전 검사 |
| development/server/http.mjs | loopback 개발 HTTP, 무작위 Bearer 계정, 입력 제한, API |
| development/server/pdf.mjs | 원본 PDF에 PNG 서명 삽입, 서명본·증명 PDF 합본 |
| development/server/ethereum.mjs | 실제 EIP-191 소유 검증, EOA SafeTx EIP-712 검증·calldata 생성. 전송 기능 없음 |
| development/server/anchor.mjs | 실제 체인 영수증/이벤트/확정 블록 검증 어댑터. 전송 기능 없음 |
| development/contracts/*.sol | 개발용 증명 레지스트리와 Safe 호출형 프로젝트 에스크로 |
| development/contracts/index.d.ts | TS 도메인 타입의 출발점 |
| development/tests | 실제 지갑 암호검증·PDF·권한·SQLite·로컬 EVM 테스트 |
| tests/workflow.cjs | 시연의 라우팅/검증 회귀 테스트 |
| scripts/build.py | 독립 HTML, 별도 개발 UI, 소스 ZIP 생성 |
## TypeScript 전환 계획
1. 현재 테스트를 기준선으로 보존. `npm ci && npm test && npm run typecheck`.
2. `contracts/index.d.ts`의 Actor/Envelope/EvidenceManifest/EscrowProposal을 `packages/domain/src/types.ts`로 이동. canonical serializer와 해시 테스트 결과를 바꾸지 말 것.
3. `core.mjs`를 `packages/domain/src/engine.ts`로 옮기고 Command/Payload/Result를 판별 유니온으로 엄격하게 정의. 현재 `EnginePort`는 임시 넓은 인터페이스이며 완전 타입화된 API가 아님.
4. store/wallet/pdf/Safe/anchor를 interface port로 분리. SQLite JSON aggregate를 PostgreSQL 정규 테이블+트랜잭션으로 대체하고 외부 blob 스토리지 연결. 테넌트 필터·버전·원자성 보존.
5. HTTP를 선택한 TS 서버(Fastify 등)로 전환, JSON schema 입력 검증 추가. OIDC/보안 초대 링크를 실 Actor로 매핑. Bearer 개발 토큰은 운영에서 제거.
6. `src/workflow.js`의 사용자 흐름·스타일을 React/TypeScript 컴포넌트로 이전. 기존 완성 시연을 덮어쓰지 말고 별도 앱으로 구현. 개발 UI는 핵심 서버 API 실행기이므로 전체 편의 옵션 연결 작업이 필요.
7. 발송은 트랜잭션 outbox→메일 작업자→멱등 webhook. 접근코드·OTP·패스키·기한·리마인더는 서버 집행. 현재 시연 옵션은 일부 로컬 시뮬레이션.
8. Safe 공식 SDK로 EIP-1271 지원 추가. current EOA65 어댑터에 계약 지갑을 억지로 끼우지 말 것.
9. 테스트넷 배포, 실제 Safe 1.4.1+ProjectEscrow 통합 검증, RPC 장애·체인 재구성·nonce 경합·서명 취소·멱등 릴레이 테스트. 외부 감사를 거쳐야 실자금 경로 개방 가능.
## 절대 혼동하면 안 되는 값
- `originalHash` = 업로드 PDF 바이트 SHA-256.
- `layoutHash` = 원본 지문+수신인/역할/순서+필드+기한+revision의 canonical SHA-256. send 이후 잠금.
- `signedHash` = 모든 서명이 합성된 최종 PDF 바이트 SHA-256.
- `commitment` = EvidenceManifest의 canonical SHA-256. 합본 PDF 지문이 아님.
- `intentHash` = 개발 정책용 지급 의도 지문. **SafeTx hash 아님.** personal_sign으로 승인되며 실제 지급에 쓸 수 없음.
- SafeTx hash = chainId/verifyingContract/nonce/calldata 등 Safe EIP-712 해시. 서버·체인 교차검증 필요.
- 로컬 취소·TTL과 온체인 취소는 다름. 개발 intent nonce와 실제 Safe nonce도 다름.
- 서버 감사 체인은 변경 탐지용. 서버 관리자가 DB 전체를 다시 쓸 수 없다는 보장은 없으며 외부 앵커/서명된 체크포인트 전에는 독립 불변성이 없음.
- 지갑 소유 확인은 신원·회사 대표권의 증명이 아님. 앵커링은 공증/글로벌 법적 효력의 자동 보장이 아님.
## 온체인 에스크로 구조
ProjectEscrow가 자금을 보유하고, Safe는 release 호출 권한을 가집니다. 따라서 Safe 소유자들의 일반 ERC20 transfer로 에스크로 조건을 우회할 수 있는 'Safe에 자금만 넣는 구조'와 구분됩니다. release(milestone,expectedEpoch,validUntil)는 검수·순서·잔액·분쟁·epoch·기한을 컨트랙트에서 검사합니다. dispute/invalidate/resolve가 epoch를 올려 이전 calldata를 무효화합니다.
현재 개발용 컨트랙트는 부분 입금·단계 지급을 다룹니다. 환불, 장기 미응답, 중재 결과 집행, 역할 복구/교체, 토큰 freeze·blacklist·비표준 동작, 업그레이드·비상정지 정책은 미완성입니다. 운영에 배포하거나 실자금을 넣지 말 것. EVM 테스트의 safe 호출자는 테스트용 EOA이며 실제 Safe 배포 통합 테스트가 아님.
## 실행/검증/전달
```bash
cd development
npm ci
npm test
npm run typecheck
npm start
# 프로젝트 루트에서
python3 scripts/build.py
node tests/workflow.cjs
```
개발 데이터/사용자 토큰/지갑 키를 commit 또는 ZIP에 포함하지 말 것. 기존 사이트 정체성(.openai/hosting.json)을 다른 프로젝트에 복제하지 말 것. 원본 PDF 수정이 필요하면 새 envelope/revision으로 재요청. 이미 서명된 PDF를 다시 생성해 기존 해시를 덮어쓰지 말 것.
사용자에게 '완료'라고 할 때 시연·로컬 개발 구현·운영 미연동 범위를 구분할 것. 브라우저 다운로드 링크 생성과 실제 기기 저장 성공은 별개. 현재 환경에서 Android 실기기 저장은 확인되지 않음.
# 개발 API 0.5
서버: http://127.0.0.1:8787, Node 24+. 모든 /api는 `Authorization: Bearer <actors.json token>`. 토큰의 tenant/id/email/role만 서버가 신뢰하며 body에서 actor를 받지 않습니다. 운영용 API gateway나 인증 서비스가 아닙니다.
- GET /health : 기능 연결 상태, 실제 자금 비활성 여부.
- GET /api/me : 연결된 사용자.
- GET /api/example : ERP 샘플 원문 및 create 입력.
- POST /api/command : `{ "command":"...", "payload":{...} }`. 성공 `{data:...}`, 실패 `{error:"CODE"}`.
## 명령
| command | payload / 의미 | 권한 |
| --- | --- | --- |
| profile | {} / 내 기본 서명인 | 로그인 사용자 |
| save-profile | {name,company,title,signature?} / 이메일은 세션에 고정 | 본인 |
| contacts | {} / 서버 서명인 주소록 | 관리자 |
| save-contact | {contactId?,name,email,company,title} / 등록·수정 | 관리자 |
| delete-contact | {contactId} | 관리자 |
| list | {} / 접근 가능한 계약 요약 | 로그인 사용자 |
| get | {id} / 원본 PDF 포함 계약 | 관리자 또는 해당 수신인 |
| create | title,pdf(base64),deadline(ISO),sequential,recipients,fields | 관리자 |
| send | {id} / 배치와 수신인 잠금 | 관리자 |
| sign | {id,layoutHash,consent:true,values:{f0:"data:image/png;base64,..."}} | 현재 라우팅 그룹의 수신인 |
| void | {id} / 미완료 계약 취소 | 관리자 |
| download | {id} / pdf,original,evidencePdf,combinedPdf,manifest,commitment | 계약 접근자, 완료 후 |
| audit | {} / 이벤트와 valid 검증 결과 | 관리자 |
| challenge | {address} / 5분·1회용 등록 요청 | 로그인 사용자 |
| wallet | {challenge,signature} / 실제 EIP-191 검증·주소 등록 | challenge 발급 사용자 |
| escrow | 아래 설정 / 완료 계약당 한 번 | 관리자 |
| fund | {id,amount:"48000000000"} / 가상 예치 | 관리자 |
| review | {id,milestone:"m0"} | 관리자 (개발 검수 역할) |
| propose | {id,milestone:"m0"} / 24시간 지급 intent | 등록된 금고 소유자 |
| approve | {id,proposal,intentHash,signature} | 서로 다른 등록 소유자 |
| cancel | {id,proposal} / 개발 nonce 증가 | 등록 소유자 |
| expire | {id,proposal} / TTL 경과 후 무효화 | 계약 접근자 |
| execute | {id,proposal} / 가상 지급, transactionHash:null | 등록 소유자 |
| dispute | {id,reason:"최소 5글자"} / pending 승인 무효화 | 계약 접근자 |
| resolve | {id,reason:"최소 5글자"} | 관리자 (개발 중재 역할) |
| safe-inspect | {id} / RPC chain/code/singleton/owners/threshold/nonce | 관리자, 설정 필요 |
| anchor-verify | {id,transactionHash:"0x..."} / 실제 영수증·이벤트·블록 검증 | 관리자, 설정 필요 |
## create 입력
recipient는 `{name,email,role:"signer"|"reviewer"|"cc",order:1}`. 서버가 배열 순서대로 r0,r1... ID를 부여합니다. field는 `{recipient:"r0",type:"signature"|"text"|"date"|"checkbox",page:1,x:0.1,y:0.7,w:0.3,h:0.08,required:true}`. 좌표는 페이지 왼쪽 위 기준 0~1. 서버가 f0,f1... ID를 부여합니다. 서명자마다 필수 서명란이 있어야 합니다.
서명 값은 PNG data URL, ASCII 문자열, boolean. 한국어/비라틴 문자는 PNG로 렌더링해 보내야 합니다. 서명 필드는 PNG 필수. 서버 PDF 렌더링은 아직 범용 문서 정규화 엔진이 아니므로 회전·crop·암호화·악성/비정상 PDF는 운영 전 별도 정규화/검사 필요. 기본 UI는 signature 배치에 집중하며 세부 문서 옵션은 시연에서 확인 가능합니다.
## escrow 설정 예시 (주소는 실제 등록 주소로 교체)
```json
{"id":"envelope-id","vault":"0x...Safe...","chainId":11155111,"token":"0x...USDC...","payee":"0x...Dayton...","owners":["0x...A...","0x...B...","0x...C..."],"threshold":2,"milestones":[{"title":"착수/진단","amount":"14400000000"},{"title":"설계/시범 개발","amount":"19200000000"},{"title":"인수인계","amount":"14400000000"}]}
```
6 decimals USDC 기준 48,000 USDC = 48,000,000,000 최소 단위. 금액은 JS Number나 부동소수점으로 저장하지 않습니다.
개발 승인 메시지: `BLOCKSIGN ESCROW DEVELOPMENT APPROVAL v1\nintent:<intentHash>`. 이 문자열의 실제 EIP-191 서명을 검증합니다. 승인 생성 자체로 자금이 이동하지 않습니다.
## Safe / 앵커 어댑터
`.env.example`의 값들을 shell 환경변수로 설정합니다(.env 자동 로딩 없음). Safe proxy runtime, singleton 주소와 runtime hash를 모두 승인 목록과 비교합니다. 빈 목록이면 거부합니다. getCode가 비어 있지 않다는 사실만으로 정품이라고 판정하지 않습니다.
SafeAdapter.prepare(config,tx,signatures)는 실제 EIP-712 EOA 서명을 복구하고 체인 owners/threshold/nonce 및 getTransactionHash 대조, 주소순 정렬 후 execTransaction calldata를 만듭니다. HTTP에는 노출하지 않은 저수준 연동 모듈입니다. ERC1271, MultiSend/DELEGATECALL, 릴레이 수수료는 지원하지 않습니다. Safe 정책 조회와 EVM 에스크로 배포를 자동 연결하지 않습니다.
앵커 검증은 설정한 registry/chain의 `anchor(bytes32)` calldata, Anchored 이벤트, 성공 영수증, 확인 수, 현재 블록 hash를 검사합니다. 이 모듈도 트랜잭션 전송은 하지 않습니다. 체인 장애나 재구성 이후 지속적 재검증 작업자는 미구현입니다.
## 오류/동시성
401 인증 실패, 403 권한, 409 도메인 상태/입력 오류, 413 본문 초과, 415 JSON 아님, 429 속도 제한, 500 미분류 오류. 세부 도메인 코드는 테스트에 고정되어 있습니다. 한 프로세스 명령 큐 + SQLite 버전 CAS로 원자적 저장. 멀티 인스턴스·대규모 프로덕션 용량을 목표로 한 저장 구현이 아닙니다.
# 구현 범위와 검증
## 구현됨
- 별도 시연 HTML과 별도 개발 UI/Node API. 저장 데이터 분리.
- 원본 PDF 실제 표시, 문서 위 투명 필드, 드래그 이동·리사이즈. 전체 시연에는 기본 서명인, 다양한 필드, 순서 변경, 필수 여부·접근코드·리마인더 UI, 저장·재개·직접 서명.
- 개발 서버: 기본 서명인·서버 주소록 등록/수정/삭제/선택, 테넌트/수신인 권한, 실제 SQLite 지속 저장, 원자적 상태 전이, 순차/동시/검토자/참조, 동의·문서 지문 검사, 취소·기한 차단.
- 실제 PNG를 PDF에 합성하고 최종 서명본 바이트 고정. 완료 증명 PDF와 합본 PDF, SHA-256 manifest 다운로드.
- 실제 EIP-191 지갑 소유 확인, 만료/일회성 challenge, 테넌트·사용자별 메시지.
- 개발 에스크로: 정수 금액, 단일 활성 제안, 중복 승인 차단, 실제 지갑 서명 검증, 정족수, TTL, 취소, 분쟁·재승인, 중복 지급 차단. execute는 가상 장부만 변경.
- Safe EIP-712 EOA65 검증/해시 교차/정렬·calldata 준비 모듈. 실제 영수증 확인 기반 앵커 검증 모듈.
- Solidity EvidenceRegistry/ProjectEscrow, 컴파일·로컬 EVM 실행 테스트. 조건·epoch는 컨트랙트가 직접 집행.
- 이벤트 hash chain으로 감사 이력 변경 검사. 외부 불변 저장의 대체물은 아님.
## 이전 버전 미연동 목록 (v0.13 변경은 HOSTED_SIGNING.md 우선)
메일·법정 실명/권한 인증·알림·추가 파일 보안·장기 백업·실제 지갑 트랜잭션 전송·Safe 배포 자동화·실제 Safe와 에스크로 통합·온체인 취소 UI·모든 시연 옵션의 서버화·EIP1271·환불·회사별 다국어 계약 전문·공식 법적 효력 검토. 개발 화면은 한국어이며 예제 API PDF 전문은 영문 테스트용입니다. 시연의 ERP 문서는 한국어입니다.
## 테스트 의미
`development/tests/engine.test.mjs`: 진짜 임시 EOA 키로 EIP-191 및 EIP-712 서명/검증, 계약 라우팅, 동의/해시, 권한/테넌트, 증명/합본 PDF, 무효화/중복 실행.
`development/tests/contracts.test.mjs`: solc 컴파일 후 Ganache 메모리 EVM에서 입금/검수/권한/지급/분쟁/해제/오래된 epoch/기한/앵커 이벤트. 테스트 safe는 EOA 대역. 실제 Safe 배포·테스트넷 RPC 테스트로 오해하지 말 것.
`development/tests/persistence.test.mjs`: 재오픈 후 저장 유지 및 버전 경합 거부.
`tests/workflow.cjs`: 시연 라우팅/입력/필수 서명란 회귀.
Node 단위 테스트는 실제 모바일 다운로드·지갑 팝업·메일 도착을 보장하지 않습니다. 브라우저가 링크를 생성해도 사용자 기기의 실제 파일 저장 성공은 별도 확인 대상입니다.
참고한 1차 문서:
https://docs.safe.global/advanced/smart-account-signatures
https://docs.safe.global/reference-smart-account/transactions/getTransactionHash
https://eips.ethereum.org/EIPS/eip-712
https://eips.ethereum.org/EIPS/eip-1271
개발 기준일: 2026-10-28 (KST).
# BLOCKSIGN 0.6 — 계약 연결형 에스크로 · 증명 · 공증
## 기존 문제와 수정
기존 `newescrow`는 계약 작성기를 열었고 금고 생성 과정이 없었습니다. 에스크로 시작 버튼이 문서 작성으로 이동해 전 과정을 시연할 수 없었습니다. `src/services.js`가 이 동작을 대체하며 계약 선택/연결, 전용 ERP 시나리오, 금고 생성, 예치와 단계별 승인·지급을 같은 페이지에서 처리합니다. 계약 화면으로 이동하는 동작은 사용자가 '원문 열람'을 명시적으로 선택한 경우뿐입니다.
랜딩은 독립 정적 페이지로 유지합니다. `demo.html#escrow`, `#notary`, `#proof`는 사용자가 해당 링크를 선택한 경우에만 기능 화면으로 진입합니다.
## 에스크로 시연
1. 기존 계약을 선택하여 연결하거나 'ERP 전체 과정 시연 시작' 선택.
2. 블록오디세이/데이톤/중재 담당자 역할로 각 참여 확인. 2/3 또는 3/3 정족수 선택.
3. 금고 생성 시연. `SIM-VAULT-...`는 시연 식별자이며 실제 Safe 주소가 아님.
4. 계약 완료 후 48,000 USDC 가상 예치.
5. 발주사 역할 검수 → 지급 요청 생성 → 서로 다른 소유자 승인 → 정족수 충족 → 지급 실행 시연.
6. 14,400 / 19,200 / 14,400 USDC 순서 지급. 잔액과 기록이 실제 브라우저 장부에 반영됨.
7. 요청 취소·만료·분쟁은 기존 승인을 무효화. 분쟁 해제 후 재검수·재승인.
8. 분쟁 중 중재자의 잔액 환불안 → 금고 정족수 승인 → 환불 시연. 종료 후 정산 PDF.
`src/service-model.js`는 순수 상태 엔진이며 금액을 최소 단위 문자열/BigInt로 처리합니다. 이전 장부와 섞지 않고 `envelope.settlement`에 v6 상태를 저장합니다. 이미 가상 지급된 구 에스크로 기록은 연결 시 이관합니다. `tests/services.cjs`가 실제 이 엔진을 검증합니다.
전용 시나리오는 `sampleScenario='escrow-v6'`의 **시연용 사전 체결 샘플**입니다. 원래 사용자의 계약과 서명을 수정하지 않습니다. 샘플 서명본은 실제 서명이 아니라는 표시가 있는 문서입니다. 이 상태 엔진은 개인키·SafeTx 서명·실제 자금 이동을 수행하지 않습니다.
기존 개발 서버의 지갑 서명 검증 에스크로 엔진, SafeAdapter, ProjectEscrow.sol은 별도로 보존합니다. 브라우저의 역할 전환과 실제 서버 사용자/지갑 매핑을 같은 인증으로 취급하면 안 됩니다. 개발용 Solidity의 환불은 아직 구현되지 않았으며, v6의 환불은 시연 장부 기능입니다.
## 계약별 문서 증명 옵션
- 독립 상품이 아니라 계약마다 선택하는 증거 보강 옵션.
- 작성 2단계와 계약 상세에서 `proofEnabled` 선택.
- 최종 서명본이 완성되면 `bsSave`에서 원문 SHA-256·서명본 SHA-256·당사자 완료/동의 시각을 묶은 canonical commitment를 자동 계산.
- 온체인 미전송이며 `status='simulation', automatic=true`로 표시.
- 선택하지 않아도 기본 전자서명·완료 근거문서 PDF는 유지.
- 개발 API `proof-policy {id, enabled}`는 완료 전에는 waiting_for_completion, 완료 후에는 prepared_not_submitted 작업 정보를 생성. 릴레이 전송 작업자는 미구현.
## 공증 신청 모델
`src/notary-model.js`는 브라우저와 개발 API에서 공유합니다. 공증 신청 준비 → 접수/보완 → 검토/예약 → 수수료 체험 → 본인확인 체험 → 화상면담 체험 → 결과 보관. 모든 완료 상태는 `completed_simulation`이며 실제 공증서 발급 상태가 아닙니다.
- 완료 계약의 서명본 해시에 신청을 묶음. 문서 지문 변경 시 후속 단계 거부.
- 신청자 자격, 목적, 미래의 희망 면담 일정, 서류·참여자·안내 확인 필요.
- 실제 주민등록번호·신분증·카드 정보를 요구하지 않음.
- 가상의 공증 검토 단계로 재현하며 실존 공증사무소가 접수/심사하는 것으로 표시하지 않음.
- 수수료는 실제 공증인이 확정하는 것으로 안내. 시연에서는 청구/결제 없음.
- 화상면담은 UI 시연이며 카메라·마이크·공증인이 연결되지 않음.
- 결과 PDF는 시연 신청 기록. 법적 공증서·도장·공증인 인증서 위조 형태로 만들지 않음.
- 실제 발급 PDF를 사용자가 수동 첨부하면 `uploaded_unverified`로 저장. 업로드 지문 계산은 진위 검증이 아님. 진위 확인은 공식 시스템으로 안내.
## 국내 실제 제공 경로 확인 (2026-10-28)
1. 법무부 전자공증시스템: https://enotary.moj.go.kr/
2. 공증인 정창섭 사무소/용인수원공증의 화상공증 안내: https://www.notary365.co.kr/enotary/
3. 대한공증인협회: https://koreanotary.or.kr/
4. 공식 전자공증 안내: https://www.mofa.go.kr/us-losangeles-ko/brd/m_21106/view.do?seq=162
위 링크는 실제 제도/사업자 정보의 참고 링크이며 BLOCKSIGN의 제휴·위임·API 연동을 뜻하지 않습니다. 공증사무소의 공개 안내를 기준으로 준비·지정공증인·신청·검토/일정·수수료·본인확인·면담·결과 확인 단계의 UI를 설계했습니다. 문서별 전자공증 적격성, 공정증서/집행력, 국적·대리권·해외 제출 가능 여부는 공증인에게 별도로 확인해야 합니다. 블록체인 앵커는 법적 공증을 대체하지 않습니다.
## 개발 API 추가
- `proof-policy {id,enabled}` 관리자 전용.
- `notary-prepare {id}` 관리자, 완료 계약에 한 번 생성.
- `notary-update {id,capacity,purpose,meeting,documents,participants,consent}` prepared/correction에서 수정.
- `notary-step {id,action,simulated:true,hearingConsent?}` 관리자. action: submit/correction/accept/pay/identify/hearing/complete. 실제 업체 접수/발급 API 없음.
`development/ui.html`의 개발자 명령 선택에도 위 명령을 추가했습니다. 실제 공증 신청은 당사자·공증인·공식 시스템을 통한 별도 절차입니다.
## Claude 후속 작업
서비스 모델을 TypeScript로 옮기되 시연과 실제 자금 실행 어댑터를 분리하세요. v6 브라우저 금고 단계, v5 개발 서버 지갑 서명, Solidity 정책을 하나로 연결하는 통합 작업과 실제 RPC·Safe 배포 검증이 필요합니다. 공증사무소 연계는 계약과 공식 제공 방식 확인 후 진행하고 공개 API가 있다고 가정하지 마세요. 공식 공증 상태/문서 진위 검증 없이 simulated 또는 uploaded_unverified를 legal issued로 승격하지 마세요.
검증 명령:
```bash
node --test tests/services.cjs tests/notary.cjs
node tests/workflow.cjs
cd development && npm test && npm run typecheck
```
# BLOCKSIGN 0.7 — 실제 공증 신청자료 관리
## 구현한 실제 기능
`/notary-live.html`은 기존 시연과 분리된 실제 자료 관리 화면입니다. 가상의 당사자, 접수번호, 결제, 공증 완료 상태를 생성하지 않습니다.
- ChatGPT 로그인 사용자별 실제 신청자료 저장(D1).
- 실제 PDF 원본 업로드/다운로드(R2). 원본 바이트와 SHA-256 보존.
- 당사자·신청 자격·목적·이용 예정 경로·자료 처리 확인 기록.
- 대표자/대리인 신청의 권한 자료 준비 여부 검사.
- 준비 완료 시 원문과 신청정보 잠금, 준비자료 manifest와 commitment 생성.
- 실제 파일을 포함한 제출용 ZIP과 신청준비안내 PDF 생성. 공식 공증서 형태로 작성하지 않음.
- 공식 접수 확인 PDF + 실제 접수번호/사무소명 기록.
- 실제 보완/일정/수수료/납부 관련 안내와 근거 PDF 연결.
- 실제 발급 공증 PDF를 수정하지 않고 보관.
- 공식 진위확인 결과를 사용자가 직접 기록하고 근거 PDF 연결.
- 소유자 권한, 원본 지문 대조, 같은 출처 Origin 검사, 버전 CAS, 이벤트 hash chain.
## 아직 실제로 연결되지 않은 부분
법무부 전자공증시스템에 대한 공개 접수 API 명세·연계 권한·제휴 사무소 계약은 확보되지 않았습니다. 공개 검색에서 바로 사용 가능한 명세를 확인하지 못했으며, API가 존재하지 않는다는 결론은 아닙니다.
따라서 공식 촉탁 제출, 공동인증서 서명, 법적 신원/대표권 심사, 실제 수수료 결제, 공증인의 화상 대면·인증서 발급은 **사용자와 지정공증인이 공식 시스템에서 수행**합니다. 이 단계가 끝나야 실제 공증이 이루어집니다. 블록싸인은 현재 자체 공증기관도, 전자공증시스템의 승인된 연계 사업자도 아닙니다.
사용자 기록을 `provider-confirmed`나 `legally-verified`로 승격하지 않습니다. 실제 공증 PDF가 업로드되어도 `result_received_unverified`, 사용자가 공식 시스템 확인 결과를 기록해도 `verification_recorded_by_user`입니다. 영수증·납부 증빙도 사용자 제공 자료입니다.
## 서버 배포
기존 Site의 project_id와 비공개 접근 범위를 유지하며 Worker ESM으로 전환합니다. 랜딩·독립 시연·개발 HTML·소스 ZIP은 그대로 제공합니다.
- `.openai/hosting.json`: d1=`DB`, r2=`BUCKET`; 기존 static 항목 제거.
- `worker/notary-api.mjs`: Web API 기반 실제 자료 관리 API. 외부 접수·메시지 발송 없음.
- `worker/index.mjs`: 정적 앱과 API 라우팅. 플랫폼 소유자 접근 정책 보존.
- `development/db/notary-schema.ts` / `drizzle/`: Drizzle 생성 D1 schema migration.
- `scripts/build-worker.py`: 기존 정적 파일을 gzip asset로 묶어 `dist/server/index.js` 생성. `dist/.openai/drizzle`에 migration 동봉.
```bash
cd development
npm ci
npm test
npm run typecheck
# 새 schema 변경 때만:
npm run db:generate
cd ..
python3 scripts/build.py
python3 scripts/build-worker.py
```
로컬 실제 자료 관리도 `cd development && npm start` 후 `/notary-live.html`에서 실행할 수 있습니다. 개발 토큰은 로컬 UI에서 입력합니다. 실제 서버 코드를 로컬 SQLite/파일 binding으로 실행하며, 로컬 인증을 hosted Worker에 포함하지 않습니다.
## API
모두 `/api/notary-live/` 하위. 플랫폼이 주입한 oai-authenticated-user-id가 필요하며 모든 case/file에 owner 조건을 적용합니다. service-access token만 있고 사용자 identity가 없으면 401입니다.
| 경로 | 기능 |
| --- | --- |
| GET capabilities, me | 실제 연결 범위와 로그인 사용자 |
| GET/POST cases | 내 신청 목록·생성 |
| GET/PATCH cases/:id | 상세·draft 수정 |
| POST cases/:id/files?kind=...&name=... | 실제 PDF 원본 저장 |
| GET cases/:id/files/:fileId | 소유자 파일 다운로드 |
| DELETE cases/:id/files/:fileId | draft 문서 제거 |
| POST cases/:id/prepare | 준비자료 잠금·manifest 생성 |
| POST cases/:id/reopen | 공식 접수 기록 전 준비 단계 복귀 |
| POST cases/:id/external-reference | 실제 접수 확인자료와 접수번호 기록 |
| POST cases/:id/observation | 근거 파일이 있는 외부 진행 안내 기록 |
| POST cases/:id/verification-note | 사용자의 공식 진위확인 기록 |
| GET cases/:id/audit | 내부 이벤트 hash chain 검사 |
PDF는 10MB/파일, 20개/case, 계정당 100개/case 제한. 단순 활성 PDF 표식 검사는 완전한 악성파일 스캐너가 아닙니다. 다중 사용자 상용 공개 전에는 전문 파일 검사·보존/삭제·백업·약관/개인정보처리방침·운영자 권한/감사·수탁/위탁 계약을 보완해야 합니다. 현재 Site는 소유자 비공개로 유지합니다.
## 실제 공증 자동 연계의 다음 작업
1. 지정공증인 사무소와 상담·제휴 범위 확정. 실제 공증업무 수행 주체와 책임을 계약으로 명확히 함.
2. 법무부 전자공증시스템 운영 측에 민간 플랫폼 연계 가능 방식과 승인 절차 확인. 공개 API가 있다고 가정하지 않음.
3. 승인된 명세가 제공되면 신청/첨부/진행상태/수수료/공증 결과·검증 API와 전자서명·본인인증 수단을 연동.
4. 공식 키·신뢰사슬·검증 프로토콜이 제공된 뒤에만 provider-confirmed/cryptographically-verified 상태 도입.
5. 당사자·공증인 참여, 실제 신청, 결제, 문서 발급과 진위확인을 포함한 end-to-end 실증.
`docs/notary-partner-inquiry.txt`는 위 확인을 위한 문의 초안입니다. 실제 발송하지 않았습니다.
해외의 별도 선택 경로로 공개 Proof/Notarize API 서버 어댑터를 추가했습니다. `docs/PROOF_OPTIONAL_API.md` 참고. 국내 신청 API에는 연결하지 않았고 실제 API 키 없이 외부 요청을 실행하지 않았습니다.
## 확인한 1차 자료 (2026-10-28)
- https://www.notary365.co.kr/enotary/manual/ : 실제 서명·참가신청·촉탁·면담·발급 흐름 안내.
- https://www.notary365.co.kr/minutes/e-notary/ : 신청·업로드는 법무부 시스템에서 진행하도록 명시.
- https://enotary.moj.go.kr/ : 공식 전자공증 시스템.
- https://www.moj.go.kr/moj/221/subview.do?enc=Zm5jdDF8QEB8JTJGYmJzJTJGbW9qJTJGMTgyJTJGNDIxMzQ3JTJGYXJ0Y2xWaWV3LmRvJTNG : 법무부 화상공증 제도 안내.
전자공증 대상과 절차는 현행 제도와 담당 공증인의 판단을 따릅니다. 블록체인 증명이나 플랫폼 전자서명만으로 공증을 대체하지 않습니다.
# 해외 공증 API 선택 경로 — Proof/Notarize
국내 공식 전자공증과 다른 서비스입니다. 한국 공증 대체, 모든 한국인/한국어 문서의 이용 가능, 국내 집행력 등을 가정하지 않습니다. 문서·당사자·사용 국가의 적격성과 수용기관 요건은 별도로 확인해야 합니다.
공식 Business API 어댑터를 `development/server/proof-adapter.mjs`에 구현했습니다. 공개 공식 문서의 create draft / retrieve / processing check / activate 흐름을 사용합니다. 실제 API 키가 없어 요청을 실행하지 않았습니다. 자동화 테스트는 요청 형식을 검증하는 mock 기반입니다.
- 기본 환경 Fairfax: https://api.fairfax.proof.com
- 운영 환경: https://api.proof.com
- 인증: 서버의 `ApiKey` header. Full Access Key만 사용. 키를 HTML/ZIP/로그에 넣지 않음.
- 생성은 `draft:true`, `suppress_email:true`, 전화번호 미전송, payer=signer.
- 자료의 국외 제공과 이용 적격성 확인이 없으면 생성 거부.
- 문서 processing_state가 모두 done인 경우만 활성화 가능.
- 운영 환경은 liveEnabled=true + 별도 activation confirmation 필요.
- 공증·본인인증·실제 비용 확인/동의·서명은 Proof의 당사자 화면에서 진행.
- 국내 화면에는 이 어댑터를 자동 활성화하지 않음. 국내 자료를 해외로 자동 전송하지 않음.
Claude 연결 예:
```js
const adapter = new ProofAdapter({
apiKey: process.env.PROOF_API_KEY,
environment: 'fairfax',
});
// 사용자와 문서의 이용 적격성 확인 + 자료 제공 동의 후에만 호출.
const draft = await adapter.createDraft({
signers: [{email: userConfirmedSignerEmail}],
documentBytes: actualPdfBytes,
externalId: blocksignCaseId,
transactionName: userConfirmedTitle,
foreignProcessingConsent: true,
eligibilityAcknowledged: true,
});
```
키/계정은 Proof Business/Fairfax 계정에서 발급해야 합니다. 사용자 대신 가입 약관을 수락하거나 유료 공증을 실행하지 않았습니다. 어댑터는 아직 hosted 국내 신청 API에 연결되지 않은 별도 서버 모듈입니다. 이를 연결하려면 사용자별 권한·동의·비용 고지·원문 해시 바인딩과 공식 결과 수신/검증을 추가해야 합니다.
확인한 공식 명세 (2026-10-28):
https://dev.proof.com/docs/business-quick-start
https://dev.proof.com/docs/api-keys
https://dev.proof.com/docs/environments
https://dev.proof.com/reference/createtransaction
https://dev.proof.com/reference/gettransaction
https://dev.proof.com/reference/activatedrafttransaction
국내 자동 접수/발급은 국내 공증사무소·공식 시스템의 권한과 명세 확보가 먼저입니다. 해외 API의 완료 응답을 국내 공증 완료로 표시하지 마세요.
# BLOCKSIGN 0.9 — 자격 사업자 공증 진행 플랫폼
## 0.9 전체 과정 확장
기존 고객 화면의 검토 대기에서 다음 진행을 찾기 어려운 문제를 수정했습니다. 시연에서 공증인 선택 후 상단 ‘지금 할 일’ 버튼을 따라가면 신청자료 확인 → 공증인 견적 → 의뢰·위탁 동의 → 분리 결제 → 운영자 누락 확인 → 면담 일정 제안 → 고객 일정 확정/변경 → 공식 접수 단계 → 각 당사자 신원·권한·의사·문서 확인 → 면담 기록 → 참여 확인 → 발급 검수 → 고객 전달 → 수령 확인으로 진행됩니다. 자동 화면 전환은 없습니다.
- `protocolVersion: 2` 신규 주문에는 실제 준비자료의 당사자 목록을 고정합니다. 기존 미완료 주문도 서버가 당사자 목록을 복원하여 새 검증 규칙을 적용합니다. 이미 전달된 발급 결과는 변경하지 않습니다.
- 신원·권한·의사 확인과 면담은 해당 공증인의 확인 기록이며 플랫폼 자체 법정 본인인증이나 영상 공증을 의미하지 않습니다. 신분증 번호·주민번호는 이 확인 메모에 입력하지 않습니다.
- 일정 변경/재지정 시 기존 면담·참여 기록을 무효화합니다. 개인 참여가 필요한 주문은 고객 일정 동의, 전 당사자 확인, 면담 기록 없이는 참여·발급이 차단됩니다.
- 반려·진행 불가 사유, 고객 보완/재제출, 업무함 메시지, 결제 후 수취인별 환불 검토를 지원합니다. 운영자는 자격자료 보류·참여 중단도 할 수 있습니다.
- 고객 수령 확인은 발급 PDF SHA-256에 바인딩됩니다. 다른 파일의 수령 확인이나 운영자의 고객 사칭은 거절합니다.
- 운영판 `GET /api/notary-market/orders/:id/package.zip`은 권한·원본 지문을 검사하며 계약 원본/근거/발급 원본/플랫폼 진행기록 PDF/manifest/audit를 스트리밍 ZIP으로 제공합니다. 원본 PDF를 수정하지 않습니다. 합계 80MB 이하, 파일당 기존 10MB 제한.
- 별도 `process-record.pdf`는 플랫폼 관리 기록이며 공증서가 아닙니다. PDF 합본은 브라우저에서 생성하는 열람용 사본으로, 원본 전자서명 검증·제출은 ZIP 개별 원본을 사용합니다.
- 독립 시연의 계약서·접수 단계 기록·발급 단계 기록은 한글이 표시되는 실제 PDF로 생성하고 실제 SHA-256을 계산합니다. `eeee...`, `ffff...` 고정 지문을 사용하지 않습니다. PDF는 IndexedDB에 보관하고 차단 시 현재 시연 메모리로 대체합니다. 시연 결과 PDF는 모두 실제 공증 효력 없음을 표시합니다.
- 시연에는 별도 파트너 참여 신청 → 가상 자격 자료 → 독립 운영자 보완/승인 → 가상 목록 등록 과정이 있습니다. 실제 제휴사나 자격을 부여하지 않습니다.
- 결제 후 고객 화면 복귀가 유실되면 `POST /orders/:id/reconcile-payment`가 저장된 수취인·주문·금액으로 PG 승인 여부를 조회해 확정된 거래만 반영합니다. 고객이 보낸 결제 완료 값은 사용하지 않습니다. PG 웹훅이나 정기 대사 작업자를 구현한 것은 아닙니다.
- 모바일 저장 링크와 PDF 열기·공유, 지원 기기의 파일 공유 메뉴를 함께 제공합니다. Android 실기기 저장 성공을 보장한 것이 아닙니다.
### TypeScript 인수인계
`worker/agency-domain.mjs`, `worker/market-api.mjs`, `worker/archive.mjs`, `src/notary-complete.js`, `development/contracts/notary-market.d.ts`의 v2 타입을 이어받으세요. 테스트에서 역할·문서 지문·일정 변경 무효화·수령 바인딩·원본 ZIP CRC/해시를 보존하세요. 시연이 호출하는 동일 도메인 함수를 운영 API와 별도로 임의 재작성하지 마세요. 기존 전자계약·멀티시그 에스크로는 유지합니다.
공식 절차 참고: https://www.moj.go.kr/moj/2306/subview.do . 정부 시스템과의 민간 접수/발급 API 계약·PG 실키·실제 제휴 공증인 없이 공식 절차를 자동 완료하지 않습니다. 이메일/푸시, PG 웹훅 및 정기 대사, 정부 진위확인 연동은 여전히 미구현 범위입니다.
## 이번 구현의 경계
고객이 공증인을 선택하고, 공증인이 적격성·업무 범위와 수수료를 확인한 다음 별도 계약에 동의하고 비용을 지불하는 구조입니다. 블록싸인은 동의한 서류 누락 확인·일정·선택 기관 전달·완료문서 전달을 관리합니다. 공증 및 법률업무는 자격 사업자가 직접 수행합니다. 이 사업 구조의 적법성 승인이나 유권해석을 받은 것은 아닙니다.
- 실제 화면: `/notary-market.html`; 신청자료 준비: `/notary-live.html`
- 독립 시연: `/notary-market-demo.html` (자격 사업자·금액·접수·발급 모두 가상, 실제 결제 없음)
- 기존 전자계약·멀티시그 에스크로 시연: `/demo.html`; 랜딩은 자동 전환하지 않습니다.
실제 서버에 신청·견적·동의·결제 원장·진행 상태·실제 PDF를 저장합니다. **자동 접수는 블록싸인 진행 업무함 접수**이며 법무부 공식 촉탁 API 접수가 아닙니다. 실제 발급은 공증인이 공식 절차에서 수행하고 발급 PDF를 등록·확인하면 고객에게 접근 권한과 다운로드를 자동 제공합니다. 이메일·푸시 통지는 아직 없습니다. 정부 시스템 API·발급문서 진위확인 연계는 제공되지 않았고 호출하지 않습니다.
## 흐름과 권한
1. 사업자 참여 신청 → 공증 자격·온라인 지정 근거·플랫폼 업무 범위 계약 PDF 제출 → 다른 운영자가 확인 근거와 재확인 기한을 기록하고 승인.
2. 고객이 목록에서 승인된 공증인 선택 → 준비 완료한 실제 계약/신청자료 연결 → 선택 기관 자료 전달과 진행 관리 동의.
3. 공증인이 서류를 보고 범위·본인 참여 필요 여부·공증료 산정 근거와 유효기간이 있는 견적 제시.
4. 고객이 공증기관 수임 조건과 플랫폼 진행 관리 조건을 각각 확인. 법적 대리권·법률상담 권한이 자동으로 부여되지 않음.
5. 공증료는 해당 기관 PG 계정으로, 활성화된 비법률 운영비는 플랫폼 PG 계정으로 각각 결제. 서버가 저장된 견적·주문·금액·통화·수취인을 검증하여 전액 확인 후 `queued` 자동 전환.
6. 운영자가 누락·일정 업무 → 공증인이 보완 요청·일정·공식 접수 근거 PDF 및 접수번호 기록 → 필요한 당사자 참여 확인.
7. 공증인이 실제 발급 PDF를 업로드하고 법정 신원·대표권·대리권·실제 공증 수행을 확인 → `delivered_by_partner` → 고객 원본 PDF 다운로드.
8. 고객 취소 요청. 결제 전에는 취소, 결제 후에는 수취인별 환불 검토. 승인된 전액 환불을 PG API에서 확인한 뒤 환불 상태 반영. 부분 환불·정산·카드 분쟁은 별도 확장 필요.
플랫폼 운영자가 공증인 대신 공증 완료를 누를 수 없습니다. 고객은 결제 완료 값을 직접 쓰거나 임의 PDF를 공증 발급문서로 등록할 수 없습니다. 발급 전 `issued` PDF는 해당 공증인만 다운로드할 수 있습니다. 사용자 전환 버튼이 있는 시연과 달리 실제 API는 플랫폼 인증 헤더로 권한을 집행합니다.
## 개발 구조와 TypeScript 이전
- `worker/agency-domain.mjs`: 부수효과 없는 상태 전이. `amCreate`, `amAct`, `amTerms`. `actor`는 서버가 부여합니다.
- `worker/market-api.mjs`: D1 낙관적 버전 검사 + R2 파일, 고객/배정 공증인/운영자 권한. 주문은 계약 PDF 지문과 준비자료 commitment를 고정합니다. 활성 주문이 있으면 원 신청자료 재개방 금지.
- `worker/toss-payments.mjs`: Toss Payments v1 승인·주문 조회·전액 취소 어댑터. 고정 API 호스트, 멱등 키, 금액/주문/통화 검증. 실제 키를 브라우저에 전달하지 않습니다.
- `src/notary-market.html`: 하나의 템플릿에서 별도 운영판/시연판 생성. 시연은 동일 도메인 전이 함수를 사용하며 서버·PG 호출 없음.
- `development/db/notary-schema.ts`: Drizzle 스키마. `drizzle/0001_powerful_wendigo.sql` 신규 3테이블. 적용된 0000 수정 금지.
- `development/tests/market.test.mjs`: 실제 저장/권한/파일/API + 모의 PG 응답 테스트. 실제 결제 테스트가 아닙니다.
- `development/contracts/notary-market.d.ts`: TypeScript 전환의 역할·상태·결과 계약.
Claude는 위 모듈들을 domain / application / infrastructure / UI 레이어로 옮기되 도메인 상태와 role guards, PDF 지문, 견적 바인딩, 멱등 결제 원장을 보존해야 합니다. 정부 API 어댑터는 승인된 명세·권한을 확보한 뒤 별도 port로 추가하세요. `governmentApiVerified`를 파트너 확인만으로 true로 바꾸지 마세요.
## 운영 설정
Sites 런타임 비밀 환경변수 또는 로컬 `.env`에 설정합니다. 저장소·ZIP·UI에 비밀키를 넣지 않습니다.
| 변수 | 내용 |
| --- | --- |
| PLATFORM_OPERATOR_EMAILS | 운영자 이메일 쉼표 목록. 호스팅은 현재 소유자만 설정. 로컬 기본 admin@blocksign.example |
| NOTARY_PAYMENT_ACCOUNTS | JSON: `{ "<승인 파트너 UUID>": {"clientKey":"test_ck_...","secretKey":"test_sk_...","mId":"..."}, "platform": {"clientKey":"...","secretKey":"...","mId":"..."} }`. 각 기관과 실제 PG 계약/승인된 수취 구조 필요 |
| NOTARY_MARKET_LIVE_PAYMENTS | `true`일 때만 live 키 허용. 기본 차단 |
| PLATFORM_NONLEGAL_FEES_ENABLED | `true`일 때만 별도 비법률 운영비 활성화. 기본 0원 |
| PLATFORM_ADMIN_FEE_KRW | 고정 운영비 정수. 공증료 비율 수수료를 계산하지 않음. 실제 업무·요금 구조 검토 후 설정 |
운영 PG 키·제휴 사업자·정부 연계 권한은 제공되지 않아 실제 비용 청구나 공식 공증은 실행하지 않았습니다. 사업자 자격은 사람이 공식 근거와 범위를 확인하는 구조이며 정부 자격 조회 API 확인으로 표시하지 않습니다. 현재 사이트는 소유자 전용이므로 실제 파트너 참여 전 정확한 참여자를 지정한 접근 권한 설정이 필요합니다. 임의 초대나 공개 전환을 하지 않았습니다.
PG 클라이언트 복귀가 유실되면 동일 주문 승인/조회로 재확인할 수 있습니다. 서버 내부 원장과 도메인 전이가 중간 실패한 경우 주문 GET이 저장된 승인/환불 원장을 재적용합니다. 실제 PG는 모바일 최상위 창에서 열립니다. 웹훅·주기적 대사 작업자·키 회전·운영 환불 예외 처리는 출시 전 추가해야 합니다. 파일은 크기·PDF 헤더 및 소유권을 검사하지만 완전한 악성 문서 검사는 추가해야 합니다.
## 검증
`cd development && npm test && npm run typecheck`, 루트에서 `node tests/workflow.cjs`, `python3 scripts/build.py && python3 scripts/build-worker.py`.
Toss 공식 명세: https://docs.tosspayments.com/reference 및 https://docs.tosspayments.com/guides/v2/payment-window/integration . 정부 시스템은 공증인이 허용된 방법으로 직접 이용하며 비밀번호 보관·무단 자동화는 구현하지 않았습니다.
# 고객 공증 흐름 v0.11
계약서 → 검토 → 견적 비교 → 결제 → 일정 → 면담 → 발급 → 완료, 8개 단계. 문서 없이 견적 단계로, 기관 확인 없이 발급으로 이동하지 않는다.
`src/notary-flow.js`가 진행 단계와 방문 가능 범위를 계산한다. `src/notary-app.js`는 단일 submit/click 처리, `src/notary-files.js`는 원본 해시 검증/자료 묶음, `src/notary-documents.js`는 준비용 인증문/리포트/결제내역을 만든다. 실제 AI 미연결.
이전 단계는 읽기 전용이며 재방문으로 결제나 발급을 반복하지 않는다. 실제 모드 상태는 서버 원본을 재조회, 별도 시연은 브라우저 보관. 모바일 하단에 이전/다음 주 동작을 고정한다.
상세 API·보안·남은 연계·TypeScript 인계는 `REVERSE_QUOTES.md`와 `CODEX_CLI.md`를 참고한다.
# Codex CLI / Claude Code 인계
이 저장소는 이미 구현된 전자계약·Safe 에스크로·증명·공증 플랫폼이다. 새로 만들지 말고 현재 기능과 상태를 보존하며 수정한다.
## 로컬에서 이어서 개발
1. `blocksign-development.zip`을 내려받아 빈 작업 디렉터리에 푼다.
2. Node.js 24 이상 사용. 현재 로컬 API는 `node:sqlite`를 사용한다. 사용자 보유 Node22/16에서는 업그레이드 필요.
3. `npm install --prefix development`
4. `python3 scripts/build.py`
5. `npm start --prefix development`
6. 출력된 loopback 주소에서 개발 화면을 연다. 테스트 데이터는 `development/data`에만 보관한다.
7. 이 폴더에서 설치된 `codex` 실행 후 ChatGPT로 로그인한다. CLI 개발 인증은 배포 서비스의 AI 호출 인증과 별개다. Claude Code도 같은 소스에서 `CLAUDE.md`를 읽고 이어서 개발할 수 있다.
자동으로 이 대화의 문맥이나 대표님 PC의 파일에 연결되지는 않는다. 이 문서와 `CLAUDE.md`, `docs/REVERSE_QUOTES.md`를 먼저 읽는다. ChatGPT 로그인 토큰을 서비스 서버 API 키로 복사하지 않는다.
## 검증
- `npm test --prefix development`
- `npm run typecheck --prefix development`
- `node --test tests/services.cjs tests/notary.cjs tests/notary-flow.cjs` (파일명은 tests 목록 확인)
- `node tests/workflow.cjs`
- `python3 scripts/build.py` / `python3 scripts/build-worker.py`
## 다음 작업
실제 AI 문서 분석은 미연결. 현재 실제 서비스의 리포트는 등록·업로드 정보 준비 점검이며, 시연의 사례 리포트는 고정 샘플이다. 실제 AI를 붙일 때는 서버 인증·개인정보 전송 동의·PDF 해석·페이지 근거·결과 버전/해시·검토자 확인이 필요하다. 자격자 최종 판단과 공식 발급은 생략하지 않는다.
배포된 서비스는 소유자 비공개다. 공개 전환이나 임의 파트너 초대는 별도 요청 없이 하지 않는다.
# 공증 역견적 v0.11
## 고객 순서
계약 PDF 준비 → 준비 점검/사례 리포트 → 자격 확인된 공증사 초대 → 공증사 견적 비교 → 선택 → 분리 결제 → 일정 → 당사자 확인·면담 → 기관 발급 원본 → 수령 및 ZIP.
계약서 준비와 공증사 선택 순서를 바로잡았다. 단계 버튼으로 미래 단계에 진입할 수 없고 이전 단계 열람으로 결제/발급을 반복하지 않는다. 시연은 별도 `notary-market-demo.html`, 실제 고객 화면은 `notary-market.html`, 실제 공증사 견적함은 `notary-bids.html`, 기존 수행·운영함은 `notary-workspace.html`.
## API
`/api/notary-market/requests`
- GET 본인 요청, 초대된 현 승인 공증사의 요청, 운영자 범위.
- POST `{caseId, partnerIds, sharingConsent:true, offline?:{amount,source,date,sameScope:true}}` 준비된 본인 문서만, 1~10개 확인된 기관만. 초대 이외 기관에는 문서 비공개.
- `/:id` GET: 고객 전체 견적, 참여 공증사는 자기 견적만.
- `/:id/contract` GET: 권한과 준비 패키지 지문 교차 확인.
- `/:id/bids` POST: 초대된 현 승인 사업자만 `{notaryFee,feeBasis,turnaroundDays,scopeReviewed:true,statutoryFeeConfirmed:true,personalAttendanceRequired}`. 플랫폼 비용은 서버 설정. 기존 견적 갱신 시 이전 견적 해시 무효.
- `/:id/select` POST `{bidId,quoteHash}`: 고객만. 유효 견적/기관/문서 확인, D1 batch 원자성으로 단일 주문 생성. 같은 선택 재요청은 기존 주문 반환, 다른 선택은 충돌. 선택한 이후 기존 주문의 결제/면담/발급 API 재사용.
- `/:id/cancel` POST: 선택 전 고객 취소.
D1 추가 migration0002; 이전 마이그레이션 수정 금지. Local D1 adapter도 batch transaction을 지원한다.
## 가격 표시
고객 제공 동일 업무 범위 오프라인 총 견적이 있을 때만 차액/비율 표시. 출처·날짜·고객 제공 여부 표시. 음수 차액은 '추가'. 근거가 없으면 할인·절감율 없음. 시연의 55,000원/35,000원 등은 모두 가정. 실제 시장가격·법정수수료 산출 결과가 아니다. 가격 경쟁이 법정 공증료 임의 할인을 유도하지 않도록 기관이 적용 규정 확인에 동의한다.
## 리포트와 문서
실제 서비스는 문서 준비 점검만 수행하며 AI API 미연결. 샘플 리포트에는 ERP 계약 조문 근거와 확인할 누락 항목을 담았다. 인증문은 공증인이 공식 서식으로 확정하기 전 준비용 초안이며 공식 증서인 것처럼 번호·직인·서명을 생성하지 않는다. 시연 PDF는 법적 공증 효력 없는 표시가 있다. 실제 결과는 공증기관 업로드 원본, PG 영수증은 PG 확인 결과의 receipt URL을 제공한다. 법정 계산서는 기관이 fee_notice PDF로 업로드 가능. 플랫폼 결제내역과 법정 계산서를 혼동하지 않는다.
## 공식 근거 확인(2026-10-29)
- 공증서식의 사용 등에 관한 규칙 제27조: 사서증서 앞 표지(별지33) 및 뒤 인증문(별지34/35). https://www.law.go.kr/법령/공증서식의사용등에관한규칙
- 같은 규칙 제21조·별지19: 수수료 지급 시 계산서 교부/보관. 실제 계산서는 해당 공증기관이 발행한다.
- 공증인 수수료 규칙 제20조 인증행위 및 제30조 임의 감액 제한. https://www.law.go.kr/법령/공증인수수료규칙
실제 발급 사례를 확보했다고 주장하지 않는다. 공식 규정의 구성에 따른 초안만 제공한다. 공식 시스템 연계/API·PG 실결제·자격 사업자 영업 개시는 별도 연결과 검증이 남았다.
# v0.12 원격 공증 / 전체 플랫폼 인계
## 제품 진입점
- `platform-demo.html`: 전자계약, 에스크로, 증명, 원격 공증, 서명인 전체 시연.
- `platform-development.html`: 동일 서비스 전체 개발 진입점.
- 모든 HTML에 전체 서비스 메뉴가 표시된다. 랜딩은 자동 이동하지 않는다.
- `blocksign-demo.zip`: HTML/PDF 서식이 포함된 별도 전체 시연 묶음.
- `blocksign-development.zip`: 기존 전자계약/Safe/증명/공증 소스, 테스트, 타입 계약, 인계 문서.
## 새 원격 공증 프로토콜3
원격 지원·지정 근거가 확인된 온라인 공증기관만 신규 견적에 초대한다.
계약서 → 검토 → 견적 비교 → 결제 → 신분증 확인 → 원격 공증 → 발급 검토 → 완료.
예약 날짜 선택을 고객 필수 단계에서 제거했다. 원격 공증도 공식 신분확인과 지정공증인의 화상 본인·문서·전자서명 의사 확인을 거친다. 실제 정부 원격 공증을 자체 화상 UI로 대체하지 않는다.
- 고객 `identity-request`: 당사자별 신분증 종류 준비 기록만 저장.
- 자격자 `identity-check`: 공식 신분증 진위·얼굴 대조 결과 및 근거 기록.
- 자격자 `remote-open`: 공식 접수·서류 확인·모든 당사자 신분확인이 있어야 가능. 연결 URL은 HTTPS enotary.moj.go.kr만 허용.
- 당사자별 계약서·대표권 확인 후 원격 의사 확인(`interview`)과 참여 확인(`attendance`), 원본 발급 등록(`issue`).
- v3는 기존 v2의 일정 확정 조건을 요구하지 않고, 원격 연결·신원 확인을 요구한다. 기존 v2 기록/감사 해시를 자동 변환하지 않는다.
- API는 주민번호·신분증 사진·여권번호 필드를 받지 않는다. 신분증 원본은 공식/기관의 보안 채널에서 확인한다. 기관이 적법한 위탁·보관·본인확인 서비스를 구성하기 전 플랫폼에 신분증 사진 업로드 기능을 열지 않는다.
- 실제 자격자 처리 화면 `notary-remote.html`, 운영 서류 확인은 기존 `notary-workspace.html`.
## 비동기 시연
`src/notary-jobs.js`: 업체 탐색/개별 견적 도착(6/11초), 결제 확인, 신분증 진위, 원격 연결, 전자서명 검토, 발급 검토. job의 시작/만료/종류를 브라우저에 저장해 새로고침 후 재개한다. 실제 모드에서는 타이머로 결제/신분확인/공증 발급을 완료하지 않는다. 실제 상태는 인증된 서버의 공증사 기록을 조회한다.
## 서식
`src/notary-forms.js`는 법무부 공개 실무 매뉴얼의 국내 사서 인증 예시(pp.70-72)에 있는 별지33/34/35 항목·순서·A4 규격을 재현한 공통 좌표 모델이다. 기존 체결문서는 제35호 확인형식의 샘플을 기본 사용한다. 제34호 직접 서명형식도 별도 PDF를 제공한다. 빈 직인/서명/등부번호에 실제 기관 정보를 임의 생성하지 않는다. 서식 재현 샘플은 실제 발급문서가 아니다.
원격 전자문서 인증의 최종 인증문은 지정공증인이 공식 시스템에서 확정한다. 법무부 전자공증의 정부 API 연계가 승인·연결되었다고 주장하지 않는다. 현재 표본의 PDF 서식과 앱 동적 PDF는 같은 좌표 모델을 사용하지만 브라우저 글꼴 차이로 픽셀 단위의 원본 PDF 복사본은 아니다.
`src/forms/*.pdf`는 임베디드 한글 글꼴을 포함한다. 재생성: `scripts/notary-form-pdfs.py --font /path/to/NotoSerifKR.ttf`. Noto Serif KR OFL 라이선스는 forms에 포함. 동적 고객 PDF는 한글 캔버스를 PDF에 포함하여 뷰어의 한글 폰트 유무에 영향받지 않는다.
공식 근거 확인일 2026-10-29:
- 법무부 화상공증 안내: https://www.moj.go.kr/moj/2306/subview.do
- 법무부 실무 매뉴얼 국내 공증 예시: https://www.immigration.go.kr/bbs/moj/111/199468/download.do (PDF 34~36쪽 / 책자70~72쪽)
- 공증서식의 사용 등에 관한 규칙: https://www.law.go.kr/법령/공증서식의사용등에관한규칙
- 지정공증인의 사무처리 등에 관한 규칙 제8/18조: https://www.law.go.kr/법령/지정공증인의사무처리등에관한규칙
계산서/결제내역은 실제 공증기관의 계산서·PG 영수증과 구분한다. 공식 계산서19 원본을 확보했다고 주장하지 않으며 실제 기관의 fee_notice 업로드를 사용한다.
# v0.13 서버 전자계약 인계 — 2026-10-30
## 이번 변경의 결과
`contracts.html`은 배포된 사이트에서 계정 인증을 받아 실제 D1/R2에 저장한다. 기존 `development.html`은 로컬 Node API/지갑/에스크로 정책 개발 도구로 유지한다. `platform-demo.html`과 `notary-market-demo.html`은 별도 브라우저 시연이다. 실제 서비스와 시연 데이터를 가져와 섞지 않는다.
- 서명인 등록, 서버 주소록, PDF 업로드, 투명 필드 이동/크기 조절/삭제/쪽 선택, 수신인 역할과 순서, 순차/동시 서명.
- 배포 서버의 create → send → sign → completed → PDF/근거/ZIP 경로. 발송은 서명 링크 생성과 수신함 노출이며, 이메일 발송 업체는 미연동이다.
- 실제 서명 PNG를 서버에서 원본 PDF에 합성한다. 한글 텍스트 필드는 브라우저에서 PNG로 렌더링해 폰트 누락을 막는다. 서버 예제는 한글 ERP 계약 PDF다.
- 발송 전 초안은 발신자만 조회한다. 수신인 인덱스가 등록되어 있어도 발송 시각이 없으면 수신함·문서 조회를 차단한다.
- 서명 요청은 계정 이메일·담당 필드·레이아웃 지문·동의·순서·기한을 모두 검사한다. 발신자라는 이유로 수신인 명의의 서명을 할 수 없다.
- 완료 PDF, 원본, 완료 근거 PDF, 합본 PDF, JSON manifest를 내려받는다. 완료 계약에서 원격 공증 신청으로 이동하면 서명 완료본을 다시 SHA-256 대조해 첨부한다. 공식 공증 접수와 발급으로 간주하지 않는다.
- D1의 version CAS로 동시 요청을 차단한다. R2 snapshot은 불변으로 보관하고 D1이 최신 snapshot을 가리킨다. 수신함은 별도 recipient 인덱스로 조회한다.
## 엔트리와 타입스크립트 전환
- `worker/esign-api.mjs`: hosted `/api/esign/me`, `/example`, `/list`, `/command`.
- `development/server/core.mjs`: Node와 Worker가 공유하는 상태 전이 엔진.
- `development/server/crypto.mjs`: 동일한 SHA-256, Web Crypto 난수, base64 바이트 처리. 개인키 없음.
- `development/server/hosted-pdf.mjs`: PDF 파싱·페이지/크롭·액티브 코드 검사.
- `development/server/pdf-portable.mjs`: Worker의 서명/근거 PDF 생성.
- `development/client/esign.ts`: 타입이 있는 SDK. React/Next/Vinext 화면에서 그대로 사용 가능.
- `development/contracts/index.d.ts`: 도메인 타입. 폼에서 actor/role을 보내 권한을 선택하는 설계로 바꾸지 말 것.
- `drizzle/0003_hosted_signing.sql`: 추가 마이그레이션. 이전 마이그레이션을 수정하지 않는다.
실행:
```bash
npm --prefix development ci
npm run build
npm test
npm run typecheck
npm --prefix development start
```
로컬에서는 `development/data/actors.json`에 생성된 테스트 토큰으로 연결한다. 배포 사이트는 Sites가 전달하는 계정 헤더를 사용하고 클라이언트 토큰 선택 UI를 표시하지 않는다. 현재 Site의 기존 접근 정책을 유지했으므로, 서명 링크를 받은 상대방도 Site 접근 권한과 지정 이메일 계정 로그인이 필요하다. 링크만으로 비공개 Site 접근을 우회하지 않는다.
## 정직한 운영 경계
다음은 코드만으로 대신 완료할 수 없다. 담당 사업자·계약·운영 설정이 있어야 활성화한다.
| 항목 | 구현 상태 | 남은 연결 |
|---|---|---|
| 전자계약 | 실제 저장/권한/서명 PDF/다운로드 구현 | 이메일 발송, 운영 본인확인, 백업·보존·삭제 정책 |
| 국내 원격 공증 | 접수/역견적/수임/PG검증/원격 확인/결과 업로드 상태기계 | 실제 자격 확인 파트너, 공식 절차, PG·정산 계약 |
| AI 검토 | 시연 사례와 준비자료 점검 | 별도 승인된 AI API 설정 및 실제 분석, 정확성 평가 |
| Safe 에스크로 | 엔진/어댑터/Solidity/로컬 EVM 테스트 | 실제 Safe 통합·배포·체인 설정·보안 검토 |
| 블록체인 증명 | 완료 지문 준비, 실제 영수증 검증 어댑터 | 레지스트리 배포·RPC·사용자 실행 |
공증료 임의 역경매·법률업무 소개료·실제 할인율을 가정하지 않는다. 동일 범위의 사용자가 입력한 오프라인 견적과만 비교한다. 실제 공증서·본인확인·결제 성공·트랜잭션 해시를 생성하거나 타이머로 완료시키지 않는다. 법적 유효성이나 공증인 자격을 프로그램 테스트가 입증하는 것은 아니다.
## 제한과 후속 운영 작업
- 업로드 PDF 5MB, 30쪽, 회전/크롭 변경 없음. PNG 필드 데이터 합계 2MB. 액티브 PDF는 거부.
- 단일 발신자 100문서, 수신함 최근 200문서. 많은 데이터의 페이지네이션/쿼터는 후속 작업이다.
- 실제 계정 로그인은 법정 신원확인이 아니다. 계정 권한 부여를 자동 확대하지 않는다.
- 현재 감사 기록은 해시 체인이지 외부 공인 타임스탬프나 PAdES 인증서 서명이 아니다.
- 불변 R2 snapshot 보존은 경쟁 요청 안전을 위한 설계다. 기간별 삭제·보존 잠금·복구·운영 모니터링을 별도로 설정해야 한다.
- 파일 리소스 부하·악성 PDF 검사·부하 테스트·운영 보안 심사는 별도 출시 작업이다.
- 임시 저장 후 수정은 새 초안으로 복제하고 기존 초안을 취소하는 방식이다. 완료본은 수정하지 않는다.
## 검증
`development/tests/hosted-esign.test.mjs`는 임시 SQLite/R2 환경에서 실제 Worker API를 실행한다. 계정 격리, 서명 순서, 담당 필드, 지문/동의, PNG 검증, PDF 이미지 합성, 근거 PDF, 해시/감사, 동시 서명 CAS, 압축 PDF 액티브 코드 차단을 검증한다. 실제 제3자 이메일, 실명 인증, PG 승인, 정부 공증, 메인넷 자금 이동은 실행하지 않았다.
## 2026-10-31 공통 UI 정리
- 기존 상단 메뉴 그리드 및 중복 시연 내비게이션 제거. PC 좌측 사이드바, 900px 이하 모바일 하단 메뉴 및 햄버거 서랍으로 통일.
- `scripts/ui_shell.py`가 공통 메뉴를 생성하고 `src/global-nav.css`, `src/global-nav.js`가 스타일·접근성·메뉴 열기/닫기·현재 경로를 처리한다. dist 파일을 직접 수정하지 말 것.
- 600px 이하 서비스 카드는 한 줄에 하나씩, PC는 2~3열. 링크 밑줄 제거, 버튼 정렬, PDF 편집 영역의 좁은 화면 정리.
- 메뉴 이동 전에 서랍을 inert로 만들면 링크 기본 동작이 차단될 수 있다. 다른 문서 이동은 브라우저 기본 동작을 유지하고, 같은 문서의 해시 이동 완료 후 서랍을 닫는다.
- 모바일 공증 단계 버튼은 하단 내비게이션 위에 고정한다. 키보드 포커스와 Escape 닫기, 배경 inert 및 안전 영역 여백을 유지한다.
# 블록싸인 기능 연결 릴리스 · 2026-11-02
## 보존한 기준
- 첫 페이지는 별도 랜딩이며 자동 이동하지 않는다.
- v12 전자계약·에스크로 시연의 화면과 업무 흐름을 유지한다.
- 전체 서비스 소개 화면은 v12 템플릿으로 복원한다. 메뉴는 PC 좌측, 1100px 이하 하단/햄버거다. 랜딩에는 업무 메뉴를 중복 주입하지 않는다.
- 기존 D1/R2 업무 기록과 이전 마이그레이션을 덮어쓰지 않는다.
## 연결·보완한 기능
- 보존된 Worker 전자계약 API, 서버 저장, 서명 PDF, 완료 근거, 공증 신청 연결을 배포에 포함한다.
- 수신인 위/아래 순서 변경 시 해당 서명란의 수신인 참조만 재매핑한다. 좌표·페이지는 유지한다.
- 수신인 삭제 시 해당 사람의 필드만 삭제한다. 나머지 필드와 순서는 보존한다.
- 행 번호가 포함된 이메일·역할·순서 검증을 저장 전에 실행한다.
- 계약서의 본인 서명란을 누르면 서명 창을 연다. 적용 버튼을 눌러 문서에 미리 반영하고, 별도 동의·제출로 서버에 확정한다.
- ZIP 다운로드를 실행하고 화면에 ZIP/PDF 재저장 링크를 함께 남긴다. 지원 단말에는 파일 공유 버튼을 제공한다.
- 모바일 PDF는 화면 폭에 맞추되 서명 좌표는 페이지 비율로 유지한다.
- `src/contract-editor.js`는 UI와 분리된 수신인/필드 편집 모델이다. TypeScript 이전 시 이 모델의 참조 보존 테스트를 유지한다.
## 실행
```sh
npm --prefix development ci
npm test
npm run typecheck
npm run build
npm --prefix development start
```
## 진입점
- `/`: 랜딩
- `/contracts.html`: 서버 전자계약
- `/platform-demo.html`: 별도 전체 시연
- `/demo.html#escrow`: 에스크로 단계별 시연
- `/notary-market.html`: 실제 공증 의뢰 관리
- `/notary-market-demo.html`: 독립 공증 시연
- `/development.html`: 로컬 API 개발 도구
- `/blocksign-development.zip`: 소스·테스트·타입·문서
- `/blocksign-demo.zip`: 독립 HTML/PDF 시연 묶음
## 외부 운영 연결
실제 공증기관 수임·자격 확인, 공식 공증 수행·발급, PG 상점·정산, 법정 신원확인, 실제 AI 분석, Safe/RPC/레지스트리 배포·실자금 실행은 운영 사업자와 설정이 필요하다. 이 릴리스는 이를 타이머·임의 직인·가짜 거래로 성공 처리하지 않는다. 공증 시연은 가상 사례를 사용하고 실제 모드와 저장소가 분리되어 있다. 실계약 서명 링크는 기존 비공개 사이트 접근 권한을 우회하지 않는다. 이메일 배달 사업자는 미연결이며 수신함·링크 전달 방식이다.
Android 실기기의 다운로드 저장 성공은 이 개발 환경에서 확인할 수 없다. 지원 API에 따라 저장 링크 또는 공유 기능을 사용한다.
## 검증 결과
- 자동 테스트 52건 통과(프런트 모델·공증·서버 서명·권한·지갑·로컬 EVM). TypeScript 검사 통과.
- 격리된 개발 데이터로 서명인 등록·순서 변경·수신인 삭제·초안 저장·발송·직접 서명·서명 적용·완료·ZIP/PDF 저장 링크 생성 확인.
- 공증 시연 1~8단계, 견적 지연 수신·결제/신원/원격/발급 대기·결과 수령·영수증 링크 생성 확인.
- `--managed-preview`에서만 생성된 로컬 테스트 계정을 선택하는 기능을 제공한다. 토큰은 HttpOnly 쿠키로 유지하며, 실제 Cloudflare Worker에는 개발 세션 경로가 없다.
# 업무 관리 및 계약 증명
기존 서비스는 기존 주소로 이용합니다. 서비스 선택 랜딩은 `/`, 개발 업무공간은 `/business.html`, 독립 시연은 `/business-demo.html`입니다. `?service=` 값은 cards, expenses, approvals, tax, erp, settings입니다. 시연 데이터는 브라우저 로컬 저장소에 저장합니다. 시연 관리자, 직원, 결재자 전환으로 카드 가져오기 → 경비 상신 → 승인 → ERP CSV/전송을 확인할 수 있습니다.
개발/호스팅 데이터는 D1 사업장 레코드와 비공개 R2 영수증에 저장됩니다. 마이그레이션 0004는 신규 테이블만 추가합니다. Sites 로그인으로 회사 생성 및 역할 지정이 가능하며 Sites 프로젝트에 대한 접근 범위는 호스팅이 제어합니다. 결재 담당자는 본인 건을 결재할 수 없습니다. ERP CSV는 원 단위 승인 경비를 안정적인 posting_id로 내보냅니다. 회사별 저장 한도는 시범 운영용입니다.
카드 CSV는 UTF-8이며 transaction_id,date,merchant,amount,employee_email,status 헤더를 사용합니다. status는 approved 또는 canceled입니다. 한 번에 500행까지 수용합니다. 같은 거래 ID의 원본 속성이 바뀌면 반영하지 않습니다. 취소 내역은 신규 상신 및 신규 ERP 전송에서 제외됩니다. 이미 ERP에 전송된 전표의 취소는 회계 담당자가 역분개해야 합니다.
## 외부 연동 계약
`BUSINESS_GATEWAY_URL` 및 `BUSINESS_GATEWAY_TOKEN`은 운영 배포 비밀입니다. 등록된 HTTPS 게이트웨이와 회사별 제공기관 연결이 필요합니다. 브라우저에는 비밀값이 내려가지 않습니다. 게이트웨이는 모든 workspaceId를 실제 기관 계정과 승인된 사업자에 매핑해야 합니다. 아래 주소는 통합 계약이며 카드사/국세청의 직접 API 명세가 아닙니다.
- POST cards/pull — {workspaceId} → {rows: 카드 CSV와 같은 속성을 가진 배열}. 취소와 지연 반영을 위해 이전 수집분을 다시 내려줄 수 있습니다.
- POST tax/collect — {workspaceId} → {rows:[{externalId,date,company,registration,description,amount,tax}]}. 외부 발급 문서 식별자로 중복을 제거합니다.
- POST tax/issue — {workspaceId,invoice} → {status:pending} 또는 {status:accepted|rejected,externalId}. 한 건에 동일 Idempotency-Key가 사용되며, 게이트웨이는 중복 발급 방지와 처리 상태 조회를 지원해야 합니다. 발급 실패 후 수정 저장하면 새 요청 키가 만들어집니다. 사업장 매핑·발급 자격·필수 필드·국세청 전송은 운영 연동에서 확인해야 합니다.
- POST erp/post — {workspaceId,posting} → {status:posted,externalId}. 동일 Idempotency-Key로 재시도 시 같은 처리 결과를 반환합니다.
카드 동기화 버튼은 공급자가 제공한 내역을 불러옵니다. 자동 수집을 켠 회사에 대해 Worker scheduled 핸들러가 카드사 자료를 수집합니다. 운영 Cloudflare Cron Trigger에 주기를 설정해야 하며 Sites 배포에는 트리거가 연결되어 있지 않습니다. 외부 키 연결 없이도 경비 승인·CSV 입력/출력은 동작합니다.
## 계약 이메일 및 증명
`RESEND_API_KEY`, `ESIGN_EMAIL_FROM`, `ESIGN_PUBLIC_ORIGIN`을 설정하면 계약 발송 시 등록된 서명자·검토자·참조인에게 역할별 초대 메일을 개별 발송합니다. 순차 계약은 메일 수신 후 계약을 확인할 수 있고 차례가 되면 서명 또는 검토할 수 있습니다. 관리자는 초대 메일의 발송 상태를 확인하거나 재시도할 수 있고, 차례가 된 수신자에게 별도 알림을 보낼 수 있습니다. 비공개 Sites에서는 관리자가 공유 설정에서 외부 수신인 이메일에 보기 권한을 먼저 부여합니다. 계약 권한은 로그인 이메일과 계약에 등록된 이메일을 대조해 확인합니다. 최종 서명이 저장되면 등록된 서명자·검토자·참조인에게 완료 메일을 개별 발송합니다. 완료 계약 화면에 발송 업체 접수 상태와 재시도 버튼을 표시합니다. 메일 링크는 해당 이메일로 로그인한 뒤 기존 계약 권한을 확인합니다.
계약 다운로드 ZIP의 01-signed-contract.pdf와 manifest.json은 `/verify-contract.html`에서 브라우저 내 SHA-256으로 대조합니다. 일치 여부와 실제 체인 기록은 따로 표시합니다. `ETH_RPC_URL`, `ETH_CHAIN_ID`, `EVIDENCE_REGISTRY`, `ANCHOR_CONFIRMATIONS`를 설정하고 호환 EvidenceRegistry를 배포하면 계약별 증명 옵션을 켠 후 소유자가 지갑으로 문서 증명 지문을 제출할 수 있습니다. 서버는 거래의 목적지, calldata, 영수증 이벤트, 정식 블록과 확정 수를 검증합니다. 체인에는 원문이나 서명인 정보가 올라가지 않습니다. 사용자 지갑이 거래 수수료를 부담합니다.
## ERP 업무
회사는 회사 설정에서 선택합니다. ERP에서 전표, 정산, 거래처, 계정과목, 발주 및 재고를 관리합니다. 전기 전표는 차·대변 동일 금액으로 기록하고 정정은 별도 역분개로 남깁니다. 월 마감은 그 월의 전표 추가·수정·전기를 막고, 마감 해제는 소유자만 할 수 있습니다. 입출금과 거래처별 증감은 전기된 전표 기준입니다. 재고 수량은 입출고 기록 또는 확정 발주의 입고에서 반영됩니다. 발주 확정은 내부 상태 변경입니다.
분개장 CSV(/api/business/journal.csv)와 기존 경비 전표 CSV는 별도 내보내기입니다. 외부 ERP 전송은 기존 BUSINESS_GATEWAY 설정을 사용합니다.
## 바로빌 직접 연결
런타임 시크릿 BAROBILL_WORKSPACES에 업무공간 UUID별 설정을 저장합니다. 키와 카드번호는 서버에서만 읽습니다. 예시 구조(값은 비밀 관리 도구에서 지정):
```json
{
"<workspace UUID>": {
"mode": "test",
"key": "<연동인증키>",
"corpNum": "<10자리 사업자번호>",
"userId": "<바로빌 회원 ID>",
"cards": [{"number": "<등록 카드 번호>", "email": "<회사 구성원 이메일>"}],
"issuer": {"name": "<공급자 상호>", "ceo": "<대표자>", "address": "<주소>", "email": "<담당 이메일>"}
}
}
```
카드 등록과 홈택스 수집 신청은 바로빌 계정에서 선행합니다. 카드 수집은 조회 기간 내 원화 승인·취소·부분취소·환불 내역을 HistoryKey로 중복 제거합니다. 카드에 취소 내역이 있으면 새 경비 연결이나 전표 전기를 잠그므로 담당자가 대조해야 합니다. 카드 자동수집은 런타임 Cron 연결이 필요합니다.
현금영수증과 세금계산서는 매입·매출 방향 및 기간으로 조회합니다. 수집한 매입 현금영수증은 담당자 배정 후 경비에서 증빙으로 선택할 수 있습니다. 전자세금계산서는 공급자와 거래처 정보가 필요합니다. 테스트 발급은 운영과 분리됩니다. 운영 발급에는 mode=live와 BAROBILL_LIVE_ISSUE=true가 필요하며 회사의 바로빌 발급 설정·자격이 준비돼 있어야 합니다. 발급과 국세청 전송 상태는 별도입니다. 직접 연동이 없는 업무공간은 기존 게이트웨이 계약을 그대로 사용할 수 있습니다. 해당 게이트웨이가 전자영수증을 제공한다면 POST receipts/pull에서 {rows:[{externalId,date,merchant,amount,direction,status}]}를 반환합니다.
## 리빙굿코리아 시연과 거래처 결제 상신
시연 페이지를 열면 생활용품 유통 업무를 가정한 카드·증빙·계산서·발주·재고·전표가 기본으로 보입니다. 거래와 금액은 시연용입니다. 데이터 변경은 브라우저의 시연 저장소에 저장됩니다. 운영 회사의 거래에는 영향을 주지 않습니다.
ERP의 결제 상신에서 전기된 미지급금 또는 외상매입금 전표를 선택하고 별도의 결재자에게 요청할 수 있습니다. 지정 결재자는 전자결재에서 승인 또는 반려합니다. 승인이 끝난 뒤 재무 담당자가 실제 지급일과 지급 증빙 번호를 입력하면 출금 전표가 생성됩니다. 은행 지급은 외부에서 처리합니다.
# BlockSign 개발·배포 가이드
2026-11-12 KST에 배포된 소스 스냅샷이다. 배포 소스 커밋은 `88b36ff9badc9afcf5460f1d38c79c8d1d87677d`다. ZIP의 `deploy/cloudflare/`와 `wrangler.jsonc.example`은 독립 배포용으로 함께 제공한 파일이다.
| 먼저 볼 파일 | 용도 |
|---|---|
| [ARCHITECTURE.md](ARCHITECTURE.md) · [아키텍처 설계도](ARCHITECTURE.svg) | 구성 요소, 서비스별 코드, 데이터 흐름 |
| [EXTERNAL_INTEGRATIONS.md](EXTERNAL_INTEGRATIONS.md) | 외부 업체, 선행 작업, 활성화 조건 |
| [AGENTS.md](../AGENTS.md) · [CLAUDE.md](../CLAUDE.md) | Codex 및 Claude 작업 시작점 |
| `dist/server/index.js` · `dist/.openai/` | 현재 Sites용 Worker 빌드와 마이그레이션 |
| `deploy/cloudflare/entry.mjs` · `wrangler.jsonc.example` | 별도 Cloudflare 계정용 Worker 입구와 설정 |
## 1. 로컬에서 실행
압축을 풀고 최상위 `BlockSign/`에서 실행한다.
```bash
node --version
python3 --version
npm --prefix development ci
npm run build
npm test
npm run typecheck
node deploy/cloudflare/smoke.mjs
npm run dev
```
Node.js 24 이상과 Python 3를 사용한다. 로컬 기본 주소는 `http://127.0.0.1:8787/`이다. 카드·전자결재·ERP 샘플을 보려면 메인의 **전체 시연**을 누른다. 개발 프리뷰의 테스트 역할은 생성된 로컬 계정을 사용한다. 포트를 바꾸려면 `PORT=8788 npm run dev`로 시작한다. 로컬 서버는 개발·검증용이며 운영은 아래 Worker 경로를 사용한다.
## 2. 기존 ChatGPT Sites에 이어서 배포
1. 사이트 소유자의 Sites 프로젝트와 연결 저장소 권한을 확인한다. `.openai/hosting.json`의 `project_id`는 기존 프로젝트를 가리킨다.
2. 기존 저장소를 체크아웃하고 이 ZIP의 소스와 비교한다. 저장소 최신 변경을 확인하고 필요한 소스만 반영한다. 위의 빌드와 검증을 실행한다.
3. 동일 프로젝트에 소스 리비전과 `dist/server/index.js`, `dist/.openai/`를 기준으로 버전을 저장·배포한다. 기존 프로젝트의 D1, R2 및 공유 설정을 사용한다. Sites 인증 헤더는 그 플랫폼의 진입 경로에서만 신뢰한다.
4. 소유자·수신인 계정으로 로그인하고 계약 발송 → 서명 → 완료 PDF 다운로드를 확인한다. 메일 테스트 전에는 계약 초대 대상과 사이트 접근 대상을 각각 확인한다.
5. 외부 사용자는 비공개 사이트 공유 설정에서 해당 이메일에 접근을 부여해야 한다. 서명 요청 메일 발송 코드만으로 공유 대상이 추가되지는 않는다.
## 3. 별도 Cloudflare Worker에 스테이징 배포
Cloudflare 계정, 도메인 관리 권한, Workers·D1·R2·Zero Trust Access 권한이 필요하다. 아래 명령은 리소스 생성 및 배포 권한이 있는 담당자가 스테이징에서 실행한다. Wrangler 4를 사용한다.
```bash
npx wrangler@4 login
npx wrangler@4 d1 create blocksign-staging
npx wrangler@4 r2 bucket create blocksign-staging-files
cp wrangler.jsonc.example wrangler.jsonc
```
1. Cloudflare Zero Trust에서 스테이징 호스트 전체를 보호하는 Self-hosted Access 애플리케이션을 만든다. 승인된 사용자 이메일만 허용하고 애플리케이션 AUD를 기록한다. 외부 서명 테스트 대상도 허용 목록에 넣는다.
2. `wrangler.jsonc`의 Custom Domain, `CF_ACCESS_AUD`, D1 ID와 이름, R2 버킷 이름, `ESIGN_PUBLIC_ORIGIN`을 실제 스테이징 값으로 변경한다. `DB`와 `BUCKET` 바인딩 이름을 사용한다. `workers_dev`와 `preview_urls`는 기본값 false로 둔다.
3. 독립 배포 어댑터는 Cloudflare Access가 인증한 `ctx.access`와 일치하는 AUD를 요구한다. 검증된 이메일로 앱 사용자 ID를 만들고 요청자가 보낸 인증 헤더를 제거한 뒤 앱에 넘긴다. Access를 활성화하기 전에는 페이지와 API가 인증을 요구한다. Cloudflare Static Assets 설정 없이 현재 Worker의 내장 자산을 사용한다.
4. 스테이징 DB에 마이그레이션을 적용하고 Worker를 배포한다. 초기 배포 후 필요한 시크릿만 등록한다. 외부 기능별 변수는 [외부 연동 계획](EXTERNAL_INTEGRATIONS.md)에 있다.
```bash
npx wrangler@4 d1 migrations apply blocksign-staging --remote
npx wrangler@4 deploy --dry-run
npx wrangler@4 deploy
npx wrangler@4 secret put RESEND_API_KEY
```
`RESEND_API_KEY`는 실제 메일 테스트가 필요한 경우에 입력한다. `ESIGN_EMAIL_FROM`은 해당 도메인에서 검증된 발신 주소로 설정한다. PG, 바로빌 운영 발급, 플랫폼 수수료는 테스트 및 승인 이후 별도 운영 설정으로 연다. 카드 자동 수집이 필요하면 Worker에 Cron Trigger를 추가하고 회사별 자동 수집을 설정한 뒤 첫 실행을 확인한다.
### 배포 직후 점검
- 비로그인 접속은 Access 로그인으로 이동하거나 Worker가 401을 반환한다. 승인된 계정은 메인과 `/api/esign/me`를 열 수 있다.
- 권한 있는 두 테스트 계정으로 발송·서명·완료 PDF를 확인하고 제3 계정에서 문서 읽기와 다운로드가 거절되는지 확인한다.
- 법인카드 샘플 → 경비 → 전자결재 → ERP 전표, 공증 샘플 → 견적 → 결제 테스트 순으로 확인한다.
- 기존 Sites에서 데이터를 이전할 경우 D1과 R2를 함께 이전하고 소유자·테넌트·감사 기록의 계정 매핑을 별도로 설계한다. 독립 Worker의 이메일 기반 ID와 기존 Sites 사용자 ID는 다르며, 이메일 변경에도 독립 Worker ID가 바뀐다. 이 ZIP의 기본 배포는 신규 DB 기준이다.
- 배포 전 DB 및 R2 백업과 복구 계획을 확인한다. Worker 버전 롤백은 스키마와 R2 데이터를 자동 복원하지 않는다.
검증 범위는 새 폴더에서의 의존성 설치와 빌드, 자동화 테스트 61개, 타입 검사, Access 어댑터의 모의 인증과 Worker 응답, Wrangler 4.92.0 배포 드라이런과 D1 로컬 마이그레이션 5개다. Worker 드라이런 크기는 약 7.74 MiB다. 새 Cloudflare 계정의 원격 배포와 외부 업체 실거래는 운영자 계정과 테스트 설정이 필요하다.
### 공식 문서
- [Cloudflare Workers의 Access 설정](https://developers.cloudflare.com/workers/configuration/cloudflare-access/)
- [D1 마이그레이션 명령](https://developers.cloudflare.com/workers/wrangler/commands/d1/)
- [Wrangler 구성](https://developers.cloudflare.com/workers/wrangler/configuration/)
# BlockSign 프로젝트 아키텍처
[전체 설계도 열기](ARCHITECTURE.svg)
Cloudflare Worker가 HTML과 API를 같은 출처에서 제공한다. 운영 화면은 API로 문서와 업무 상태를 읽고 쓴다. 시연 화면은 브라우저 저장소와 샘플을 사용한다. 운영 계정·문서·금액은 D1/R2에 보관된다.
## 서비스와 코드 위치
| 기능 | 화면 및 조작 | 서버와 규칙 | 저장 |
|---|---|---|---|
| 메인·서비스 선택 | `src/landing.html`, `src/platform-home.html`, `scripts/ui_shell.py`, `src/global-nav.*` | `scripts/build.py`가 페이지 생성, `worker/index.mjs`가 전달 | 정적 빌드 |
| 전자계약 | `src/contracts.html`, `src/contract-editor.js`, `src/contract-integrations.js`, `development/client/esign.ts` | `/api/esign/*` → `worker/esign-api.mjs` → `development/server/core.mjs`, `hosted-pdf.mjs` | D1 `esign_records`, `esign_recipients`; R2 문서 상태와 PDF 스냅샷 |
| 초대·서명 완료 메일 | 계약 발송·완료 및 관리자 재시도 | `worker/esign-mail.mjs` → Resend | D1 `esign_mail_dispatch` 접수 및 중복 방지 |
| 계약 진본 확인 | `src/verify-contract.html`, 계약 편집기의 증명 버튼 | 브라우저 SHA-256, `worker/evidence-rpc.mjs`, `development/contracts/EvidenceRegistry.sol` | 서명 PDF·manifest, 선택 시 체인에 지문 |
| 에스크로 | `src/assets.html`, `src/services.js`, `src/service-model.js` | 시연 금고와 별도 `development/server/ethereum.mjs`, `development/contracts/ProjectEscrow.sol` | 시연 브라우저 저장소. 실자금 경로는 배포 및 통합 필요 |
| 공증 신청자료 | `src/notary-live.html` | `/api/notary-live/*` → `worker/notary-api.mjs` | D1 `notary_live_cases`; R2 첨부와 결과 |
| 공증 견적·파트너·수임 | `src/notary-market.html`, `src/notary-app.js`, `src/notary-flow.js`, `src/notary-workspace.html`, `src/notary-bids.html`, `src/notary-remote.html` | `/api/notary-market/*` → `worker/market-api.mjs`, `reverse-market.mjs`, `agency-domain.mjs`, `toss-payments.mjs` | D1 파트너·견적·주문·결제; R2 증빙·결과 PDF |
| 법인카드·경비·전자결재 | `src/business.html`, `src/business.js`, `src/business-documents.js` | `/api/business/*` → `worker/business-api.mjs`, `business-domain.mjs`, `barobill.mjs` | D1 `business_workspaces`; R2 영수증 첨부 |
| 영수증·세금계산서 | `src/business-documents.js` | `worker/barobill.mjs`의 수집·발급·국세청 상태 조회, `business-api.mjs`의 회사별 권한 | D1 업무공간과 연동 상태 |
| ERP 전표·정산·거래처·발주·재고 | `src/business-finance.js` | `worker/finance-domain.mjs`, `business-api.mjs`; 외부 ERP는 계약된 게이트웨이 | D1 업무공간 재무 상태 |
| 파일·증적 다운로드 | 계약·공증 완료 화면 | `development/server/hosted-pdf.mjs`, `worker/archive.mjs` | R2 원본, 결과 PDF와 감사 근거 |
CSS는 공통 내비게이션 `src/global-nav.css`, 문서·에스크로 `src/services.css`와 업무 화면 `src/business.css`에서 관리한다. 빌드는 소스와 자산을 조합해 `dist/`를 만들고 `worker/assets.generated.mjs`와 `dist/server/index.js`를 생성한다. 스키마의 배포 기준은 `drizzle/0000–0004`다.
## 주요 처리 흐름
- **계약** 작성·수신인 지정 → 발송·초대 메일 → 순서에 따른 검토·서명 → 최종 PDF·감사 근거 → 완료 메일. 문서 접근은 소유자·등록 수신인과 역할을 확인한다. 참조인은 완료 문서를 열 수 있고 서명은 할 수 없다.
- **공증** 신청자료 보관 → 자격 확인된 파트너 견적 → 선택·결제 확인 → 공식 절차·결과 파일 전달. PG 승인 결과와 공식 공증 결과는 별개로 기록된다. 정부 API와 해외 Proof는 국내 흐름에 연결되어 있지 않다.
- **재무** 법인카드·증빙 수집 → 경비 상신 → 전자결재 → 전표·정산. 결제 상신 승인 뒤 은행에서 지급한 증빙을 기록하면 출금 전표가 반영된다. 외부 ERP 전송에는 게이트웨이 규격과 인증이 필요하다.
- **권한** Sites는 플랫폼 인증을 쓰고, 독립 Worker는 Cloudflare Access에서 검증된 이메일과 AUD를 확인한다. 사업자·파트너·계약 단위 권한은 서버에서 별도로 판단한다. 결제 키, 카드번호, 정부 시스템 자격증명, 지갑 비밀키는 프론트엔드에 넣지 않는다.
세부 계약은 [API.md](API.md), [HOSTED_SIGNING.md](HOSTED_SIGNING.md), [BUSINESS.md](BUSINESS.md), [NOTARY_MARKET.md](NOTARY_MARKET.md), [REMOTE_NOTARY.md](REMOTE_NOTARY.md)를 참고한다.
# 외부 연동과 업체별 선행 작업
기준일 2026-11-12 KST. 기존 배포 환경에서 확인된 설정 키는 `PLATFORM_OPERATOR_EMAILS`다. 아래 연동은 코드 또는 테스트 수준의 준비 상태다. 실제 계정·승인·키·공식 결과를 확보한 뒤 활성화한다.
## 먼저 처리할 순서
| 우선순위 | 업체·기관 | 당사 담당과 준비물 | 완료 조건 |
|---|---|---|---|
| 1 | Cloudflare / 기존 ChatGPT Sites | 인프라 담당이 배포 경로와 도메인을 확정한다. 독립 Worker는 D1·R2와 Access를 연결한다. 기존 Sites는 소유자 권한과 외부 서명자 이메일 허용을 확인한다. | 소유자·수신인·제3 계정 권한 테스트 통과 |
| 2 | Resend | 인프라 담당이 발신 도메인을 등록하고 DNS 인증을 완료한다. 발송 전용 키, 발신 주소, 실제 계약 링크의 HTTPS 주소를 확정한다. | 외부 테스트 수신인이 초대 링크로 접속하고, 완료 메일 수신 및 중복 방지 확인 |
| 3 | 바로빌·카드사·홈택스 | 재무 담당이 바로빌 개발 파트너와 회사 계정을 준비한다. 카드 사용내역과 홈택스 수집 항목을 등록하고, 테스트 연동인증키·사업자번호·회원 ID를 확보한다. | 카드 승인/취소, 현금영수증, 매입·매출 계산서 수집을 원장과 대조. 시험 발급과 국세청 전송 상태를 확인 |
| 4 | 국내 자격 공증사무소·법무부 전자공증시스템 | 제휴·법무 담당이 취급 문서 범위, 자격 증빙, 개인정보 책임, 수임·환불·결과 전달 절차를 합의한다. 공식 시스템 연동이 필요하면 허용된 권한·명세를 서면으로 요청한다. | 공증인 1곳으로 자격 승인 → 견적 → 공식 절차 → 결과 전달을 검증 |
| 5 | 토스페이먼츠 | 재무·제휴 담당이 테스트 MID 및 클라이언트·시크릿 키를 받는다. 공증 파트너별 수취 구조, 정산·환불, 플랫폼 비용 항목의 계약 적합성을 확인한다. | 테스트 주문 승인·조회·취소와 재시도 검증 후 운영 계약 및 키 확보 |
| 6 | 고객사 ERP 업체 또는 사내 ERP | 고객 ERP 담당이 전표·정산 필드, 계정 코드, 중복 키, 취소·실패 응답, 인증 규격과 시험 환경을 제공한다. | 동일 전표 재전송 시 중복 생성이 없고, 내보내기·전송 결과가 대사됨 |
| 7 | EVM RPC 제공자·Safe | 블록체인 담당이 대상 체인, RPC, 검증된 Safe 배포 주소와 코드 해시를 확정하고 EvidenceRegistry와 ProjectEscrow의 테스트넷 절차를 준비한다. | 증명 트랜잭션을 대조하고, 실자금 에스크로는 정족수·분쟁·환불·복구까지 별도 검증 |
| 선택 | Proof / Notarize | 해외 서비스 담당이 Fairfax 테스트 키, 문서와 당사자 적격성, 정보 국외 처리 동의를 확인한다. | 별도 해외 경로로 테스트. 국내 공증에는 연결되어 있지 않음 |
전자계약 자체를 먼저 사용한다면 1–2부터 진행한다. 법인카드·세금계산서·현금영수증을 실데이터로 다루려면 3이 추가된다. 공증과 에스크로 운영 준비는 관련 항목의 담당자가 별도로 진행한다.
## 변수 및 활성화 조건
| 구분 | 런타임 키 | 현재 구현 범위 및 남은 일 |
|---|---|---|
| 독립 Worker | `CF_ACCESS_AUD`, 바인딩 `DB`, `BUCKET` | ZIP에 Access 인증 어댑터와 설정 예시 포함. 실제 Cloudflare 애플리케이션과 호스트 연결 필요 |
| 메일 | `RESEND_API_KEY`, `ESIGN_EMAIL_FROM`, `ESIGN_PUBLIC_ORIGIN` | 발송 시 역할별 초대 메일, 최종 서명 후 완료 메일, 관리자 재시도 및 접수 중복 방지. 외부 사이트 접근은 별도 권한 |
| 바로빌 | `BAROBILL_WORKSPACES`, `BAROBILL_LIVE_ISSUE` | UUID별 `mode`, `key`, `corpNum`, `userId`, 등록 카드 매핑, 공급자 정보를 [BUSINESS.md](BUSINESS.md)에 명시. 테스트부터 시작하고 회사 승인 후에만 운영 발급 허용 |
| 국내 공증 | `PLATFORM_OPERATOR_EMAILS` | 신청자료·견적·파트너 상태·결과 전달 구현. 자격 검토와 공식 접수/발급은 제휴 공증인의 공식 절차가 필요 |
| 토스페이먼츠 | `NOTARY_PAYMENT_ACCOUNTS`, `NOTARY_MARKET_LIVE_PAYMENTS` | 파트너 UUID별 `clientKey`, `secretKey`, `mId`. 운영 결제는 별도 플래그로 잠겨 있음. `PLATFORM_NONLEGAL_FEES_ENABLED` 및 `PLATFORM_ADMIN_FEE_KRW`는 요건 확인 후 사용 |
| 외부 ERP | `BUSINESS_GATEWAY_URL`, `BUSINESS_GATEWAY_TOKEN` | 전송 게이트웨이 계약에 맞는 서버를 고객이 연결해야 함. 카드·계산서 수집은 바로빌 직접 연동과 구분 |
| 문서 증명 | `ETH_RPC_URL`, `ETH_CHAIN_ID`, `EVIDENCE_REGISTRY`, `ANCHOR_CONFIRMATIONS` | PDF 해시 대조는 브라우저에서 가능. 온체인 검증은 RPC·레지스트리 배포 후 설정 |
| Safe | `SAFE_RUNTIME_HASHES`, `SAFE_SINGLETON_ADDRESS`, `SAFE_SINGLETON_RUNTIME_HASH` | 로컬 개발 검증 어댑터와 Solidity 제공. 키 입력만으로 기존 hosted 금고가 실자금으로 전환되지는 않음 |
| 해외 Proof | `PROOF_API_KEY` | `development/server/proof-adapter.mjs`의 별도 어댑터. 국내 hosted 경로 연결·실호출 미검증 |
카드 자동 수집은 회사별 설정과 Worker Cron 연결이 모두 필요하다. ERP의 결제 상신은 내부 승인·지급 증빙 기록 기능이다. 실제 은행 송금 연동은 별도 범위다.
### 공식 문서
- [Resend 발신 도메인](https://resend.com/docs/dashboard/domains/introduction)
- [바로빌 개발자센터](https://dev.barobill.co.kr/)
- [법무부 전자공증시스템](https://enotary.moj.go.kr/)
- [토스페이먼츠 결제 API](https://docs.tosspayments.com/en/api-guide)
- [Safe Smart Account v1.4.1](https://docs.safe.global/reference-smart-account/overview)
- [Proof Business API](https://dev.proof.com/docs/business-quick-start)