Set up AI dev environment for recordingtest (#2)
- CLAUDE.md with collaboration rules and Planner/Generator/Evaluator cycle - .claude/ agents, commands, skills, hooks per Claude Code conventions - Sprint Contracts for sut-prober, normalizer, recorder, player, diff-reporter - SUT catalog (EG-BIM Modeler, 187 plugins) and .gitignore excluding SUT tree - PROGRESS.md / PLAN.md as shared agent handoff state - Solution scaffold targeting sut-prober PoC Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
19
docs/history/2026-04-07_이슈2-AI-AutomationPeer-부착옵션.md
Normal file
19
docs/history/2026-04-07_이슈2-AI-AutomationPeer-부착옵션.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# 2026-04-07 이슈 #2 — AI 기반 AutomationPeer 부착 옵션 기록
|
||||
|
||||
- **이슈**: kimminsung/recordingtest#2
|
||||
- **소요 시간**: ~3분
|
||||
- **Context 사용량**: ~70k tokens
|
||||
|
||||
## 결정/기록
|
||||
|
||||
SUT 커스텀 컨트롤에 AutomationPeer를 부착하는 작업을 AI로 자동화하는 보조 전략을 메모리에 남김. Golden-file이 1차 전략이지만, element-aware 레코딩 보강이 필요해질 때 꺼낼 카드.
|
||||
|
||||
### 핵심
|
||||
- 패턴 정형화로 80% AI 자동 생성 가능
|
||||
- ControlType/패턴 매핑과 `AutomationProperties.Name`은 사람 리뷰 필요
|
||||
- SUT 저장소엔 별도 브랜치/PR로 제안, 직접 커밋 금지
|
||||
- recordingtest 저장소에는 가이드/스크립트만, SUT 코드 변경은 fork/PR로 분리
|
||||
|
||||
## 산출물
|
||||
- 메모리: `project_recordingtest_automationpeer_ai.md`
|
||||
- MEMORY.md 인덱스 갱신
|
||||
21
docs/history/2026-04-07_이슈2-CLAUDE-md-progress-plan-규칙.md
Normal file
21
docs/history/2026-04-07_이슈2-CLAUDE-md-progress-plan-규칙.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# 2026-04-07 이슈 #2 — CLAUDE.md에 PROGRESS/PLAN 협업 규칙 추가
|
||||
|
||||
- **이슈**: kimminsung/recordingtest#2
|
||||
- **소요 시간**: ~3분
|
||||
- **Context 사용량**: ~76k tokens
|
||||
|
||||
## 변경 내용
|
||||
|
||||
`CLAUDE.md` 에 §0 "세션 시작 시 필독" 섹션 신설. 여러 에이전트 협업을 위한 공유 메모리로 `PROGRESS.md`(끝난 일)와 `PLAN.md`(할 일) 운영 규칙 명시.
|
||||
|
||||
### 핵심 규칙
|
||||
- 세션 시작: PROGRESS.md + PLAN.md 먼저 read
|
||||
- 시작 시: PROGRESS.md에 in progress 표시
|
||||
- 종료 시: PROGRESS.md(done 이동) + PLAN.md(완료 제거/다음 단계) + history 파일 (3종 세트)
|
||||
- 충돌 시 최신 커밋 기준 머지, 모호하면 사용자에 질문
|
||||
|
||||
§7 Claude 작업 원칙에도 같은 내용 반영.
|
||||
|
||||
## 다음 단계
|
||||
|
||||
PROGRESS.md / PLAN.md 실제 파일은 셋업 단계에서 작성 예정 (현재는 CLAUDE.md 규칙만 정의).
|
||||
26
docs/history/2026-04-07_이슈2-CLAUDE-md-작성.md
Normal file
26
docs/history/2026-04-07_이슈2-CLAUDE-md-작성.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# 2026-04-07 이슈 #2 — CLAUDE.md 작성
|
||||
|
||||
- **이슈**: kimminsung/recordingtest#2
|
||||
- **소요 시간**: ~5분
|
||||
- **Context 사용량**: ~63k tokens
|
||||
|
||||
## 작업 내용
|
||||
|
||||
프로젝트 셋업 전, recordingtest(WPF 입력 회귀 자동화 도구)의 운영 지침인 `CLAUDE.md`를 루트에 작성. 셋업은 미실시.
|
||||
|
||||
## 포함 섹션
|
||||
|
||||
1. 프로젝트 정체성 / SUT 개요
|
||||
2. 핵심 전략 — Golden-file 회귀
|
||||
3. 아키텍처 구성요소(8개 모듈) 우선순위
|
||||
4. 기술 스택 가이드 (FlaUI, Win32 hook, JSON/YAML, LFS)
|
||||
5. 설계 원칙 8개 (결정성, element-aware, 타이밍, marshaling, 체크포인트, 아티팩트, 침습 최소화, 마스킹)
|
||||
6. 환경 제약 (세션0, DPI, GPU)
|
||||
7. 작업 흐름 규칙 (히스토리 필수)
|
||||
8. 디렉터리 구조(예정)
|
||||
9. 비목표
|
||||
10. 결정 로그 위치
|
||||
|
||||
## 다음 단계
|
||||
|
||||
사용자 승인 후 실제 솔루션/프로젝트 셋업 진행.
|
||||
28
docs/history/2026-04-07_이슈2-SUT-EGBIM-분석.md
Normal file
28
docs/history/2026-04-07_이슈2-SUT-EGBIM-분석.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# 2026-04-07 이슈 #2 — SUT (EG-BIM Modeler) 폴더 분석
|
||||
|
||||
- **이슈**: kimminsync/recordingtest#2
|
||||
- **소요 시간**: ~5분
|
||||
- **Context 사용량**: ~82k tokens
|
||||
|
||||
## 분석 대상
|
||||
|
||||
`d:/MYCLAUDE_PROJECT/recordingtest/EG-BIM Modeler/` — SUT 실행파일 일습.
|
||||
|
||||
## 핵심 발견
|
||||
|
||||
- WPF + .NET, 3D 엔진 `HmEG.dll`, 렌더 SharpDX D3D11
|
||||
- MEF plugin `Plugins/Eg*Plugin/` 수십~100개+
|
||||
- **PDB 동봉** → 리플렉션/엔진 침습 비용 ↓
|
||||
- `Json/` 폴더에 텍스트 설정 다수 — golden-file 1차 타깃으로 적합
|
||||
- 자체 저장 포맷 `.hme`/`.egm` — 파서·정규화 규칙 필요
|
||||
- 3D 뷰포트는 D3D surface로 UIA 사각지대 확정
|
||||
|
||||
## 전략 반영
|
||||
|
||||
- sut-prober 첫 PoC: `Plugins/` 스캔 + `Json/` 스냅샷
|
||||
- engine-bridge: HmEG 리플렉션으로 카메라/씬그래프 접근
|
||||
- 모델 포맷 파서 모듈 분리
|
||||
|
||||
## 산출물
|
||||
- 메모리: `project_sut_egbim_modeler.md`
|
||||
- MEMORY.md 인덱스 갱신
|
||||
@@ -0,0 +1,68 @@
|
||||
# 2026-04-07 이슈 #2 — .claude/ 에이전트·커맨드·스킬·훅 셋업
|
||||
|
||||
- **이슈**: kimminsung/recordingtest#2
|
||||
- **소요 시간**: ~15분
|
||||
- **Context 사용량**: ~95k tokens
|
||||
|
||||
## 작업 내용
|
||||
|
||||
Claude Code 공식 포맷 조사(claude-code-guide 에이전트) 후, recordingtest 운영에 필요한 커스터마이즈를 `.claude/` 하위에 생성.
|
||||
|
||||
### Subagents — `.claude/agents/*.md`
|
||||
- **sut-explorer** — EG-BIM Modeler 정적 분석(플러그인/Json/어셈블리). SUT 실행 금지.
|
||||
- **diff-triager** — 회귀 실패 분류(real bug / intentional / normalization gap / env drift / flaky).
|
||||
- **scenario-author** — 자연어 → 시나리오 YAML 생성.
|
||||
|
||||
### Slash commands — `.claude/commands/*.md`
|
||||
- **/sut-probe** — sut-explorer 위임, 카탈로그 생성.
|
||||
- **/regress** — 회귀 실행 + 실패 자동 triage.
|
||||
- **/approve** — received → approved 승격, 사유 강제.
|
||||
- **/handoff** — PROGRESS/PLAN/history 3종 세트 갱신.
|
||||
- **/progress** — PROGRESS.md/PLAN.md 요약 출력.
|
||||
|
||||
### Skills — `.claude/skills/<name>/SKILL.md`
|
||||
- **golden-file-normalizer** — 정규화 규칙 카테고리/원칙/저작 가이드.
|
||||
- **flaui-cookbook** — FlaUI 런칭/대기/엘리먼트 캡처/3D 뷰포트 폴백/함정.
|
||||
|
||||
### Hooks — `.claude/settings.json` + `.claude/hooks/*.sh`
|
||||
- **SessionStart** → `session-start-progress.sh`: PROGRESS.md/PLAN.md 자동 주입.
|
||||
- **PreToolUse(Bash)** → `guard-sut-launch.sh`: EG-BIM Modeler.exe 실행 경고.
|
||||
- **PreToolUse(Edit|Write)** → `guard-sut-folder.sh`: SUT 폴더 수정 차단(exit 2).
|
||||
- **Stop** → `stop-handoff-reminder.sh`: 오늘 history 파일/PROGRESS/PLAN 누락 시 /handoff 권장.
|
||||
|
||||
## 원칙
|
||||
|
||||
- 포맷은 claude-code-guide 조사 결과를 따름(frontmatter: name/description/allowed-tools/tools/model).
|
||||
- SUT 폴더는 **read-only** — 훅으로 강제.
|
||||
- 실제 모듈(src/*)은 아직 미생성 — /regress 등은 건드릴 파일이 없으면 early-exit.
|
||||
|
||||
## 산출물
|
||||
|
||||
```
|
||||
.claude/
|
||||
├── agents/
|
||||
│ ├── sut-explorer.md
|
||||
│ ├── diff-triager.md
|
||||
│ └── scenario-author.md
|
||||
├── commands/
|
||||
│ ├── sut-probe.md
|
||||
│ ├── regress.md
|
||||
│ ├── approve.md
|
||||
│ ├── handoff.md
|
||||
│ └── progress.md
|
||||
├── skills/
|
||||
│ ├── golden-file-normalizer/SKILL.md
|
||||
│ └── flaui-cookbook/SKILL.md
|
||||
├── hooks/
|
||||
│ ├── session-start-progress.sh
|
||||
│ ├── guard-sut-launch.sh
|
||||
│ ├── guard-sut-folder.sh
|
||||
│ └── stop-handoff-reminder.sh
|
||||
└── settings.json (hooks 섹션 추가)
|
||||
```
|
||||
|
||||
## 다음 단계
|
||||
|
||||
- PROGRESS.md / PLAN.md 실제 파일 작성 (셋업 단계에서)
|
||||
- src/ 모듈 scaffold
|
||||
- 훅 bash 스크립트 실제 동작 검증
|
||||
34
docs/history/2026-04-07_이슈2-golden-file-전략-채택.md
Normal file
34
docs/history/2026-04-07_이슈2-golden-file-전략-채택.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# 2026-04-07 이슈 #2 — Golden-file 회귀 전략 채택
|
||||
|
||||
- **이슈**: kimminsung/recordingtest#2
|
||||
- **소요 시간**: ~5분
|
||||
- **Context 사용량**: ~58k tokens
|
||||
|
||||
## 결정
|
||||
|
||||
사용자 제안 채택: **수동 테스트 입력 레코딩 → 리플레이 후 저장 파일을 베이스라인과 diff** 하는 golden-file 회귀 방식을 1차 검증 수단으로 삼는다. (ApprovalTests 패턴과 동형)
|
||||
|
||||
## 근거
|
||||
|
||||
- SUT(WPF+MEF+HmEG)에 AutomationPeer/probe 부착 협조 비용 회피
|
||||
- 결과물 파일 자체가 검증 기준 → 직관적, 사용자가 시나리오 작성 가능
|
||||
- 픽셀 비교 의존도 ↓ → viewport-verifier 우선순위 하향
|
||||
|
||||
## 성립 조건 / 함정
|
||||
|
||||
1. **결정성**: 저장 파일의 타임스탬프/GUID/경로/부동소수점/순서 → 정규화 파이프라인 필수
|
||||
2. **입력 재현 정확도**: 타이밍·포커스·IME·3D 드래그 픽셀 증폭
|
||||
3. **비교 범위**: 저장 파일만 vs +중간 체크포인트 vs +엔진 상태 sidecar
|
||||
4. **베이스라인 관리**: `*.approved`/`*.received` 워크플로, 큰 파일 LFS
|
||||
5. **진단**: 단계별 스냅샷으로 갈라진 지점 이분 탐색
|
||||
|
||||
## 모듈 우선순위 재조정
|
||||
|
||||
핵심: **recorder + player + 정규화 모듈 + diff-reporter**
|
||||
보조: engine-bridge(sidecar JSON 덤프 용도)
|
||||
후순위: viewport-verifier(픽셀 비교)
|
||||
|
||||
## 다음 단계
|
||||
|
||||
- 저장 파일 포맷 조사 (텍스트/바이너리, 정규화 가능 영역)
|
||||
- recorder PoC 범위 정의
|
||||
@@ -0,0 +1,41 @@
|
||||
# 2026-04-07 이슈 #2 — Planner/Evaluator 에이전트 & Sprint Contract 도입
|
||||
|
||||
- **이슈**: kimminsung/recordingtest#2
|
||||
- **소요 시간**: ~10분
|
||||
- **Context 사용량**: ~108k tokens
|
||||
|
||||
## 배경
|
||||
|
||||
Anthropic "Harness Design for Long-Running Agent Applications" 기사를 읽고, 핵심 원칙을 recordingtest에 반영.
|
||||
|
||||
## 추가된 것
|
||||
|
||||
### 에이전트
|
||||
- `.claude/agents/planner.md` — 요청 → Sprint Contract + PLAN.md 엔트리. 구현 금지.
|
||||
- `.claude/agents/evaluator.md` — 완료된 모듈을 Sprint Contract 기준으로 독립 채점. 자기 작업 평가 금지.
|
||||
|
||||
### 커맨드
|
||||
- `.claude/commands/contract.md` — `/contract <name>`
|
||||
- `.claude/commands/evaluate.md` — `/evaluate <name>`
|
||||
|
||||
### CLAUDE.md
|
||||
- §0.1 "작업 사이클 — Planner → Generator → Evaluator" 섹션 신설
|
||||
- Sprint Contract / DoD 객관성 / 독립 평가 원칙 명시
|
||||
- 컨텍스트 위생: compaction 대신 reset, Stop hook 경고 준수, scaffolding audit 상시 항목
|
||||
- 디렉터리 구조에 `docs/contracts/`, `PROGRESS.md`, `PLAN.md` 추가
|
||||
|
||||
### 메모리
|
||||
- `project_recordingtest_harness_design.md` 신규
|
||||
- MEMORY.md 인덱스 갱신
|
||||
|
||||
## 원칙 요약
|
||||
|
||||
1. 생성자와 평가자는 같은 에이전트가 겸하지 않는다.
|
||||
2. DoD는 객관적으로 검증 가능해야 한다.
|
||||
3. 컨텍스트가 차면 요약하지 말고 파일에 쏟고 리셋.
|
||||
4. evaluator fail → PROGRESS.md에 done으로 넘기지 않는다.
|
||||
5. `.claude/` 비계는 주기적으로 감사·축소.
|
||||
|
||||
## 다음 단계
|
||||
|
||||
PROGRESS.md / PLAN.md 실제 부트스트랩 (첫 번째 Sprint Contract 작성부터).
|
||||
26
docs/history/2026-04-07_이슈2-구현고려사항-정리.md
Normal file
26
docs/history/2026-04-07_이슈2-구현고려사항-정리.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# 2026-04-07 이슈 #2 — 구현 고려사항 정리
|
||||
|
||||
- **이슈**: kimminsung/recordingtest#2
|
||||
- **소요 시간**: ~5분
|
||||
- **Context 사용량**: ~52k tokens
|
||||
|
||||
## 정리한 고려사항 카테고리
|
||||
|
||||
1. **레코딩/리플레이 안정성** — 좌표 vs element, 타이밍, 포커스/Z-order, IME
|
||||
2. **WPF/MEF 특성** — Custom AutomationPeer, plugin 비동기 로드, Dispatcher marshaling
|
||||
3. **3D 뷰포트(HmEG) 검증** — 픽셀 비교 한계, 엔진 내부 상태 검증, 픽킹 안정성
|
||||
4. **환경/재현성** — DPI, 멀티모니터, 시계/랜덤 격리, CI 세션 0 제약
|
||||
5. **테스트 자산 관리** — JSON/YAML 시나리오, 베이스라인 이미지 LFS, 모듈화
|
||||
6. **진단/디버깅** — 실패 아티팩트(스샷·UIA 덤프·엔진 상태), 영상 녹화, diff 오버레이
|
||||
7. **보안/안전** — 입력 마스킹, 권한 일치
|
||||
8. **거버넌스** — SUT 코드 변경 협조(AutomationPeer/probe), 유지보수 비용
|
||||
|
||||
## 핵심 인사이트
|
||||
|
||||
- 픽셀 비교보다 **엔진 내부 상태(engine-bridge)** 가 훨씬 안정적 → 우선순위 상향
|
||||
- **SUT 팀 협조** 가 기술적 난제보다 큰 장애물 (AutomationPeer/probe 부착)
|
||||
- WPF는 세션 0에서 못 돌므로 CI는 대화형 세션 agent 필요
|
||||
|
||||
## 다음 단계
|
||||
|
||||
위 고려사항을 sut-prober PoC 설계에 반영.
|
||||
41
docs/history/2026-04-07_이슈2-리서치-에이전트분해.md
Normal file
41
docs/history/2026-04-07_이슈2-리서치-에이전트분해.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# 2026-04-07 이슈 #2 — 리서치 및 Agent 분해
|
||||
|
||||
- **이슈**: kimminsung/recordingtest#2 — 요구사항 컨텍스트 엔지니어링과 AI 개발환경 셋팅
|
||||
- **소요 시간**: ~15분
|
||||
- **Context 사용량**: ~45k tokens
|
||||
|
||||
## 작업 내용
|
||||
|
||||
WPF + MEF 플러그인 + 자체 HmEG 3D 엔진으로 구성된 SUT를 대상으로 한 입력 회귀 테스트 자동화 도구의 접근법을 웹 리서치하고, 단계별 agent로 분해하여 메모리에 저장.
|
||||
|
||||
### 리서치 결론
|
||||
|
||||
- **UIA 1순위**: FlaUI (.NET native, WPF 정밀 제어). WinAppDriver는 정체, Appium은 그 래퍼.
|
||||
- **3D 뷰포트**: UIA 불가 → 좌표 입력 + 픽셀/이미지 비교 + 엔진 in-process hook 하이브리드.
|
||||
- **MEF plug-in**: 각 plugin 프로젝트에 custom `AutomationPeer` 부착, plugin 상태를 probe로 노출.
|
||||
- **레코딩**: Win32 low-level hook + UIA element path + offset 동시 저장(해상도 내성).
|
||||
|
||||
### Agent 분해(예정)
|
||||
|
||||
1. sut-prober — UIA 트리 덤프, MEF plugin 목록
|
||||
2. recorder — element-aware 입력 캡처
|
||||
3. player — 재생/동기화
|
||||
4. viewport-verifier — 3D 스크린샷 비교
|
||||
5. engine-bridge — HmEG 상태 노출
|
||||
6. test-runner — 시나리오 실행/리포트
|
||||
7. diff-reporter — 실패 시각화
|
||||
|
||||
## 산출물
|
||||
|
||||
- 메모리: `project_recordingtest_goal.md`, `project_recordingtest_plan.md`
|
||||
- 본 히스토리 파일
|
||||
|
||||
## 다음 단계
|
||||
|
||||
`sut-prober` PoC부터 시작 — 사용자 결정 대기.
|
||||
|
||||
## 참고 링크
|
||||
|
||||
- [FlaUI vs WinAppDriver 2026](https://www.testsprite.com/use-cases/en/the-most-accurate-alternatives-to-winappdriver)
|
||||
- [WPF Custom AutomationPeer](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/controls/ui-automation-of-a-wpf-custom-control)
|
||||
- [TestComplete WPF Record/Replay](https://support.smartbear.com/testcomplete/docs/app-testing/desktop/wpf/index.html)
|
||||
51
docs/history/2026-04-07_이슈2-병렬-스캐폴드-contracts.md
Normal file
51
docs/history/2026-04-07_이슈2-병렬-스캐폴드-contracts.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# 2026-04-07 이슈 #2 — 병렬 스캐폴드 + Sprint Contracts 일괄
|
||||
|
||||
- **이슈**: kimminsung/recordingtest#2
|
||||
- **소요 시간**: ~20분
|
||||
- **Context 사용량**: ~130k tokens
|
||||
|
||||
## 작업 내용
|
||||
|
||||
"병렬화 가능한 부분 병렬 구현" 요청에 따라, 독립 파일들을 한 세션에서 병렬 Write로 일괄 생성.
|
||||
|
||||
### 부트스트랩 문서
|
||||
- `PROGRESS.md` — 공유 상태 파일 확장 (Done/In progress/Blocked/Scaffolding review)
|
||||
- `PLAN.md` — P0~P3 우선순위 큐 + 작업 규칙
|
||||
|
||||
### Sprint Contracts (5건)
|
||||
`docs/contracts/` 하위:
|
||||
- `sut-prober.md` — 187개 플러그인 카탈로그 + json-configs + assemblies 덤프
|
||||
- `normalizer.md` — 기본 프로파일 5규칙, idempotent
|
||||
- `recorder.md` — element-aware 입력 캡처, IME·마스킹 포함
|
||||
- `player.md` — 10회 중 9회 성공, 고정 sleep 금지
|
||||
- `diff-reporter.md` — JSON/텍스트 의미 diff, triager 연동
|
||||
|
||||
각 contract는 planner 에이전트 규격(Goal / DoD / Interfaces / Out of scope / Evaluation plan / Risks)을 준수하며, DoD 항목은 모두 객관적으로 검증 가능.
|
||||
|
||||
### SUT 카탈로그 v0
|
||||
- `docs/sut-catalog/catalog.md` — 어셈블리·UI스택·Json 설정·저장 포맷·영향 요약
|
||||
- `docs/sut-catalog/plugins.md` — 187개 플러그인 전체 목록 (사전순)
|
||||
|
||||
### 솔루션 스캐폴드 (sut-prober PoC)
|
||||
- `recordingtest.sln`
|
||||
- `Directory.Build.props` (net8.0, nullable, warnings-as-errors)
|
||||
- `src/Recordingtest.SutProber/` 4개 파일:
|
||||
- `Recordingtest.SutProber.csproj`
|
||||
- `Program.cs` — CLI 진입, `--sut`/`--out` 인자
|
||||
- `PluginScanner.cs` — 정렬된 플러그인 엔트리 스캔
|
||||
- `JsonConfigScanner.cs` — Json/*.json top-level 키 + 의심 필드 휴리스틱
|
||||
- `AssemblyScanner.cs` — HmEG*/Editor*/HmGeometry* 어셈블리 + PDB 존재
|
||||
|
||||
**주의**: sut-prober 구현은 contract를 **선제적으로 맞추지는 않음** — 빌드·실행·evaluator 검증은 별도 Generator 세션의 몫. 현재는 컴파일 가능한 뼈대 수준.
|
||||
|
||||
## 병렬화 전략
|
||||
|
||||
- 파일 간 의존성 0인 것들만 병렬 Write
|
||||
- Edit는 기존 파일 의존 → 순차 처리
|
||||
- 에이전트 스폰 대신 단일 세션 다중 도구 호출로 context 오버헤드 최소화
|
||||
|
||||
## 다음 단계
|
||||
|
||||
1. **Generator 세션**에서 sut-prober 빌드/실행 → 카탈로그 산출물 생성
|
||||
2. **Evaluator 세션**에서 `/evaluate sut-prober` → contract DoD 채점
|
||||
3. pass 시 PROGRESS.md → PLAN.md 제거 → P1 항목 착수
|
||||
Reference in New Issue
Block a user