Pogun backend. Spring Boot 4 API server for missing-pet notices, shelter notices, community, DM, notifications, presence, admin console, and AI similarity workflows.
이 저장소는 Pogun 서비스 백엔드입니다.
주요 책임:
- Firebase Google / Apple 로그인 검증
- 사용자 온보딩, 프로필, 지역, 탈퇴 처리
- 실종 공고 / 보호소 공고 / 커뮤니티 CRUD 및 검색
- 공고 기반 1:1 DM 채팅 및 읽음 처리
- FCM 기반 앱 푸시 및 인앱 알림
- Redis 기반 presence 추적
- 관리자 세션, 권한, Passkey(WebAuthn) step-up
- AI 분석 결과 수신 및 유사 공고 연결
- 운영용 관리자 대시보드 / 트래픽 로그 / 알림 발송
핵심 특성:
- 영속 데이터: PostgreSQL
- 단기 상태 / presence / 캐시: Redis
- 인증 원천: Firebase ID Token
- 파일 저장: AWS S3
- 실시간 채팅: STOMP WebSocket (
/ws/chat) - 운영 배포: GitHub Actions -> Docker Hub -> EC2
This repository contains the Pogun backend.
Primary responsibilities:
- Verify Firebase Google / Apple sign-in
- Handle onboarding, profile, region, and account withdrawal
- Provide CRUD and search for missing-pet notices, shelter notices, and community posts
- Support notice-based 1:1 direct messaging with read receipts
- Deliver in-app notifications and FCM push
- Track user presence with Redis
- Manage admin session, permissions, and Passkey(WebAuthn) step-up
- Receive AI analysis results and connect similar notices
- Provide admin dashboard, traffic logs, and broadcast notification APIs
Core platform choices:
- Persistent storage: PostgreSQL
- Short-lived state / presence / cache: Redis
- Identity source: Firebase ID Token
- File storage: AWS S3
- Realtime chat: STOMP WebSocket (
/ws/chat) - Deployment path: GitHub Actions -> Docker Hub -> EC2
flowchart LR
UA["User App / Web"] --> BE["Spring Boot Backend"]
AF["Admin Frontend (pawgen)"] --> BE
ST["Local Static Test UI"] --> BE
BE --> DB["PostgreSQL"]
BE --> RD["Redis"]
BE --> FB["Firebase Auth / Admin SDK"]
BE --> S3["AWS S3"]
BE --> FCM["Firebase Cloud Messaging"]
BE --> KK["Kakao Local API"]
BE --> SH["Shelter Public API"]
BE --> AI["AI Analysis Caller / Callback"]
AF --> WA["Browser WebAuthn / Passkey"]
WA --> BE
- 일반 사용자 앱과 관리자 프론트는 같은 백엔드를 사용합니다.
- 일반 API는 Firebase 인증 기반입니다.
- 관리자 API는 Firebase 로그인 이후 백엔드 관리자 세션 + Passkey step-up을 사용합니다.
- 채팅은 WebSocket, 나머지 대부분은 REST API 중심입니다.
- Presence, 캐시, 일부 단기 상태는 Redis를 사용합니다.
- User clients and the admin frontend share the same backend.
- General APIs use Firebase-backed authentication.
- Admin APIs use Firebase sign-in followed by backend-issued admin session plus Passkey step-up.
- Chat uses WebSocket, while most other features use REST APIs.
- Presence, cache, and short-lived state are stored in Redis.
- Java 17
- Spring Boot 4
- Spring MVC
- Spring Security
- Spring Data JPA / Hibernate
- PostgreSQL
- Spring Data Redis
- Spring WebSocket + STOMP
- AWS SDK v2 S3
- Firebase Admin SDK
- Firebase Cloud Messaging
- Yubico
webauthn-server-core - Zalando Logbook
- springdoc OpenAPI / Swagger UI
- Bun + Playwright for browser E2E
기준 패키지: src/main/java/com/example/pogun
config- 보안, Firebase, S3, WebSocket, warmup, 인덱스 초기화, presence, 로깅
controller- REST / WebSocket 진입점
service- 핵심 비즈니스 로직
repository- JPA persistence
entity- DB 모델
dto- 요청 / 응답 스펙
주요 도메인:
auth,useradmin,adminauthmissingpetshelterpetcommunitynoticechatnotificationpresenceaistorage
-
인증 / 사용자
- Firebase ID Token 검증
- Pending social signup -> onboarding -> user 생성
- Google / Apple provider 동기화
-
관리자 콘솔
- 관리자 로그인
- 관리자 세션 발급 / 갱신
- Passkey 등록 / MFA / step-up
- 사용자 / 공고 / 신고 / 알림 / 트래픽 조회
-
실종 공고 / 보호소 공고
- 목록 / 상세 / 검색 / 작성 / 수정 / 삭제
- AI source / analysis result / similar notices
- 인덱스 및 캐시 기반 조회 최적화
-
커뮤니티
- 게시글 / 댓글 / 대댓글 / 좋아요 / 투표
- 관리자 상세 조회 지원
-
DM
- 공고 기반 1:1 채팅
- 실시간 메시지 전송
- 읽음 처리
- 이미지 메시지
- 오프라인 수신자에만 푸시
-
알림
- 인앱 알림 저장
- 읽음 / 전체 읽음
- FCM 토큰 관리
- 관리자 브로드캐스트
-
Presence
ONLINE / IDLE / OFFLINE- Redis session store
- stale session reconcile
-
Auth / User
- Firebase ID Token verification
- Pending social signup -> onboarding -> user creation
- Google / Apple provider synchronization
-
Admin Console
- Admin sign-in
- Admin session issue / refresh
- Passkey registration / MFA / step-up
- User / notice / report / notification / traffic inspection
-
Missing Pet / Shelter
- List / detail / search / create / update / delete
- AI source / analysis result / similar notices
- Index and cache based query optimization
-
Community
- Posts / comments / replies / likes / polls
- Admin detail inspection support
-
DM
- Notice-based 1:1 chat
- Realtime delivery
- Read receipts
- Image messages
- Push only for offline receivers
-
Notifications
- In-app notification persistence
- Read / read-all
- FCM token management
- Admin broadcast send
-
Presence
ONLINE / IDLE / OFFLINE- Redis-backed session store
- Stale-session reconciliation
- Client gets Firebase ID Token.
- Client calls
POST /api/auth/login. - Backend verifies token with Firebase.
- Backend returns:
- completed user session context, or
- pending onboarding state
- Admin frontend gets Firebase ID Token.
- Frontend calls
POST /api/admin/auth/login. - Backend verifies admin eligibility and email verification state.
- Backend returns next step:
- email verification required
- passkey registration required
- MFA / step-up required
- authenticated
- Backend issues admin session token after successful admin flow.
보안 경계:
/api/admin/auth/login: public entry/api/admin/auth/**:ROLE_ADMIN_CONSOLE/api/admin/**:ROLE_ADMIN- 일반
/api/**: Firebase 인증 필요
- Endpoint:
/ws/chat - Broker prefixes:
/topic,/queue - Application prefix:
/app - User prefix:
/user
- Client connects to
/ws/chat. - STOMP auth interceptor verifies Firebase token.
- Message send enters controller/service.
- Message persists in PostgreSQL.
- Backend fans out room/user updates through STOMP.
- Push notification goes through async event listener only when receiver is offline.
- REST heartbeat:
POST /api/presence/heartbeat - WebSocket activity also refreshes presence
- Redis stores active presence sessions
- Scheduler reconciles stale sessions
- Source of truth for users, notices, community, chat, notifications, admin data
- JPA / Hibernate with
ddl-auto: update - Query/index optimization applied in missing pet and community paths
- Presence session state
- Cache for selected read-heavy APIs
- Short-lived operational state
- Profile images
- Notice images
- Community images
- DM image uploads
- Firebase Auth / Admin SDK
- Firebase Cloud Messaging
- AWS S3
- Kakao Local API
- Shelter Public API
- AI callback / similarity pipeline
- Java 17
- Bun
- Docker / Docker Compose
- PostgreSQL / Redis connection via env
.env- shared runtime values
.env.local- local-only overrides
- 로컬 결제 검증 테스트는
SPRING_PROFILES_ACTIVE=local기준으로 진행합니다. application-local.yml이.env.local을 읽도록 구성되어 있습니다..env.local에 아래 값을 채우면 Apple Sandbox 검증 설정이 로컬 서버에 반영됩니다.APPLE_APP_STORE_ENABLED=trueAPPLE_APP_STORE_KEY_IDAPPLE_APP_STORE_ISSUER_IDAPPLE_APP_STORE_BUNDLE_IDAPPLE_APP_STORE_APP_APPLE_ID(production 서명 검증용 App Apple ID, sandbox에서는 비워둘 수 있음)APPLE_APP_STORE_PRIVATE_KEY_BASE64APPLE_APP_STORE_ENVIRONMENT=sandboxAPPLE_APP_STORE_APP_ACCOUNT_TOKEN_REQUIRED=false
- 테스트 순서:
- 로컬 서버 실행
- iOS Sandbox Tester 계정으로 결제 수행 (
appAccountToken에는 백엔드 사용자 UUID를 설정) - 앱/프론트에서 받은
transactionId또는signedTransactionInfo로 백엔드 결제 검증 API 호출 - 결제 적립 후 수동 AI 분석 요청 API 호출로 차감까지 확인
- Sandbox 결제는 실제 카드 과금이 발생하지 않는 테스트 흐름입니다.
- iOS 앱에서
appAccountToken전달이 안정화되면APPLE_APP_STORE_APP_ACCOUNT_TOKEN_REQUIRED=true로 전환해 결제를 현재 로그인 사용자에게 강제 바인딩합니다. - App Store Server Notifications V2 URL은
POST /api/payments/apple/notifications입니다. Apple의signedPayload를 검증한 뒤 환불/취소 알림은 구매 상태를REFUNDED또는REVOKED로 바꾸고 미사용 크레딧만 회수합니다.
./gradlew bootRun또는 Docker Compose:
docker compose up -d기본 헬스체크:
GET /health./gradlew test./gradlew bootJarbunx playwright test --config=playwright/playwright.config.ts또는 package script:
bun run playwright:test리포트:
bun run playwright:report파일: .github/workflows/deploy-ec2.yml
배포 흐름:
dev브랜치 push 또는 수동 실행- GitHub Actions가 checkout
- JDK 17 / Gradle cache 세팅
./gradlew test bootJar --build-cache --parallel- Docker image build + push
- 이전 SHA 태그 cleanup
- EC2에
docker-compose.yml업로드 - EC2
.env생성 docker compose pull- Redis 보장 후 app 재기동
/health통과 시 배포 완료
Deployment path:
- Push to
devor trigger workflow manually - GitHub Actions checks out code
- Sets up JDK 17 and Gradle cache
- Runs
./gradlew test bootJar --build-cache --parallel - Builds and pushes Docker image
- Cleans old SHA tags
- Uploads
docker-compose.ymlto EC2 - Writes runtime
.envon EC2 - Pulls fresh image
- Ensures Redis is healthy, then restarts app
- Finalizes deploy after
/healthpasses
- Multi-stage build
- Extracts layered Spring Boot jar
- Runs from slim Debian runtime
- Uses custom healthcheck + entrypoint scripts
- Excludes
static/**frombootJar
app- backend container
- env-driven port / startup opts
- depends on Redis health
redis- Redis 7 alpine
- optional password
- persistent volume
GET /health- Swagger / OpenAPI
- Zalando Logbook based admin traffic logging
- Admin traffic APIs
- Admin dashboard summary APIs
- Presence-derived admin user state inspection
아래 문서들이 세부 구현을 설명합니다.
- Backend Architecture
- DM WebSocket Integration Guide
- Admin User Presence
- Admin Traffic and Notification Guide
- Admin Traffic Polling Fix
- AI Similar Notices Flow
- Missing Pet Region Scope Guide
- Admin Community Post Detail
- Admin Feature
- Admin Fetch
코드 파악 순서:
src/main/java/com/example/pogun/DemoApplication.javasrc/main/resources/application.ymlsrc/main/java/com/example/pogun/config/security/SecurityConfig.javasrc/main/java/com/example/pogun/service/auth/AuthService.javasrc/main/java/com/example/pogun/service/adminauth/AdminAuthService.javasrc/main/java/com/example/pogun/service/missingpet/MissingPetService.javasrc/main/java/com/example/pogun/service/shelterpet/ShelterPetService.javasrc/main/java/com/example/pogun/service/community/CommunityService.javasrc/main/java/com/example/pogun/service/noticechat/NoticeChatService.javasrc/main/java/com/example/pogun/service/notification/NotificationService.javasrc/main/java/com/example/pogun/service/user/UserPresenceService.java.github/workflows/deploy-ec2.yml
- Main app profile: env-driven
- Admin Passkey runtime: enabled through backend config
- Static backend test pages: local/test usage, excluded from production bootJar
- Production deploy target: Docker on EC2