title: 펑크폴 리팩토링 마스터플랜 (A→B 신규 구축) — 단계별 계획 + 단계별 측정모델
type: 계획
date: 2026-07-03
priority: P0
projects: [punkpoll-v2]
services: [아키텍처, 리팩토링, 측정모델, 마이그레이션]
purpose: peter 지시 — A(현재 prod) 무접촉 유지, B(리팩토링본) 별도 구축. 치밀한 단계별 마스터플랜 + 각 단계 측정모델. 완성 후 jegwon 논의 → dev 실행.


펑크폴 리팩토링 마스터플랜 (A→B)

유형: 계획 (jegwon 논의 대상 — 논의·확정 후 dev 실행)
저자: manager · 2026-07-03 · 근거: Phase 0 as-built 6건(전건 게이트 PASS)·계약 C-01·결정로그 D-001~D-043
원칙: A(현재 버전)는 검증·전환 완료 전까지 무접촉. B(리팩토링본)는 별도 사본으로 신규 작성(기존 코드 수정·복사 없이 as-built 를 명세로만 사용).

0. 용어·불변 원칙

1. A 무접촉 — B 구축·검증·전환 전 과정에서 A의 코드/DB/트래픽 변경 없음.
2. B는 신규 작성 — as-built 명세를 근거로 재작성. 기존 코드 붙여넣기 금지.
3. 모든 단계는 측정모델로 완료 판정. 측정 미달 = 다음 단계 진입 금지(보수적 게이트).
4. 이중 독립검증 — dev 구현 + manager 게이트(별도 경로 재현). 불확실 = 거부.
5. 인간 게이트 — prod 전환·실채널 연결은 jegwon/오너 승인.
6. 모든 소통은 refactor-chat 중심.
7. A 기능 무수정 원칙(jegwon 2026-07-07 재천명) — 우리는 A의 현재 구조·기능을 B로 리팩토링하는 것이지 A 기능을 수정하는 것이 아니다. 기능·UX·구조 = A 그대로. 보안 강화조차 UX/기능이 바뀌면 구현 전 jegwon 상정 필수(사례: 지갑 '연결' UX divergence).
8. 최종 목적 = 다른 AI 개발자가 B 코드를 손쉽게 구현/재사용 — A의 불필요 코드(부채)는 미이식(제외 근거 기록), 살아있는 기능은 전부 이식. 코드 기준: 도메인 분리·계약 명시·테스트 동반·A소스 ref 주석.


1. A/B 물리 분리 설계 (디렉토리·계정·인프라 — manager 결정)

1.1 저장소 (GitHub)

1.2 로컬 디렉토리

1.3 모노레포 내부 구조 (B) — manager 결정


punkpoll-v2/
├─ apps/
│  ├─ web/                 # Next.js 14 — BFF(구 punkpoll_web 경계) + wallet(non-custodial) 모듈
│  ├─ core-api/            # NestJS — 비즈니스·인증(JWT)·결제(KCP)·콜백 수신·상태머신
│  ├─ chain-worker/        # NestJS — TX 파이프라인·nonce 단일화·토큰/FT·IPFS·온체인 이벤트 검증
│  └─ messenger-gateway/   # NestJS — 카카오/텔레그램·OAuth·nullifier 발급·알림톡(NCP)
├─ packages/
│  ├─ contracts/           # zod 계약 + 계약 테스트(C-01~C-12) — as-built ground-truth 고정
│  ├─ crypto/              # nullifier v2·HMAC 서명·암복호 (키는 전부 env/KMS, 소스 평문 0)
│  ├─ db/                  # punkpoll_v2_* 스키마·마이그레이션·리포지토리
│  ├─ events/              # BullMQ 이벤트 스키마·큐 어댑터(콜백 단일화)
│  ├─ config/              # env 스키마(zod)·설정 로더 (M1: 시크릿 소스 0 강제)
│  └─ shared/              # 공통 타입·유틸·에러코드
├─ infra/                  # PM2 ecosystem·.env 템플릿(주입식)·배포 스크립트
├─ test/                   # E2E(시뮬레이터 연계)·통합·부하·카오스
└─ tooling/                # 마이그레이션 대사(reconcile)·sanitize·A/B 동등성 비교

1.4 런타임 환경 (같은 EC2, 계정 분리 — D-002)

자원A (현행)B (신규)
서버계정ubuntupunkpoll-v2 (신규 리눅스 유저, 격리)
프로세스PM2(ubuntu)PM2(punkpoll-v2), 포트 별도 대역(예: 9600~)
Redis기존 :6379:6380 별도 인스턴스
DB기존 platform/mina**로컬 MySQL 신규 스키마 punkpoll_v2_***
시크릿현행(일부 유출)전량 신규 발급·env/KMS 주입, 소스 평문 0
도메인현행v2 전용 서브도메인(예: v2.punkpoll.com) — 검증용, 실채널 미연결
블록체인Avalanche mainnetFuji testnet 또는 dry-run(온체인 미제출) 강제 — Phase 6 전환 시점에만 mainnet 스위치
결제(KCP)실결제sandbox(site_cd T0000) 강제 — 실결제 방지
전환(Phase 6) 전까지 B는 실사용자/실채널과 미연결. A와 트래픽 격리.
B 체인 격리 (dev 역제안 반영, 안전 필수)★: B의 chain-worker 가 실채널 미연결이어도 Avalanche mainnet 에 TX 제출 시 실자산 이중 민팅·이중 리워드·실가스 발생(A가 이미 mainnet 사용 중). 따라서 B chain-worker 는 환경변수로 체인 분리(as-built #3 txSender 에 Fuji/Mainnet RPC 공존 확인) — Phase 1~5 전 구간 Fuji/dry-run 강제, mainnet TX 0건(→ M11 감사). mainnet 스위치는 Phase 6 cutover 에서만.

2. 단계별 마스터플랜 (Phase → Step) + 단계별 측정모델

각 Step은 [목표] [산출물] [측정모델(지표·목표·측정방법·게이트)] [의존성] [리스크] 로 구성. 측정모델 게이트를 통과해야 다음 Step 진입.


Phase 0 — 분석·계약 기반 (대부분 완료, 참조)

A의 현재 동작을 증거로 고정한 단계. 이미 완료분은 B 설계의 입력.
Step목표산출물상태
0.1as-built 명세(6 저장소군)as-built/*.md✅ 완료(D-009~028)
0.2C-01 콜백 계약 16종contracts/callbacks/✅ 완료(D-041/042)
0.3나머지 계약(C-02~C-12) ground-truthcontracts/⏳ 진행

측정모델(Phase 0): as-built 저장소 커버리지 100%(6/6 ✅) · 계약 그룹 12개 중 ground-truth 문서화 비율(현재 C-01 완료). 게이트: manager 이중검증 PASS.


Phase 1 — B 기반 구축 (Foundation)

빈 모노레포 + 인프라 + 계약 스위트 실행환경. "코드는 아직 없지만 뼈대와 검증장치가 선다."

Step 1.1 — 모노레포 스캐폴드 + 인프라 셋업

Step 1.2 — packages/config·crypto·db 기반

Step 1.3 — 계약 스위트 완성·실행 (C-01~C-12)

Step 1.4 — ★관측성 기반(계측·구조화 로그·알림)★ (D-051): A는 모니터링이 약해 split-brain 미지급을 오래 못 잡음. B는 처음부터 메트릭·구조화 로그·트레이싱·알림을 내장 → 무결성 위반(미지급→성공기록 등)·에러·지연을 즉시 표면화.

Phase 1 완료 판정(측정모델 종합): 빌드·CI 그린 / 시크릿 0 / 계약 100% 통과 / 인프라 헬스 OK / 관측성·알림 동작. 미달 시 Phase 2 진입 금지.


Phase 2 — 세로 슬라이스 1개 E2E (Vertical Slice)

파이프라인 한 경로를 처음부터 끝까지 B로 실제 동작. 아키텍처 리스크를 조기 검증.

Step 2.1 — 슬라이스 선정·구현: 설문 생성 → 배포(core-api→chain-worker) → 온체인(★Fuji testnet 강제★) → 결과 콜백 확정(→core-api) → 상태 반영. BullMQ 이벤트 큐·HMAC·nonce 단일화·온체인 이벤트 검증 포함. (결제 경로 포함 시 KCP sandbox T0000.)

fee payer 관리 — 참여 우선 QoS 풀(D-052)★: A는 유형별(배포/참여/토큰) 전용 fee payer + 2계층 메모리 nonce(재시작 리셋·drift·6월 정체). B: chain-worker 단일 계층 + 공유 fee payer 풀 + QoS(참여 최우선). ①nonce 단일 소스·영속(Redis/DB)·원자 할당·온체인 자가치유(getTransactionCount 대조) ②공유 풀(유형 무관 최한가 계정 분배, 가동률↑) ③참여(투표/join) 전용 예약 용량·우선순위 레인 — 배포/토큰 버스트가 참여를 굶기지 않음 ④계정별 nonce 격리(막힌 TX=그 계정만) ⑤유형 태깅(정산·관측) ⑥master→slave AVAX 자동 top-up+잔액 알림. 측정: 부하 시 참여 TX 우선 지연<목표·참여 starvation 0·nonce 재시작 유실/중복 0(M5).

Phase 2 완료 판정: 슬라이스 E2E 100% + 무결성/멱등/인증 축 통과. 아키텍처 확정.


Phase 3 — 기능 등가 확장 (도메인별 병렬)

슬라이스에서 검증된 골격 위에 A의 전 기능을 도메인별로 재구축. 각 도메인은 계약을 무회귀 만족.
Step도메인as-built 근거측정모델(핵심 지표)
3.1인증(JWT·OAuth·nullifier 발급) + ★단일 신원 서비스·통합 회원등록★#1·#2·#5로그인/refresh 계약 100%, nullifier 발급 결정성, first-touch 등록 멱등
3.2결제(KCP 주문·승인·취소·잔액·PUNK)#1결제 계약 100%, 금액 정합 대사 0 오차
3.1b★PII 암호화(주민번호·전화번호)★ (D-049)#1저장 평문 0·알림톡 발송 시에만 복호화·복호 경로 인가 통제
3.3참여/투표(joinSurvey→IPFS→온체인→콜백) + ★설문 생명주기·중단/일시정지·리워드 에스크로★#2·#4·#5이중리워드 0, 무결성 축 통과, 생명주기 상태전이·반환 정합
3.4토큰/FT/SBT/IPFS#3·#4배포·민팅 계약 100%, IPFS 멱등, ★즉시 CID 발급 + 지연 Pinata 핀★(아래 주)
3.5챗봇(카카오 4채널·텔레그램·알림톡)#5카카오 응답 p99<4.5s, 채널 config화(복제 0)
3.6지갑(non-custodial, ★WebView surface + 플랫폼 백엔드 공유★)#6개인키 서버 전송 0, 서명 왕복 정상, WebView 임베드 동작, 플랫폼 신원 공유
3.7web BFF·관리자·통계#1·#6BFF 21경로 계약 100%

측정모델(Phase 3 각 Step 공통): ①해당 도메인 계약 테스트 100% 통과 ②A 대비 회귀 0(골든샘플·대사) ③보안 불변식(시크릿 0·인증 필수·fail-closed) ④성능 목표치(도메인별) ⑤체인 격리 준수(Fuji/dry-run, mainnet TX 0=M11)·결제 sandbox. 게이트: manager 도메인별 이중검증.

통합 회원 등록·단일 신원 서비스 — jegwon 요구(D-047)★: A는 회원 등록 권한이 챗봇 signupService 에 있어 '챗봇 먼저 써야 회원' 잔재(플랫폼 로그인→needs_signup / attemptDirectSignup 도 챗봇 호출). B: core-api 단일 신원 서비스가 회원+nullifier 생성 권한 보유, 플랫폼 OAuth·챗봇 auth 둘 다 이 하나를 호출. findOrCreateMember(provider, 외부ID) 멱등 → 진입점(플랫폼/챗봇)·순서·동시성 무관 first-touch 가 회원+nullifier 원자적 생성, 챗봇 의존 제거 → 어디서 처음 쓰든 즉시 회원·챗봇 정상. 범위: 같은 provider 자동통합 포함 / 교차 provider(카카오↔텔레그램 한 사람) 링크는 기반만(신원모델 Canonical User(1)←ProviderIdentity(N) 스키마로 미래 확장 가능하게 설계, 링크 로직·전화 매칭 UI 는 이번 제외).
설문 생명주기·중단/일시정지·리워드 에스크로 — jegwon 요구(D-046)★: A엔 배포 중단이 없음. B는 설문 생명주기 상태머신으로 제공: DRAFT→QUEUED→SUBMITTING→CONFIRMING→ACTIVE→(PAUSED↔ACTIVE)→STOPPED/CANCELLED. 규칙: ①단계별 중단 안내수수료: 온체인 전송 前 취소=가스 0·리워드 전액반환 / 전송 중·후 취소=이미 쓴 가스 차감·나머지 리워드 즉시 반환등록 완료 후 '중지': 참여 차단 + 미지급 리워드 즉시 반환 ④참여 일시중지/재개: 온체인 Pausable(트러스트리스) 권장. 리워드 에스크로 필수(배포 시 재원 예치→참여마다 지급→중지/취소 시 잔액 반환). ★반환액 = 에스크로 총액 − 참여자에게 지급해야 할 금액(기지급 + 참여했으나 미지급 owed 둘 다 예약)★ = 참여자 권리 보호 후 잉여만 반환. 반환도 온체인 TX라 큐·무결성 검증 대상(미반환→반환됨 기록 0). 측정: 상태전이 정합·수수료 계산 정확·반환액=에스크로−(지급+owed) 정확·반환 무결성.
pin 서버(IPFS) 설계 원칙 — jegwon 정정 반영(D-045)★: pin 서버의 주역할 = 대량 참여 시 Pinata rate limit 우회용 '즉시 CID 발급' (영속성/GC 방지는 부차). B 는 3.4 에서 ① 참여 시 CID 즉시 발급(임계경로, Pinata 대기 없음) → 파이프라인 즉시 진행 ② Pinata 핀 업로드는 BullMQ(:6380) 큐로 순차·rate-limit·재시도 후처리 ③ CID 기준 멱등(A의 중복 핀 작업 갭 해소) = '즉시 CID + 지연 핀' 분리 패턴. 측정: 대량 참여 부하에서 CID 발급 지연<목표·Pinata 큐 순차 소진·중복 핀 0.

Phase 3 완료 판정: 전 도메인 계약 100% + 회귀 0 + 보안 불변식 충족.


Phase 4 — nullifier v2 마이그레이션 (연속성 보장)

A의 nullifier(공유 평문키 기반)와 B의 신규 nullifier 체계 간 유권자 신원 연속성 보존.

Step 4.1 — 호환 계층 설계·구현: 구키 복호 → 신키 재암호 매핑, 온체인 영구 호환(과거 발급 nullifier 무효화 금지).

Step 4.2 — ★split-brain 오염 데이터 온체인 소급 대사★ (D-050): A의 구버전 워커가 '미지급을 성공으로 기록'한 과거 오염 데이터는 A 중지만으론 안 사라짐. 마이그레이션 시 A의 '성공' 레코드를 온체인 이벤트와 대조 → 불일치(가짜 성공=실제 미지급) 교정/플래그 → B는 검증된 데이터로 시작.

Phase 4 완료 판정: 연속성 100% 대사 통과.


Phase 5 — 섀도 운영 (A 병행, 무전환)

B를 A와 나란히 돌리되 실채널 미연결. 시뮬레이터/미러로 A와 동등성·성능 검증.

Step 5.1 — 섀도 실행·동등성 검증: sim.punkpoll.com 시뮬레이터를 B 대상으로 확장, A vs B 출력 동등성 비교(tooling/동등성).

Phase 5 완료 판정: 동등성·성능·안정성 목표 달성 → 전환 준비 완료.


Phase 6 — 전환(Cutover) — 인간 게이트

검증된 B로 실제 전환. 오너가 채널 연결, A 중지. 롤백 경로 상시 확보.

Step 6.1 — 단계적 전환: DB 최종 이관·정합 대사 → 채널/도메인 전환(오너) → 소규모 카나리 → 전량 → A 중지(관찰기간 후).

Phase 6 완료 판정: 전환 안정 + 롤백 준비 확인 + A 안전 중지.


3. 측정모델 총괄 지표 (전 단계 관통, KPI)

ID지표목표측정 방법연계 Phase
M1시크릿 소스 평문0건gitleaks/CI 전 파일 스캔1~
M2계약 테스트 통과율100%packages/contracts CI1·3
M3파이프라인 E2E 통과율100%시뮬레이터 시나리오2·3
M4TX 무결성(미지급→성공기록)0건chain-worker 테스트+온체인 대사2·3
M5nonce 안전(재시작 중 유실/중복)0건카오스 테스트2
M6카카오 응답 p99<4.5sgateway 계측3
M7nullifier 연속성100%마이그레이션 대사4
M8A/B 출력 동등성100%(오차 정의)동등성 비교 tooling5
M9A 무접촉변경 0A repo/서버 감사1~6
M10전환 안정성·롤백목표·리허설 성공실트래픽·롤백 리허설6
M11B mainnet TX (전환 전)0건chain-worker RPC 감사·온체인 조회1~5 (dev 역제안)
M12PII(주민번호·전화번호) 저장 평문0건DB 스캔·복호 경로 감사3 (D-049)
M13split-brain 오염 소급 대사'성공' 레코드 온체인 대조 100%·가짜성공 교정온체인 대사 스크립트4 (D-050)
M14관측성·무결성 알림위반 주입 시 알림 발화알림 재현1~ (D-051)

4. 실행·거버넌스

5. 논의 안건 (jegwon)

1. A/B 분리 설계(§1) — 특히 같은 EC2 병행(D-002) vs 별도 인스턴스, v2 서브도메인.
2. 디렉토리/모노레포 구조(§1.3) 확정 여부.
3. 단계 순서·측정모델 목표치(§2·§3) — 특히 무결성(M4)·동등성(M8) 허용 오차, 전환(Phase6) 조건, B 체인 격리(Fuji/dry-run, M11 mainnet TX 0)·결제 sandbox 확정 (dev 역제안).
4. nullifier 마이그레이션(Phase 4) 우선순위·리스크 수용.
5. 일정·자원(섀도 운영 EC2 여력).


다음: 이 마스터플랜을 refactor-chat 에 공유 → jegwon 논의 → 확정분으로 dev 실행(Phase 1.1부터). 확정 전 prod 무접촉·구현 착수 없음.

6. 방법론 최적화 로드맵 (jegwon 승인 2026-07-07 — AI 하이브리드 리팩토링 5방법론 + wikidocs 템플릿 + 세션 실증 종합)

진단: 계획 루프·사람-AI 분업·승인 게이트는 최신 방법론과 이미 일치. 최대 갭 = 검증 자동화 — 치명 트랩 5건(env 미배선·stale-dist·십진/wei·toFixed 절삭·merge-drop)이 전부 유닛 green 뒤에 숨었고 reviewer 수동 렌즈만 잡음(검증 사람 병목).

우선순위항목내용시점
P0PR 위험등급+롤백 1줄모든 PR 본문에 Low/Med/High + 롤백 커밋범위 명시. 배포 공지에도 롤백 1줄즉시 발효
P0대형건 1페이지 계획서남은 대형건(커스텀토큰·M4 컷오버)만 전후·단계·롤백 계획서즉시
P1자동 A/B parity diff핵심 공개 엔드포인트 A(prodPool)↔B(v2) 응답 골든 diff 하니스(CI). 2층 구조: 자동 diff=1차 그물(값 어긋남 대량 조기포착) / reviewer=2차 의미론 렌즈(의도된 divergence 판정·정수검산·온체인 바이트대조·인과규명) — 대체 아닌 증강T5 실증 후 착수(backend1+reviewer 설계)
P1e2e 머지게이트 승격컴포지션 e2e(풀루프 불변식)를 PR 머지게이트로
P2codemod 롱테일푸터/정적 22페이지 + 명확 패턴 반복 일괄 변환(커버리지 가속). 코어(온체인·도메인)는 제외 — 사람승인 루프 유지P1 후
P3측정 보강①OPTIMIZATION_REPORT A대비B 정량표(LOC·복잡도) ②커버리지 실측→코어 80% 게이트 결정 ③로그인 게이트 페이지 인증 픽스처 골든 캡처순차

하지 않을 것: 전면 자동 리팩토링(사람 게이트 제거)·DL 스멜탐지 별도 도입(자동 A-diff가 대체)·코어 도메인 codemod.