feat: 웹사이트 표준화 검사 도구 구현
- 4개 검사 엔진: HTML/CSS, 접근성(WCAG), SEO, 성능/보안 (총 50개 항목) - FastAPI 백엔드 (9개 API, SSE 실시간 진행, PDF/JSON 리포트) - Next.js 15 프론트엔드 (6개 페이지, 29개 컴포넌트, 반원 게이지 차트) - Docker Compose 배포 (Backend:8011, Frontend:3011, MongoDB:27022, Redis:6392) - 전체 테스트 32/32 PASS Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
700
FEATURE_SPEC.md
Normal file
700
FEATURE_SPEC.md
Normal file
@ -0,0 +1,700 @@
|
||||
# 기능 정의서 (Feature Specification)
|
||||
|
||||
## 1. 기능 목록 (Feature Inventory)
|
||||
|
||||
| # | 기능명 | 우선순위 | 카테고리 | 상태 |
|
||||
|---|--------|---------|---------|------|
|
||||
| F-001 | URL 입력 및 검사 시작 | Must | Core | 정의완료 |
|
||||
| F-002 | HTML/CSS 표준 검사 | Must | Inspection | 정의완료 |
|
||||
| F-003 | 접근성(WCAG) 검사 | Must | Inspection | 정의완료 |
|
||||
| F-004 | SEO 최적화 검사 | Must | Inspection | 정의완료 |
|
||||
| F-005 | 성능/보안 검사 | Must | Inspection | 정의완료 |
|
||||
| F-006 | 실시간 검사 진행 상태 | Must | UX | 정의완료 |
|
||||
| F-007 | 검사 결과 대시보드 | Must | Dashboard | 정의완료 |
|
||||
| F-008 | 상세 이슈 목록 | Must | Dashboard | 정의완료 |
|
||||
| F-009 | 검사 이력 저장 | Should | History | 정의완료 |
|
||||
| F-010 | 검사 이력 목록 조회 | Should | History | 정의완료 |
|
||||
| F-011 | 트렌드 비교 차트 | Should | History | 정의완료 |
|
||||
| F-012 | PDF 리포트 내보내기 | Should | Export | 정의완료 |
|
||||
| F-013 | JSON 리포트 내보내기 | Should | Export | 정의완료 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 기능 상세 정의
|
||||
|
||||
---
|
||||
|
||||
### F-001: URL 입력 및 검사 시작
|
||||
|
||||
- **설명**: 사용자가 URL을 입력하고 검사 시작 버튼을 클릭하면, 4개 카테고리(HTML/CSS, 접근성, SEO, 성능/보안)를 동시에 검사한다.
|
||||
- **우선순위**: Must
|
||||
- **관련 사용자 스토리**: "웹 개발자로서, URL을 입력하면 해당 웹사이트의 표준 준수 여부를 한 번에 검사하고 싶다, 개별 도구를 여러 개 사용하지 않기 위해."
|
||||
|
||||
#### 입력 (Inputs)
|
||||
|
||||
| 필드명 | 타입 | 필수 | 검증 규칙 | 설명 |
|
||||
|--------|------|------|----------|------|
|
||||
| url | string | Y | 유효한 URL 형식 (http:// 또는 https://) | 검사 대상 URL |
|
||||
|
||||
#### 처리 규칙 (Business Rules)
|
||||
|
||||
1. URL 형식을 검증한다 (프로토콜 포함 필수)
|
||||
2. http:// URL은 그대로 허용한다 (HTTPS 여부는 보안 검사 항목)
|
||||
3. 검사 ID(inspection_id)를 UUID로 생성한다
|
||||
4. 4개 카테고리 검사를 비동기 병렬로 시작한다
|
||||
5. 검사 상태를 Redis에 저장하고, SSE로 클라이언트에 진행률을 스트리밍한다
|
||||
6. 모든 카테고리 완료 시 종합 점수를 계산하고 MongoDB에 결과를 저장한다
|
||||
7. URL 접근 불가 시 즉시 에러를 반환한다 (타임아웃: 10초)
|
||||
|
||||
#### 출력 (Outputs)
|
||||
|
||||
| 상황 | HTTP 상태 | 응답 |
|
||||
|------|----------|------|
|
||||
| 검사 시작 성공 | 202 | `{ "inspection_id": "uuid", "status": "running", "url": "..." }` |
|
||||
| URL 형식 오류 | 422 | `{ "detail": "유효한 URL을 입력해주세요" }` |
|
||||
| URL 접근 불가 | 400 | `{ "detail": "해당 URL에 접근할 수 없습니다" }` |
|
||||
|
||||
#### 수락 기준 (Acceptance Criteria)
|
||||
|
||||
- [ ] 유효한 URL 입력 시 검사가 시작되고 inspection_id가 반환된다
|
||||
- [ ] http://, https:// 프로토콜이 없는 URL은 422 에러를 반환한다
|
||||
- [ ] 접근 불가능한 URL은 400 에러와 명확한 메시지를 반환한다
|
||||
- [ ] 검사 시작 후 4개 카테고리가 병렬로 실행된다
|
||||
- [ ] 검사 시작 응답 시간은 2초 이내이다 (검사 자체는 비동기)
|
||||
|
||||
---
|
||||
|
||||
### F-002: HTML/CSS 표준 검사
|
||||
|
||||
- **설명**: 대상 URL의 HTML5 문법 유효성, CSS 유효성, 시맨틱 태그 사용 여부를 검사하고 0-100 점수와 이슈 목록을 제공한다.
|
||||
- **우선순위**: Must
|
||||
- **관련 사용자 스토리**: "웹 개발자로서, 내 웹사이트의 HTML/CSS가 W3C 표준을 준수하는지 확인하고 싶다, 브라우저 호환성과 코드 품질을 보장하기 위해."
|
||||
|
||||
#### 검사 항목
|
||||
|
||||
| # | 검사 항목 | 심각도 기본값 | 설명 |
|
||||
|---|----------|-------------|------|
|
||||
| H-01 | DOCTYPE 선언 | Major | `<!DOCTYPE html>` 존재 여부 |
|
||||
| H-02 | 문자 인코딩 | Major | `<meta charset="utf-8">` 존재 여부 |
|
||||
| H-03 | 언어 속성 | Minor | `<html lang="...">` 존재 여부 |
|
||||
| H-04 | title 태그 | Major | `<title>` 존재 및 비어있지 않은지 |
|
||||
| H-05 | 시맨틱 태그 사용 | Minor | header, nav, main, footer, section, article 사용 여부 |
|
||||
| H-06 | 이미지 alt 속성 | Major | 모든 `<img>`에 alt 속성 존재 여부 |
|
||||
| H-07 | 중복 ID | Critical | 동일 ID가 여러 요소에 사용되는지 |
|
||||
| H-08 | 빈 링크 | Minor | href가 비어있거나 "#"인 `<a>` 태그 |
|
||||
| H-09 | 인라인 스타일 | Info | inline style 사용 여부 (권고 사항) |
|
||||
| H-10 | Deprecated 태그 | Major | `<font>`, `<center>` 등 사용 중단 태그 |
|
||||
| H-11 | heading 계층 구조 | Minor | h1-h6 순서 건너뜀 여부 |
|
||||
| H-12 | viewport meta | Major | `<meta name="viewport">` 존재 여부 |
|
||||
|
||||
#### 점수 계산
|
||||
|
||||
```
|
||||
점수 = 100 - (Critical * 15 + Major * 8 + Minor * 3 + Info * 1)
|
||||
최소 0점, 최대 100점
|
||||
```
|
||||
|
||||
#### 출력 구조
|
||||
|
||||
```json
|
||||
{
|
||||
"category": "html_css",
|
||||
"score": 85,
|
||||
"total_issues": 5,
|
||||
"issues": [
|
||||
{
|
||||
"code": "H-07",
|
||||
"severity": "critical",
|
||||
"message": "중복 ID 발견: 'main-content'",
|
||||
"element": "<div id=\"main-content\">",
|
||||
"line": 45,
|
||||
"suggestion": "각 요소에 고유한 ID를 부여하세요"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 수락 기준 (Acceptance Criteria)
|
||||
|
||||
- [ ] HTML 문서를 파싱하여 12개 검사 항목을 모두 검사한다
|
||||
- [ ] 각 이슈에 심각도(Critical/Major/Minor/Info)가 정확히 분류된다
|
||||
- [ ] 점수가 0-100 범위로 계산된다
|
||||
- [ ] 이슈별 해당 HTML 요소와 라인 번호가 포함된다
|
||||
- [ ] 이슈별 개선 제안(suggestion)이 포함된다
|
||||
- [ ] CSS 인라인 스타일 검사가 동작한다
|
||||
- [ ] Deprecated 태그를 정확히 감지한다
|
||||
|
||||
---
|
||||
|
||||
### F-003: 접근성(WCAG) 검사
|
||||
|
||||
- **설명**: WCAG 2.1 AA 기준으로 웹 접근성을 검사하고 0-100 점수와 이슈 목록을 제공한다. Playwright + axe-core 기반.
|
||||
- **우선순위**: Must
|
||||
- **관련 사용자 스토리**: "웹 개발자로서, 내 웹사이트가 장애인을 포함한 모든 사용자가 접근 가능한지 확인하고 싶다, WCAG 가이드라인을 준수하기 위해."
|
||||
|
||||
#### 검사 항목
|
||||
|
||||
| # | 검사 항목 | WCAG 기준 | 심각도 기본값 | 설명 |
|
||||
|---|----------|----------|-------------|------|
|
||||
| A-01 | 이미지 대체 텍스트 | 1.1.1 | Critical | img, area, input[type=image]에 alt 속성 |
|
||||
| A-02 | 색상 대비 | 1.4.3 | Major | 텍스트/배경 대비율 AA 기준 (4.5:1) |
|
||||
| A-03 | 키보드 접근성 | 2.1.1 | Critical | 모든 기능이 키보드로 접근 가능 |
|
||||
| A-04 | 포커스 표시 | 2.4.7 | Major | 키보드 포커스가 시각적으로 표시 |
|
||||
| A-05 | 폼 레이블 | 1.3.1 | Critical | input/select/textarea에 label 연결 |
|
||||
| A-06 | ARIA 속성 유효성 | 4.1.2 | Major | ARIA 역할/속성이 올바르게 사용 |
|
||||
| A-07 | 링크 목적 | 2.4.4 | Minor | 링크 텍스트가 목적을 명확히 설명 |
|
||||
| A-08 | 페이지 언어 | 3.1.1 | Major | html lang 속성 존재 |
|
||||
| A-09 | 건너뛰기 링크 | 2.4.1 | Minor | skip navigation 링크 존재 |
|
||||
| A-10 | 자동 재생 제어 | 1.4.2 | Major | 자동 재생 미디어에 정지/음소거 컨트롤 |
|
||||
|
||||
#### 점수 계산
|
||||
|
||||
```
|
||||
axe-core 결과 기반:
|
||||
- violations (위반): Critical -20, Serious -10, Moderate -5, Minor -2
|
||||
- passes (통과): 기본 100점에서 위반 감점
|
||||
최소 0점, 최대 100점
|
||||
```
|
||||
|
||||
#### 출력 구조
|
||||
|
||||
```json
|
||||
{
|
||||
"category": "accessibility",
|
||||
"score": 72,
|
||||
"total_issues": 8,
|
||||
"wcag_level": "AA",
|
||||
"issues": [
|
||||
{
|
||||
"code": "A-02",
|
||||
"severity": "major",
|
||||
"wcag_criterion": "1.4.3",
|
||||
"message": "텍스트와 배경의 색상 대비가 부족합니다 (2.3:1, 최소 4.5:1 필요)",
|
||||
"element": "<p class=\"light-text\">",
|
||||
"suggestion": "텍스트 색상을 더 어둡게 하거나 배경을 더 밝게 조정하세요"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 수락 기준 (Acceptance Criteria)
|
||||
|
||||
- [ ] Playwright로 대상 URL을 로드하고 axe-core를 실행한다
|
||||
- [ ] WCAG 2.1 AA 기준으로 접근성 위반 사항을 감지한다
|
||||
- [ ] axe-core의 violations 결과를 한국어 메시지로 변환한다
|
||||
- [ ] 각 이슈에 WCAG 기준 번호(예: 1.4.3)가 포함된다
|
||||
- [ ] 점수가 0-100 범위로 계산된다
|
||||
- [ ] 색상 대비 검사에서 실제 대비율 수치가 포함된다
|
||||
- [ ] 이슈별 해당 HTML 요소 정보가 포함된다
|
||||
|
||||
---
|
||||
|
||||
### F-004: SEO 최적화 검사
|
||||
|
||||
- **설명**: 검색엔진 최적화 관련 항목을 검사하고 0-100 점수와 이슈 목록을 제공한다.
|
||||
- **우선순위**: Must
|
||||
- **관련 사용자 스토리**: "웹사이트 관리자로서, 내 사이트가 검색엔진에 최적화되어 있는지 확인하고 싶다, 검색 노출을 개선하기 위해."
|
||||
|
||||
#### 검사 항목
|
||||
|
||||
| # | 검사 항목 | 심각도 기본값 | 설명 |
|
||||
|---|----------|-------------|------|
|
||||
| S-01 | title 태그 | Critical | 존재, 길이 (10-60자), 고유성 |
|
||||
| S-02 | meta description | Major | 존재, 길이 (50-160자) |
|
||||
| S-03 | meta keywords | Info | 존재 여부 (참고용) |
|
||||
| S-04 | OG 태그 | Major | og:title, og:description, og:image 존재 |
|
||||
| S-05 | Twitter Card | Minor | twitter:card, twitter:title 존재 |
|
||||
| S-06 | canonical URL | Major | `<link rel="canonical">` 존재 |
|
||||
| S-07 | robots.txt | Major | /robots.txt 접근 가능 여부 |
|
||||
| S-08 | sitemap.xml | Major | /sitemap.xml 접근 가능 여부 |
|
||||
| S-09 | H1 태그 | Critical | H1 존재, 1개만 존재 |
|
||||
| S-10 | 구조화 데이터 | Minor | JSON-LD, Microdata, RDFa 존재 여부 |
|
||||
| S-11 | favicon | Minor | favicon 존재 여부 |
|
||||
| S-12 | 모바일 친화성 | Major | viewport meta 태그, 반응형 |
|
||||
| S-13 | URL 구조 | Minor | 깔끔한 URL (특수문자 최소) |
|
||||
| S-14 | 이미지 alt 속성 | Major | SEO 관점에서 이미지 설명 존재 |
|
||||
|
||||
#### 점수 계산
|
||||
|
||||
```
|
||||
점수 = 100 - (Critical * 15 + Major * 8 + Minor * 3 + Info * 1)
|
||||
최소 0점, 최대 100점
|
||||
```
|
||||
|
||||
#### 출력 구조
|
||||
|
||||
```json
|
||||
{
|
||||
"category": "seo",
|
||||
"score": 68,
|
||||
"total_issues": 6,
|
||||
"issues": [
|
||||
{
|
||||
"code": "S-04",
|
||||
"severity": "major",
|
||||
"message": "Open Graph 태그가 누락되었습니다: og:image",
|
||||
"suggestion": "<meta property=\"og:image\" content=\"이미지URL\">를 추가하세요"
|
||||
}
|
||||
],
|
||||
"meta_info": {
|
||||
"title": "사이트 제목",
|
||||
"title_length": 25,
|
||||
"description": "사이트 설명...",
|
||||
"description_length": 120,
|
||||
"has_robots_txt": true,
|
||||
"has_sitemap": false,
|
||||
"structured_data_types": ["JSON-LD"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 수락 기준 (Acceptance Criteria)
|
||||
|
||||
- [ ] HTML 파싱으로 meta 태그, OG 태그, 구조화 데이터를 검사한다
|
||||
- [ ] robots.txt와 sitemap.xml의 존재 여부를 HTTP 요청으로 확인한다
|
||||
- [ ] title 길이, description 길이를 측정하고 권장 범위를 벗어나면 이슈로 보고한다
|
||||
- [ ] H1 태그가 없거나 2개 이상이면 이슈로 보고한다
|
||||
- [ ] 구조화 데이터(JSON-LD, Microdata) 존재 여부를 감지한다
|
||||
- [ ] 점수가 0-100 범위로 계산된다
|
||||
- [ ] 각 이슈에 개선 제안(suggestion)이 포함된다
|
||||
- [ ] meta_info 객체에 현재 상태 요약이 포함된다
|
||||
|
||||
---
|
||||
|
||||
### F-005: 성능/보안 검사
|
||||
|
||||
- **설명**: 보안 헤더, HTTPS 적용, 기본 성능 메트릭을 검사하고 0-100 점수와 이슈 목록을 제공한다.
|
||||
- **우선순위**: Must
|
||||
- **관련 사용자 스토리**: "웹사이트 운영자로서, 보안 취약점과 성능 문제를 파악하고 싶다, 안전하고 빠른 서비스를 제공하기 위해."
|
||||
|
||||
#### 검사 항목
|
||||
|
||||
| # | 검사 항목 | 심각도 기본값 | 설명 |
|
||||
|---|----------|-------------|------|
|
||||
| P-01 | HTTPS 사용 | Critical | HTTPS 프로토콜 사용 여부 |
|
||||
| P-02 | SSL 인증서 유효성 | Critical | 인증서 만료/유효성 확인 |
|
||||
| P-03 | Strict-Transport-Security | Major | HSTS 헤더 존재 및 max-age |
|
||||
| P-04 | Content-Security-Policy | Major | CSP 헤더 존재 여부 |
|
||||
| P-05 | X-Content-Type-Options | Minor | nosniff 설정 여부 |
|
||||
| P-06 | X-Frame-Options | Minor | clickjacking 방지 설정 |
|
||||
| P-07 | X-XSS-Protection | Info | XSS 방지 헤더 (deprecated 알림) |
|
||||
| P-08 | Referrer-Policy | Minor | 리퍼러 정책 설정 여부 |
|
||||
| P-09 | Permissions-Policy | Minor | 권한 정책 헤더 존재 |
|
||||
| P-10 | 응답 시간 | Major | 초기 응답 시간 (TTFB) |
|
||||
| P-11 | 페이지 크기 | Minor | HTML 문서 크기 (권장 < 3MB) |
|
||||
| P-12 | 리다이렉트 수 | Minor | 리다이렉트 체인 길이 (권장 < 3) |
|
||||
| P-13 | Gzip/Brotli 압축 | Minor | 응답 압축 적용 여부 |
|
||||
| P-14 | 혼합 콘텐츠 | Major | HTTPS 페이지에서 HTTP 리소스 로드 |
|
||||
|
||||
#### 점수 계산
|
||||
|
||||
```
|
||||
보안 점수 (70% 가중치):
|
||||
HTTPS/SSL(30%) + 보안 헤더(40%)
|
||||
|
||||
성능 점수 (30% 가중치):
|
||||
응답 시간(40%) + 페이지 크기(30%) + 압축(30%)
|
||||
|
||||
종합 = 보안 점수 * 0.7 + 성능 점수 * 0.3
|
||||
최소 0점, 최대 100점
|
||||
```
|
||||
|
||||
#### 출력 구조
|
||||
|
||||
```json
|
||||
{
|
||||
"category": "performance_security",
|
||||
"score": 78,
|
||||
"total_issues": 4,
|
||||
"sub_scores": {
|
||||
"security": 82,
|
||||
"performance": 70
|
||||
},
|
||||
"issues": [
|
||||
{
|
||||
"code": "P-04",
|
||||
"severity": "major",
|
||||
"message": "Content-Security-Policy 헤더가 설정되지 않았습니다",
|
||||
"suggestion": "CSP 헤더를 추가하여 XSS 공격을 방지하세요"
|
||||
}
|
||||
],
|
||||
"metrics": {
|
||||
"ttfb_ms": 450,
|
||||
"page_size_bytes": 1250000,
|
||||
"redirect_count": 1,
|
||||
"compression": "gzip",
|
||||
"https": true,
|
||||
"ssl_valid": true,
|
||||
"ssl_expiry_days": 89
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 수락 기준 (Acceptance Criteria)
|
||||
|
||||
- [ ] HTTPS 사용 여부와 SSL 인증서 유효성을 검사한다
|
||||
- [ ] 주요 보안 헤더 9개(P-03~P-09)의 존재 여부를 검사한다
|
||||
- [ ] TTFB(Time To First Byte)를 측정한다
|
||||
- [ ] 페이지 크기를 측정하고 권장 범위를 초과하면 이슈로 보고한다
|
||||
- [ ] 응답 압축(Gzip/Brotli) 적용 여부를 확인한다
|
||||
- [ ] HTTPS 페이지에서 HTTP 리소스 로드(혼합 콘텐츠)를 감지한다
|
||||
- [ ] 보안/성능 각각의 서브 점수와 종합 점수를 계산한다
|
||||
- [ ] metrics 객체에 측정값 요약이 포함된다
|
||||
|
||||
---
|
||||
|
||||
### F-006: 실시간 검사 진행 상태
|
||||
|
||||
- **설명**: 검사 진행 중 4개 카테고리의 진행률을 SSE(Server-Sent Events)로 실시간 스트리밍한다.
|
||||
- **우선순위**: Must
|
||||
- **관련 사용자 스토리**: "사용자로서, 검사가 얼마나 진행되었는지 실시간으로 확인하고 싶다, 검사 완료까지 기다리는 동안 진행 상태를 파악하기 위해."
|
||||
|
||||
#### SSE 이벤트 구조
|
||||
|
||||
```
|
||||
event: progress
|
||||
data: {
|
||||
"inspection_id": "uuid",
|
||||
"status": "running",
|
||||
"overall_progress": 45,
|
||||
"categories": {
|
||||
"html_css": { "status": "completed", "progress": 100 },
|
||||
"accessibility": { "status": "running", "progress": 60, "current_step": "색상 대비 검사 중..." },
|
||||
"seo": { "status": "running", "progress": 30, "current_step": "robots.txt 확인 중..." },
|
||||
"performance_security": { "status": "pending", "progress": 0 }
|
||||
}
|
||||
}
|
||||
|
||||
event: category_complete
|
||||
data: {
|
||||
"inspection_id": "uuid",
|
||||
"category": "html_css",
|
||||
"score": 85,
|
||||
"total_issues": 5
|
||||
}
|
||||
|
||||
event: complete
|
||||
data: {
|
||||
"inspection_id": "uuid",
|
||||
"status": "completed",
|
||||
"overall_score": 76,
|
||||
"redirect_url": "/inspections/{inspection_id}"
|
||||
}
|
||||
|
||||
event: error
|
||||
data: {
|
||||
"inspection_id": "uuid",
|
||||
"status": "error",
|
||||
"message": "검사 중 오류가 발생했습니다"
|
||||
}
|
||||
```
|
||||
|
||||
#### 처리 규칙 (Business Rules)
|
||||
|
||||
1. SSE 엔드포인트는 `GET /api/inspections/{inspection_id}/stream`
|
||||
2. 검사 시작 후 클라이언트가 SSE 연결
|
||||
3. 각 카테고리의 진행 단계마다 progress 이벤트 발행
|
||||
4. 카테고리 완료 시 category_complete 이벤트 발행 (부분 결과 제공)
|
||||
5. 모든 카테고리 완료 시 complete 이벤트 발행
|
||||
6. 오류 발생 시 error 이벤트 발행
|
||||
7. SSE 연결 타임아웃: 120초 (검사 최대 시간)
|
||||
|
||||
#### 수락 기준 (Acceptance Criteria)
|
||||
|
||||
- [ ] GET /api/inspections/{id}/stream 엔드포인트가 SSE 스트림을 반환한다
|
||||
- [ ] Content-Type이 text/event-stream이다
|
||||
- [ ] 4개 카테고리의 개별 진행률(0-100)이 실시간으로 업데이트된다
|
||||
- [ ] 현재 검사 단계 텍스트(current_step)가 제공된다
|
||||
- [ ] 카테고리 완료 시 해당 카테고리의 점수가 즉시 제공된다
|
||||
- [ ] 모든 검사 완료 시 종합 점수와 결과 페이지 URL이 제공된다
|
||||
- [ ] 오류 발생 시 error 이벤트가 발행된다
|
||||
- [ ] 프론트엔드에서 SSE 이벤트를 수신하여 프로그레스 바를 업데이트한다
|
||||
|
||||
---
|
||||
|
||||
### F-007: 검사 결과 대시보드
|
||||
|
||||
- **설명**: 검사 완료 후 종합 점수와 4개 카테고리별 점수를 시각적으로 표시하는 대시보드 페이지.
|
||||
- **우선순위**: Must
|
||||
- **관련 사용자 스토리**: "사용자로서, 검사 결과를 한눈에 파악하고 싶다, 웹사이트의 전반적인 품질 수준을 빠르게 이해하기 위해."
|
||||
|
||||
#### 대시보드 구성 요소
|
||||
|
||||
1. **종합 점수 게이지**: 0-100 원형 게이지 (색상: 0-49 빨강, 50-79 주황, 80-100 초록)
|
||||
2. **카테고리별 점수 카드**: 4개 카드에 각 카테고리 점수 + 이슈 수
|
||||
3. **점수 등급 레이블**: A+(90-100), A(80-89), B(70-79), C(60-69), D(50-59), F(0-49)
|
||||
4. **이슈 요약 바**: Critical/Major/Minor/Info 각각의 개수 막대
|
||||
5. **검사 메타 정보**: URL, 검사 일시, 소요 시간
|
||||
|
||||
#### API 엔드포인트
|
||||
|
||||
```
|
||||
GET /api/inspections/{inspection_id}
|
||||
```
|
||||
|
||||
#### 응답 구조
|
||||
|
||||
```json
|
||||
{
|
||||
"inspection_id": "uuid",
|
||||
"url": "https://example.com",
|
||||
"created_at": "2026-02-12T10:00:00Z",
|
||||
"duration_seconds": 35,
|
||||
"overall_score": 76,
|
||||
"grade": "B",
|
||||
"categories": {
|
||||
"html_css": { "score": 85, "grade": "A", "total_issues": 5, "critical": 0, "major": 2, "minor": 2, "info": 1 },
|
||||
"accessibility": { "score": 72, "grade": "B", "total_issues": 8, "critical": 1, "major": 3, "minor": 3, "info": 1 },
|
||||
"seo": { "score": 68, "grade": "C", "total_issues": 6, "critical": 1, "major": 2, "minor": 2, "info": 1 },
|
||||
"performance_security": { "score": 78, "grade": "B", "total_issues": 4, "critical": 0, "major": 2, "minor": 1, "info": 1 }
|
||||
},
|
||||
"summary": {
|
||||
"total_issues": 23,
|
||||
"critical": 2,
|
||||
"major": 9,
|
||||
"minor": 8,
|
||||
"info": 4
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 수락 기준 (Acceptance Criteria)
|
||||
|
||||
- [ ] 검사 결과 페이지 URL이 `/inspections/{inspection_id}` 형식이다
|
||||
- [ ] 종합 점수가 원형 게이지 형태로 표시된다
|
||||
- [ ] 점수에 따라 게이지 색상이 빨강/주황/초록으로 변한다
|
||||
- [ ] 4개 카테고리별 점수와 이슈 수가 카드 형태로 표시된다
|
||||
- [ ] 점수 등급(A+, A, B, C, D, F)이 표시된다
|
||||
- [ ] 심각도별 이슈 개수가 요약되어 표시된다
|
||||
- [ ] 검사 URL, 일시, 소요 시간이 표시된다
|
||||
|
||||
---
|
||||
|
||||
### F-008: 상세 이슈 목록
|
||||
|
||||
- **설명**: 검사에서 발견된 모든 이슈를 카테고리별/심각도별로 필터링하여 상세하게 표시한다.
|
||||
- **우선순위**: Must
|
||||
- **관련 사용자 스토리**: "웹 개발자로서, 발견된 이슈들의 상세 내용과 개선 방법을 확인하고 싶다, 문제를 하나씩 수정하기 위해."
|
||||
|
||||
#### 이슈 목록 기능
|
||||
|
||||
1. **카테고리 필터**: 전체 / HTML/CSS / 접근성 / SEO / 성능/보안
|
||||
2. **심각도 필터**: 전체 / Critical / Major / Minor / Info
|
||||
3. **정렬**: 심각도 높은 순 (기본값) / 카테고리별
|
||||
4. **이슈 카드**: 코드, 심각도 배지, 메시지, 해당 요소, 개선 제안
|
||||
|
||||
#### API 엔드포인트
|
||||
|
||||
```
|
||||
GET /api/inspections/{inspection_id}/issues?category=html_css&severity=critical
|
||||
```
|
||||
|
||||
#### 수락 기준 (Acceptance Criteria)
|
||||
|
||||
- [ ] 전체 이슈 목록이 카드 형태로 표시된다
|
||||
- [ ] 카테고리별 필터링이 동작한다 (4개 카테고리 + 전체)
|
||||
- [ ] 심각도별 필터링이 동작한다 (Critical/Major/Minor/Info + 전체)
|
||||
- [ ] 기본 정렬은 심각도 높은 순이다
|
||||
- [ ] 각 이슈에 코드, 심각도 배지, 메시지, 개선 제안이 표시된다
|
||||
- [ ] 해당 HTML 요소가 코드 블록으로 표시된다 (있는 경우)
|
||||
|
||||
---
|
||||
|
||||
### F-009: 검사 이력 저장
|
||||
|
||||
- **설명**: 모든 검사 결과를 MongoDB에 자동 저장하여 이후 조회 및 비교에 활용한다.
|
||||
- **우선순위**: Should
|
||||
- **관련 사용자 스토리**: "웹사이트 관리자로서, 과거 검사 결과를 다시 볼 수 있길 원한다, 시간에 따른 품질 변화를 추적하기 위해."
|
||||
|
||||
#### 처리 규칙 (Business Rules)
|
||||
|
||||
1. 검사 완료 시 결과를 MongoDB inspections 컬렉션에 자동 저장
|
||||
2. 저장 항목: URL, 검사 일시, 4개 카테고리 결과(점수, 이슈), 종합 점수
|
||||
3. 동일 URL에 대한 다중 검사 결과 저장 (덮어쓰기 아님)
|
||||
4. 저장 용량 관리: URL당 최대 100건, 초과 시 가장 오래된 결과 삭제
|
||||
|
||||
#### 수락 기준 (Acceptance Criteria)
|
||||
|
||||
- [ ] 검사 완료 시 결과가 MongoDB에 자동 저장된다
|
||||
- [ ] 저장된 결과에 URL, 검사 일시, 전체 점수, 카테고리별 점수가 포함된다
|
||||
- [ ] 동일 URL로 여러 번 검사해도 각각 개별 레코드로 저장된다
|
||||
- [ ] 저장된 결과를 inspection_id로 조회할 수 있다
|
||||
|
||||
---
|
||||
|
||||
### F-010: 검사 이력 목록 조회
|
||||
|
||||
- **설명**: 저장된 검사 이력을 목록 형태로 조회한다.
|
||||
- **우선순위**: Should
|
||||
- **관련 사용자 스토리**: "사용자로서, 이전에 검사했던 URL들의 결과 목록을 보고 싶다, 특정 검사 결과를 다시 확인하기 위해."
|
||||
|
||||
#### API 엔드포인트
|
||||
|
||||
```
|
||||
GET /api/inspections?page=1&limit=20&url=example.com
|
||||
```
|
||||
|
||||
#### 파라미터
|
||||
|
||||
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|
||||
|---------|------|------|--------|------|
|
||||
| page | int | N | 1 | 페이지 번호 |
|
||||
| limit | int | N | 20 | 페이지당 항목 수 (최대 100) |
|
||||
| url | string | N | - | URL 필터 (부분 일치) |
|
||||
| sort | string | N | -created_at | 정렬 기준 |
|
||||
|
||||
#### 수락 기준 (Acceptance Criteria)
|
||||
|
||||
- [ ] 검사 이력 목록이 테이블 형태로 표시된다
|
||||
- [ ] 각 행에 URL, 검사 일시, 종합 점수, 등급이 표시된다
|
||||
- [ ] 페이지네이션이 동작한다
|
||||
- [ ] URL 검색 필터가 동작한다
|
||||
- [ ] 행 클릭 시 해당 검사 결과 상세 페이지로 이동한다
|
||||
- [ ] 최신 검사 순으로 기본 정렬된다
|
||||
|
||||
---
|
||||
|
||||
### F-011: 트렌드 비교 차트
|
||||
|
||||
- **설명**: 동일 URL에 대한 과거 검사 결과를 시계열 라인 차트로 비교한다.
|
||||
- **우선순위**: Should
|
||||
- **관련 사용자 스토리**: "웹사이트 관리자로서, 시간에 따른 점수 변화를 차트로 보고 싶다, 개선 노력의 효과를 확인하기 위해."
|
||||
|
||||
#### API 엔드포인트
|
||||
|
||||
```
|
||||
GET /api/inspections/trend?url=https://example.com&limit=10
|
||||
```
|
||||
|
||||
#### 응답 구조
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://example.com",
|
||||
"data_points": [
|
||||
{
|
||||
"inspection_id": "uuid",
|
||||
"created_at": "2026-02-01T10:00:00Z",
|
||||
"overall_score": 72,
|
||||
"html_css": 80,
|
||||
"accessibility": 65,
|
||||
"seo": 70,
|
||||
"performance_security": 73
|
||||
},
|
||||
{
|
||||
"inspection_id": "uuid",
|
||||
"created_at": "2026-02-10T10:00:00Z",
|
||||
"overall_score": 78,
|
||||
"html_css": 85,
|
||||
"accessibility": 72,
|
||||
"seo": 68,
|
||||
"performance_security": 86
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 수락 기준 (Acceptance Criteria)
|
||||
|
||||
- [ ] 동일 URL의 과거 검사 결과가 시계열 라인 차트로 표시된다
|
||||
- [ ] 종합 점수 + 4개 카테고리 점수 라인이 각각 표시된다
|
||||
- [ ] 각 데이터 포인트에 마우스 호버 시 상세 점수가 툴팁으로 표시된다
|
||||
- [ ] 데이터 포인트 클릭 시 해당 검사 결과 페이지로 이동한다
|
||||
- [ ] 최소 2건 이상의 검사 결과가 있어야 차트가 표시된다
|
||||
- [ ] 검사 결과가 1건이면 "비교할 이력이 없습니다" 메시지 표시
|
||||
|
||||
---
|
||||
|
||||
### F-012: PDF 리포트 내보내기
|
||||
|
||||
- **설명**: 검사 결과를 PDF 파일로 생성하여 다운로드한다.
|
||||
- **우선순위**: Should
|
||||
- **관련 사용자 스토리**: "프로젝트 매니저로서, 검사 결과를 PDF로 다운로드하고 싶다, 팀이나 클라이언트에게 공유하기 위해."
|
||||
|
||||
#### PDF 리포트 구성
|
||||
|
||||
1. **표지**: 프로젝트명, 검사 URL, 검사 일시
|
||||
2. **종합 점수 요약**: 종합 점수 + 4개 카테고리 점수
|
||||
3. **카테고리별 상세**: 각 카테고리의 이슈 목록 (심각도순)
|
||||
4. **개선 제안 요약**: 우선순위별 개선 제안 리스트
|
||||
|
||||
#### API 엔드포인트
|
||||
|
||||
```
|
||||
GET /api/inspections/{inspection_id}/report/pdf
|
||||
```
|
||||
|
||||
#### 수락 기준 (Acceptance Criteria)
|
||||
|
||||
- [ ] PDF 파일이 정상적으로 생성되어 다운로드된다
|
||||
- [ ] Content-Type이 application/pdf이다
|
||||
- [ ] 파일명이 `web-inspector-{url-slug}-{date}.pdf` 형식이다
|
||||
- [ ] PDF에 종합 점수, 카테고리별 점수, 이슈 목록이 포함된다
|
||||
- [ ] PDF에 한국어 텍스트가 올바르게 렌더링된다
|
||||
- [ ] 파일 크기가 합리적이다 (일반적으로 < 5MB)
|
||||
|
||||
---
|
||||
|
||||
### F-013: JSON 리포트 내보내기
|
||||
|
||||
- **설명**: 검사 결과를 JSON 파일로 다운로드한다.
|
||||
- **우선순위**: Should
|
||||
- **관련 사용자 스토리**: "개발자로서, 검사 결과를 JSON으로 다운로드하고 싶다, 자동화 파이프라인에서 결과를 처리하기 위해."
|
||||
|
||||
#### API 엔드포인트
|
||||
|
||||
```
|
||||
GET /api/inspections/{inspection_id}/report/json
|
||||
```
|
||||
|
||||
#### 수락 기준 (Acceptance Criteria)
|
||||
|
||||
- [ ] JSON 파일이 정상적으로 생성되어 다운로드된다
|
||||
- [ ] Content-Type이 application/json이다
|
||||
- [ ] Content-Disposition이 attachment로 설정된다
|
||||
- [ ] 파일명이 `web-inspector-{url-slug}-{date}.json` 형식이다
|
||||
- [ ] JSON에 전체 검사 결과(점수, 이슈, 메트릭)가 포함된다
|
||||
- [ ] JSON 구조가 GET /api/inspections/{id} 응답과 동일하다
|
||||
|
||||
---
|
||||
|
||||
## 3. API 엔드포인트 요약
|
||||
|
||||
| Method | Path | 기능 ID | 설명 |
|
||||
|--------|------|---------|------|
|
||||
| POST | /api/inspections | F-001 | 검사 시작 |
|
||||
| GET | /api/inspections/{id}/stream | F-006 | SSE 진행 상태 스트림 |
|
||||
| GET | /api/inspections/{id} | F-007 | 검사 결과 조회 |
|
||||
| GET | /api/inspections/{id}/issues | F-008 | 이슈 목록 조회 |
|
||||
| GET | /api/inspections | F-010 | 검사 이력 목록 |
|
||||
| GET | /api/inspections/trend | F-011 | 트렌드 데이터 |
|
||||
| GET | /api/inspections/{id}/report/pdf | F-012 | PDF 리포트 다운로드 |
|
||||
| GET | /api/inspections/{id}/report/json | F-013 | JSON 리포트 다운로드 |
|
||||
| GET | /api/health | - | 헬스체크 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 비즈니스 규칙 (Global Business Rules)
|
||||
|
||||
- 모든 API 응답은 JSON 형식 (`Content-Type: application/json`, 리포트 다운로드 제외)
|
||||
- 에러 응답은 `{ "detail": "에러 메시지" }` 형식
|
||||
- 검사 타임아웃: 카테고리당 60초, 전체 120초
|
||||
- URL 접근 타임아웃: 10초
|
||||
- 동시 검사 제한: 없음 (MVP 단계)
|
||||
- 검사 결과는 삭제 기능 없이 영구 보존 (MVP 단계)
|
||||
- 모든 시간은 UTC 기준으로 저장, 프론트엔드에서 로컬 타임존으로 변환 표시
|
||||
|
||||
---
|
||||
|
||||
## 5. 비기능 요구사항
|
||||
|
||||
| 항목 | 기준 |
|
||||
|------|------|
|
||||
| API 응답 시간 | 검사 시작 API < 2초 |
|
||||
| 검사 소요 시간 | 전체 검사 < 120초 |
|
||||
| SSE 이벤트 지연 | < 500ms |
|
||||
| 동시 사용자 | 최소 10명 (MVP) |
|
||||
| 페이지 로드 | 프론트엔드 초기 로드 < 3초 |
|
||||
| PDF 생성 | < 10초 |
|
||||
| 브라우저 지원 | Chrome, Firefox, Safari, Edge 최신 버전 |
|
||||
| 한국어 지원 | UI 전체 한국어, PDF 리포트 한국어 |
|
||||
Reference in New Issue
Block a user