프로젝트 개요
무엇을 만드는가
Lumipet Re-ID (고양이 재식별) 파이프라인을 웹에서 실행하고 결과를 시각적으로 확인할 수 있는 웹 서비스. 현재 별도 저장소(lumipet-reid)에 존재하는 Python 기반 추론 파이프라인(ReIdModel, ReIdPredictor, BasePredictor, StreamLoader 등, PyTorch/YOLO/ArcFace/ wildlife-tools 기반)을 감싸는 웹 프론트/백엔드를 새로 구축하는 프로젝트입니다. 파이프라인 자체(모델 구조, 학습, 정확도)는 이 프로젝트의 범위가 아니며, 이미 존재하는 추론 로직을 웹 인터페이스로 노출하는 것이 목표입니다.
왜 만드는가
현재는 스크립트/커맨드라인으로만 파이프라인을 실행하고 결과를 확인할 수 있음.
이를 웹 화면으로 옮겨
(1) 결과를 눈으로 바로 확인하고 검증하기 쉽게 만들고,
(2) 이후 웹캠·휴대폰 카메라를 통한 실시간 입력으로 확장할 수 있는 기반을 마련하며,
(3) 장기적으로 모바일 앱으로 이어질 수 있는 API 계층을 미리 구축해두기 위함입니다.
단계별 목표 (현재 어디까지가 확정이고 어디부터가 미정인지)
| 단계 | 내용 | 확정 여부 |
|---|---|---|
| 1단계 (지금 진행 대상) | 로컬 폴더의 이미지/영상 파일을 입력받아, 탐지된 개체의 BBox와 ReID 매칭 결과(개체 이름/유사도 등)를 웹 화면에 표시 | 확정 — 이번 작업 범위 |
| 2단계 | 휴대폰 또는 외부 웹캠의 실시간 영상 스트림을 입력받아 동일한 처리를 실시간으로 수행 | 방향은 확정, 구체적 구현 방식(전송 프로토콜, 온디바이스 처리 범위 등)은 미정 — 6장, 7장의 Phase 4 참고 |
| 3단계 이후 | 결과를 저장하거나 다른 기기로 전송 | 방향만 언급됨, 세부 사양 미정 |
| 모바일 앱화 | React Native 등으로 별도 앱 제작 | 여부 자체가 미정 — “할 수도 있다” 수준 |
지금 이 시점에서 확정된 기술 스택
- 백엔드: FastAPI (Python) — 기존 파이프라인과의 통합 용이성, 비동기/WebSocket 지원 때문에 선정
- 프론트엔드: React + Vite (TypeScript) — 캔버스 기반 BBox 시각화, 향후 실시간 스트리밍 구현의 표준 생태계, React Native 전환 시 코드 재사용성 때문에 선정
- 아키텍처는 도메인(feature) 기준 구조를 따르고, AI 실행 로직(
ai/)은 도메인이 아니라 여러 도메인이 공유하는 인프라 계층으로 분리 (12장 참고)
이 프로젝트의 설계 원칙 (코드를 작성할 때 최우선으로 고려할 것)
“기획 세부사항이 자주 바뀔 가능성이 크다.” 이것이 이 문서 전체를 관통하는 단일 제약조건입니다. 따라서:
- 변경의 영향 범위를 국소화하는 구조를 우선한다 — 한 기능을 고칠 때 다른 기능이 깨지지 않도록 도메인별로 코드를 격리 (8장)
- 백엔드-프론트엔드 타입을 자동 동기화해서, API 필드가 바뀌었을 때 프론트엔드가 빌드 타임에 즉시 알아채도록 한다 (8-4장) — 이 프로젝트에서 가장 중요한 안전장치
- 지금 필요하지 않은 것은 미리 만들지 않는다 — 인증, DB, 다중 사용자, 마이크로서비스 분리 등은 실제로 요구사항이 될 때까지 도입하지 않음(과설계 방지)
- 온디바이스 AI 연산(모바일 탐지 등)이나 실시간 스트리밍 프로토콜처럼 아직 결정되지 않은 사양은 나중에 갈아엎기 쉬운 지점에 위치시킨다(예:
ai/계층 분리, 도메인별 격리)
지금 범위가 아닌 것 (Non-goals — 오버엔지니어링 방지용 명시)
- 사용자 인증/로그인, 다중 사용자 권한 관리
- 프로덕션 규모의 트래픽 대응, 마이크로서비스 분리, GPU 추론 서버 별도 스케일링
- 모바일 앱 실제 구현(여부조차 미정 — API가 “나중에 재사용 가능한 형태”이기만 하면 충분하고, 지금 앱을 염두에 둔 특별한 작업을 할 필요는 없음)
- 결과 데이터베이스화(현재는 화면에 표시하는 것까지가 목표. 저장이 필요해지면 그때
results/도메인 추가)
아키텍처 설계 전제
기획 변경 가능성이 높으므로, 핵심 목표는 “변경의 영향 범위 국소화(Localize)”. 한 기능 수정 시 다른 기능이 깨지지 않는 구조 우선.
FastAPI 백엔드 설계
도메인(Feature) 기준 분리 원칙
- Netflix Dispatch에서 영감을 받은 구조 .
fastapi-best-practices(zhanymkanov): github 대표 예시.- 기술적 파일 타입(routers, models 등) 분류 지양
- 기능(Domain) 단위 분리 채택 (e.g.,
auth,detection,reid) - 요구사항 변경 시 하나의 도메인 폴더 내부만 수정하여 리팩토링 비용 최소화
- 구조 예시
src/ ├── auth/ │ ├── router.py # 엔드포인트 │ ├── schemas.py # 요청/응답 Pydantic 모델 │ ├── models.py # DB 모델(ORM) │ ├── service.py # 비즈니스 로직 │ ├── dependencies.py # 이 도메인 전용 Depends │ ├── exceptions.py │ └── constants.py ├── detection/ # 예: 탐지 관련 도메인 │ ├── router.py │ ├── schemas.py │ ├── service.py # ReIdPredictor 호출 등 │ └── ... ├── reid/ # 예: ReID 매칭 관련 도메인 │ └── ... ├── media/ # 예: 영상/이미지 업로드·스트리밍 관련 │ └── ... ├── core/ # 전역 설정, 보안, 로깅 ├── db/ # DB 세션, 베이스 클래스 └── main.py
도메인 내부 계층 분리 원칙
router.py: HTTP 요청/응답 제어 전담. 비즈니스 로직 배제.service.py: 실제 비즈니스 로직(모델 추론, 매칭 등) 구현.schemas.py: Pydantic 요청/응답 모델. DB 모델(models.py)과 엄격히 분리.
비동기 및 추론 처리 아키텍처
- 짧은 요청(단일 이미지 추론) : 이벤트 루프 블로킹 방지를 위해 FastAPI의
async def엔드포인트에서run_in_executor또는 스레드풀로 GPU 추론 실행. - 긴 작업(영상 배치 처리) :
BackgroundTasks활용. 부하 증가 시 Celery/RQ 같은 별도 워커 큐로 분리.- 진행 상황 조회 API를 별도로 두는 패턴이 일반적
- 실시간 스트리밍 : WebSocket 라우터 분리 (
media/또는streaming/도메인). - 모델 로딩 :
lifespan컨텍스트 매니저로 앱 시작 시 한 번만 로드해 전역에 유지(요청마다 로드하지 않도록)- 이후
Depends로 모델 인스턴스를 각 라우터에 주입
- 이후
React 프론트엔드 설계
Feature 기준 구조 (bulletproof-react 패턴)
bulletproof-react(alan 2207): 대표 github- 기술 스택 중심이 아닌 기능 중심으로 UI 및 로직 결합
- ESLint(
import/no-restricted-paths)를 통해 Feature 간 직접 참조 차단 권장 - 예시 구조
src/ ├── app/ # 라우팅, 전역 프로바이더 ├── components/ # 여러 feature에서 공유하는 순수 UI 컴포넌트 ├── features/ │ ├── detection/ # 예: 탐지 결과 화면 │ │ ├── api/ # 이 feature 전용 API 호출 훅 │ │ ├── components/ # 이 feature 전용 컴포넌트(BBox 오버레이 등) │ │ └── hooks/ │ ├── reid-match/ # 예: 매칭 결과 화면 │ └── media-upload/ # 예: 영상 업로드/스트리밍 화면 ├── hooks/ # 전역 공유 훅 ├── lib/ # 외부 라이브러리 래퍼(axios 인스턴스 등) └── types/ # 전역 공유 타입
상태 관리 원칙
- 서버 상태 (추론 결과 등) :
TanStack Query(React Query) 활용.- 캐싱·재요청·로딩상태를 자동 처리해주고, 백엔드 스키마가 바뀌어도 훅 하나만 고치면 됨
- 클라이언트 UI 상태 (모달 창 등) :
useState,Zustand등 가벼운 도구 사용. - 서버 상태와 UI 상태 혼합 금지.
- 서버 상태를 Redux 전역 상태에 억지로 넣지 않기
FastAPI - React 통합 설계
OpenAPI 명세 기반 타입 자동 동기화. 기획 변경 대응에 가장 핵심적인 요소.
- FastAPI의 Pydantic ↔ OpenAPI ↔ TypeScript 클라이언트 자동 생성
- 장점 : 백엔드 API 응답 구조(필드) 변경 시, 프론트엔드 빌드 시점에 타입 에러로 즉시 인지 가능. “화면
undefined노출 사고” 원천 차단. - 백엔드에서 필드 하나를 추가/삭제/이름 변경 → 프론트엔드 타입이 자동으로 갱신됨 → 빌드 시점(런타임 아님)에 프론트엔드 코드에서 즉시 타입 에러로 드러남
sequenceDiagram
participant B as FastAPI (Backend)
participant O as OpenAPI Spec
participant F as React (Frontend)
B->>O: Pydantic 스키마 기반 자동 문서화
O->>F: 클라이언트 SDK/Type 자동 생성
Note over F: 백엔드 변경 사항이 빌드 에러로 즉시 감지됨
요약 디렉토리 구조
lumipet-reid-web/
├── backend/
│ ├── src/
│ │ ├── media/ # 업로드/스트리밍
│ │ ├── detection/ # 객체 탐지 도메인
│ │ ├── reid/ # ReID 매칭 도메인
│ │ ├── results/ # 결과 저장/조회
│ │ ├── core/ # 전역 설정 및 모델 lifespan
│ │ └── main.py
├── frontend/
│ ├── src/
│ │ ├── features/
│ │ │ ├── video-input/
│ │ │ ├── detection-view/
│ │ │ └── reid-results/
│ │ └── lib/api-client/ # OpenAPI 기반 자동 생성 클라이언트
└── docker-compose.yml
학습 자료 및 레퍼런스
| 참고 자료 | 성격 | 링크 |
|---|---|---|
fastapi/full-stack-fastapi-template |
FastAPI + React 통합 레퍼런스 (OpenAPI 클라이언트 자동 생성 포함) | Github 링크 |
zhanymkanov/fastapi-best-practices |
FastAPI 도메인 기준 구조 실무 컨벤션 | Github 링크 |
alan2207/bulletproof-react |
React Feature 중심 아키텍처 표준 레퍼런스.문서(docs/project-structure.md)만 읽어도 도움이 큼 |
Github 링크 |
| FastAPI - Concurrency | 비동기 처리(GPU 추론 블로킹 방지) 원리 | FastAPI Docs |
| FastAPI 공식 문서 — Bigger Applications | 공식, 기본기 | FastAPI Docs |
| TanStack Query 공식 문서 | 서버 상태 관리(React) | TanStackQuery |
검색 방법 팁
- “FastAPI large application structure”, “FastAPI domain driven structure” — 구조 관련 최신 글 검색
- “React feature-based architecture”, “React screaming architecture” — 프론트 구조 관련
- “OpenAPI TypeScript client generation” 또는 “openapi-typescript-codegen”, “orval” — 자동 클라이언트 생성 도구 비교
- GitHub 검색 시
stars:>1000 fastapi react template형태로 필터링하면 검증된 저장소만 걸러볼 수 있음 - 저장소를 고를 때는 최근 커밋 날짜(활발히 유지보수되는지)와 Issues/PR 논의 내용(실무에서 겪는 문제와 해법)을 함께 보는 것이 문서 자체보다 더 유용한 경우가 많습니다
C
Contents
