2026-03-24 13:17:16 +09:00
|
|
|
# Traeon (트래온) - 택배 배송조회 웹 구현 계획서
|
|
|
|
|
|
|
|
|
|
## 개요
|
|
|
|
|
|
|
|
|
|
개인용 택배 배송조회 웹 애플리케이션. 운송장 번호를 등록하면 배송 상태를 조회하고, 백그라운드에서 자동 갱신하며, 상태 변경 시 알림을 보내는 서비스다. 기존 Docker 인프라와 fromis_9 프로젝트의 기술 스택/패턴을 따른다.
|
|
|
|
|
|
|
|
|
|
## 기술 스택
|
|
|
|
|
|
|
|
|
|
| 영역 | 기술 |
|
|
|
|
|
|------|------|
|
|
|
|
|
| Frontend | React 18, Vite, Tailwind CSS, Zustand, React Query |
|
|
|
|
|
| Backend | Fastify 5, MySQL2, node-cron |
|
|
|
|
|
| 배송조회 | delivery-tracker 셀프호스팅 (GraphQL API) |
|
|
|
|
|
| DB | MariaDB (기존 인프라) |
|
|
|
|
|
| 인프라 | Docker Compose, Caddy 리버스 프록시 |
|
|
|
|
|
|
|
|
|
|
## 프로젝트 구조
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
/docker/traeon/
|
|
|
|
|
├── docker-compose.yml
|
|
|
|
|
├── .env
|
|
|
|
|
├── docs/
|
|
|
|
|
│ └── plan.md # 이 문서
|
|
|
|
|
├── frontend/
|
|
|
|
|
│ ├── Dockerfile
|
|
|
|
|
│ ├── package.json
|
|
|
|
|
│ ├── vite.config.js
|
|
|
|
|
│ ├── tailwind.config.js
|
|
|
|
|
│ ├── postcss.config.js
|
|
|
|
|
│ └── src/
|
|
|
|
|
│ ├── main.jsx
|
|
|
|
|
│ ├── App.jsx
|
|
|
|
|
│ ├── index.css
|
|
|
|
|
│ ├── api/
|
|
|
|
|
│ │ └── parcels.js # API 클라이언트 함수
|
|
|
|
|
│ ├── components/
|
|
|
|
|
│ │ ├── ParcelForm.jsx # 운송장 등록 폼
|
|
|
|
|
│ │ ├── ParcelList.jsx # 택배 목록
|
|
|
|
|
│ │ ├── ParcelCard.jsx # 개별 택배 카드
|
|
|
|
|
│ │ ├── TrackingTimeline.jsx # 배송 추적 타임라인
|
|
|
|
|
│ │ └── CarrierSelect.jsx # 택배사 선택 드롭다운
|
|
|
|
|
│ └── stores/
|
|
|
|
|
│ └── useParcelStore.js # Zustand 상태관리
|
|
|
|
|
│
|
|
|
|
|
└── backend/
|
|
|
|
|
├── Dockerfile
|
|
|
|
|
├── package.json
|
|
|
|
|
└── src/
|
|
|
|
|
├── server.js # 진입점
|
|
|
|
|
├── app.js # Fastify 앱 빌드
|
|
|
|
|
├── config/
|
|
|
|
|
│ └── index.js # 환경변수 설정
|
|
|
|
|
├── plugins/
|
|
|
|
|
│ ├── db.js # MySQL2 연결
|
|
|
|
|
│ └── tracker.js # delivery-tracker GraphQL 클라이언트
|
|
|
|
|
├── routes/
|
|
|
|
|
│ ├── index.js # 라우트 통합
|
|
|
|
|
│ ├── parcels.js # CRUD + 조회 라우트
|
|
|
|
|
│ └── carriers.js # 택배사 목록 라우트
|
|
|
|
|
├── services/
|
|
|
|
|
│ ├── parcel.js # 택배 비즈니스 로직
|
|
|
|
|
│ ├── tracker.js # delivery-tracker API 호출
|
|
|
|
|
│ ├── cron.js # 자동갱신 스케줄러
|
|
|
|
|
│ └── notification.js # 알림 서비스 (Discord/Telegram webhook)
|
|
|
|
|
└── utils/
|
|
|
|
|
└── error.js # 에러 처리
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 데이터베이스 스키마
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
CREATE TABLE parcels (
|
|
|
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
carrier_id VARCHAR(50) NOT NULL, -- 택배사 코드
|
|
|
|
|
carrier_name VARCHAR(100) NOT NULL, -- 택배사 이름
|
|
|
|
|
tracking_number VARCHAR(100) NOT NULL, -- 운송장 번호
|
|
|
|
|
label VARCHAR(200), -- 사용자 별칭
|
|
|
|
|
status VARCHAR(50) DEFAULT 'pending', -- 배송 상태
|
|
|
|
|
last_detail TEXT, -- 최근 배송 상세 (JSON)
|
|
|
|
|
last_checked_at DATETIME, -- 마지막 조회 시각
|
|
|
|
|
delivered_at DATETIME, -- 배송 완료 시각
|
|
|
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
|
|
UNIQUE KEY uq_carrier_tracking (carrier_id, tracking_number)
|
|
|
|
|
);
|
|
|
|
|
|
2026-03-24 14:03:49 +09:00
|
|
|
CREATE TABLE carriers (
|
2026-03-24 18:57:42 +09:00
|
|
|
id VARCHAR(50) PRIMARY KEY, -- 택배사 코드 (예: cjlogistics)
|
2026-03-24 14:03:49 +09:00
|
|
|
name VARCHAR(100) NOT NULL, -- 택배사 이름
|
|
|
|
|
short_name VARCHAR(20) NOT NULL, -- 약칭 (로고 없을 때 이니셜용)
|
|
|
|
|
color VARCHAR(7) NOT NULL, -- 브랜드 컬러 (#hex)
|
|
|
|
|
logo_url VARCHAR(500), -- RustFS에 저장된 로고 이미지 URL
|
|
|
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
|
|
|
);
|
|
|
|
|
|
2026-03-24 18:57:42 +09:00
|
|
|
-- 기본 택배사 데이터 (5개)
|
|
|
|
|
-- | id | name | logo_url |
|
|
|
|
|
-- |--------------|------------|------------------------------------------------|
|
|
|
|
|
-- | cjlogistics | CJ대한통운 | https://s3.caadiq.co.kr/traeon/logo/cjlogistics.svg |
|
|
|
|
|
-- | hanjin | 한진택배 | https://s3.caadiq.co.kr/traeon/logo/hanjin.svg |
|
|
|
|
|
-- | lotte | 롯데택배 | https://s3.caadiq.co.kr/traeon/logo/lotte.svg |
|
|
|
|
|
-- | epost | 우체국택배 | https://s3.caadiq.co.kr/traeon/logo/epost.svg |
|
|
|
|
|
-- | logen | 로젠택배 | https://s3.caadiq.co.kr/traeon/logo/logen.svg |
|
|
|
|
|
|
2026-03-24 13:17:16 +09:00
|
|
|
CREATE TABLE tracking_events (
|
|
|
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
parcel_id INT NOT NULL,
|
|
|
|
|
status VARCHAR(50),
|
|
|
|
|
description TEXT,
|
|
|
|
|
location VARCHAR(200),
|
|
|
|
|
event_time DATETIME,
|
|
|
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
FOREIGN KEY (parcel_id) REFERENCES parcels(id) ON DELETE CASCADE
|
|
|
|
|
);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## API 설계
|
|
|
|
|
|
|
|
|
|
| Method | Path | 설명 |
|
|
|
|
|
|--------|------|------|
|
|
|
|
|
| `GET` | `/api/parcels` | 전체 택배 목록 (상태별 필터) |
|
|
|
|
|
| `POST` | `/api/parcels` | 운송장 등록 |
|
|
|
|
|
| `GET` | `/api/parcels/:id` | 개별 택배 상세 + 추적 이벤트 |
|
|
|
|
|
| `PUT` | `/api/parcels/:id` | 별칭 수정 |
|
|
|
|
|
| `DELETE` | `/api/parcels/:id` | 운송장 삭제 |
|
|
|
|
|
| `POST` | `/api/parcels/:id/refresh` | 수동 새로고침 |
|
2026-03-24 14:03:49 +09:00
|
|
|
| `GET` | `/api/carriers` | 지원 택배사 목록 (로고 URL 포함) |
|
2026-03-24 13:17:16 +09:00
|
|
|
|
|
|
|
|
## 구현 단계
|
|
|
|
|
|
2026-03-24 18:57:42 +09:00
|
|
|
### 1단계: 프로젝트 초기 세팅 ✅
|
2026-03-24 13:17:16 +09:00
|
|
|
|
2026-03-24 18:57:42 +09:00
|
|
|
- [x] `docker-compose.yml` 작성
|
2026-03-24 13:17:16 +09:00
|
|
|
- `traeon-frontend`: node:20-alpine, 포트 80, 네트워크 `app`
|
|
|
|
|
- `traeon-backend`: node:20-alpine, 포트 80, 네트워크 `app` + `db`
|
|
|
|
|
- `delivery-tracker`: 셀프호스팅 컨테이너, 네트워크 `app`
|
|
|
|
|
- Watchtower 제외 레이블
|
2026-03-24 18:57:42 +09:00
|
|
|
- [x] `.env` 파일 작성 (DB 접속정보 등)
|
|
|
|
|
- [x] Caddy에 `traeon.caadiq.co.kr` 도메인 추가
|
|
|
|
|
|
|
|
|
|
### 2단계: Frontend 구현 (더미 데이터) ✅
|
|
|
|
|
|
|
|
|
|
- [x] Vite + React + Tailwind 초기 세팅
|
|
|
|
|
- [x] 더미 데이터 준비 (택배사 목록, 배송 중/완료 샘플 데이터)
|
|
|
|
|
- [x] 메인 페이지
|
|
|
|
|
- 운송장 등록 폼 (커스텀 드롭다운 + 택배사 로고 + 운송장 번호 + 별칭)
|
|
|
|
|
- 택배 목록 (카드형, 필터 탭으로 배송중/완료 구분)
|
|
|
|
|
- 각 카드에 택배사 로고, 현재 상태, 등록일 표시
|
|
|
|
|
- [x] 상세 페이지
|
2026-03-24 13:17:16 +09:00
|
|
|
- 배송 추적 타임라인 (세로 타임라인 UI)
|
2026-03-24 18:57:42 +09:00
|
|
|
- 수동 새로고침 버튼 (상단 배치)
|
|
|
|
|
- 삭제/수정 기능 (제목 옆 아이콘)
|
|
|
|
|
- [x] Zustand로 UI 상태 관리 (필터, 정렬)
|
|
|
|
|
- [x] framer-motion 애니메이션 적용
|
|
|
|
|
- [x] PC/모바일 반응형 대응 (lg 브레이크포인트)
|
|
|
|
|
- [x] SVG 파비콘 로고 추가
|
|
|
|
|
- [x] Pretendard 폰트 적용
|
2026-03-24 14:03:49 +09:00
|
|
|
|
|
|
|
|
### 3단계: Backend 구현 + 연동
|
|
|
|
|
|
2026-03-24 18:57:42 +09:00
|
|
|
- [x] Fastify 앱 세팅 (app.js, server.js) — fromis_9 패턴
|
|
|
|
|
- [x] DB 플러그인 + 테이블 자동 생성 (parcels, tracking_events, carriers)
|
|
|
|
|
- [x] 기본 택배사 5개 데이터 자동 삽입 (CJ대한통운, 한진, 롯데, 우체국, 로젠)
|
|
|
|
|
- [x] 택배사 로고 SVG를 RustFS에 업로드하고 carriers 테이블에 logo_url 저장
|
|
|
|
|
- [x] delivery-tracker 셀프호스팅 (Docker 이미지 빌드, Apollo Server 포트 4000)
|
|
|
|
|
- [x] delivery-tracker GraphQL 클라이언트 플러그인 (tracker.js)
|
|
|
|
|
- [x] API 라우트 구현 (parcels CRUD + carriers 목록 + 수동 새로고침)
|
2026-03-24 19:36:40 +09:00
|
|
|
- [x] Frontend를 더미 데이터에서 실제 API로 전환
|
2026-03-24 14:03:49 +09:00
|
|
|
- Vite 프록시 설정 (`/api/` → backend)
|
2026-03-24 19:36:40 +09:00
|
|
|
- React Query로 데이터 페칭 (택배 목록, 상세, 택배사 목록)
|
|
|
|
|
- 등록/수정/삭제/새로고침 mutation + 캐시 무효화
|
|
|
|
|
- 택배사 로고를 RustFS URL에서 로드
|
2026-03-24 14:03:49 +09:00
|
|
|
- [ ] 자동갱신 cron 서비스 (node-cron)
|
|
|
|
|
- 배송 중인 택배: 30분 간격 자동 조회
|
|
|
|
|
- 배송 완료된 택배: 조회 중단
|
|
|
|
|
- 상태 변경 감지 시 알림 트리거
|
|
|
|
|
- [ ] 알림 서비스
|
|
|
|
|
- Discord Webhook 또는 Telegram Bot API
|
|
|
|
|
- 설정 가능한 Webhook URL (.env)
|
2026-03-24 13:17:16 +09:00
|
|
|
|
|
|
|
|
### 4단계: Docker 배포
|
|
|
|
|
|
|
|
|
|
- [ ] Frontend Dockerfile (node:20-alpine, 개발모드)
|
|
|
|
|
- [ ] Backend Dockerfile (node:20-alpine, 개발모드)
|
|
|
|
|
- [ ] `docker compose up -d --build` 로 실행 확인
|
|
|
|
|
- [ ] Caddy 리버스 프록시 설정 확인
|
|
|
|
|
|
|
|
|
|
## delivery-tracker 셀프호스팅 연동
|
|
|
|
|
|
|
|
|
|
delivery-tracker는 GraphQL API를 제공한다. Backend에서 GraphQL 쿼리로 배송 정보를 조회:
|
|
|
|
|
|
|
|
|
|
```graphql
|
|
|
|
|
query Track($carrierId: ID!, $trackingNumber: String!) {
|
|
|
|
|
track(carrierId: $carrierId, trackingNumber: $trackingNumber) {
|
|
|
|
|
lastEvent {
|
|
|
|
|
time { datetime }
|
|
|
|
|
status { code name }
|
|
|
|
|
description
|
|
|
|
|
}
|
|
|
|
|
events {
|
|
|
|
|
edges {
|
|
|
|
|
node {
|
|
|
|
|
time { datetime }
|
|
|
|
|
status { code name }
|
|
|
|
|
description
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 참조할 기존 파일
|
|
|
|
|
|
|
|
|
|
| 파일 | 용도 |
|
|
|
|
|
|------|------|
|
|
|
|
|
| `/docker/fromis_9/docker-compose.yml` | Docker 서비스 구성 패턴 |
|
|
|
|
|
| `/docker/fromis_9/frontend/vite.config.js` | Vite 프록시 설정 |
|
|
|
|
|
| `/docker/fromis_9/backend/src/app.js` | Fastify 플러그인 로드 패턴 |
|
|
|
|
|
| `/docker/fromis_9/backend/src/plugins/db.js` | MySQL2 연결 패턴 |
|
|
|
|
|
| `/docker/fromis_9/backend/src/routes/index.js` | 라우트 통합 패턴 |
|
|
|
|
|
| `/docker/fromis_9/backend/src/server.js` | 서버 진입점 패턴 |
|
|
|
|
|
| `/docker/caddy/Caddyfile` | Caddy 도메인 추가 위치 |
|
|
|
|
|
|
|
|
|
|
## 검증 방법
|
|
|
|
|
|
|
|
|
|
1. `docker compose up -d --build` 로 전체 서비스 기동
|
|
|
|
|
2. `docker compose logs -f` 로 에러 확인
|
|
|
|
|
3. 브라우저에서 `traeon.caadiq.co.kr` 접속, 운송장 등록/조회 테스트
|
|
|
|
|
4. cron 자동갱신 로그 확인
|
|
|
|
|
5. 알림 Webhook 수신 테스트
|