Skip to content

Commit c1a3f92

Browse files
committed
docs(spec): sync SPEC.md architecture/CI/ops sections to actual implementation (ADR-014)
1 parent e260680 commit c1a3f92

1 file changed

Lines changed: 101 additions & 79 deletions

File tree

‎docs/SPEC.md‎

Lines changed: 101 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -275,26 +275,30 @@ feat: project scaffolding + health endpoint
275275

276276
## 3. 스코프
277277

278-
### 3.1 v1 포함 카테고리
278+
### 3.1 실제 카테고리와 규모 (2026-09-24 기준, ADR-014)
279279

280-
| 카테고리 | 목표 데이터 수 | 우선순위 |
281-
|---|---|---|
282-
| **Smartphones** | ~500 (2020년 이후 주요 모델) | P0 |
283-
| **SoCs** | ~200 (Snapdragon, MediaTek, Apple, Exynos, Tensor) | P0 |
284-
| **Discrete GPUs** | ~150 (NVIDIA RTX, AMD Radeon, Intel Arc) | P1 |
285-
| **Brands** | ~50 (제조사·SoC 메이커) | P0 |
286-
287-
### 3.2 v2+ 확장 (시간순)
288-
289-
1. 태블릿
290-
2. 노트북·랩탑 (CPU 포함)
291-
3. 데스크탑 CPU
292-
4. 디스플레이 모듈 (패널 제조사·스펙)
293-
5. 카메라 센서 (Sony IMX 등)
294-
6. 무선 이어폰 / 헤드폰
295-
7. 스마트워치 / 웨어러블
296-
8. 게이밍 콘솔
297-
9. SBC (라즈베리파이 등)
280+
> 아래 표는 2026-05 최초 계획 당시 "목표"였다. 실제로는 계획보다 훨씬 큰 규모(과거 최대 111만 레코드, 2026-09-17 게임을 `game-catalog`로 분리한 뒤 약 19.1만)로 확장됐고, "2020년 이후 주요 모델만"이 아니라 1989~2026년 전 시대를 다룬다. 최신 수치는 `site/public/v1/index.json`이 정본이며 아래는 스냅샷이다.
281+
282+
| 카테고리 | 실제 레코드 수 | 비고 |
283+
|---|---:|---|
284+
| **Smartphones** | 93,396 | 전체의 대다수 |
285+
| **Websites** | 40,084 | |
286+
| **Software** | 42,493 | |
287+
| **Tablets** | 3,455 | |
288+
| **CPUs** | 3,993 | |
289+
| **SoCs** | 2,104 | |
290+
| **GPUs** | 2,030 | |
291+
| **Laptops** | 1,951 | |
292+
| **Monitors** | 882 | |
293+
| **Watches** | 433 | |
294+
| **PDAs** | 140 | |
295+
| **Brands** | 207 | |
296+
297+
게임(962,384건)은 2026-09-17 `GetTechAPI/game-catalog`로 이력 보존 분리(별도 레포, 점수·검증 대상 아님 — 별개 정체성이라는 게 분리 기준, §3.3 참고). software/websites는 한 번 분리를 검토했으나 "테크 데이터"라는 정체성이 같아 TechAPI에 유지하기로 결정(2026-09-18).
298+
299+
### 3.2 확장 이력 (시간순, 완료된 것)
300+
301+
애초 "v2+"로 미뤘던 항목 대부분이 이미 구현됐다: 태블릿·워치·PDA(모바일 기기 계열), 노트북(CPU 포함), 데스크탑 CPU, 디스크리트 GPU, 소프트웨어, 웹사이트. 아직 없는 것: 디스플레이 모듈 단독 엔티티, 카메라 센서, 무선 이어폰/헤드폰, 게이밍 콘솔, SBC — 수요가 확인되면 §22와 동일한 절차(엔진 먼저 병합 → 서브모듈 bump → 데이터 PR)로 추가.
298302

299303
### 3.3 절대 안 다룰 영역
300304

@@ -1427,97 +1431,100 @@ chore: bump fastapi to 0.115
14271431

14281432
## 16. CI/CD
14291433

1430-
### 16.1 GitHub Actions 워크플로
1434+
> ADR-014 (2026-09-24): 아래는 2026-09 기준 **실제 운영 중인** 워크플로다. 이전 판(§16.2~16.4의 Railway/Fly.io/Sentry 절차)은 한 번도 실행된 적 없는 원안이라 삭제했다 — 서버 배포가 실제로 필요해지면 ADR-010을 다시 근거로 복원한다.
1435+
1436+
### 16.1 GitHub Actions 워크플로 (실제)
1437+
1438+
**TechAPI**
14311439

14321440
| 워크플로 | 트리거 | 작업 |
14331441
|---|---|---|
1434-
| `test.yml` | PR, push | 테스트 + 린트 + 타입체크 |
14351442
| `validate-data.yml` | PR (data/ 변경) | JSON 스키마 검증 |
1436-
| `deploy-prod.yml` | push to main | Railway/Fly.io 배포 |
1437-
| `dump-data.yml` | main 머지 (data/ 변경) | api-data 리포에 정적 JSON 푸시 |
1438-
| `weekly-stale.yml` | cron (월요일) | 30일 넘은 Backlog 라벨링 |
1439-
| `release.yml` | tag (v*) | 릴리스 노트 + 패키지 배포 |
1443+
| `pr-metadata.yml` | PR 열림 | 담당자·라벨·마일스톤·프로젝트 필드 자동 부여 |
1444+
| `request-engine-pr-validation.yml` | PR | TechEngine에 검증 요청 (relay) |
1445+
| `bump-engine.yml` | TechEngine 릴리스 | 서브모듈 포인터 자동 bump |
1446+
| `notify-engine.yml` | `data/` push | TechEngine에 변경 알림 (무한루프 방지용 paths-ignore 적용) |
1447+
| `deploy-pages.yml` | `main` push | GitHub Pages 배포 (공개 사이트) |
1448+
| `verify-command.yml` | 수동/커맨트 트리거 | 검증 계층 커맨드 실행 |
1449+
| `verify-report.yml` | PR | Tier 0 분석 봇 코멘트 |
14401450

1441-
### 16.2 환경 분리
1451+
**TechEngine**
14421452

1443-
| 환경 | 도메인 | DB | 배포 트리거 |
1444-
|---|---|---|---|
1445-
| **local** | `localhost:8000` | Docker Postgres | 수동 |
1446-
| **staging** | `staging.api.techapi.dev` | Supabase (별도 프로젝트) | PR 머지 to `develop` (Phase 3+) |
1447-
| **production** | `api.techapi.dev` | Supabase 메인 | main 머지 |
1453+
| 워크플로 | 트리거 | 작업 |
1454+
|---|---|---|
1455+
| `test.yml` | PR, push | 테스트 + 린트 |
1456+
| `validate-data.yml` | PR | TechAPI 데이터 스키마 검증 |
1457+
| `techapi-pr-validation-comment.yml` | TechAPI PR | `npm run build`로 사이트 빌드 검증 + TechEngineBot 리뷰 코멘트 |
1458+
| `techapi-verify-comment.yml` | TechAPI PR | 검증 계층 분석 코멘트 |
1459+
| `weekly-ingest.yml` | cron (주간) | 신규 SKU 수집 → TechAPI PR |
1460+
| `weekly-refresh.yml` | cron (주간) | 실사이트 스크레이핑 + 덤프 갱신 |
1461+
| `dump-refresh.yml` | cron + 수동 | 스크레이핑 없이 현재 데이터로 정적 덤프만 재생성 |
1462+
| `refresh-data.yml` | 수동 | 데이터 리프레시 (tar 묶음 업로드) |
1463+
| `verify-network.yml` | cron (월요일) + 수동(`apply` 입력) | Tier 1-3 네트워크 검증 + `verified` 승급, TechAPI에 human-gated PR |
1464+
| `verify-status.yml` | `data/` push + 매일 | `data/_verify/status.json` 집계 갱신 |
1465+
| `bump-techapi.yml` | TechAPI 릴리스 | 서브모듈 포인터 자동 bump |
1466+
| `notify-techapi.yml` | TechEngine push | TechAPI에 변경 알림 |
1467+
| `coverage-report.yml` | 매일 | 커버리지 갭 이슈 자동 갱신 |
1468+
| `deploy-pages.yml` | `main` push | GitHub Pages 배포 |
1469+
1470+
**TechMachine** (레포 관리 전용, 서비스 코드 아님) — 매일 org 전체 워크플로 상태 점검, 문제 목록이 바뀔 때만 메인테이너 멘션 알림. 위성 레포 생성 틀도 여기서 제공.
1471+
1472+
### 16.2 환경
1473+
1474+
단일 환경만 존재한다: **GitHub Pages 정적 사이트** (`https://gettechapi.github.io/TechAPI/`), `main` 브랜치가 소스. `develop`은 PR 통합용이며 배포되지 않는다(develop 화면 미리보기는 아직 없음, §22 참고). 로컬 DB(SQLite)는 덤프 생성 시점에만 존재하는 임시 산출물이다.
14481475

1449-
### 16.3 배포 절차
1476+
### 16.3 배포 절차 (실제)
14501477

14511478
```
1452-
1. main 머지
1479+
1. data/ PR이 develop에 rebase-merge
14531480
↓
1454-
2. test.yml 통과
1481+
2. develop → main 릴리스 PR (merge commit)
14551482
↓
1456-
3. Docker 이미지 빌드
1483+
3. deploy-pages.yml이 site/를 빌드해 GitHub Pages에 배포
14571484
↓
1458-
4. Railway/Fly.io에 push
1459-
↓
1460-
5. 헬스체크 (`/v1/health` 200)
1461-
↓
1462-
6. 트래픽 전환 (zero-downtime)
1463-
↓
1464-
7. Sentry에 release 마킹
1485+
4. notify-engine.yml이 TechEngine에 알림 → bump-engine이 필요시 반영
14651486
```
14661487

14671488
### 16.4 롤백
14681489

1469-
```bash
1470-
# Railway
1471-
railway rollback
1472-
1473-
# Fly.io
1474-
fly releases list
1475-
fly deploy --image registry.fly.io/techapi:v0.3.5
1476-
```
1490+
`main`에서 이전 커밋으로 되돌리는 revert PR을 만들고 다시 `deploy-pages.yml`이 돌게 한다. 별도 배포 플랫폼(Railway/Fly.io)이 없으므로 플랫폼 롤백 명령은 존재하지 않는다.
14771491

14781492
---
14791493

14801494
## 17. 운영·관측
14811495

1482-
### 17.1 로깅
1496+
> ADR-014 (2026-09-24): Sentry/Better Stack/UptimeRobot/Supabase는 도입된 적 없다. 실제 운영·관측은 **TechMachine**(`GetTechAPI/TechMachine`)이 org 레벨에서 담당한다. 아래는 실제 운영 방식.
14831497
1484-
- **포맷**: 구조화 JSON
1485-
- **레벨**: DEBUG (로컬), INFO (스테이징), WARN (프로덕션)
1486-
- **수집**: Better Stack 또는 Axiom (무료 티어)
1487-
- **필수 필드**: `timestamp`, `level`, `request_id`, `path`, `status`, `latency_ms`
1498+
### 17.1 상태 점검
14881499

1489-
### 17.2 모니터링
1500+
- **TechMachine `health.py`**: 매일 org의 모든 활성 레포·워크플로 최신 실행을 워크플로 단위로 조회 (취소/시간초과도 문제로 간주). 최근 N개 실행만 보는 방식은 저빈도 워크플로의 실패를 놓쳐서(주간 워크플로가 취소돼도 4일간 미발견) 워크플로별 조회로 바꿨다.
1501+
- 결과는 **[TechMachine #1](https://github.com/GetTechAPI/TechMachine/issues/1)** 이슈 하나에 계속 갱신.
14901502

1491-
| 지표 | 도구 | 알림 임계치 |
1492-
|---|---|---|
1493-
| 에러율 | Sentry | 5min 동안 1%+ |
1494-
| 응답 시간 | Better Stack | P95 > 500ms |
1495-
| 가용성 | UptimeRobot | 5xx 또는 응답 없음 |
1496-
| DB 연결 | Supabase 대시보드 | 80% 풀 |
1497-
| 디스크 사용 | 호스팅 대시보드 | 80% |
1503+
### 17.2 알림
14981504

1499-
### 17.3 알림
1505+
- 문제 목록이 **바뀔 때만** `@메인테이너` 멘션 댓글 (동일 실패 반복이나 "모두 정상"은 알리지 않음 — 알림 피로 방지).
1506+
- 이메일·Discord/Slack webhook·Sentry 등 별도 알림 채널은 없음. GitHub Issue 코멘트가 유일한 채널.
15001507

1501-
- **이메일**: 메인테이너 (모든 P0)
1502-
- **Discord/Slack webhook**: 빌드 실패, 배포 완료
1503-
- **GitHub Issue 자동 생성**: P0 발생 시
1508+
### 17.3 로깅
1509+
1510+
- 서버가 없으므로 요청 단위 구조화 로깅은 해당 없음.
1511+
- 각 GitHub Actions 워크플로 실행 로그가 사실상의 로그 저장소 (기본 보관 기간 적용).
15041512

15051513
### 17.4 백업
15061514

1507-
| 자산 | 빈도 | 보관 | 복구 시간 목표 |
1515+
| 자산 | 빈도 | 보관 | 비고 |
15081516
|---|---|---|---|
1509-
| Postgres | 일 1회 (Supabase 자동) | 7일 (Free) ~ 30일 (Pro) | 1시간 |
1510-
| GitHub 리포 | Git이 곧 백업 | 영구 | 10분 |
1511-
| 환경 변수 | password manager | 영구 | 5분 |
1512-
| 이미지 | GitHub | 영구 | - |
1517+
| 데이터 (`data/`) | 커밋마다 | 영구 (Git 이력) | DB 백업 불필요 — 파일이 곧 원본 |
1518+
| GitHub 리포 | Git이 곧 백업 | 영구 | |
1519+
| 정적 덤프 (`site/public/v1`) | 커밋마다 | 영구 | 데이터에서 재생성 가능, 백업이라기보다 산출물 |
1520+
| 환경 변수/시크릿 | GitHub Secrets | 영구 | password manager는 미사용 |
15131521

15141522
### 17.5 사고 대응 (Incident Response)
15151523

1516-
1. **감지**: 알림 수신
1517-
2. **분류**: P0 (서비스 다운) / P1 (성능 저하) / P2 (부분 장애)
1518-
3. **대응**: 롤백 우선 → 원인 분석
1519-
4. **소통**: 상태 페이지 업데이트 (Phase 3+)
1520-
5. **사후 분석**: GitHub Issue로 post-mortem 작성
1524+
1. **감지**: TechMachine #1 코멘트 (또는 사용자 직접 발견)
1525+
2. **분류**: 데이터 문제(validate 실패) / CI 워크플로 실패 / 사이트 빌드 실패 — "서비스 다운"은 해당 없음(정적 사이트라 GitHub Pages 가용성에 종속)
1526+
3. **대응**: 원인이 코드면 fix PR, 데이터면 revert 또는 후속 보정 PR
1527+
4. **사후 분석**: 심각한 경우 `.claude/worklog_*.md`에 기록 (커밋 메시지·PR·이슈에는 에이전트 흔적을 남기지 않음)
15211528

15221529
---
15231530

@@ -1805,7 +1812,7 @@ TechAPI의 **핵심 목표 중 하나**. TechPicks 외에 다양한 앱·플랫
18051812

18061813
### ADR-002: DB는 Supabase Postgres
18071814
- **날짜**: 2026-05-26
1808-
- **상태**: Accepted
1815+
- **상태**: Superseded by ADR-014 (2026-09-24) — 실행된 적 없음, 실제는 정적 덤프 생성용 로컬 SQLite
18091816
- **결정**: Supabase 호스팅 Postgres
18101817
- **대안**: 자체 호스팅 Postgres, MySQL, MongoDB
18111818
- **근거**: 무료 티어 충분, 운영 부담 적음, RLS 활용 가능, 어드민 UI 호환
@@ -1883,7 +1890,7 @@ TechAPI의 **핵심 목표 중 하나**. TechPicks 외에 다양한 앱·플랫
18831890

18841891
### ADR-010: 전용 서버 (FastAPI on Railway/Fly.io) — 서버리스/Next.js 대신
18851892
- **날짜**: 2026-05-26
1886-
- **상태**: Accepted
1893+
- **상태**: Superseded by ADR-014 (2026-09-24) — 배포된 적 없음, 실제는 정적 덤프 + GitHub Pages. 아래 근거는 §22 재검토 시 유효
18871894
- **결정**: FastAPI를 Railway 또는 Fly.io에 배포하는 **전용 서버 모델**. Next.js 풀스택 / 정적 / Cloudflare Workers / Vercel Serverless 등 대안은 모두 검토 후 비채택.
18881895
- **검토한 대안**:
18891896
- **정적 전용**: 인증·복잡 쿼리 불가 → 핵심 요구 불충족
@@ -1954,6 +1961,21 @@ TechAPI의 **핵심 목표 중 하나**. TechPicks 외에 다양한 앱·플랫
19541961
- **대안**: (a) Wikipedia/Wikidata만 계속 사용 — 검증률 상한 ~24-25%로 목표 미달. (b) GSMArena 전면 크롤링 허용 — ToS 위반 리스크 과도. (c) 공식 파트너십/라이선스 체결 — 별도 트랙으로 계속 타진, 이 ADR과 배타적이지 않음.
19551962
- **근거**: 인용 정정은 새로운 데이터를 추출하지 않고, 이미 팀이 정당하게 보유한(Kaggle을 통해 리라이선스된) 데이터의 **출처 표기만 사실대로 교정**하는 행위. 요청량은 레코드당 최대 2회(사이트맵은 1회 캐시, 페이지 확인 1회)로 제한되고 요청 간 최소 1초 간격을 지킨다.
19561963

1964+
### ADR-014: 정적 덤프 + GitHub Pages 전용 아키텍처 (라이브 서버 미배포, ADR-002·ADR-010 대체)
1965+
1966+
- **날짜**: 2026-09-24
1967+
- **상태**: Accepted (실제로는 수개월 전부터 이 방식으로 운영 중이었고, 이 ADR은 문서를 실제 구현에 맞춘 것)
1968+
- **배경**: §4·§16·§17이 여전히 ADR-001/002/010 당시 계획(FastAPI 서버를 Railway/Fly.io에 상시 배포, Supabase Postgres, Sentry/Better Stack/UptimeRobot 모니터링, `api.techapi.dev` 도메인)을 서술하지만, 실제로는 그 서버가 한 번도 배포된 적이 없다. Railway/Fly.io 설정 파일이 리포에 존재하지 않고, `deploy-prod.yml`·`release.yml`·`weekly-stale.yml`도 존재하지 않는다. 실제 운영 중인 워크플로는 §16.1의 새 표를 참고.
1969+
- **결정**: 문서를 실제와 일치시킨다. TechAPI는 **정적 JSON 덤프(`site/public/v1`) + GitHub Pages**로만 서비스한다.
1970+
- 데이터 원천은 `data/` 아래 파일 단위 JSON (Postgres/Supabase 아님). `app/config.py`의 `database_url` 기본값도 로컬 SQLite(`sqlite:///./techapi.db`)이며, 이는 덤프 생성 시 레코드를 메모리 안에서 재현하기 위한 임시 DB이지 상시 서비스 DB가 아니다.
1971+
- 배포는 `deploy-pages.yml`(TechAPI) 하나. 인증·동적 쿼리·요청 단위 과금이 필요해지면 그때 서버 모델을 재검토한다(ADR-010의 "재검토 트리거" 조건은 유효하게 유지).
1972+
- 운영·관측은 Sentry/Better Stack/UptimeRobot/Supabase 대시보드가 아니라 **TechMachine**(`GetTechAPI/TechMachine`, 매일 org 전체 워크플로 상태 점검 후 실패 목록이 바뀔 때만 메인테이너 멘션)이 담당한다. 상세는 §17 개정판 참고.
1973+
- **영향**:
1974+
- ADR-002(Supabase Postgres)와 ADR-010(전용 서버/Railway·Fly.io)은 **폐기가 아니라 미실행 상태로 대체(superseded)** — Phase 4+에서 인증/동적 쿼리가 실제로 필요해지면 재소환 가능한 계획으로 남겨둔다.
1975+
- §16.1, §17을 이 ADR에 맞춰 갱신(아래).
1976+
- §3.1의 "목표 데이터 수"는 2026-05 최초 계획 당시 수치라 2026-09 기준 실제 규모와 크게 다름 — 실제 수치로 갱신.
1977+
- **재검토 트리거**: ADR-010과 동일 — 인증이 필요해지거나(토큰 발급·요청 제한), 정적 파일로 표현 불가능한 동적 쿼리(전문 검색, 복합 필터)가 실제로 요청될 때.
1978+
19571979
---
19581980

19591981
## 24. 용어집

0 commit comments

Comments
 (0)