Skip to content

feat: add TechAPI data layer - #16

Merged
Seungpyo1007 merged 3 commits into
developfrom
feat/techapi-client
Aug 7, 2026
Merged

feat: add TechAPI data layer#16
Seungpyo1007 merged 3 commits into
developfrom
feat/techapi-client

Conversation

@Seungpyo1007

Copy link
Copy Markdown
Owner

Closes #4

배경

v1에는 도메인 데이터 계층이 없었다. 제품 4종이 Phone.dart 안에 Map 리터럴로 박혀 있었고 모델 클래스도 리포지토리도 없었다. 위젯을 짓기 전에 데이터 계층부터 세운다.

소스 추상화

abstract class TechApiSource {
  Uri detail(String collection, String slug);
  Uri list(String collection);
  Uri index();
}

api.techapi.dev가 아직 미배포(DNS 미해결)라 DumpSource(GitHub Pages 정적 덤프)가 기본값이다. 덤프는 TechEngine의 app/dump.py실제 FastAPI 엔드포인트를 인프로세스로 replay해 생성하므로 REST와 응답 스키마가 같다. 차이는 URL 조립 하나뿐이고, 테스트로 그 사실을 고정해뒀다.

REST   /v1/smartphones/galaxy-s25
덤프   /v1/smartphones/galaxy-s25/index.json

DTO

Smartphone Cpu Gpu Soc Brand CollectionPage.

score 스키마가 컬렉션마다 다르다. 공통 ScoreMetric{index, percentile, tier, era, source}을 두고 나눴다.

컬렉션
smartphone performance, camera, battery, display, value + perf
cpu single, multi
gpu graphics
soc cpu, system

build.yaml에서 field_rename: snake를 전역 적용해 base_model_slugbaseModelSlug 매핑을 자동화했다.

데이터셋 특성 — 거의 모든 필드가 nullable

이건 방어적 설계가 아니라 실제 응답이 그렇다. energy-200 레코드는 score 객체가 있는데도 개별 축이 null이다.

"score": { "overall": 13.3, "performance": null, "value": null,
           "perf": { "index": null, "tier": null, "era": "2014-2016" } }

SoC의 manufacturerid조차 없이 온다. 그래서 Brand.id도 nullable이다.

오류 처리

FailureNetworkFailure / NotFoundFailure / ParseFailure / ServerFailure로 나눴다. UI가 원인에 따라 다르게 반응해야 하기 때문이다 — 네트워크 문제는 재시도 버튼을, 없는 레코드는 빈 상태를 보여야 한다.

리포지토리는 예외를 던지지 않고 Result<T>를 반환한다. DTO 파싱 중 터지는 TypeErrorParseFailure로 감싸 밖으로 새지 않는다.

검증

테스트 25건 전부 통과. 픽스처는 손으로 만든 가짜가 아니라 실제 덤프에서 내려받은 응답이다. 스키마가 바뀌면 테스트가 깨지고, 그게 의도다.

완료 기준 충족 — 위젯 없이 테스트만으로 galaxy-s25의 5축과 종합을 뽑아낸다.

tool/smoke_techapi.dart로 실제 원격 왕복도 확인했다.

Galaxy S25 (Samsung) — Snapdragon 8 Elite
  종합 60.8  성능 88.9  카메라 36.1
  배터리 54.4  화면 63.8  가치 59.0
  등급 A · 상위 92.0%
없는 slug -> NotFoundFailure

flutter analyze lib/core lib/data lib/domain test toolNo issues found.

부수 변경

  • environment.sdk^3.5.0^3.8.0. json_serializable 6.14가 요구한다
  • freezed는 pub이 처음 프리릴리스(4.0.0-dev.3)를 골랐다. 데이터 계층 기반에 dev 버전은 부적절하다고 판단해 안정 버전 ^3.0.0(해석 결과 3.2.5)으로 내렸다

후속 (이 PR 범위 밖)

스마트폰 목록 인덱스 크기를 계측했다 — 19 MB / 93,396건. 앱 시작 시 통째로 받는 건 불가능하다. #8에 기록해뒀다.

v1에는 도메인 데이터 계층이 없었다. 제품 정보가 화면 코드 안에 Map
리터럴로 박혀 있었고 모델 클래스도 리포지토리도 없었다. 위젯을 짓기
전에 데이터 계층부터 세운다.

소스 추상화
- TechApiSource: DumpSource(GitHub Pages 정적 덤프) / RestSource(api.techapi.dev)
- 덤프는 실제 엔드포인트를 인프로세스로 replay해 생성되므로 REST와 응답
  스키마가 같다. 차이는 URL 조립뿐이라 그 지점만 흡수한다
- api.techapi.dev는 아직 미배포라 DumpSource가 기본값

DTO (freezed + json_serializable)
- Smartphone, Cpu, Gpu, Soc, Brand, CollectionPage
- score는 컬렉션마다 축이 다르다. 공통 ScoreMetric을 두고
  SmartphoneScore(5축) / CpuScore(single·multi) / GpuScore(graphics) /
  SocScore(cpu·system)로 나눴다
- 데이터셋 특성상 거의 모든 필드가 nullable이다. score 객체가 있어도
  개별 축이 null인 레코드가 흔하다
- build.yaml에서 field_rename: snake 전역 적용

오류 처리
- Failure를 NetworkFailure / NotFoundFailure / ParseFailure / ServerFailure로 분류
- 리포지토리는 예외를 던지지 않고 Result<T>를 반환한다. DTO 파싱 중
  터지는 TypeError도 ParseFailure로 감싸 밖으로 새지 않게 한다

테스트 25건
- 픽스처는 손으로 만든 가짜가 아니라 실제 덤프에서 내려받은 응답이다.
  스키마가 바뀌면 테스트가 깨지고 그게 의도다
- 완료 기준 충족: 위젯 없이 테스트만으로 galaxy-s25의 score 5축과
  overall을 뽑아낸다
- tool/smoke_techapi.dart로 실제 원격 왕복도 확인

Closes #4
@Seungpyo1007 Seungpyo1007 added this to the v2.0.0 milestone Aug 7, 2026
@Seungpyo1007 Seungpyo1007 added enhancement New feature or request v2-rebuild v2 전면 재구축 (TechAPI 기반) phase-1 labels Aug 7, 2026
@Seungpyo1007 Seungpyo1007 self-assigned this Aug 7, 2026
CI의 코드 생성 최신성 검사가 잡아냈다. 재생성 결과가 커밋된 것과
4,873줄 삽입 / 9,005줄 삭제만큼 달랐다.

원인은 생성 시점과 pubspec 수정 순서. build_runner를 돌릴 때
environment.sdk 가 아직 ^3.5.0 이었고, json_serializable 이 요구하는
^3.8.0 으로 올린 건 그 뒤였다. freezed 와 json_serializable 은 패키지의
language version 에 따라 다른 코드를 뽑기 때문에 생성물이 낡은 채로 남았다.

생성 로그에 "language version (3.5.0) does not match required range ^3.8.0"
경고가 떠 있었는데 SDK 제약만 올리고 재생성하지 않았다.

재생성 후 테스트 25건 그대로 통과.
@Seungpyo1007
Seungpyo1007 merged commit 8339db8 into develop Aug 7, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request v2-rebuild v2 전면 재구축 (TechAPI 기반)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant