- docs/REFACTOR_POLICY.md (신규): 8 결정포인트 + 본 wave 한정 DP9-DP11, 합의 이력(DRY 3회 / 공격적 DELETE / 전체 typecheck 강제) - docs/REFACTOR_WAVE1_REPORT.md (신규): 정량 산출, 검증, SKIP/이월, 메타 학습 M1-M6, Wave 2 계획 - memory/project_status.md: Wave 1 섹션 추가
8.9 KiB
리팩토링 Wave 1 보고서
일시: 2026-07-22 | 스킬:
/refactor-wave| 범위:apps/desktop+packages/{core,ui,i18n}
0. 합의 사항 (정책)
| 결정 | 값 |
|---|---|
| 범위 | desktop + 공유 packages (web/admin/site/server/mobile 이월) |
| 초점 | 데드코드/토큰SSOT/i18n/타입-IPC-아키텍처 전부 |
| 커밋 주기 | WS별 분리 커밋 + 즉시 검증 (R5/R7) |
| DP7 DRY 임계치 | 3회 |
| DP9 데드코드 강도 | 공격적 DELETE (외부 API 노출 export는 grep 후 KEEP) |
| DP6 typecheck 범위 | 전체 모노레포 강제 |
정책 문서: docs/REFACTOR_POLICY.md (신규 작성)
1. 정량 산출물
| WS | 산출 | 커밋 |
|---|---|---|
| WS1 토큰/DS | theme-vars dark/light 5변수 SSOT 정합(v1 주황→파랑), DS 미사용 3종 삭제(MetalDial/ButtonGroup/CrtDisplay, -324행), StatRing hex 10색→토큰 | b820c78 |
| WS2 메인/IPC/AppConfig | ipc-channels SSOT 9그룹/키 추가, 하드코딩 채널 SSOT 교체(불일치 4건 preload 재검증), AppConfig 7키 추가, as never 16건 제거, require 3건→static, services/index.ts 데드 제거 |
aef4428 |
| WS3 렌더러 | accent.amber→main 91건/34파일, 매직 리터럴→d3roTypo/d3roRadius 37건 |
078304d |
| WS4 i18n | date.today/yesterday 중복 버그 수정(ko/en), 고아 키 967건 삭제(109+858) | 87f2dac |
사용자 노출 버그 2건 해소: (a) 한국어 날짜 "TODAY"/"YESTERDAY" 표시 → "오늘"/"어제", (b) 팝업=주황/렌더러=파랑 색상 충돌 → 정합.
2. 검증 결과
| 게이트 | 결과 |
|---|---|
| typecheck (desktop/core/ui/i18n/admin/api-client) | ✅ GREEN |
typecheck (@d3ro/web) |
⚠️ pre-existing 1건 (teams/[id]/page.tsx Supabase 쿼리 타입) — web은 범위 외, 이월 |
| lint (내 변경 영역 45파일) | ✅ 0 errors (12 warnings = pre-existing unused vars, 이월) |
lint (전체 eslint .) |
⚠️ pre-existing — apps/mobile-rn/.eslintrc.js가 @react-native extends(패키지 미설치)로 전체 붕괴 + pre-existing 23 errors. 별도 lint 정리 wave 필요 |
| test | ✅ desktop 41/41 + api-client 19/19 |
| build | 미실행 (빌드 영향 WS 없음 — 패키지 의존성 제거는 WS5 2차) |
| UI 화면 확인 | 미실행 — UI 변경(amber/토큰)은 시각 동등(별칭 동일값 치환), 팝업 색 정합은 typecheck로 검증. 권장: npm run dev로 1회 육안 확인 |
3. SKIP / 이월 항목 (명확한 사유)
| 항목 | 사유 | 후속 |
|---|---|---|
theme.ts accent.amber 별칭 제거 |
accent.amber가 web/admin/site/mobile/ui-native에서 수십 곳 사용 → 공유 패키지 토큰 제거 시 전체 깨짐 (DP6 위반) |
Wave 2: 전체 모노레포 amber→main 치환 |
| theme-vars 평행 SSOT 구조 단일화 (theme.ts RAW에서 파생) | 값 정합만으로 버그 해소됨. 구조 재설계는 회귀 위험 | Wave 2 |
B6 팝업 _i18n 주입 + 색상 토큰화 |
WS1(토큰)/WS4(i18n키) 산출물 소비 → 2차 wave (사용자 합의) | WS5 2차 |
B5 AppConfig SSOT 잔여 (CloudSyncService Supabase as never) |
PK/컬럼 타입 구조 이해 선행 필요 | Wave 2 |
| B8 서비스-IPC 결합 분리(11서비스 webContents.send→EventEmitter 역전) | 아키텍처 재설계, 반나절~하루 | 별도 Phase |
| 타 locale 334키 누락 (번역 파이프라인) | 번역 자동화(DeepL/AI) 별도 구축 | 별도 Phase |
ipcSuccess/ipcError 헬퍼 통일, catch {} 패턴 |
시간 관계 | Wave 2 |
web teams/[id] typecheck 에러, 전체 lint pre-existing 부채 |
범위 외 | 별도 lint/type wave |
4. 메타 학습 (이번 wave에서 습득)
M1. 공유 패키지 토큰 변경은 모든 소비 앱에 영향 — "부분 치환 + 별칭 제거" 불가
packages/ui/src/theme.ts의 accent.amber deprecated 별칭을 제거하려 했으나, web/admin/site/mobile/ui-native가 수십 곳에서 d3roPalette.accent.amber를 import 사용. desktop만 치환해도 별칭은 공유 패키지에 남겨야 함. → 이식 인사이트 P7 신설.
M2. typecheck GREEN이 고아 키 검증의 충분조건이 아니다 (P1 재검증 가치 입증)
WS4에서 camelCase license.feature.* 15키를 고아로 오팅할 뻔. 그러나 LicenseService.getTierComparison()이 featureLabel: 'license.feature.llmProcess'(camelCase)를 할당하고 t(row.featureLabel)로 프로퍼티 패스스루 참조. featureLabel: string(느슨한 타입) + as Parameters<typeof t>[0] 캐스트가 TranslationKey strict를 우회 → typecheck가 잡지 못함. grep 동적/변수 보간 + 프로퍼티 할당 검증이 상호보완적으로 작동. 런타임 버그(라이선스 비교표 빈 라벨) 15건 예방. → P1 강화.
M3. 감사·구현 에이전트는 typecheck를 회피하는 경향 — 프롬프트에 "EXIT 0 직접 확인" 강제
WS1·WS3이 "메인 작업자가 통합 후 수행" / "PowerShell이라 로컬 실행" 핑계로 typecheck를 돌리지 않음. 통합 단계 재검증으로 cover했으나, 에이전트 프롬프트에 "typecheck는 본인이 직접 EXIT 0까지 확인하고, 안 되면 원인 보고"를 hard requirement로 박아야. → SKILL R7 강화.
M4. lint 게이트의 pre-existing 부채 — "내 영역 errors 0"으로 재해석
전체 eslint .가 apps/mobile-rn config 문제로 붕괴 + pre-existing 23 errors. codebase가 원래 lint GREEN이 아니었음. "통합 후 lint GREEN"(R7)이 비현실적. **"내가 건드린 영역의 lint errors 0" + "pre-existing은 별도 wave"**로 게이트 재해석. → SKILL R7 명시 갱신.
M5. 병렬 WS에서 같은 토큰을 다른 파일이 참조하면 동시 진행 OK
WS1(theme.ts 정의)과 WS3(렌더러 참조)이 동시 진행 가능 — 서로 다른 파일. 단, "별칭 제거"는 참조 치환(WS3) 완료 후 순차. 파일 영역 분할(R3)만으로 충분; 토큰 의존성은 참조/정의 파일 분리로 해소.
M6. JSON duplicate-key 버그는 grep/count로 잡기 어렵다 → CI 체크 권장
date.today 중복 정의(JSON last-wins)가 한국어 "TODAY" 표시 버그를 낳음. 정적 분석으로 탐지 어려움. jq -r 'keys' file | sort | uniq -d 또는 duplicate-key-detector CI 단계 권장. (Agent C 제안 채택)
5. 다음 wave 계획
Wave 2 (후속):
- WS5 2차: 팝업 5종
_i18n주입 + CSS 색상 토큰화(--d3-wave-*,--d3-status-*) — WS1/WS4 산출물 소비 - 전체 모노레포
accent.amber→main치환 (web/admin/site/mobile/ui-native) → theme.ts 별칭 제거 - theme-vars 평행 SSOT 구조 단일화 (theme.ts RAW 파생)
- AppConfig SSOT 잔여 (CloudSyncService Supabase 타입)
- 미사용 의존성 8종 제거 (package.json) + electron-builder Linux 섹션
- ipcSuccess/ipcError 헬퍼 통일 + catch 패턴
별도 Phase:
- 서비스-IPC 결합 분리 (아키텍처)
- 타 locale 334키 번역 파이프라인
- 전체 lint pre-existing 부채 정리 (mobile-rn config 포함)
- web
teams/[id]Supabase 타입 수정
6. 워크스트림별 세부
WS1 (b820c78)
- theme-vars.ts:
--d3-accent-main(dark #f25b29→#3b82f6, light→#2563eb),--d3-bg-card(dark #242427→#111a30),--d3-text-dimLabel(dark #5c2615→#4e5f85, light #b07040→#5a6f96). nord/solarized/catppuccin/dracula는 이미 정합(변경 없음). - DS 3종 삭제: 렌더러 import 0건 재검증 후 barrel export 제거 + 파일 삭제.
- StatRing: RING_COLORS hex →
var(--d3-gradient-wave1-4)+d3roPalette.tag.*.
WS2 (aef4428)
- ipc-channels.ts SSOT 추가: INSTRUCTION(GET_ALL/GET_BY_ID/CREATE/UPDATE/DELETE/REORDER), SYSTEM_AUDIO(ENABLE/DISABLE_LOOPBACK), POPUP_RESULT(PREPARE/MEASURED/SHOW), POPUP_HISTORY(7), POPUP_COMMAND(6), POPUP_CAPTION(HIDE), VOICE_PARTIAL(PARTIAL_TRANSCRIPT), CLIPBOARD(COPY), APP(DATA_CHANGED), VOICE_CONVERSATION.FINISH_LISTENING
- AppConfig 7키: customInstructions(CustomInstruction[]), llmChains(LLMChain[]), voiceCommandRules(VoiceCommandRule[]), voiceCommandsEnabled(boolean), activeInstructionId(string), activeChainId(string|null), captionAudioSource(mic|system|both)
- IPC 불일치 재검증: preload에서 result:prepare/show/measured, voice:partialTranscript 미사용 확인 → 안전하게 SSOT 통일
WS3 (078304d)
- amber 91건: 27파일에서 accent.main 사용으로 전환
- 토큰 37건: d3roTypo(label/small/body/heading/value/compact/engrave), d3roRadius(small/xs/inner)
- P4 제외: DashboardPage 스탯 fontSize(34/26/30px), 레이아웃 width, 토큰 미존재 값(10px, fontWeight 800, letterSpacing 다수)
WS4 (87f2dac)
- date 버그: ko/en 두 번째 정의(uppercase 잔해) 삭제
- 고아 967건 삭제 (네임스페이스별: meeting 27, onboarding 26, license UI 9, dashboard 8, voiceAction 7, voiceCommand 7, chain 6, memo 6, context 3, mobile 3, *.loading 3, status/common 4)
- KEEP 20건: camelCase license.feature 15(
featureLabel패스스루), nav 5(labelKey패스스루)