QA: SPRINT-002 review iteration 1 — FAILED (blocking 2)
This commit is contained in:
92
.qa/SPRINT-002-review-1.md
Normal file
92
.qa/SPRINT-002-review-1.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# SPRINT-002 QA Review — Iteration 1
|
||||
|
||||
- **검증일시:** 2026-04-04 02:41 UTC
|
||||
- **검증자:** 다랑이 (Evaluator)
|
||||
- **결과:** ❌ FAILED (blocking 2건)
|
||||
|
||||
## 검증 항목
|
||||
|
||||
| 항목 | 결과 |
|
||||
|------|------|
|
||||
| npm install (backend) | ✅ |
|
||||
| npm install (frontend) | ✅ |
|
||||
| prisma generate | ✅ |
|
||||
| npm test (backend) | ✅ 11/11 pass |
|
||||
| npm run build (backend) | ✅ |
|
||||
| npm run build (frontend) | ✅ |
|
||||
| FE SSR 렌더링 확인 | ✅ |
|
||||
| /projects/[id] 동적 라우트 | ✅ |
|
||||
|
||||
## Sprint 001 non-blocking 수정 확인
|
||||
|
||||
| 항목 | 상태 |
|
||||
|------|------|
|
||||
| CORS 화이트리스트 | ✅ 해결 |
|
||||
| DATABASE_URL throw | ✅ 해결 |
|
||||
| SSH_KEY_PATH throw | ✅ 해결 |
|
||||
| SSH 에러 마스킹 | ✅ 해결 |
|
||||
| LayoutShell 분리 | ✅ 해결 |
|
||||
| Sidebar↔MainContent 연동 | ✅ 해결 |
|
||||
| API 응답 IP 제거 | ✅ 해결 |
|
||||
| console.log → Logger | ✅ 해결 |
|
||||
| theme.ts 적용 | ✅ 직접 import 패턴 (OK) |
|
||||
| npm audit 7개 | ❌ 미해결 (devDep chain) |
|
||||
|
||||
## Sprint 002 설계 대조
|
||||
|
||||
| 설계 항목 | 일치 |
|
||||
|-----------|------|
|
||||
| GiteaService (org repos, repo detail, PRs) | ✅ |
|
||||
| GET /api/projects | ✅ |
|
||||
| GET /api/projects/:id | ✅ |
|
||||
| GET /api/projects/:id/tasks | ✅ |
|
||||
| POST /api/projects/:id/sprints | ✅ |
|
||||
| PATCH /api/tasks/:id | ✅ |
|
||||
| GET /api/activity (limit, offset) | ✅ |
|
||||
| GET /api/projects/:id/activity | ✅ |
|
||||
| SprintAccordion 컴포넌트 | ✅ |
|
||||
| TaskTable + 필터링 | ✅ |
|
||||
| TabNav (Sprints/Tasks/Activity) | ✅ |
|
||||
| ProgressBar | ✅ |
|
||||
| TaskBadge (7개 상태) | ✅ |
|
||||
| ActivityFeed 타임라인 | ✅ |
|
||||
| ProjectCard + 링크 | ✅ |
|
||||
| 메인 대시보드 프로젝트 섹션 | ✅ |
|
||||
| 메인 대시보드 활동 피드 | ✅ |
|
||||
|
||||
## 🔴 Blocking 이슈
|
||||
|
||||
### CR-001: GiteaService GITEA_BASE_URL/GITEA_TOKEN 미설정 시 앱 부팅 실패
|
||||
- **파일:** `backend/src/gitea/gitea.service.ts`
|
||||
- **문제:** constructor에서 `throw new Error()` → DI 실패 → 앱 전체 부팅 실패
|
||||
- **설계 불일치:** 핸드오프에서 "Gitea API 토큰 없으면 graceful fallback으로 DB only"라고 명시했으나 코드는 throw
|
||||
- **수정:** Optional 패턴으로 변경. client를 null로 두고 메서드에서 빈 배열/null 반환
|
||||
|
||||
### CR-002: CreateSprintDto/UpdateTaskDto에 class-validator 미적용
|
||||
- **파일:** `backend/src/tasks/tasks.service.ts`
|
||||
- **문제:** plain class DTO — ValidationPipe 없이 아무 값이나 DB 직행
|
||||
- **위험:** status에 임의 문자열, number에 음수, 예상 외 필드 주입 가능
|
||||
- **수정:** class-validator 데코레이터 추가 + main.ts에 ValidationPipe 적용
|
||||
|
||||
## Non-blocking 이슈
|
||||
|
||||
### 코드 품질 (code-reviewer)
|
||||
| ID | 이슈 |
|
||||
|----|------|
|
||||
| CR-003 | iteration 증가 로직 — 정확하지만 메서드 분리로 가독성 개선 권장 |
|
||||
| CR-004 | limit/offset Query 파라미터 NaN 미처리 — ParseIntPipe 적용 권장 |
|
||||
| CR-006 | giteaRepos 키 매칭 — giteaId null 방어 필요 |
|
||||
| CR-007 | ProjectDetailPage useState<any> 3곳 — 인터페이스 정의 권장 |
|
||||
| CR-008 | CORS 에러에 origin 값 노출 — generic 에러 반환 권장 |
|
||||
| CR-009 | npm audit 7개 — devDependency 확인 후 prod 0이면 수용 가능 |
|
||||
|
||||
### 보안 감사 (security-auditor)
|
||||
| ID | 이슈 | 심각도 |
|
||||
|----|------|--------|
|
||||
| SA-005 | API 인증 없음 (전체) — Sprint-003 필수 | Medium |
|
||||
| SA-006 | PATCH /tasks/:id 인증 없음 (write) | High |
|
||||
| SA-007 | POST /projects/:id/sprints 인증 없음 (write) | High |
|
||||
| SA-008 | limit/offset 클램핑 없음 (대량 조회 가능) | Medium |
|
||||
| SA-012 | Helmet 미적용 | Medium |
|
||||
| SA-013 | Rate limiting 없음 | Medium |
|
||||
| SA-014 | GiteaService 에러 시 Authorization 헤더 노출 가능 | Medium |
|
||||
Reference in New Issue
Block a user