회의록 — 제작 계획 (교차검토 4라운드)

이 문서는 설계 회의 기록 원문입니다. 2026-10-01 교차검토 4라운드의 전체 트레이스이고, 결론만 보시려면 그림으로 보는 설명서 의 「앞으로 남은 일」 절이 같은 내용을 짧게 담고 있습니다. 수정 전인 보안 사항의 구체 위치는 이 사본에서 가렸습니다. 특허 발명설명서는 출원 확인 전까지 게시하지 않습니다.

패널 — 9개 프로그램 제작 계획 (설계 · 착수 순서 · 의존성 · 스케줄)

안건(한 문장): 1차 출시에 필요한 8개 프로그램을 어떤 순서로 · 어떤 의존성으로 · 어떤 구간에 나눠 제작하고, 미착수 3개(배치 · 로그 Writer · 안드로이드 요원앱)의 착수 시점과 목 데이터 화면 → 실제 API 연동 전환 시점을 어디로 잡는가.

개발 방식: 에이전트 하네스 — 기획설계 패널 5역할을 「전 직원」으로 돌려 교차검토하고, 스킬·워크플로로 분할 제작한다(대표 2026-10-01).

사실 기반 (패널에 공통 제공)

# 프로그램 스택 상태 1차
1 사용자 웹 front-app(3000) Next.js 39 라우트 · 목 데이터 · API 미연동 ✅
2 백오피스 admin-app(3001) Next.js 운영 15화면 · 의존성 미설치 ✅
3 API Gateway NestJS 동작 · 테스트 21 ✅
4 Core API NestJS 동작 · 테스트 37 ✅
5 Admin API NestJS 동작 · 테스트 38 ✅
6 배치 apps/batch NestJS 없음 ✅
7 로그 Writer NestJS 없음 ✅
8 요원 안드로이드 앱 Kotlin 없음 ✅
9 AI · 최적화 Python/FastAPI 없음 ❌ 3차(D140)

라운드 1 — 독립 제안 (blind)

domain-architect (사업·도메인)

없으면 멈추는 것 — 자격증 승인(없으면 지원 모수 0, D48) · 용역 등록→요율 고정→공고 발행(D127⑯·D76) · 지급 서류(F-AUTH-02) · 출퇴근+지오펜스(정산의 유일한 원천) · 구역 밖 출근 승인(승인 대기가 남으면 정산 마감 자체가 차단, 09 §5.2) · 정산 마감→명세→확정→지급완료(이중지급 방어, D87). 오프라인으로 버틴다 — 방문결과·명부(1차 끔) · 교육 · 조직도 · 발주처 리포트 · 공지·고객센터 · 구역 추천.

배치는 「나중 것」이 아니다 — 09 §7.1 이 「정산 마감 전 그 기간 요약 완료가 마감 조건」이라 못 박았다. 배치 없이는 첫 정산이 불가능하다.

착수 묶음: W0(admin-app 의존성 · 02 에 1차 ON/OFF 태그 · 09 §7.6 적재) → A 가입·심사·자격승인 ∥ 앱 스캐폴드 → B 공고·요율·콜·선발 → C 출퇴근·위치·구역밖승인 ∥ 배치 3잡 ∥ 로그Writer → D 정산 마감→명세→확정 → E 파기·경보·공지(운영 개시+30일 데드라인). 목→API: 동선 단위. 첫 전환은 가입·심사·자격승인(A). 단 근태 백엔드는 이미 동작하니 병행 파일럿. 앱: 「파일럿=웹 / 출시=앱」 2단 게이트 권고. 로그 Writer: 발행(LogPublisher)이 트랜잭션이라 유실은 없음 → Writer 본체는 첫 월간 점검 전까지 유예 가능(추정).

이 순서가 깔면 안 되는 전제(미결): ★L1 위치신고 전 위치 기능 ON 불가(만들되 끄는 스위치) · E16 이 동의률·접촉률이면 업무보고 오프라인인 1차에서 정산 불가 → D88 유지가 전제 · L14 와 ★L13 충돌(묶음 D 착수 전 확정) · 1차에 본부장·팀장 모드가 3차(D141)인데 선발·구역밖승인의 주체가 그들 → 1차는 본사 대행으로만 성립.

system-architect (기술·시스템)

진짜 선후관계는 셋뿐: ① core-api 엔드포인트 → 그 동선의 프론트 연동(프로그램 단위가 아니다) ② core-api 토큰 발급(deviceId 클레임) → 안드로이드 인증(지금은 테스트가 직접 서명) ③ batch 자동마감·세무 스냅샷 → 정산 명세 참값 검증. log-writer 는 개발을 막지 않는다 — 출시만 막는다.

검증된 나쁜 사실 둘 — ① front-app/src/mocks/ 디렉터리가 없다. 목 데이터가 35개 파일에 const MOCK 으로 흩어져 CLAUDE.md 의 「한 곳에 모은다」가 이미 깨져 있다. ② front-app 에 Core API 호출 계층이 없다(callApi 하나뿐, CORE_API 환경변수 사용처 0). D91 서버액션 경로는 설계만 있고 코드가 없다.

계약 공유 권고: 생성된 OpenAPI 타입을 단일 소스로 — /api/docs-json → openapi-typescript → front-app/src/api/schema.gen.ts(커밋) → CI 재생성 diff 0. 갈라지면 빌드가 먼저 깨진다. 버린 대안: libs/contracts 공유 패키지(워크스페이스 밖·데코레이터 번들 유입) · 손편집 타입(현행, 컴파일러가 불일치를 못 잡음). 배치·Writer 는 설계는 있고 코드만 없다(확인): withAdvisoryLock 은 @deprecated + 호출처 0이고 트랜잭션 락이라 D112 가 금지한 방식 · DbQueueLogPublisher 발행측 완성, 소비측 0 → 유실 아니라 적체. 세션 락을 둘이 공유하니 같은 묶음에서 한 번만 짠다. 안드로이드 선결 4항: core-api 로그인 deviceId 클레임 · app_release 버전 정책 행 · Play Integrity 서비스 계정 · 오프라인 큐 계약(과거 72h·미래 5m·PERIOD_CLOSED 409 재시도 금지). 순서: S0 타입 파이프라인·mocks 추출·admin-app npm i → S1 core-api 확장 ∥ log-writer+세션락 ∥ batch 뼈대 → S2 프론트 동선 연동 ∥ admin-api 정산 ∥ batch 스냅샷·파기 → S3 안드로이드 → 상시 CI. 하네스 분할 경계 = (apps/ 하나) × (테이블 오너십 하나). 직렬화할 충돌 지점 셋: libs/db/schema.ts(kysely-codegen 생성물화가 병렬화 선결) · libs/common(LogPublisher·decideFenceApproval) · 두 앱 공통 컴포넌트·tokens.css. 통합 테스트는 포트 3개를 점유하니 단일 직렬 게이트로 남긴다(추정).

security-compliance-reviewer (보안·법규)

프로그램 판정
로그 Writer 출시 전 필수 — 없으면 법정 보존 자체가 미이행
배치 3갈래(요청 레인B · 철회자 위치 02:00 · 30일 기한류 02:30) 출시 전 필수
배치 나머지(90일 파티션 DROP · 3년 · 5년) 출시 후 허용
안드로이드 위치를 1차에 켜면 출시 전 필수 / 위치를 빼면 조건부 가능

배치 없음 = 파기 의무 미이행. docs/10 §2 가 스스로 적었다 — 「지금은 실제로 지워지는 데이터가 없다」. V_ERASURE_DUE·V_ERASURE_QUEUE 는 대상과 기한을 계산만 한다. 출시 직후 시계가 도는 것: 삭제 요구 10일(법정) · 위치 철회자 이동경로 즉시 · 통장·등본 확인+30일 · 세대명부 반입+30일 · 가입 미완료 30일. 로그 Writer 없음 = LOG_AUDIT 영구 공백 · 체인 길이 0 · inbox 무한 적체. 터지는 곳: 개인정보보호법 §29 접속기록 · 위치정보법 §16② 확인자료(미보존이 곧 위반) · §24 「누가 내 위치를 봤나」(★L22) · 근무일 제외·보수 이의(★L26·27·32) · Break-glass 입증(L25). 「API 가 최종 테이블에 직접 쓴다」 임시 구현 불허 — ① 체인은 단일 활성 소비자 전제(다중 인스턴스가 PREV_HASH 경합하면 체인이 끊긴다) ② 파티션 키가 chained_at ③ LOG_AUDIT 는 append-only 라 나중에 고칠 수 없다 → 잘못 적재된 1차 운영분은 영구히 증거력이 없다. 위치: 백엔드에 위치 핑 수집 엔드포인트가 없다(log_location_ping 쓰기 0건). 웹 대체 불허 — 15분 백그라운드 핑 불가, 「72시간 미전송 폐기」·「명부 캐시 파기」·「철회 즉시 중단」의 집행 주체가 앱뿐(10 §2.3·2.4). 앱을 늦추면 위치를 1차에서 함께 빼야 한다(그러면 ★L1 신고 전에도 출시 가능 — 이점). ★ 선결은 전부 「문서·법률 먼저」: ★L1 · ★L2(본인확인기관 계약) · ★L15 · ★L16(파기 배치·세무 스냅샷 구현 전 — 명시) · ★L28 · ★L29(「화면을 먼저 만들면 다시 만든다」). 예외: 파기 엔진·갈래 코드표·체인 골격은 지금 짜도 된다 — 보관기간 값은 뷰에 있고 법률 답은 값만 바꾼다. 변호사 확인: 접속기록 보관 하한(1년 vs 2년) · 파기 배치 미가동 기간의 보유가 §21 위반인가 · 확인자료 미보존 제재 수준.

ux-field-ops-reviewer (현장 UX·운영)

1차 필수 동선은 5화면: 로그인(PIN) → 홈 → 오늘 근무(고지→GPS→출근) → 퇴근 → 내 근무. 방문결과가 꺼지면 요원이 앱을 켜는 이유는 「오늘 일당이 찍혔나」 하나다. 끊기면: work-today 없으면 그날 일당이 없다(팀장이 종이에, 본사가 손입력 → 플랫폼 존재 이유 소멸) · my-work 없으면 월말 분쟁이 전부 전화 · 출근 버튼 앞 재인증은 금지(고령 요원이 아침에 못 들어온다). zone-map 은 지도 없이 근무구역명·사업기간 텍스트 카드로 1차 유지(D141). /calls 는 1차 범위지만 전화로 대체 가능(추정, 현장 확인 필요) — 근태는 대체 불가.

최대 결함 — 1차에 승인자가 없다. D141 은 본부장·팀장 모드를 3차로 두는데 구역 밖 출근 승인은 1차 근태의 필수 조건이다(D81, 09 §3.7). (field)/fence 가 3차로 밀리면 1차에서 구역 밖 출근이 영구 대기로 적체하고 지오코딩 오류 한 건이 요원 일당을 먹는다 → 승인 화면은 1차, 주체는 본사 백오피스. admin-app 에 그 화면이 없다.

겹침: field-recruit(후보 선발) vs recruit-ops(요율·콜 발송)는 경계 선명. 겹치는 건 대시보드 — field-dashboard 의 「모수 제외 승인·교육 이수」 타일은 본사 업무와 중복, 1차엔 백오피스에만. 연동 우선순위: ① 본사 용역 개설+인력 사전등록+배정(없으면 출근 API 가 꽂을 데가 없다) ② 요원 출근→퇴근(실기기에서만 드러나는 것: GPS 정확도·지오펜스·시각 오차) ③ 배치 자동마감+위치 요약(없으면 퇴근 미체크 세션이 열린 채 남고 정산 마감 조건이 영구히 미충족 — 1차 blocker) ④ 정산→명세→내 수당 ⑤ 콜함·선발 ⑥ 로그 Writer(없으면 「내 위치 이용내역」이 법정 열람권 화면인데 영구 빈 화면). 앱은 1차를 버틸 수 없다 — 09 §3.2 가 요구하는 Foreground Service·15분 백그라운드·지속 알림·배터리 예외가 모바일 웹에 구조적으로 없다. ① 화면 꺼짐 즉시 위치 중단 → 위치 공백이 요원 과실로 기록 ② 오프라인 큐가 브라우저 캐시라 탭 종료로 사라진다(「사흘 안에 연결되면 인정」 약속 불이행) ③ 장갑+주소창으로 터치 저하 ④ 콜 24시간 푸시가 잠금화면에서 안 뜬다 → 앱은 우선순위 2번과 동시. 오프라인 병행: 같은 근태를 2~3회 입력(요원→종이 일보→전산 엑셀→본사 시스템). 중복을 없애는 한 화면 = 「일자별 출근 명부 출력/CSV」(앱 기록 → 종이 일보 서식 그대로) → 우선순위 4번과 묶어 1차에. 종이 서식 실물 확인 필요.

라운드 2 — 상호 교차 검토

자기 철회·정정 (네 관점 모두 발생 — 수렴 신호)

누가 무엇을 철회·정정했나
domain 「로그 Writer 유예 가능」 철회 — 보존 의무와 증거력을 혼동했다. 「파일럿=웹/출시=앱 2단 게이트」 철회 — D141 1차 범위에 「지도사앱·출퇴근/동선 위치관리」가 명문이라 범위 왜곡이다. 「첫 전환=가입·심사」 철회
system 「앱 S3 마지막」 철회 — 백엔드에 위치 수집 경로가 0건이라 앱이 S3 면 1차 위치 원천이 영구히 빈다. 「35파일」 → 실제 18파일 27개 const MOCK 정정
security 「영구히 증거력 없음」의 범위 정정 — 적체 = 복구 가능 / 오적재 = 복구 불가 두 문장은 각각 맞다. 「배치 3갈래 전부 출시 전 필수」 과했다 → 기한 재계산(아래)
ux 「/calls 는 전화로 대체 가능」 철회 — 콜 수락이 위치 동의를 받는 유일한 지점(field-calls 「수락 → 위치 동의 → 배정」)이라, 빼면 동의 없이 지오펜스를 돌리게 된다

C1 로그 Writer — 합의: 1차 출시 게이트. 임시 직접 쓰기 불허

C2 안드로이드 / 위치 — 합의: 최소 앱 = 네이티브 쉘 4개 + 나머지 WebView

C3 승인자 — 합의: D141 수정 불필요. 백엔드는 이미 끝났고 화면 하나만 없다

C4 첫 연동 동선 — 합의: S0 → 용역개설+사전등록(손입력)+자격승인+배정 → 근태

라운드 2 에서 새로 나온 것

라운드 3 — 비판 + 조정 (design-critic)

모더레이터가 직접 검증한 핵심 주장 — 6건 전부 사실:

주장 검증
batch_run 테이블이 DDL 에 없다 사실 — db/ddl/ 전체 0건. 09 §7.2·§7.4 가 전부 이 테이블 조회를 전제
주민등록번호 컬럼이 없다 사실 — 05_member.sql:45 에 「암호화 대상」 주석만, 컬럼 없음
세무 스냅샷 테이블이 없다 사실
log_location_ping 파티션 키가 단말 시각 사실 — PARTITION BY RANGE (recorded_at)(10_log.sql:79). 21_comments.sql:589 가 「서버 수신 시각으로 바뀐다(D112 — 단말 시계가 틀리면 파기에서 빠진다)」
CI 워크플로 0개 사실 — .github/workflows/ 없음
인증 경로에 템플릿 잔재 사실 — 인증 경로에 템플릿 잔재가 남아 있다 — OS4U 는 계정 비밀번호를 쓰지 않는데 템플릿 백엔드 호출이 남아 있다. 구체 위치·형태는 수정 전까지 이 문서에서 가린다

이 검증이 계획의 전제를 바꾼다. 「DB 완료 90테이블·49뷰」(실측 93·49)가 패널을 오인하게 했다 — 설계는 닫혔지만 D112 구현 대기 DDL 이 빠져 있다. CLAUDE.md 의 「DDL·시드·검증 완료」 표기를 「설계 완료 · D112 구현분 미적재」로 고쳐야 한다(증류 승인 대상).

모더레이터 판정:

비판 판정 조치
batch_run DDL 부재 ⓐ 채택 묶음 3 에 batch_run + 멱등 유니크 DDL · db/test 회귀 재측정 명시
정산 선결 DDL 부재(주민번호·세무 스냅샷·지급 보류 게이트) ⓐ 채택 묶음 3.5 「정산 선결 DDL」 신설. 입구 조건 = ★L16·★L13·L14 확정
log_location_ping 단말시각 파티션 + §16② 확인자료 분리 테이블 부재 ⓐ 채택 위치를 켜면 묶음 2 입구에 D112 파티션 전환 + 확인자료 분리. 출시 게이트에 ★L1 만 적은 것은 불충분
인증 경로의 템플릿 잔재 ⓐ 채택 묶음 0 에 「인증 경로 교체」. 보안 사항이라 가장 먼저
CI diff 0 대신 run-all.sh 에 git diff --exit-code 한 줄 ⓐ 채택 타입 생성은 유지(중복 타입 20~30개 논거 유효), CI 신설은 묶음 R 로
WebView 혼합 앱의 숨은 비용 ⓑ 절충 my-work 는 네이티브 + 읽기 캐시(신호 약한 재개발 구역에서 가장 많이 보는 화면), notices 만 WebView. 세션 교환 계약(네이티브 PIN 토큰 → front-app 쿠키 세션)을 S1 동결 목록에 추가. Play 백그라운드 위치 민감권한 심사 리드타임을 출시 게이트에 날짜로 박는다
알림 발송 B 레인 배치 부재 ⓐ 채택 배치를 ⓐ(마감·요약) · ⓑ(파기) · ⓒ(B 1분 레인 — 알림 폴백 푸시→알림톡→문자 · 콜 24시간 기한 · 공고 예약게시) 셋으로. ⓒ는 묶음 2 와 같은 구간
09:00 묶음 경보 vs 「30분 임계」 모순 ⓐ 채택 승인 대기 발생 시 즉시 알림을 묶음 2 에 포함. 첫 용역 1주 발생률 측정 체크포인트
끝에서 끝까지가 묶음 4 에야 나온다 ⓐ 채택 묶음 1 끝에 「1인·1일 골든 케이스」 수직 슬라이스(배정 → 수동 출퇴근 1건 → golden_payout.sql 기대값 대조). 반일. work_wage_snapshot 은 deny_change 로 못 고치므로 요율 오류를 묶음 4 가 아니라 여기서 잡아야 한다
위치 ON/OFF 가 4곳을 지배하는데 기한 없음 ⓒ 보류 → 대표 결정 아래 O1. 자동마감 퇴근시각 추정이 「마지막 구역 내 핑」 1순위인데 핑이 없으면 출근 시각으로 떨어져 근무시간 0 — 라운드 2 가 놓친 것
domain 의 파일럿 게이트 철회는 양보였다 ⓑ 절충 되살릴 수 있으나 위치 OFF 전제에서만 → O1 에 흡수
1차에 필요한데 목록에 없는 것들 ⓐ 채택 묶음 R(출시 준비) 신설: 배포 파이프라인 · dev/staging/prod + Secret · log_inbox 적체 경보 · 복구 런북(복원 후 파기 배치 먼저) · 운영자 계정·MFA·IP 제한 · NCP 계정 · 알림톡 발신 프로필 · Play 개발자 계정 · 장애 시 종이 대체 절차. 리드타임 있는 외부 신청(★L1·★L2·Play·알림톡)은 묶음 0 과 동시에 접수

critic 이 반증에 실패한(견고한) 부분: C1 「임시 직접 쓰기 불허」 · C3 「승인자 = 본사 백오피스는 기존 결정의 이행」.


라운드 4 — 종합

합의된 계획 — 8묶음 (순서이자 게이트)

묶음 내용 완료 판정
0 기반 auth.ts 인증 경로 교체 + 인증 경로 교체 · OpenAPI→schema.gen.ts 생성 + run-all.sh 에 git diff --exit-code · const MOCK 동선별 추출 준비 · admin-app npm i · docs/02 에 1차 ON/OFF 태그 · 외부 신청 접수(★L1·★L2·Play·알림톡) 타입 생성 재현 · 템플릿 인증 경로 0
1 첫 동선 용역 개설 + 요율 고정 + 인력 사전등록(손입력 한정 — 명단 반입은 L17) + 자격 등록·승인 + 배정 · 끝에 골든 케이스 수직 슬라이스 golden_payout.sql 기대값 일치
2 근태 출퇴근 + 위치 핑 엔드포인트 + 최소 앱(네이티브: PIN·출퇴근·Foreground 위치+오프라인 큐·푸시·my-work 읽기캐시 / WebView: notices) + admin-app 구역밖 승인 화면 + 즉시 알림 + 배치 ⓒ 실기기 1대로 출근→퇴근 1건 · 승인 1건
3 마감 배치 ⓐ(자동마감·기간 요약) + batch_run DDL + 로그 Writer(6파일) + libs/db 세션 락 체인 연속성 e2e · 재시작 후 prev_hash 이어짐
3.5 정산 선결 주민번호 암호화 컬럼 · 세무 스냅샷 테이블 · 지급 보류 게이트 DDL db/test 회귀 재측정
4 정산 마감 → 명세 → 확정 → 지급완료 + 지급서류 + 출근 명부 CSV(C1 선행) 1용역 1회차 정산이 손계산과 일치
5 잔여 콜(최소 = 「동의+수락」) · 가입·심사 셀프 전환 · 공지·고객센터 —
R 출시준비 병행 레인 — 배포·환경분리·Secret · 적체 경보 · 복구 런북 · 운영자 계정·MFA·IP · 종이 대체 절차 복구 리허설 1회

출시 게이트: 로그 Writer · 배치 ⓐ · 배치 ⓑ「가입 미완료 30일」 갈래 · 묶음 R 복구 리허설 · (위치를 켠다면) 앱 + ★L1 신고 + D112 파티션 전환 + 확인자료 분리 + Play 민감권한 심사 완료일. 1차 OFF: 방문결과 · 명부(2차) · 구역 추천 · AI·최적화(3차, D140).

하네스 레인 분할 = (apps/ 하나) × (테이블 오너십 하나). 직렬화할 충돌 지점 셋: libs/db/schema.ts(kysely-codegen 생성물화가 병렬화 선결) · libs/common · 두 앱 공통 컴포넌트·tokens.css. libs/db 세션 락은 Writer 레인이 먼저 짜고 batch 가 받는다(동시 금지). 통합 테스트는 포트 3개를 점유하니 단일 직렬 게이트.

미해결 — 보류 (해소 조건 명시)

# 무엇 왜 지금 못 정하나 해소 조건
O1 위치를 1차에 켜는가 묶음 2·3 내용, 배치 ⓑ 범위, 09 §7.1 마감 조건, D138 동의 게이트, 자동마감 퇴근시각 추정을 동시에 지배한다 대표 결정 — 묶음 1 착수 전. 켜면: 앱+★L1+D112 파티션 전환+확인자료 분리. 끄면: 「위치 미수집 용역」 플래그 + 마감 조건 N/A 규칙 + 자동마감 대체 순서(예정 종료시각) 를 09 §7.1 에 명문화 + 대리출근 방어 0 수용
O2 구역밖 승인 화면의 정보 범위 security(좌표·지도 금지, 거리만) × ux(거리+방향+동일현장 타 요원 성공 좌표가 최강 단서) 모더레이터 절충안 제시 → 대표 확인: 좌표·지도 핀 없음 + 거리(m)·방향·GPS 정확도 + 동일 현장·동일 시각 성공/실패 집계(n 중 m)
O3 승인 미처리 SLA 18시 자동승인인가 에스컬레이션인가 대표 결정
O4 E16 성과급 배분 기준 기존 미결. 동의률·접촉률이면 업무보고 오프라인인 1차에서 계산 불가 대표 결정 — D88(개별성과 비례) 유지가 1차의 전제
O5 ★L13 × L14 — 명세 수취인 ≠ 소득자 미등록자를 팀장·본부장 통해 지급하면 원천징수 주체와 어긋난다 묶음 3.5 입구 조건
O6 변호사 4건 ① 미체인 log_inbox 가 §16② 「자동 기록·보존」인가 ② 사내 요원 근태 목적 위치 수집이 위치기반서비스 신고 대상에서 빠지는가 ③ 파기 배치 미가동 기간의 보유가 §21 위반인가 ④ 출력물 종이 반출의 위탁·안전조치 요건 외부 자문

rubric

다음 액션

  1. 대표: O1(위치 ON/OFF) · O3 · O4 · O2 확인. O1 은 묶음 1 착수 전.
  2. 모더레이터: 승인 시 증류 — docs/01 §4 로드맵 · docs/02 1차 ON/OFF 태그 · CLAUDE.md 「DDL 완료」 표기 정정 · docs/09 §7.1(위치 OFF 시 마감 조건) · 결정 로그 신규 D.
  3. 즉시 착수 가능(결정과 무관): 묶음 0 전체 + 외부 신청 접수.