유형: 현황 (A 코드베이스 품질 감사 — B 리팩토링 반영용)
최종 업데이트: 2026-07-07 (manager-as-main + Explore 3에이전트 병렬 감사)
A 코드베이스 최적화·클린코드 감사 (punkpoll_web → B)
목적: A(www.punkpoll.com = punkpoll_web) 전 페이지 파악 완료 후, 기존 A 코드의 dead code·중복코드·최적화·클린코드 대상을 정리해 B 리팩토링에 반영한다. 전제: 도메인 기능은 A와 동일(클론) 유지, 구조/품질만 개선. 추측 금지, 전부 file:line 근거.
요약 임팩트: 데드코드 제거 ~5-8% · 중복 통합 ~600-700 LOC 절감 · 폴링/거대컴포넌트/상태이중화가 3대 구조 부채.
불변/개선 경계 (reviewer 프레이밍 — 최적화 트랙 규율 원칙)
'A 기능 무수정'과 '최적화'가 충돌하지 않도록 경계를 못박는다:
- 불변 (A 관찰가능 동작): 클릭→목적지, Vote=sendMeJoinSurvey 챗봇, 팔로우 LoginModal 게이트, 좋아요/댓글 다중카드·다중창 실시간 반영, 사이드패널·차트 표현, 온체인 semantics(M4 이벤트게이트·nonce·settle 항등식). 절대 불변.
- 개선 가능 (A 구현 방식 부채): setInterval 100ms 폴링·상태 3중화·거대 컴포넌트·.jsx·인라인 api·빈 catch. A의 부채라 B가 더 깨끗이 해도 됨(목표=다른 AI가 쉽게 쓰는 코드). 예: C2 폴링→순수 store 구독은 관찰 동작(실시간 sync) 동일하면 A정합, 위반 아님.
PR별 reviewer 검증: C1 4곳 게이트/creatorSe/롤백 동일 렌더 · C2 다중창 BroadcastChannel 실시간 회귀(2창 캡처) · C3 voteYn/status 노출조건+챗봇+LoginModal · C4/C5/C6 출력 URL/컬럼/렌더 불변 · 워커코어 settle/participation 재실증. 각 항목에 reviewer A정합 판정 부착.
1. Dead Code (B에 포팅 제외)
1-1. 데드 라우트 3
| 라우트 | 파일 | 근거 |
/explore-2 | app/(pages)/explore-2/page.jsx | 인바운드 링크 0, routes.js 미정의 (self-import만) |
/daily | app/(pages)/daily/page.jsx | '/daily' 참조 0 (self만) |
/citizen | app/(pages)/citizen/page.jsx | routes.js:7 //citizen 주석처리 = 도달 불가 (페이지는 홈 리다이렉트) |
1-2. 미참조 컴포넌트 4
IFrameReport (components/.../report/IFrameReport.jsx) — import 0 (ReportDetail은 ReportChart 사용)PoliticalChart·Daily·Explore2 — 데드 라우트에만 종속 → 전이적 데드
1-3. 주석처리 블록 (포팅 전 제거)
- ChannelInfo.jsx:34
// const [shortUrl...], :349-368 // <Link ...> - UserMenuPanel.jsx
// <Link> 래퍼 - ChannelPageTitle.jsx 주석 JSX 블록, Participants.jsx:63-68 주석 컬럼(Memo)
1-4. 데드 익스포트 4 (constants/table.js)
CHANNEL_TX_TABLE_HEADER·CHANNEL_DEPLOY_TABLE_HEADER·CHANNEL_FOLLOWER_TABLE_HEADER·CHANNEL_MANAGER_TABLE_HEADER — 참조 0
2. 중복 코드 (공유 훅/유틸로 통합) — ~600-700 LOC 절감
| # | 클러스터 | 중복 위치 | 통합안 | 절감 |
| C1 | 팔로우/언팔 토글 | ChannelProfile:19-35·ChannelInfo:46-76·channel/page:71-97·Token:126-157 | useFollowChannel(uid, onSuccess) | 40-50 |
| C2 | 좋아요/댓글 동기화 (store+BroadcastChannel+setInterval 100ms) | ShareButton·CardActions·DetailSideModal·poll/Poll (각 useEffect 3블록) | usePollSyncState(surveyUid) + normalizeCount util | 180-200 |
| C3 | Vote 핸들러 (로그인체크→sendMeJoinSurvey) | VoteButton:23-38·CardInfo:33-43·AdminPollCardInfo:31-41 | useVoteHandler(sid,{checkStatus}) | 25-30 |
| C4 | 블록탐색기 URL (avax/minascan) | Transaction·UserPublicKey·InfoWallet·TokenHistory·admin모달들·PaymentHistory (10+곳) | utils/blockExplorerLinks (getAvax/getMinascan/auto) | 60-80 |
| C5 | 매니저 테이블 셋업 (TanstackTableCommon 컬럼·정렬·페이징) | voters/Participants·Followers·TokenHolders (각 ~142줄 동일) | useManagerTableSetup(config) or <ManagerDataTable> | 280-320 |
| C6 | 빌더 스위치 5분기 | manager/builder/Builder.jsx:98-137 (ai/token/live/vote/default 모두 유사) | config 맵 기반 | 10-20 |
B 신규 공유파일: hooks/{useFollowChannel, useVoteHandler, usePollSyncState, useManagerTableSetup} · utils/{blockExplorerLinks, countNormalization}
3. 최적화·클린코드 대상 (A 동작 유지, 구조만)
3-1. 폴링/타이머 (이벤트·스토어 구독으로 전환)
| 위치 | 문제 |
| ShareButton:99·CardActions:130·poll/Poll:101 | setInterval(checkGlobalState, 100) = 100ms 폴링 재렌더 (스토어 구독으로) |
| SendHistory:95 | 1s 폴링 |
| EmbedPickerModal:43 | 500ms 팝업 감지 폴링 (postMessage로) |
| SharePollCard:121 | 카드마다 1s 카운트다운 interval (100카드=100타이머 → 공유 useCountdown) |
| DarkModeContext:143 | 1s 다크모드 백업 폴링 (storage 이벤트와 중복) |
| admin Dashboard:2046·Scheduler:37 | 30s (document.hidden 체크 없음) |
3-2. 거대 컴포넌트 (300줄+ / 다중 책임) — 상위
| 컴포넌트 | 줄수 | 분리안 |
| AdminDashboardContent | 2286 | 탭/헬스/배포/ SSE 훅 분리 |
| VoterRegistrationModal | 1031 | 스텝 컴포넌트 |
| AdminPollCard | 926 | 헤더/액션/토글 |
| create-wallet-modal | 807 | 위저드 |
| Comments | 794 | 리스트/필터/액션 |
| PunkPurchase | 713 | 결제수단/KCP/주문 |
| PhoneBookNumberTable | 707 | 테이블/액션/필터 |
| SharePollCard | 561 | 표시/카운트다운/폰폼/통계 |
| builder Poll | 565 | 질문/리워드/푸터 (상태 store로) |
| Sidebar | 428 · ChannelInfo | 418 · TokenChart 438 | 서브컴포넌트 분리 |
3-3. 상태 이중화 (로컬 useState + 글로벌 store 미러) — 단일 소스로
- PollCard:23·ShareButton:12·DetailSideModal:25·AdminPollCard:36 — props+local+store 3중 소스, 폴링으로 동기화 → store selector 직접 구독
- BroadcastChannel 리스너 매 렌더 재생성(ShareButton:113·DetailSideModal:50) — deps를 surveyUid만
- 콜백 프롭 체인(onLikeChange/onCommentChange page→card→ShareButton) → store 직접 갱신
- 빌더 프롭 드릴 4단계(Poll→Questions→…→Actions) → store + surveyUid만
3-4. 재렌더/메모
- PollCard·AdminPollCard 리스트 React.memo 없음 → 형제 갱신에 전체 재렌더
- AdminDashboardContent 30+ 비메모 .map
- SharePollCard 가시성 변경 시 fetch+폴링 이중발동
3-5. 일관성
- 전부 .jsx (0 .tsx) — B는 TS 우선(카드·store부터)
- 인라인 api.* 99+곳 vs services/ 33개 혼용 → services 계층 일원화
i18n.i18n.language 어색한 접근 → useLanguage 훅- Link vs router.push 혼용 · 하드코딩 문자열 vs i18n 키 혼용
3-6. 에러 처리
- 빈 catch/
.catch(()=>{}) 10+곳 (copilot·builder·PunkPurchase) — 무음 실패 - 주석 console.error 25+곳 — 제거 + ErrorBoundary/토스트
4. B 반영 우선순위
Tier 1 (고임팩트·저복잡): useFollowChannel · blockExplorerLinks · useVoteHandler · 데드코드 3라우트+4컴포넌트+4익스포트 제외
Tier 2 (고임팩트·중복잡): usePollSyncState(폴링→구독) · useManagerTableSetup · 상태 단일소스화
Tier 3 (구조): 거대 컴포넌트 분리 · services 계층 일원화 · TS 마이그레이션 · 에러바운더리
A-parity 불변: 모든 도메인 로직은 A와 동일. 위는 전부 구조/품질 개선(사용자 관찰 동작 무변).
5. v2 백엔드(core-api·chain-worker) 감사 — backend4 도메인 분석 (읽기전용)
A 프론트(1~4)와 별개로, B/v2 백엔드 코드의 dead/중복도 같이 정리. reviewer 가드레일: 통합해도 M4 이벤트게이트·nonce reconcile·settle 항등식·hmac 콜백 semantics 불변(온체인 동작 보존).
5-1. Dead code
fuji.chain.ts:18-22 SURVEY_REGISTRY_ABI(deploySurvey/recordParticipation) — 사용처 0. 구 단일컨트랙트 잔재. 실동작=ContractFactory(SURVEY_NFT_V2_ABI):238 / registerParticipationWithNFTV2:272 (T2b per-survey factory 전환으로 폐기)FujiChainAdapter 생성자 3번째 인자 contractAddress + env SURVEY_REGISTRY_ADDRESS — vestigial(검증만·미사용, per-survey는 job별 surveyContract)
5-2. Stale 네이밍/주석 (구 모델 잔재)
recordParticipation 참조: participation.worker.ts:2·main.ts:46·index.ts:7 (실제 registerParticipationWithNFTV2)SURVEY_REGISTRY_ADDRESS 에러문구 fuji.chain.ts:30 (실제 per-survey contractAddress)
5-3. 최대 중복 — 워커 스캐폴드 7개 (임팩트 큼)
- deploy·participation·transfer·sbt·token·deposit·settle 이 동일 골격 반복: Deps 6건·nonce.reconcile+mutex.run 6건·M4 이벤트검증+INTEGRITY_VIOLATIONS+TX_FAILURES 7건·hmac 콜백 5건
- 제안: 공용
runChainJob 코어(base) 추출 — nonce예약+mutex+M4검증+메트릭+콜백 캡슐화. 워커별로 큐명·파서·submit·이벤트타입·콜백빌더만 주입. ~700줄 → 코어 ~120 + 워커당 ~30. '다른 AI가 쉽게 쓰는 코드베이스' 목표 직결 - 가드레일(reviewer): 코어화 후에도 (a)M4 무이벤트=실패 게이트 (b)순차 nonce+down-reconcile 순서 (c)settle 항등식 deposit=보상+잉여 값 보존. PR시 settle/participation 재데모 또는 하니스로 회귀 없음 확인
5-4. 검토 대상 — custodial 전환(#151) 후 지갑 서비스 병존
- non-custodial
WalletService(register=클라 주소등록) vs WalletCustodyService(provision=서버생성) 병존. register가 provision으로 상당부분 대체 — 통합 검토 필요. verify/balance/me 는 유효(유지)
6. A 백엔드 모듈 감사 (진행중 — 모듈별 file:line)
[정정 2026-07-07] live/dead는 실 prod pm2 데몬 기준(/doc/daemons). 코드 config 변형(ecosystem 3개 등) 하나만 보고 단정한 판정 오류 정정: PunkpollLightApi2=live(LightApi 아님)·txConfirmationWorker.v2=live(별도 repo -Ver2, dead 아님)·kakaoServerRefactored(Node)=live(PHP dead). FungibleToken은 Mina 컨트랙트코드(FungibleToken.ts·zkPunkManager)만 dead, LightApi2-Main(9400) API서버=live(참여큐+IPFS+콜백). 단 모듈 내부 import 도달성(redisNonceManager import 0=dead)은 변형 무관 정적사실로 유효.
jegwon 지시: 운영 전체 모듈로 확장. reviewer/backend4/backend1/dev·dev2 분담. 온체인 semantics·A 관찰동작 불변 가드레일.
6-1. txSender (온체인 배포·참여·리워드·콜백 데몬) — reviewer 1차 (src/ 14,835줄·15모듈)
- 거대 파일(단일책임 분리 대상): txMonitor.js 2567 · rpcManager 1211 · tokenRegistryService 1073 · contractService 961 · txSender.js 893.
- [정정] TX복구 6파일 = 중복 아님, 실패모드별 책임분리 서브시스템 (reviewer 실코드 재확인·submanager 지적): txResendService=①dropped TX(mempool eviction) 재전송+②NO_EVENTS(tokenId 충돌·무이벤트) 재전송 / txRecoveryService=③tx_failed 자동복구(재시도제한+지수백오프) / txPendingRecoveryService=④온체인 전송됐으나 tx_pending 미등록 복구 / txPendingService=TX 생명주기 상태관리 / txConfirmer(데몬)=pending→confirmed+콜백 / txRecovery(데몬)=복구 오케스트레이션. 감사 포인트=파일 통합이 아니라, B chain-worker(BullMQ 재시도/DLQ+워커코어) 대체 시 4실패모드(dropped·no-event·미등록·failed-retry) 전부 보존 여부를 G6로 검증. NO_EVENTS 게이트=M4(무이벤트=실패) 직결. (블라인드 통합 금지.)
- RPC 견고성 = circuit-breaker 패턴 2레벨(통합 대상, 삭제 아님): circuitBreaker.js(잡루프 레벨·3데몬 실사용) vs rpcManager 자체 서킷(provider 레벨 :112·147-189). 같은 패턴 2레벨 각 구현 → 재사용 util 1개로 통합하되 양 가드(잡루프 정지·provider 스킵) 보존. robustProvider(transport 레벨 드랍감지) vs txResendService(lifecycle 레벨) 드랍처리 2레벨 분산.
- 일회성 스크립트(B 미포팅): scripts/(reprocessSurvey679·testDecryption·recoverPendingTx 등) 운영/복구용.
- 핵심 검증 파일(A 온체인 semantics 원천·G6 기준선): callback.js(748·nullifier/reward)·participationSigner·redisNonceManager·signerService(custodial 서명).
- (진행: 각 파일 file:line dead/중복 + A→B provenance 대조 계속)
6-2~ (나머지 10 모듈) — 분담 착수 대기
kakaoChatBot · punkpollBotAvax · bizchat · punkpoll_api(Spring Boot) · auth-gateway · ipfs · blockchainApi(+Ver2) · FungibleToken · punkpollUtil · standalone_wallet · admin
reviewer 1차 명백 데드파일(공유분): kakaoServer.js.deprecated·server_backup.js·*.backup·channelmanager.bak·channelmanager-mapper.bak / 원본 vs Refactored 병존(kakaoServer vs kakaoServerRefactored·messageHandlers vs messageHandlersRefactored) → 라이브 판별 후 죽은쪽 제거.
6-2. ⚠️ [폐기·재작성] kakaoChatBot(PHP) 감사 = 죽은 코드베이스 대상 오류. 실 live=kakaoChatBotNodeJs/kakaoServerRefactored.js(Node, pm2 kakao-punkpoll). PHP본은 레거시 dead. 카카오 도메인 라이브러리 재작성 필요(/doc/daemons 기준). 아래 PHP 분석은 무효.
- 역할: Kakao webhook → kakaoChatBot.php(진입) → inc_trans_command.php(라우팅) → inc_utility_wellcome_{punkpoll,tbridge}.php(설문로드) → inc_utility_user_answer*.php(응답). Live DB=mysql.7.0.class.php.
- Dead: mysql.class.php(997·폴백/데드)·thoting_dev.php·kakao_utiltyBotSharePunkpollNew.php(41KB 고아)·inc_showTodayPunkpollList.php(846·6곳 주석) + 주석 require 12개(getOneTimeLoginToken·inc_chkKakaoAuth·inc_process_talk 등).
- 원본 vs Refactored 병존: tbridge = punkpoll의 specialized 버전(국민투표/발안/소환 제거). 채널 라우팅 botId 명시비교 → Strategy 패턴 대상.
- 거대 파일: inc_math_switchcase.php 8599 · kakaoChatBot.php 4599 · inc_utility_wellcome_punkpoll 4297 · inc_utility_makeForm 4221.
- 중복: punkpoll vs tbridge WHERE절·사용자조회 SQL 50%+ 중복 · 답변 핸들러 3분산 · Kakao JSON 템플릿 중복.
- 🔴 보안:
addslashes() SQL 이스케이프 21곳(Prepared Statement 미사용=SQL injection 위험) · 전역변수 100+.
6-3. punkpoll_api (설문/채널/유저 CRUD·참여수집) — manager 取合 (Spring Boot 552파일·59.6K LOC)
- 역할: 설문작성(MySurveyService)→배포(SysRequestService 1501)→알림톡(AdminAlimtalkService)→콜백수집(SysResponseService 851)→리워드/SBT(SurveyAIService). MyBatis 59 XML mapper.
- Dead: VoterScheduleController(전체 주석)·DebugController(4 테스트EP·"운영 제거 필요")·SearchController 마이그레이션 3·UserController [DEV] 3·PaymentController 테스트3·AuthController issueTestToken·80 미사용 mapper 쿼리·VoteEvent @Deprecated.
- 중복: 채널관리 삼원화(ChannelManagerService 464 vs AdminChannelManagerService 306 vs ChannelManagementMapper 88)·응답래핑 불일치(ResponseEntity 20+ vs ApiResponse 140)·@PreAuthorize 고정문자열 125회·DTO/VO 184클래스 분산.
- 거대 서비스(분리): SysRequestService 1501·MySurveyService 1390·AdminHealthCheckService 1331. Fat controller SysResponseController 692.
- N+1: SurveyService.getResult() 문항×항목 중첩쿼리·AdminUserPageMapper 7 LEFT JOIN(5초+).
- B 매핑: 설문/채널/유저/댓글 CRUD는 v2가 대체(데드 제거 가능) / A-only 유지=배포workflow·콜백수집·admin대시보드·결제·스케줄러.
6-4. punkpoll-auth-gateway (카카오/텔레그램 OAuth·JWT·nullifier) — manager 取合 (NestJS)
- 역할: /oauth/kakao/authorize→callback(토큰교환+nullifier생성+ticket)→/api/auth/ticket/exchange. Redis state(5min)+ticket(60s) HMAC 서명. 멀티테넌트 DatabaseBotIdService(dev/main).
- Dead: app.controller/app.service(AppModule 미등록)·share.controller getKakaoChannelName(service와 중복).
- 🔴 보안(즉시): nullifier.ts:4,7
NULLIFIER_KEY+IV 하드코딩+평문 로그(키 로테이션 불가) · configuration.ts:51 default-state-secret/default-ticket-secret 폴백 · auth.service 전반 userNullifier·토큰·OAuth응답 console.log(클라우드 로그 노출). - 중복: 암호화 유틸 2개(nullifier.ts vs encryption.util.ts 동일 키)·IP추출 4회·OAuth 토큰교환 2경로.
- 구조: guards/strategies 부재(인라인 검증) → OAuthStrategy 인터페이스+@UseGuards 필요 · auth.service 533줄 분리(Orchestration/Signup/Error) · 챗봇 signup URL 하드코딩(localhost:6001).
6-5. punkpoll-ipfs (참여내용 IPFS·Pinata·BullMQ) — manager 取合 (Node 1080 LOC·컴팩트)
- 역할 달성: 로컬 IPFS add(동기)→즉시 CID / BullMQ 1 concurrent+1s+3retry→Pinata rate limit 우회. jegwon 정의(즉시 CID+지연핀) 부합.
- Dead: pinataService.getPinStatus(정의만·호출0).
- 중복: S3 backup try-catch 2곳(173-179 vs 217-223) 동일.
- 🔴 정확성: server.js:185
JSON.parse(req.body.metadata) try-catch 없음(악성 JSON→500) · 멱등성 갭: 같은 CID 2회→중복 job 생성(getJobByCid 체크 필요) · S3 backfill fire-and-forget silent 손실. - 최적화: server.js 395줄(routes 분리)·getJobs 전상태 로드 후 필터(N+1)·journalctl 매요청·dashboard HTML 196줄 인라인.
6-6. punkpollBotAvax (텔레그램 진입·설문참여) — manager 取合 (Node)
- 역할: telegramBot/index.js(2067·진입+메뉴혼재)→bot/{callback,message,commands}→routes/{survey 2191,auth 1450,wallet,panel}. services/{alimtalk 2341,survey-management,blockchain}. punkpollSystemApi.js(1684 독립서버).
- Dead: telegramBot.js.legacy(6283)·punkpollSystemApi.js.backup(7844)·.bak(2288)·test_step*.js·chatbotTest 등.
- 🔴 보안(최우선):
${sId}/${chatId} 문자열 삽입 SQL 118곳(survey.routes 등) = SQL injection. 타입검증 부재. - 중복: 메시지 송신 래퍼 3변형(sendBotMsg/WithPhoto/OnlyPhoto)·DB pool 3곳·axios 호출패턴·kakao와 메시지로직 분리발전(공유 없음).
- 거대: alimtalk.service 2341·survey.routes 2191·index 2067·auth.routes 1450.
6-7. bizchat-reward-api — ⚠️ 감사 대상 제외 (jegwon 2026-07-07: 펑크폴 프로젝트 아님. clawdbot-kakaotalk도 제외). 아래는 참고용 관찰(클린 구조 모범 사례로만 인용).
- 역할: BizChat 리워드 적립(save)·동의조회·리다이렉트. Client+Routes+Middleware+Zod Types. Vitest 테스트 있음. 1424 LOC(최대 243).
- Dead/중복: 없음. 파일 전부 <250줄, ZodError/ApiError 분류처리, env Zod 검증.
- → V3 참고: 이 구조(TS+Zod 입력검증+에러분류+테스트+작은 파일)가 B가 지향할 클린 모범. 다른 모듈 리팩토링 시 기준.
6-8. punkpollUtil (panelManager — 패널관리·응답 스케줄링) — manager 取合 (Node)
- 역할: 시나리오→GPT 가중치→DB 패널삽입→시간대별 스케줄. panelManager.js 1463(거대). 5503 LOC.
- 🔴 보안:
${sId} SQL injection 7곳(424·443·451·593·597·611·701). - Dead/이슈: node-fetch import 미사용·테스트 없음·매직넘버(600·5*60*1000)·dbConnection.js:67 //initTables 주석.
- 중복: customLog/console.log 101회 산재·getConnection try-finally 반복.
6-9. standalone_wallet (웹뷰 지갑) — manager 取合 (Next.js, dev2 도메인)
- 역할: 지갑 생성/import·자산목록(assets-list 1289)·송수신·QR·웹뷰 브릿지(postMessage). Zustand+React Query+ethers.
- 🔴 CRITICAL 보안: create-wallet-modal.jsx:196
privateKey 평문 서버 전송 + 상태 저장(메모리 노출)·wallet-utils 전 함수 평문 PK 반환. → B custodial 전환(서버생성+KEK)이 이 결함 근본 제거([[project_punkpoll_wallet_custodial]] 정합). - Dead: avalanche-rpc.ts(400 전체 미사용·wallet-utils와 중복)·utils/axiosInstance.js(중복)·components/lib/utils.ts(중복)·
utlis/ 오타폴더. - 버그: wallet-utils:84 mainnet에 testnet RPC URL·BTC 가짜주소(ethers)·use-wallet send/buy 스텁(mock).
- 거대: assets-list 1289·ResultsModal 1097·create-wallet-modal 807.
6-10. punkpoll_admin (관리자 콘솔) — manager 取合 (⚠️ SUPERSEDED)
- LIVE 판정: 폐기됨(SUPERSEDED). archived/ Express+EJS(마지막 커밋 2025-08) vs punkpoll_web/app/admin(React/Next, 2026-04 최신·15+페이지). B는 punkpoll_web/app/admin 참조, 이 저장소 포팅 제외.
- Dead: surveyService_backup.js(264)·createAggregationTables/Individually 스크립트·TODO 다수·console.log 114곳.
- 중복: 대시보드 통계쿼리 3중(dashboardService vs optimized vs database.js)·Repository 패턴 부재.
- 🔴 SQL injection: channelService
LIMIT ${parseInt}·OFFSET ${} (parseInt이나 파라미터화 권장).
7. 교차 발견 (전 모듈 공통 — V3 규율)
- 🔴 SQL injection 만연: kakao(addslashes 21)·telegram(${} 118)·punkpollUtil(7)·admin(LIMIT/OFFSET)·punkpoll_api 일부. V3 전 모듈 Prepared Statement/파라미터 바인딩 강제(보안 게이트).
- 🔴 개인키 평문: standalone_wallet create-wallet:196 → B custodial(서버생성+KEK)로 근본 제거.
- 🔴 auth-gw 키 하드코딩: nullifier 암호화키 코드 상수+평문로그 → env+로테이션.
- 거대 파일 만연: 각 모듈 최대파일 1000~8599줄(kakao switchcase 8599·telegram alimtalk 2341·api SysRequest 1501). 단일책임 분리 공통 과제.
- 원본 vs Refactored/backup 병존: kakao·telegram·api·admin 모두 .legacy/.bak/.backup·Refactored 병존 → 라이브 판별 후 죽은쪽 제거.
- ✅ 클린 모범 = bizchat-reward-api: TS+Zod 입력검증+에러분류+테스트+작은 파일. V3 전 모듈 지향 기준.
- 폐기 확인: punkpoll_admin(→web/app/admin) · A 데드라우트(explore-2·daily·citizen).
6-11. 온체인 3모듈 (txSender·punkpollAvaxBlockChainApi·PunkpollFungibleTokenAvax) — backend4 리버스엔지니어링 + reviewer G6
상세: docs/ONCHAIN_A_TO_B_REVERSE_ENGINEERING.md (backend4). B 매핑 reviewer G6 PASS.
- [정정] A 현재 온체인 = Avalanche C-Chain(Fuji 43113/mainnet 43114). PUNK=Avalanche ERC20(0x6023E6…/0xE1Cb8E…)+메타tx(가스대납). Mina(PunkpollFungibleTokenAvax o1js)=Avalanche 이전 레거시·미사용(앞선 'A=Mina' 표기는 Explore요약 미검증 오류·jegwon 지적). 통폐합: A 이원 온체인TX(txSender ~15k + blockchainApi ~5k) → B Avalanche(Fuji) 단일. Avalanche→Avalanche.
- G6 불변 보존 PASS: 참여서명 keccak256(participant,tokenId,participationTime,surveyContract,chainId) B fuji.chain.ts:114 동일(필드순서·chainId) / 정산 T5 실증(4e15=2e15+2e15) / M4 무이벤트=실패(B가 A보다 강함) / nullifier=resolveAUser 값조회(아래 §7).
- B 갭 = 기능 parity 갭 아님, 프로덕션 운영복원력 갭(프로덕션 컷오버 게이트): ①TX복구 4모드(B=nonce 자가치유만) ②RPC 페일오버 멀티프로바이더·서킷(B=단일RPC) ③멀티 fee-payer 풀(B=단일) ④콜백 깊이(A50 vs B3). tokenId 충돌=B 결정적 채번(#141)이 우수·갭 아님. → 워커 공용코어에 포트로 내장(프로덕션 전 필수).
7-1. nullifier parity vs security 해소 (backend1 resolveAUser·reviewer G6 PASS)
- 긴장: A nullifier = encryptString(userId, 고정키 punkpollSystemNullifier2024dufma, AES-256-CBC 결정적). 키를 바꾸면 A 기존 데이터 매칭 붕괴(parity), 유지하면 대칭 고정키 역산 위험(security).
- 해법(채택): B가 고정키를 코드/env에 둘 필요 없음.
resolveAUser(main.ts:214)가 카카오 profileImg로 A users 테이블 조회 → 저장된 nullifier 값을 읽음(재계산 아님). 결과: aUserNullifier = A users 저장값 일치(parity O) + B 고정키 미보유(역산 불가·auth-gw 하드코딩 키 제거 O). "A 결함(고정키 역산)만 제거·관찰동작(값 일치) 보존" = V2 my-result M12 정정과 동일 패턴. reviewer G6 PASS. - 전제(G3 배선 검증): 크로스호스트 prodPool로 A users 조회 가능해야 함(지갑페어/resolveAUser 배선 선행).
- ⏳ jegwon 결정 필요(블로커 아님): B-native 신규 유저(A users에 없음)의 nullifier 발급 정책 — 조회할 A 값 없으므로 새 발급 필요. A 매칭 불필요(순수 B 유저)면 B키로 프레시 발급(참여서명은 tokenId/participant 기반이라 nullifier 파생과 독립).
6-11 보강 (reviewer 온체인 3모듈 first-pass 상세):
- 핵심발견 — A 온체인 TX 이원 시스템: punkpollAvaxBlockChainApi(~5k)가 txSender와 온체인 TX 제출 역할 겹침. contractService(4969·최대)·signerService·multiFeePayerService(2363)·transactionService가 txSender와 중복. A는 TX 제출을 2모듈로 이원화 → B 단일 chain-worker로 통폐합 시 두 시스템 합집합 동작 보존 검증 필요(txSender 4복구모드 + blockchainApi multiFeePayer + 토큰 semantics).
- blockchainApi 데드/부채: contractService.backup·multiFeePayer.bak·jobProcessor.bak3·txConfirmationWorker.v2 병존 다수 · txConfirmationWorker 백틱 SQL(injection §7) · multiFeePayerService=B에 없는 G3(멀티 fee-payer) 원천.
- PunkpollFungibleTokenAvax = ⚠️실역할=PunkpollLightApi(IPFS+참여큐+콜백 레이어·pm2 9400·live). Mina o1js 토큰코드(FungibleToken.ts·zkPunkManager)=레거시 데드. A 현재 PUNK는 Avalanche ERC20(txSender가 관리). B PUNK ERC20(0x804b). = 이 모듈은 포팅 대상 아님(레거시).
- 온체인 통폐합 결론: A 이원 온체인TX(txSender+blockchainApi ~20파일, 둘 다 Avalanche) → B 단일 chain-worker + PUNK ERC20 = 최대 통폐합. (Mina 모듈=레거시 제외) G6=참여서명/정산/M4/nullifier PASS·운영복원력 갭(복구·RPC·멀티signer)은 프로덕션 컷오버 게이트.
8. 모듈 감사 1차 종료 (2026-07-07)
펑크폴 13개 모듈 전수 감사 완료. 프론트(web·admin폐기) + 코어API(api·auth-gw·ipfs) + 메신저(kakao·telegram) + 온체인(txSender·blockchainApi·FungibleToken) + 운영(punkpollUtil) + 지갑(standalone_wallet) + B백엔드(v2). deep file:line은 리팩토링 착수 시 기능단위로.
다음(P0 잔여): 역엔지니어링 기획문서 통합 · 기능별 리팩토링 체크리스트(A출처+G1~G6) · 측정모델 문서.