# 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 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 |