티스토리 뷰
✏️ 큐시즘 33기 밋업 프로젝트 - 세모산(SEMOSAN)
큐시즘 33기 밋업 프로젝트에서 세모산(SEMOSAN) 백엔드 개발자로 참여했다.
세모산은 사용자가 산과 등산 코스를 탐색하고, 자신의 등산 기록을 남기며, 커뮤니티를 통해 경험을 공유할 수 있도록 돕는 서비스다. 단순히 산 정보를 보여주는 것을 넘어 트래킹, 기록, 좋아요, 알림, 커뮤니티 기능까지 포함한 등산 경험 기반 서비스로 기획되었다. 나는 이번 프로젝트에서 Spring Boot 기반 백엔드 개발을 맡았고, 인증/유저, 산/코스, 등산 기록, 푸시 알림, 커뮤니티 일부 기능과 운영 안정화 작업을 담당했다.
✏️ 맡았던 역할
- 첫 번째는 인증과 유저 기능이다. 소셜 로그인, 카카오 로그인 방식 개선, 로그아웃, 마이페이지, 유저 프로필 조회, 랜덤 닉네임 생성, 온보딩 검증, 회원탈퇴 로직 등을 구현했다.
- 두 번째는 산과 등산 기록 관련 기능이다. 산 정보 조회, 등산 기록, 트래킹 세션, 산별 등산 기록 목록, 코스 좋아요, 유저 레벨 기반 산 추천 로직, 트래킹 안내 난이도 후기 등록 등을 개발했다.
- 세 번째는 커뮤니티와 세모피드 기능이다. 자유게시판 신고 및 차단, 댓글/대댓글 알림, 게시글 좋아요 여부 응답, 세모피드 이모지 반응, 세모피드 이모지 알림 등을 구현했다.
- 마지막은 알림과 운영 안정화 작업이다. FCM 기반 푸시 알림, iOS APNs 설정, TestFlight 환경 푸시 대응, Discord 서버 에러 알림, Flyway 적용, DB 제약 조건 수정, 회원탈퇴 시 FK 제약 위반 해결 등을 맡았다.
- 처음에는 기능을 하나씩 구현하는 것이 주된 목표였지만, 프로젝트가 진행될수록 단순 구현보다 실제로 서비스가 문제없이 동작하게 만드는 것이 훨씬 중요하다는 것을 느꼈다.
✏️ 가장 오래 붙잡았던 문제: iOS 푸시 알림
이번 프로젝트에서 가장 기억에 남는 문제는 iOS 푸시 알림이었다.
서버에서는 FCM을 통해 정상적으로 메시지를 보내고 있었다. 하지만 iOS에서는 특정 상황에서 알림이 오지 않거나, 백그라운드 상태에서 예상대로 동작하지 않는 문제가 있었다. 처음에는 단순히 서버에서 메시지 형식을 잘못 만든 문제라고 생각했다. 하지만 파고들수록 iOS 푸시는 Android와 다르게 APNs 설정, 헤더, payload 구조, 앱 상태, TestFlight 환경까지 함께 맞아야 정상적으로 동작한다는 것을 알게 되었다.
특히 일반 푸시와 백그라운드 푸시는 필요한 설정이 달랐다. 일반 알림에서는 APNs payload에 aps.alert와 같은 필드가 필요했고, 백그라운드 알림에서는 content-available 설정과 push type 설정이 중요했다. 또한 TestFlight 환경에서는 APNs production 설정을 고려해야 했다.
이 과정에서 APNs 헤더 설정을 고치고, iOS 일반 푸시 수신을 위해 필수 payload를 추가하고, 백그라운드 푸시가 TestFlight에서 동작하지 않는 문제를 해결했다. 이 경험을 통해 외부 플랫폼 연동 문제는 서버 코드만 보고 판단해서는 안 된다는 것을 배웠다. 서버 로그, FCM 응답, 클라이언트 수신 상태, iOS 정책, 테스트 환경까지 함께 봐야 했다.
"서버에서 보냈다"와 "사용자가 받았다"는 완전히 다른 문제다.
백엔드 입장에서는 메시지를 성공적으로 전송하면 끝이라고 생각하기 쉽다. 하지만 실제 서비스에서는 사용자의 기기에 도착하고, 의도한 방식으로 표시되고, 필요한 동작까지 이어져야 기능이 완성된다.
✏️ 단순해 보였지만 복잡했던 좋아요 기능
또 하나 기억에 남는 작업은 좋아요 동시 요청 처리였다.
좋아요 기능은 처음 보면 단순하다. 사용자가 좋아요를 누르면 저장하고, 다시 누르면 취소하면 된다. 하지만 실제로는 동시에 여러 요청이 들어올 수 있고, 그 과정에서 중복 생성이나 삭제 충돌이 발생할 수 있다.
예를 들어 사용자가 버튼을 빠르게 여러 번 누르거나, 네트워크 지연으로 같은 요청이 거의 동시에 처리되면 DB 제약 조건 위반이 발생할 수 있다. 이때 단순히 예외를 500 에러로 내려주는 것은 사용자 경험상 좋지 않다. 그래서 좋아요 처리에서 발생할 수 있는 충돌 상황을 공통으로 처리하도록 정리했다. 각 서비스마다 비슷한 예외 처리 로직을 반복해서 넣는 대신, 공통 핸들러를 두어 중복 코드를 줄이고 흐름을 명확하게 만들었다.
작은 기능일수록 예외 상황을 놓치기 쉽다. 좋아요는 서비스에서 자주 호출되는 기능이고, 사용자가 빠르게 반복해서 누를 수 있는 기능이다. 그렇기 때문에 단순 CRUD보다 실제 사용 패턴을 기준으로 설계해야 했다.
✏️ 회원탈퇴는 유저 하나를 지우는 일이 아니었다
처음에는 회원탈퇴를 단순히 유저 데이터를 삭제하거나 비활성화하는 기능으로 생각하기 쉽다. 하지만 실제로는 유저와 연결된 데이터가 많았다. 등산 기록, 피드백, 좋아요, 게시글, 댓글 등 여러 도메인과 관계가 얽혀 있었다.
이 과정에서 course_difficulty_feedbacks와 관련된 FK 제약 위반으로 500 에러가 발생했다. 애플리케이션 코드에서는 회원탈퇴 로직이 수행되는 것처럼 보였지만, DB에서는 참조 무결성 제약 때문에 삭제가 실패하고 있었다. 이 문제를 해결하면서 DB 제약 조건과 애플리케이션 삭제 순서가 맞아야 한다는 것을 다시 느꼈다.
JPA 연관관계만 보고 판단하는 것이 아니라, 실제 DB 테이블 간 관계와 FK 제약 조건을 함께 확인해야 했다. 회원탈퇴는 단순한 기능이 아니라 서비스 전체 도메인 관계를 점검하게 만드는 기능이었다. 어떤 데이터를 삭제할지, 어떤 데이터는 남길지, 삭제 순서는 어떻게 가져갈지 고민해야 했다.
✏️ Flyway를 적용하며 느낀 DB 변경 관리의 중요성
팀 프로젝트에서 DB 스키마를 수동으로 맞추는 방식은 위험하다. 누군가는 로컬 DB에 컬럼을 추가했지만 다른 팀원은 반영하지 못할 수 있고, 배포 환경에서는 어떤 SQL이 적용되었는지 추적하기 어렵다. Flyway를 적용하면서 DB 변경사항을 코드처럼 관리할 수 있게 되었다. 마이그레이션 파일을 통해 어떤 시점에 어떤 테이블이나 제약 조건이 추가되었는지 명확히 남길 수 있었다.
물론 시행착오도 있었다. 마이그레이션 버전이 꼬이거나, 제약 조건이 누락되어 다시 수정하는 일도 있었다. 하지만 이런 경험을 통해 DB 변경도 애플리케이션 코드만큼 신중하게 관리해야 한다는 것을 배웠다. 특히 운영 환경에서는 이미 적용된 마이그레이션을 함부로 수정할 수 없다. 그래서 초반부터 버전 규칙과 작성 방식을 팀 내에서 명확히 정하는 것이 중요하다고 느꼈다.
✏️ 리팩토링을 통해 코드의 책임을 정리하다
프로젝트 후반에는 기능 추가뿐 아니라 리팩토링 작업도 진행했다.
대표적으로 유저 조회 로직을 UserReader를 통해 통일하고, 소유권 검증을 엔티티 메서드로 정리했다. 또한 ConstraintViolationException 파싱 로직을 유틸로 분리하고, 좋아요 충돌 처리도 공통화했다.
처음에는 각 서비스에서 필요한 로직을 바로 작성하는 방식이 빠르게 느껴졌다. 하지만 기능이 늘어나면서 같은 패턴의 코드가 여러 곳에 반복되기 시작했다. 유저를 조회하고, 없으면 예외를 던지고, 작성자인지 확인하고, 제약 조건 예외를 파싱하는 흐름이 여러 서비스에 흩어졌다. 리팩토링을 하면서 가장 중요하게 생각한 것은 추상화를 위한 추상화를 하지 않는 것이었다. 단순히 코드를 줄이는 것이 목적이 아니라, 변경이 생겼을 때 한 곳에서 관리할 수 있도록 책임을 정리하는 것이 목적이었다.
✏️ 협업하면서 배운 것
이번 프로젝트는 짧은 기간 안에 기획, 디자인, iOS, 백엔드가 함께 결과물을 만들어야 했다. 그래서 기술 구현만큼 커뮤니케이션도 중요했다. 특히 API 명세는 프론트엔드와 백엔드 사이의 약속이었다. 응답 필드 하나가 추가되거나, 에러 응답 형식이 달라지거나, 인증 방식이 바뀌면 클라이언트 구현에도 바로 영향을 준다.
iOS 푸시 알림 문제를 해결할 때도 협업의 중요성을 많이 느꼈다. 서버에서 어떤 payload를 보내는지, iOS에서 어떤 상태에서 수신하는지, TestFlight 환경인지, 앱 설정은 어떻게 되어 있는지 함께 확인해야 했다. 백엔드 혼자서는 원인을 끝까지 좁히기 어려운 문제였다.
Discord 서버 에러 알림, PR 생성 및 머지 알림, README 정리, 커스텀 커맨드 추가 같은 작업도 진행했다. 이런 작업들은 직접적인 서비스 기능은 아니지만, 팀이 더 빠르고 안정적으로 개발하는 데 도움을 주었다. 협업 생산성을 높이는 작업도 충분히 가치 있다는 것을 느꼈다.
✏️ 이번 프로젝트를 통해 배운 것
이번 프로젝트를 통해 백엔드 개발은 API를 만드는 일에서 끝나지 않는다는 것을 많이 느꼈다.
API가 정상 응답을 내려주는 것도 중요하지만, 실제 서비스에서는 그 뒤에 더 많은 것들이 있다. DB 제약 조건이 맞는지, 외부 플랫폼 연동이 실제 환경에서 동작하는지, 클라이언트와 약속한 응답 형식이 유지되는지, 운영 중 문제가 발생했을 때 빠르게 알 수 있는지까지 고려해야 한다.
세모산 프로젝트를 하며 인증, 도메인 설계, DB 마이그레이션, 푸시 알림, 커뮤니티 기능, 운영 알림까지 폭넓게 경험할 수 있었다. 짧은 기간의 밋업 프로젝트였지만, 실제 서비스를 만드는 과정에서 마주칠 수 있는 문제들을 많이 겪었다. 무엇보다 기능을 구현하는 개발자에서 한 단계 더 나아가, 서비스가 안정적으로 동작하도록 고민하는 개발자가 되어야겠다고 느꼈다.
세모산은 나에게 단순한 팀 프로젝트가 아니라, 백엔드 개발자로서 실제 서비스처럼 생각하는 법을 배운 프로젝트였다.
✏️ 회고
세모산은 밋업 프로젝트 아이디어 발제가 된 순간부터 계속 관심이 갔던 프로젝트였다. 등산이라는 주제가 신선하기도 했고, 기술적으로도 도전해볼 것들이 많겠다는 생각이 들었기 때문이다.
기업 프로젝트를 하면서 다른 개발자들의 깃허브를 구경하다 보니 개인적으로 같이 팀을 하고 싶다고 생각했던 사람들이 몇 명 있었는데, 운이 좋게도 모두 같은 팀으로 모이게 됐다. 그래서인지 세모산 자체에 더 진심으로 임할 수 있었고, 팀원들과 많이 친해질 수 있었던 좋은 기회이기도 했다.
처음엔 전시회까지 다 구현해낼 수 있을까 걱정도 있었는데, 든든한 팀원들 덕분에 잘 마무리할 수 있었다. 시험기간을 빼면 약 2달 정도를 함께 작업했는데, 최근 인스타 스토리나 갤러리를 보면 세모산이 8~90%를 차지할 정도로 그만큼 열심히 했던 것 같다. 오랜만에 정말 재밋게 플젝을 한 것 같은데, 이번 기수가 끝나더라도 빠지는 사람 없이 계속 함께할 수 있으면 좋겠다.
'Back-End > 회고' 카테고리의 다른 글
| [현대오토에버 / 부트캠프] 현대오토에버 모빌리티 SW스쿨 4기 웹/앱 합격 후기 (2) | 2026.06.22 |
|---|---|
| [한국대학생IT경영학회 / 큐시즘] 큐시즘 33기 백엔드 파트 합격후기 (0) | 2026.02.08 |
- Total
- Today
- Yesterday
- 유클리드 호제법
- html
- 알고리즘 공부
- Do it!
- DFS
- 세그먼트 트리
- DP
- CSS
- c++ string
- 투 포인터
- 이분 매칭
- 반복문
- js
- 유니온 파인드
- 자료구조
- 백준 풀이
- 카운팅 정렬
- HTML5
- 자바
- 스프링 부트 crud 게시판 구현
- 자바스크립트
- BFS
- C++ Stack
- 알고리즘
- 백준
- java
- 에라토스테네스의 체
- 우선순위 큐
- C++
- 스택
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
