이설아seola12e
전체 프로젝트
PROJECT 02북마크 · 검색팀 프로젝트 (Leets 5기)

INSIGHT BOX

정보는 기억하지만 어디에 저장했는지는 잊어버리는 문제에서 출발해, 맥락 기록 · 리마인드 · 검색으로 저장한 콘텐츠를 다시 찾도록 돕는 북마크 서비스

PERIOD
2025.06.17 — 2025.08.07 (약 7주)
TEAM
10인 (BE 4 · FE 4 · 디자인 2)
ROLE
카카오 로그인 · JWT 인증 · 카테고리/태그 · 회원 관리
LINKS
GitHub
INSIGHT BOX 홈 화면 — 검색 중심 홈, 직관적 카테고리, 최근 저장 콘텐츠

01프로젝트 개요

유튜브 · 블로그 · 노션 등에 흩어진 자기계발 콘텐츠를 저장해 두고도, 어디에 저장했는지 몰라 다시 찾지 못하는 문제를 인터뷰와 설문으로 확인하고 기획한 서비스입니다. 링크를 저장할 때 카테고리 · 태그 · 메모로 맥락을 남기고, 카카오톡 알림으로 다시 보도록 리마인드하며, 제목 · 태그 · 플랫폼 필터 검색으로 저장한 콘텐츠를 되찾을 수 있습니다. 저는 백엔드에서 카카오 소셜 로그인과 JWT 인증, 카테고리 · 태그 도메인, 회원 관리를 맡았습니다. 서비스를 배포까지 마쳤고, Leets 5기 프로젝트 3팀 중 운영진 평가 1위를 받았습니다.

GOAL 1‘맥락’ 기록으로 저장하기 — 카테고리 · 태그 · 메모
GOAL 2리마인드로 기억 굳히기 — 카카오톡 알림
GOAL 3검색 최적화로 기억 되찾기 — 제목 · 태그 · 플랫폼 필터

02담당 역할

카카오 소셜 로그인인가 코드 기반 카카오 로그인 API를 구현해 카카오 토큰 발급 · 사용자 정보 조회 · 회원 저장 후 JWT를 발급하고, 배포 · 로컬 환경별 Redirect URI를 요청 파라미터로 받도록 개선
JWT 인증 · 재발급JWT 인증 필터와 Stateless Security 설정, Refresh Token 소유자 검증 후 재발급(만료가 가까울 때만 Refresh Token 교체), 토큰 만료 시 401을 반환하는 인증 예외 처리
카테고리 · 태그카테고리 · 태그 CRUD와 생성 개수 제한(사용자당 카테고리 15개 · 카테고리당 태그 10개), 카테고리 조회 시 최근 썸네일 3개 · 사용 플랫폼 반환, 북마크와 얽힌 삭제 정책 설계
회원 관리닉네임 변경, 회원 탈퇴(ACTIVE · DELETED 상태 관리, 카카오 연결 끊기, 토큰 삭제), 사용자가 저장한 플랫폼 목록 조회 API

03기술 스택

Spring SecurityJWT 인증 필터를 필터 체인에 추가하고 세션을 Stateless로 설정. 인증 실패 시 기본 403 대신 AuthenticationEntryPoint로 401을 내려, 클라이언트가 토큰 재발급 흐름을 탈 수 있도록 함
JWTAccess · Refresh Token을 분리하고 Refresh Token을 DB에 저장해 요청 토큰이 해당 사용자의 것인지 검증. 남은 유효 기간이 기준보다 짧을 때만 Refresh Token을 함께 재발급
Kakao OAuth2프론트에서 받은 인가 코드로 서버가 카카오 토큰과 사용자 정보를 조회하는 방식. 카카오 토큰은 알림 발송에도 쓰여 DB에 보관하고, 탈퇴 시 카카오 연결 끊기(unlink)까지 처리
MySQLAmazon RDS(MySQL)에서 카테고리 · 태그 · 북마크 · 북마크-태그 매핑 관계를 관리. 삭제 정책에 맞춰 매핑 테이블까지 함께 정리
Java 21Spring Boot 3.5Spring Data JPAQueryDSLSwaggerDockerGitHub ActionsAWS EC2 · RDSAmazon S3

04시스템 아키텍처

인증 흐름. 카카오 인가 코드로 로그인하면 서버가 카카오 토큰 · 사용자 정보를 조회하고 JWT를 발급합니다. 이후 요청은 JWT 필터가 검증하고, 만료 시 401을 받은 클라이언트가 Refresh Token으로 재발급을 요청합니다.
INSIGHT BOX 백엔드 아키텍처 — Route 53, EC2(Caddy · Let's Encrypt), Spring Boot, FastAPI, Amazon RDS(MySQL), S3, Kakao OAuth2, GitHub Actions와 Docker Hub
백엔드 전체 구성 (팀 공동, 최종 발표 자료). Route 53 → EC2의 Caddy(Let's Encrypt HTTPS)를 거쳐 Spring Boot 서버와 링크 미리보기용 FastAPI 서버로 연결되고, GitHub Actions → Docker Hub로 이미지를 배포합니다.

05주요 구현 기능

5.1

인가 코드 기반 카카오 로그인

프론트엔드가 카카오 인증 후 받은 인가 코드와 Redirect URI를 GET /api/v1/auth/login/kakao로 전달하면, 서버가 카카오 토큰 발급 → 사용자 정보 조회 → 회원 저장(최초 로그인 시 가입) → JWT 발급을 하나의 트랜잭션에서 처리하고 토큰을 응답 body로 반환합니다. 재로그인 시에는 사용자가 바꾼 닉네임을 카카오 닉네임으로 덮어쓰지 않도록 했습니다.

5.2

Refresh Token 소유자 검증과 조건부 재발급

Refresh Token의 서명 · 만료를 검증한 뒤, DB에 저장된 사용자의 Refresh Token과 일치하는지 확인합니다. Access Token은 매번 새로 발급하고, Refresh Token은 남은 유효 기간이 설정한 기준보다 짧을 때만 교체해 DB에 갱신합니다.

if (shouldReissueRefreshToken(refreshTokenRemainingTime)) {
    String reissuedRefreshToken = jwtProvider.createRefreshToken(user);
    user.updateJwtTokens(reissuedAccessToken, reissuedRefreshToken);
} else {
    user.updateJwtAccessToken(reissuedAccessToken);
}
5.3

북마크를 고려한 카테고리 · 태그 삭제 정책

처음에는 북마크가 있으면 카테고리 · 태그를 삭제할 수 없게 했지만, 사용 흐름에 맞춰 정책을 바꿨습니다. 카테고리를 삭제하면 하위 태그 · 북마크 · 북마크-태그 매핑을 함께 삭제하고, 태그는 어떤 북마크의 유일한 태그일 때만 삭제를 막아 북마크가 태그 없이 남지 않도록 했습니다.

06트러블슈팅

ISSUE 01

프론트 연동 시 카카오 로그인 리다이렉트 문제

문제
프론트엔드와 연동하자 카카오 로그인 후 리다이렉트가 맞지 않아 로그인 결과(JWT)를 프론트에서 받지 못했고, 배포 이후에는 로컬과 배포 환경의 Redirect URI가 서로 달라 한쪽에서 로그인이 실패했음
원인
서버의 OAuth2SuccessHandler가 로그인 성공 이후 리다이렉트까지 처리하는 구조였고, 카카오 Redirect URI도 서버 설정에 하나로 고정되어 있었음
해결
Handler를 제거하고 프론트가 받은 인가 코드로 로그인하는 API를 추가해 JWT를 응답 body로 반환. 이후 Redirect URI도 요청 파라미터로 받아 카카오 토큰 요청에 그대로 사용하도록 변경
결과
포트 3000 · 8000 등 서로 다른 Redirect URI 환경에서 같은 API로 로그인 확인 · 등록되지 않은 Redirect URI는 카카오 서버가 거부
ISSUE 02

토큰 만료 시 401이 아닌 403이 반환되는 문제

문제
Access Token이 만료된 뒤 API를 호출하면 403이 반환되어 클라이언트가 재발급이 필요한 상황인지 구분할 수 없었고, 토큰 재발급 API 호출도 오류가 났음
원인
Spring Security에 인증 실패 처리(AuthenticationEntryPoint)를 지정하지 않아 기본 403이 내려갔고, 재발급 API가 permitAll 경로에 빠져 있어 만료된 토큰으로는 접근할 수 없었음
해결
SecurityConfig에 exceptionHandling().authenticationEntryPoint()를 추가해 인증 실패 시 401과 에러 코드를 반환하고, 로그인 · 토큰 재발급 API를 permitAll에 추가
결과
토큰 만료 → 401 → 재발급 → 재요청으로 이어지는 인증 흐름 정상화

07회고

KEEP · 잘한 점

PR마다 작업 내용과 Swagger · DB 테스트 결과를 함께 남겨, 프론트엔드와 백엔드 팀원 모두 변경 사항을 빠르게 확인할 수 있었습니다. 카테고리 · 태그 삭제 정책처럼 기획이 바뀐 부분도 테스트 케이스를 붙여 공유하며 맞춰 갔습니다.

PROBLEM · 아쉬운 점

인증 흐름을 서버 기준으로만 먼저 설계해, 프론트엔드와 연동하는 단계에서야 로그인 리다이렉트 · 403 반환 · 재발급 API 접근 같은 문제를 발견했고 마감 직전에 수정이 몰렸습니다. 회원 상태 필드처럼 스키마가 바뀔 때 기존 데이터를 수동으로 맞춰야 했던 점도 아쉬웠습니다.

TRY · 다음에는

로그인 · 토큰 만료 · 재발급처럼 클라이언트와 맞물리는 흐름은 설계 단계에서 응답 형식과 상태 코드까지 먼저 합의하고, Security 설정을 포함한 인증 흐름을 통합 테스트로 검증해 보고 싶습니다. 스키마 변경도 마이그레이션 도구로 이력을 관리해 보고 싶습니다.