본문으로 건너뛰기
김찬호

Find My Item

1차 MVP 완료 후 하차 (서비스 운영 중)

찾아줘

진행률100%
WebPWAiOS (예정)Android (예정)
2025.09 ~ 2026.06 (2차 MVP 전환 시점 하차)
6명 (백엔드 Lead, 3 BE + 3 FE)

프로젝트 설명

지도에서 분실물을 등록하고 주변 사람들과 실시간 채팅으로 소통하는 커뮤니티 서비스입니다. 백엔드 Lead로 Spring Boot 3.5 + JPA/QueryDSL 기반 API 설계, AWS EC2 단일 인스턴스에 dev/prod 컨테이너를 docker-compose로 이중화 운영하고, GitHub Actions → ECR → EC2 자동 배포 파이프라인과 Prometheus·Grafana·Loki 모니터링 스택을 구축했습니다. k8s(deployment/service) + ArgoCD GitOps 매니페스트까지 작성해 쿠버네티스 전환 준비를 마쳤습니다. 1차 MVP 출시·운영까지 백엔드를 이끌었고(전체 커밋의 약 54%인 707개, PR 161개 작성), 2차 MVP 전환 시점(2026.06)에 하차했습니다.

  • 단일 EC2 인스턴스 위에 dev(8081) / prod(8080) Spring Boot 컨테이너 + Redis + Alloy(log shipper)를 docker-compose로 이중화 — 같은 이미지에 SPRING_PROFILES_ACTIVE만 바꿔 운영/개발 병행
  • GitHub Actions CI/CD: develop push → Gradle 빌드 → Docker 이미지 ECR 푸시(커밋 SHA + latest 이중 태깅) → EC2 SSH appleboy/ssh-action으로 docker compose pull/up -d 무중단 배포, concurrency group으로 중복 배포 차단
  • 모니터링 스택: Micrometer + Prometheus(9090) 메트릭 수집, Grafana(3000) 대시보드, Grafana Alloy가 컨테이너 로그를 Loki(3100)로 집계 — 15d retention + structured logging (logstash-logback-encoder)
  • k8s 매니페스트(Deployment + Service ClusterIP)와 ArgoCD Application(자동 sync + prune + selfHeal + CreateNamespace) 작성 — develop 브랜치 k8s/ 경로를 GitHub에서 선언적으로 추적
  • Web Push(VAPID) 직접 구현: nl.martijndwars:web-push + BouncyCastle로 브라우저 푸시 구독/발송, PWA 백그라운드 알림 지원
  • 21개 도메인 모듈화(post/chatroom/chatmessage/notification/report/user/auth/admin/map 등) + Flyway V1~V6 마이그레이션(풀텍스트 인덱스, 채팅방 스냅샷 컬럼, 푸시 구독 테이블, 썸네일 URL 컬럼)
  • 이미지 썸네일 파이프라인: 업로드 시 썸네일 생성 → S3 저장, 목록 조회는 썸네일 URL 응답(없으면 원본 폴백), 게시물 삭제 시 썸네일 동반 삭제 — 목록 로딩 트래픽 절감
  • SSE(SseEmitter) 인앱 실시간 알림 + Web Push 백그라운드 알림 이원화, 회원 탈퇴 시 카카오 연결 끊기·7일 경과 재가입 재활성화 등 계정 라이프사이클 플로우 구현
  • Git Flow + PR 리뷰 게이트(review-gate.yml) + PR 리뷰 리마인더 자동화, Conventional Commits 컨벤션 팀 표준화

기술 스택

Spring Boot 3.5.5Java 17Spring Security + JWTSpring Data JPAQueryDSLSpring WebSocket (STOMP)Web Push (VAPID)FlywayMySQL 8Redis 7Next.js 15TypeScriptStorybookPlaywrightAWS EC2AWS ECRAWS RDSAWS S3Docker ComposeGitHub ActionsKubernetesArgoCDPrometheusGrafanaLokiGrafana AlloyKakao OAuthSlack Webhook

아키텍처

사용자 (Web / PWA)
  │
  ▼
Vercel — Next.js 15 Frontend
  ├─ www.finditem.kr (운영, main)
  └─ fmi-fe.vercel.app (개발, develop)
  │  지도 / 실시간 채팅(STOMP) / Web Push 구독 / Kakao OAuth
  │
  ▼  HTTPS · WSS
AWS EC2 (ap-northeast-2, ubuntu)
  └─ docker-compose.yml
       ├─ fmi-prod  :8080  (SPRING_PROFILES_ACTIVE=prod, ECR latest)
       ├─ fmi-dev   :8081  (SPRING_PROFILES_ACTIVE=dev,  ECR latest)
       ├─ redis     :6379  (세션/채팅 pub-sub, AOF persistence)
       └─ alloy            (Docker 소켓 → 컨테이너 로그 → Loki)
  │
  ├─ AWS RDS MySQL 8   (Flyway V1~V6 마이그레이션)
  ├─ AWS S3            (fmi-project-s3-bucket, 이미지 업로드)
  └─ AWS ECR           (fmi-backend:<git-sha> + :latest)

CI/CD — GitHub Actions (.github/workflows/ci-cd.yml)
  develop push → ci(Gradle bootJar) → deploy
    → AWS 인증(configure-aws-credentials)
    → ECR login → docker build + push (SHA + latest)
    → appleboy/ssh-action → EC2에서 docker compose pull/up -d
    → docker image prune (이전 이미지 정리)

Monitoring (monitoring/docker-compose.yml, 별도 stack)
  Spring Actuator /prometheus  ──▶  Prometheus (15d retention)
  컨테이너 stdout  ──▶  Alloy  ──▶  Loki  ──▶  Grafana 통합 대시보드

GitOps (k8s/, argocd/ — 전환 준비)
  ArgoCD Application → GitHub(k8s/) auto-sync (prune + selfHeal)
    ├─ Deployment(ghcr.io/find-my-item/fmi-be:latest)
    │   readiness /actuator/health/readiness
    │   liveness  /actuator/health/liveness
    └─ Service ClusterIP :80 → :8080

AWS EC2 단일 인스턴스 위에 Docker Compose로 Redis + Spring Boot(prod/dev 동시 운영) + Grafana Alloy(로그 수집기)를 오케스트레이션하는 2-tier 아키텍처입니다. GitHub Actions가 develop push를 감지해 Gradle 빌드 → ECR 푸시 → EC2 SSH로 docker compose pull/up 무중단 배포를 수행합니다. Spring Actuator가 노출하는 /prometheus 메트릭을 Prometheus가 스크랩하고, Alloy가 Docker 소켓을 통해 컨테이너 stdout을 Loki로 전달해 Grafana 단일 대시보드에서 메트릭·로그를 통합 조회합니다. Kubernetes Deployment/Service 매니페스트와 ArgoCD Application(auto-sync + selfHeal + prune)도 리포지토리에 포함해, 트래픽 증가 시 k8s로 즉시 GitOps 전환할 수 있도록 준비해두었습니다.

주요 기능

지도 기반 분실물 등록/검색

분실·습득 위치를 지도 핀으로 등록하고, 반경 기반으로 주변 게시물을 탐색. QueryDSL로 복합 필터(기간/카테고리/지역) 동적 쿼리 구성

WebSocket 실시간 채팅

Spring WebSocket(STOMP) + Redis pub/sub으로 분실물 등록자와 발견자 간 1:1 채팅. wss://www.finditem.kr/ws 엔드포인트로 프로덕션 트래픽 처리

SSE + Web Push 알림 이원화

앱 사용 중에는 SSE(SseEmitter) 스트림으로 인앱 실시간 알림, 백그라운드에서는 Web Push(VAPID)로 푸시. nl.martijndwars:web-push + BouncyCastle로 VAPID 키페어 발급/서명, 알림 생성 시 Web Push 발송 자동 연동

이미지 썸네일 파이프라인

이미지 업로드 시 썸네일을 생성해 S3에 원본과 함께 저장. 목록 조회 응답은 썸네일 URL 우선(없으면 원본 폴백), 게시물 삭제 시 썸네일까지 정리해 스토리지·목록 로딩 트래픽 절감

회원 탈퇴·재가입 플로우

탈퇴 시 카카오 연결 끊기(Admin Key) 처리, 7일 경과 탈퇴 유저 재가입 시 계정 재활성화, 약관 동의 API(PATCH /users/me/terms) 분리, 심사용 테스트 계정 재가입 제한 면제

dev/prod 컨테이너 이중화

같은 EC2 인스턴스에 동일 ECR 이미지로 fmi-prod(8080) + fmi-dev(8081) 컨테이너를 동시 기동. SPRING_PROFILES_ACTIVE와 DB 커넥션만 분기해 운영 영향 없이 dev 실환경 검증

GitHub Actions → ECR → EC2 CI/CD

develop push 시 Gradle 빌드 → Docker 이미지를 커밋 SHA + latest 이중 태깅으로 ECR 푸시 → EC2 SSH로 docker compose pull/up -d 수행. concurrency group으로 동시 배포 차단, 25분 타임아웃

Prometheus + Grafana + Loki 모니터링

Micrometer로 Spring Actuator /prometheus 메트릭 노출, Prometheus(15d retention)가 스크랩. Grafana Alloy가 Docker 로그를 Loki로 전달해 Grafana 단일 대시보드에서 메트릭·로그 통합 조회

k8s + ArgoCD GitOps 준비

Deployment(readiness/liveness probe + replicas) + Service(ClusterIP) 매니페스트와 ArgoCD Application(auto-sync + prune + selfHeal)을 리포지토리에 포함. GitHub k8s/ 경로 변경 시 즉시 선언적 배포 전환 가능

Flyway 스키마 마이그레이션

V1__init → V6__add_post_image_thumbnail_url까지 6단계 버전 관리. 풀텍스트 인덱스, 게시물 soft delete, 채팅방 스냅샷 컬럼, 푸시 구독 테이블, 썸네일 URL 컬럼을 순차 적용. baseline-on-migrate로 기존 DB 호환

Kakao OAuth 3-환경 분리

dev / release / prod 각각의 Kakao REST API Key + Redirect URI를 GitHub Secrets로 주입해 환경별 OAuth 앱 분리. JWT + HttpOnly 쿠키 세션, 요청 Origin 기준 쿠키 Domain 동적 설정으로 서브도메인(릴리즈 환경) 대응

21개 도메인 모듈 구조

post / chatroom / chatmessage / notification / report / inquiry / user / auth / admin / ipblock / userblock / notice / comment 등 기능별 도메인 패키지 분리. 도메인 내부에서 controller/service/repository/dto 계층화

보안 · 운영 기능

JWT 기반 인증 + Spring Security 필터, IP 차단(ipblock) · 유저 차단(userblock) · 금칙어 필터(banned-words.txt), Slack Webhook으로 문의·신고 실시간 알림

Git Flow + 리뷰 게이트

develop 기반 feature/#N 브랜치 전략, main/develop 직접 push 금지, PR 리뷰 게이트 워크플로우(review-gate.yml) + 리뷰 미완료 PR 리마인더 자동 발송

Storybook + Playwright E2E

FE에서 Storybook으로 컴포넌트 문서화(Chromatic 호스팅), Playwright로 핵심 사용자 시나리오(등록/검색/채팅) 자동화 테스트

기능

#지도 기반 등록/검색#WebSocket 실시간 채팅#SSE + Web Push(VAPID) 알림#이미지 썸네일 파이프라인#Kakao OAuth 로그인#dev/prod 컨테이너 이중화#ECR + GitHub Actions CI/CD#Prometheus + Grafana + Loki 모니터링#k8s + ArgoCD (GitOps 준비)#Flyway 스키마 버전 관리#QueryDSL 동적 쿼리#Storybook + Playwright E2E#6인 팀 · 백엔드 Lead
Find My Item (찾아줘) 스크린샷
Find My Item (찾아줘) 아이콘