Pack 1 Core Layer
최근 갱신: 2026-04-22 (오버나이트 자율 세션 25 PR 반영)
Pack 1 민사 회수 6 유형의 엔진 · 출력 템플릿 · 법원 서면 · 어댑터 를 모두 순수 함수로 구현한 3-tier 아키텍처.
- Tier 1 — 엔진 (순수 함수 계산): 6 유형 ×
_lib/*-settlement.ts - Tier 2 — 출력 템플릿 (결정론 텍스트 생성):
- 공통 3부작 (
_lib/recovery-output/— 청구취지 · 요약 계산표 · CSV) - 법원 서면 5종 (
_lib/*-text.ts— 내용증명·지급명령·소장·답변서·준비서면)
- 공통 3부작 (
- Tier 3 — 어댑터 (CaseData + 엔진 결과 → 서면 입력): 3종 (지급명령·소장·답변서)
모든 Tier 는 AI 호출 0 · Firestore 호출 0 · 결정론. UI 와 Server Action 의 책임은 "이 3-tier 를 호출하고 결과를 렌더/저장" 까지.
1. Tier 1 — 회수 유형 엔진
| # | 회수 유형 | 엔진 파일 | 핵심 규칙 |
|---|---|---|---|
| 1 | 대여금 | debt-settlement.ts | 대여일부터 이자 연속 누적 · 민법 §477·§479 |
| 2 | 공사대금 | construction-settlement.ts | 변제기 이후 지연손해금 · 상법 §54 default 6% |
| 3 | 구상금 | subrogation-settlement.ts | 대위변제일 즉시 이행기 · 법정이자 (민법 §441) |
| 4 | 약정금 | agreement-damages.ts | 이행기 이후 지연손해금 · 3분기 이율 |
| 5 | 임대차보증금 | lease-deposit.ts | 공제 개념 + 반환 이행기 기산 |
| 6 | 양수금 | assigned-claim.ts | 양도 메타 + 양도인/양수인 변제 분류 |
1.1 공통 규약
- 입력:
claim+repayments[]+asOfDate(YYYY-MM-DD, KST) - 출력:
outstandingPrincipal·outstandingInterest/Damages·totalOutstanding·applications[]·engineVersion - 정수 원 단위
Math.floor절사 — 원미만 금지 - 365일 고정, 초일불산입·말일산입 (민법 §157)
- 결정론: 같은 입력 → 같은 출력. 같은 날짜 변제는
id사전순 tiebreak - engineVersion v1 stamp: 공식 변경 시 bump → snapshot drift 방어
- Property test (fast-check, 100 runs/엔진) — 잔여 ≥ 0 · 원본 ≤ amount
1.2 이율 해결 (construction 이후 공통)
1순위: agreedRatePercent (민법 §397 ①) → rateSource = "agreed"
2순위: statutoryRatePercent === 6 → "statutory-commercial-6" (상법 §54)
3순위: 기본 → "statutory-civil-5" (민법 §379)
1.3 충당 순서 (§479)
지연손해금/이자 → 원본
지정충당 (§476) appropriationOverride:
"principal"— 원본 먼저, 잔액은 이자"interest"/"damages"— 이자만, 초과분 drop
2. Tier 2 — 출력 템플릿
2.1 공통 3부작 (recovery-output/)
| 템플릿 | 파일 | 용도 |
|---|---|---|
| 청구취지 문장 | claim-text.ts | 소장·준비서면 붙여넣기 |
| 요약 계산표 (마크다운) | summary-table.ts | 법원 제출용 한글 서식 |
| CSV export (UTF-8 BOM) | csv-export.ts | 엑셀 첨부 서면 |
각 템플릿은 범용 builder + 유형별 adapter 5종. 대여금은 기존
settlement-output/ 유지 (Phase 0 MVP).
2.2 법원 서면 5종
| 서면 | 파일 | 단계 |
|---|---|---|
| 내용증명 | demand-notice-text.ts | 소 전 (민법 §174 최고) |
| 지급명령 | payment-order-text.ts | 독촉절차 (민소법 §462) |
| 소장 | complaint-text.ts | 통상 · 소액재판 (소액 isSmallClaim 자동) |
| 답변서 | answer-brief-text.ts | 피고 대응 (민소법 §256) |
| 준비서면 | preparatory-brief-text.ts | 본안 진행 (민소법 §274) |
모든 서면은:
- 당사자·법원·제목·본문·첨부·서명 표준 섹션
- 클립보드 복사 → 한글 서식 붙여넣기 전제 (HTML/PDF 는 별도 경로)
- 중립 어조 — 협박·감정 표현 금지 (증거 가치 유지)
3. Tier 3 — 어댑터
| 어댑터 | 파일 | 매핑 |
|---|---|---|
| 지급명령 | payment-order-adapter.ts | CaseData + calc → PaymentOrderInput |
| 소장 | complaint-adapter.ts | CaseData + calc → ComplaintInput (+ isSmallClaim 자동) |
| 답변서 | answer-brief-adapter.ts | CaseData → AnswerBriefInput (엔진 결과 불필요) |
어댑터 책임:
- 유형별 이자 기산일 자동 (이행기+1 또는 출재일)
- 유형별 이자 명칭 자동 ("지연손해금"·"법정이자"·"이자")
- 유형별 사건명/청구종류 자동 (
RECOVERY_TYPE_LABEL) CaseData.client/opponent→Party필드 매핑 헬퍼 동반
4. Unified Dispatch
4.1 recovery-dispatch.ts
const calc = calculateRecovery({ type: "construction", input: {...} });
// calc.type === "construction", calc.result === ConstructionSettlementResult (discriminated)
const text = buildRecoveryClaimText(calc, { plaintiffName, defendantName });
// 유형별 적절한 라벨·기산일·이자 명칭 자동
const summary = toRecoverySummary(calc);
// { type, outstandingPrincipal, outstandingInterest, totalOutstanding,
// appliedRatePercent, asOfDate, engineVersion }
4.2 document-bundle.ts
const bundle = buildDocumentBundle({ caseData, calc, court, filingDate, causeLines });
// {
// claimText, summaryText, csvText,
// paymentOrderText, complaintText,
// summary
// }
한 번의 호출로 사건의 전체 문서 풀세트 생성. UI "문서 풀세트" 버튼 직통.
5. Input Validation
5.1 recovery-input-schemas.ts
5 유형별 Zod 스키마 3조:
ClaimInputSchema·RepaymentInputSchema·SettlementInputSchema(top-level refine)
UI 폼 (React Hook Form + Zod resolver) · Server Action 경계 런타임 검증.
엔진 내부 validateInput 은 최종 방어선.
5.2 CaseData 확장
CaseData.recoveryType?: RecoveryType (optional) — 미지정 시 resolveCaseRecoveryType() 이 "debt" 기본값.
6. Persistence & Diff
6.1 recovery-snapshot-schema.ts
6 회수 유형 공통 Firestore 스냅샷 Zod 스키마 (discriminated union).
- 경로:
tenants/{tid}/cases/{caseId}/recoverySnapshots/{id} type필드로 유형 분기. Interest (debt·subrogation) vs Damages (나머지 4) 필드 자동 구분.frozen: literal(true)— 동결 스냅샷만 저장.assertCurrentRecoveryEngineVersion(type, result)— 저장 직전 drift 방어.RecoverySnapshotStaleError— 수정 시도 차단 에러.
6.2 recovery-summary-diff.ts
두 RecoveryResultSummary 비교 → 재계산/스냅샷 diff.
recoverySummaryDiff(from, to)→{ *Delta, asOfDateDeltaDays, engineVersionMismatch }summarizeDiff(diff)→ UI 한 줄 요약 "+1,234,567원 · 기준일 +31일"- 유형 불일치 시
RecoveryTypeMismatchErrorthrow.
7. Phase 0 Week 4 Citation Precision Gate
7.1 측정 모듈 (lib/eval/citation-precision.ts)
computePrecision · computeRecall · computeF1기본 메트릭evaluateCitationPrecision(cases)— micro/macro 병행 집계evaluateWeek4Gate(metrics)— Precision ≥ 0.95 hard gaterenderCitationPrecisionReport(metrics, gate)— 마크다운 리포트
7.2 Fixture (lib/eval/citation-fixtures.ts)
10 건 초기 ground-truth 데이터셋. 6 회수 유형 + multi-statute · 법원 계층 · no-citation · mixed 커버.
7.3 CLI Runner (scripts/eval-citation-precision.ts)
NODE_PATH=apps/web/node_modules npx tsx scripts/eval-citation-precision.ts
- Fixture 전체 실행 → Precision/Recall/F1 계산 → 마크다운 리포트 표준출력 +
reports/citation-precision-report.md저장. - FAIL 시 exit 1 (CI 게이트 용).
8. 테스트 집계 (2026-04-22 세션 기준)
| 레이어 | 신규 테스트 |
|---|---|
| 엔진 5 (공사대금·구상금·약정금·임대차·양수금) | 77 |
| 출력 템플릿 3 (청구취지·요약·CSV) | 32 |
| 법원 서면 5 | 29 |
| 어댑터 5 | 25 |
| 통합 (dispatch·bundle·E2E·CaseData type) | 34 |
| Zod 스키마 (입력 · 스냅샷) | 27 |
| Diff (Recovery summary) | 13 |
| Week 4 Citation Precision (module · fixtures · CLI) | 20 |
| 합계 | ~257 |
누적 프로젝트 테스트: 2112+.
7. UI 통합 대기 목록
Pack 1 Core Layer 는 완성. 아래는 UI 층 책임:
- Settlement 탭 분기:
CaseData.recoveryType으로 유형별 입력 폼 렌더. - 문서 생성 버튼:
buildDocumentBundle()호출 → 결과 modal/drawer 표시. - Server Action 래핑: Firestore snapshot 저장 + 버전 관리.
- 한글 서식 export: 텍스트 → 한글/PDF 변환 (Phase 1 후반).
8. 관련 문서
- Pack 1 Product Spec
- Pack 1 Phase 0 체크리스트
- Pack 1 데이터 모델
- 세션 changelog (2026-04-22)