1. 한눈에 보기
SoccerGPS는 앱에서 1차 계산 → 서버에서 검증·재계산하는 2단 구조입니다. 네트워크가 끊겨도 앱이 로컬(Room DB)에 계속 기록하므로 경기 데이터가 유실되지 않습니다.
1수집Android · FusedLocation 1Hz
2로컬 저장Room DB (오프라인 대비)
3업로드HTTPS + JWT
4분석Lambda 재계산
5리포트DynamoDB + S3
2. 경기 기록 데이터 흐름
- 경기 시작 — 사용자가 앱에서 시작을 누르면 Foreground Service가 기동합니다. 화면이 꺼져도 수집이 유지됩니다.
- GPS 수집 —
FusedLocationProviderClient가 1초 간격으로 좌표를 수집하고 즉시 Room DB에 적재합니다. - 실시간 계산 — 앱이 누적 거리·현재 속도·스프린트 횟수를 계산해 즉시 표시합니다. 서버 왕복이 없어 지연이 없습니다.
- 업로드 — 경기 종료 시 트랙 배열을
POST /matches/{id}/track으로 한 번에 전송합니다. 실패하면 로컬 큐에 남겨 재전송합니다. - 서버 분석 — Lambda가 원본 트랙을 S3에 보관하고, 정확도 필터를 적용해 지표를 재계산한 뒤 요약을 DynamoDB에 저장합니다.
- 리포트 조회 — 앱이
GET /matches/{id}/analytics로 최종 지표와 히트맵을 받아 리포트를 렌더링합니다.
3. 구간별 통신 · 보안
| 구간 | 프로토콜 | 인증 · 보안 | 비고 |
|---|---|---|---|
| App ↔ API Gateway | HTTPS (REST/JSON) | TLS 1.2+, JWT Bearer | 모든 보호 라우트에 토큰 필수 |
| API Gateway ↔ Lambda | AWS 내부 호출 | IAM 리소스 정책 | 퍼블릭 노출 없음 |
| Lambda ↔ DynamoDB · S3 | AWS SDK (HTTPS) | IAM Role (최소권한) | 테이블·버킷 ARN 단위 제한 |
| Lambda ↔ Cognito | AWS SDK (HTTPS) | IAM Role | 회원가입·로그인 처리 |
| Browser ↔ 웹사이트 | HTTPS | CloudFront + ACM 인증서 | S3 직접 접근 차단(OAC) |
오프라인 내구성
업로드는 경기 종료 시점에 배치로 수행됩니다. 네트워크가 없으면 Room DB에 그대로 남아 있다가 연결이 복구될 때 재전송되므로, 경기장 통신 환경이 나빠도 데이터가 사라지지 않습니다.
4. 주요 API 엔드포인트
| 메서드 | 경로 | 인증 | 설명 |
|---|---|---|---|
| GET | /health | 공개 | 헬스체크 |
| POST | /auth/signup | 공개 | 회원가입 |
| POST | /auth/login | 공개 | 로그인 (JWT 발급) |
| POST | /matches | JWT | 경기 생성 |
| GET | /matches | JWT | 내 경기 이력 |
| POST | /matches/{id}/track | JWT | GPS 트랙 업로드 + 분석 |
| GET | /matches/{id}/analytics | JWT | 분석 결과 · 히트맵 |
| POST | /teams | JWT | 팀 생성 |
| GET | /teams/{id}/stats | JWT | 팀 통계 · 랭킹 |
5. 데이터 저장 구조
DynamoDB 단일 테이블 설계로 조회 패턴을 커버하고, 용량이 큰 원본 트랙은 S3로 분리해 저장 비용을 낮춥니다.
| PK | SK | 엔티티 | 주요 속성 |
|---|---|---|---|
USER#<userId> | PROFILE | 사용자 | email, name, weightKg |
USER#<userId> | MATCH#<matchId> | 경기 요약 | distance, maxSpeed, sprints |
MATCH#<matchId> | ANALYTICS | 분석 결과 | avgSpeed, heatmap(S3 키) |
TEAM#<teamId> | PROFILE | 팀 | name, ownerId, inviteCode |
TEAM#<teamId> | MEMBER#<userId> | 팀원 | role, joinedAt |
- 원본 트랙 경로:
s3://<bucket>/tracks/<matchId>.json— 30일 후 STANDARD_IA로 자동 전환 GSI1(GSI1PK=TEAM#<teamId>)로 팀 단위 랭킹·통계를 한 번의 Query로 조회- DynamoDB는 온디맨드 과금 → 유휴 시 비용이 발생하지 않음