우주공부선
스터디 목표 설정·학습 기록·공유 플랫폼
배경
할 일 목록과 타이머는 기록은 남기지만, 쌓인 기록이 눈에 보이는 보상으로 이어지지는 않습니다. 우주공부선(Space Study Ship) 은 공부를 게임처럼 만든 학습 관리 앱입니다. 공부한 시간을 연료로 바꾸고, 그 연료로 행성과 지역을 해금하며 우주를 탐험합니다.
2026년 1학기 창의학기제 과제로 진행한 1인 과제였습니다. 서버의 초기 멀티모듈 구조와 배포 설정은 다른 기여자가 잡아 두었습니다.
맡은 역할
- Flutter 앱 전체 — 할 일, 타이머, 연료, 탐험, 배지, 게스트 모드와 로그인
- 서버 도메인 기능 — Spring Boot·PostgreSQL로 할 일, 연료, 타이머 세션, 탐험
- 서버 인증 기능 — Google·Apple 로그인 토큰 검증, 기기별 세션, 회원 탈퇴
- 기획과 보고 — 주차별 개발 계획, 주간 보고서와 최종 발표
과정
로그인 없이 도는 앱부터 만들었습니다. 1~5주차에 타이머, 할 일, 연료·탐험·배지를 기기 안에서 동작하게 만들고, 7~12주차에 서버와 로그인을 붙였습니다. 덕분에 게스트 모드와 로그인 후 서버 저장을 함께 지원하게 됐습니다.
서버 연결 단계에서 시간을 가장 많이 쓴 건 정합성이었습니다. 기록 저장과 연료 충전 중 하나만 성공하면 공부 기록과 보상이 어긋났습니다. 그래서 기록 저장, 연료 충전, 학습시간 반영을 하나의 트랜잭션으로 묶어 중간에 실패하면 모두 취소되게 했습니다.
같은 오류를 세 번 만났습니다. 로그아웃과 게스트 전환에서 인증 코드와 저장소가 서로를 참조해 Riverpod 순환 의존성 오류가 났습니다. 처음 두 번은 문제가 난 곳만 고쳤고, 세 번째에 인증 코드가 데이터 계층을 바로 호출하도록 전체를 정리했습니다.
기술적 결정
공부를 우주 탐험 게임으로
- 상황기존 Todo·타이머 앱은 기록에 그쳐, 꾸준히 쓸 동기와 성취감이 약했습니다.
- 결정타이머 30분마다 연료 1을 주고 남은 분은 이월하며, 연료로 행성과 지역을 해금하고 학습 목표를 채우면 배지를 줍니다.
저장 요청마다 식별키를 붙여 중복 지급 방지
- 상황모바일 앱은 통신이 끊기면 같은 공부 기록을 다시 보내, 연료가 두 번 지급될 수 있습니다.
- 결정저장 요청에
Idempotency-Key를 붙여 이미 처리한 키는 기존 결과만 돌려주고, 동시 요청은 유니크 제약 위반을 잡아 다시 조회했습니다.
기기별 세션 관리를 위해 Refresh Token을 DB로 이동
- 상황기존 서버는 Refresh Token을 Redis에 회원당 하나만 저장해, 한 기기의 세션만 유효했습니다.
- 결정토큰을 기기 테이블에 저장하고 토큰 안에 기기 ID를 넣어, 로그아웃·재발급 때 기기를 구분했습니다.
- 결과배포 직후 기존 사용자는 한 번 강제 로그아웃되는데, 설계 때 의도한 결과입니다.
결과
- 학기 말까지 앱과 서버가 연동된 베타 버전을 완성했고, 최종 발표 때 Google Play 비공개 테스트 버전을 게시했습니다.
- 탐험 콘텐츠는 행성 8개·세부 지역 30개, 배지는 6개 범주 25개입니다.
- 서버 API는 인증 6, 할 일·카테고리 8, 타이머 3, 연료 2, 탐험 4개로 모두 23개입니다.
- 학기 중 보고서 기준으로 프론트엔드·백엔드 자동 테스트 240개 이상이 통과했습니다.
- 소셜 화면은 샘플 데이터로 구성돼 있으며, 소셜과 배지의 서버 연동은 남은 과제입니다.
배운 점
- 재요청이나 계정 전환 같은 상황은 처음부터 설계에 넣어야 합니다. 연료 중복 지급 위험과 순환 의존성 오류를 겪고 나서 알게 된 점입니다.
- 기대효과는 사용자 데이터로 확인하기 전까지 가설로 둬야 합니다. 공부를 더 오래 하게 되는지는 아직 확인하지 못했고, 재방문율과 연속 학습일로 확인하려 합니다.





