모든 프로젝트
Selected Work 2025 · Backend
클래스업 학생앱 - 타이머
서비스
클래스업 학생앱 - 타이머 서비스
Role
백엔드 전반 (타이머 API · DB 설계 · Mongo / DynamoDB 마이그레이션)
Timeline
2025.08 – 2025.10
Category
Backend
— Overview

이 프로젝트는.

앱 종료·백그라운드 전환에도 학습 시간이 안정적으로 누적되도록 서버 중심 타이머 구조를 설계한 프로젝트

— Challenge

결정의 흐름.

“무엇을 만들었나” 보다 “왜 그렇게 결정했나” 를 남깁니다.

01·ARCHITECTURE

클라이언트 타이머를 서버 중심 상태 관리로 전환

앱 환경에서는 화면 종료나 백그라운드 전환이 자주 발생해, 클라이언트만으로는 학습 시간의 신뢰성을 보장하기 어려웠습니다. 서버가 시작 시각과 활성 상태를 관리하도록 구조를 바꿨습니다.

  • 시작 시 startedAt 저장
  • 활성 상태는 tb_user_timer_status에서 관리
  • 조회 시 현재 시각 - startedAt으로 경과 시간 계산
  • 종료 시 durationSec 확정 저장
02·CONSISTENCY

사용자별 단일 활성 타이머 보장

동시에 여러 타이머가 켜지면 학습 시간이 중복 누적될 수 있었습니다. 이를 막기 위해 활성 타이머 상태를 별도 테이블로 분리하고, 사용자 기준 유니크 제약을 적용했습니다.

  • tb_user_timer_status.userId 유니크 제약
  • 중복 시작 방지
  • 활성 타이머 조회 로직 단순화
  • 학습 시간 정합성 확보
03·PERFORMANCE

기록 조회 성능 개선

타이머 기록이 쌓이면서 사용자별 공부 기록 조회가 느려졌습니다. 실제 조회 패턴이 userId 조건 + startedAt 정렬이라는 점을 기준으로 인덱스와 페이지네이션을 다시 설계했습니다.

  • userId + startedAt 복합 인덱스 추가
  • offset 기반 페이지네이션을 startedAt 키셋 페이지네이션으로 전환
  • 주요 쿼리 실행 시간 77% 단축
  • 무한 스크롤 조회 성능 30% 개선
04·OPERATION

운영 환경 전환과 시간대 정합성 처리

운영 환경에서는 AWS 연동과 고가용성을 고려해 MongoDB 기반 구조를 DynamoDB로 전환했습니다. 또한 UTC/KST 차이로 날짜가 어긋나는 문제를 막기 위해 시간 변환을 공통 처리했습니다.

  • MongoDB 기반 개발 구조에서 DynamoDB 운영 구조로 전환
  • Mongoose Hook 기반 UTC/KST 변환 적용
  • 날짜 단위 학습 기록 정합성 확보
  • Joi + Swagger로 요청 검증과 API 명세 자동화
— Impact

숫자로 남긴 결과.

Query Cut
MongoDB `userId + startedAt` 복합 인덱스
Pagination Gain
`startedAt` 기준 키셋 페이지네이션
SQL Tuning
MySQL EXPLAIN 기반 쿼리 튜닝
— Stack

사용한 도구들.

Tools & Technologies
Express.jsTypeScriptMySQLSequelizeMongoDBDynamoDBJoiSwaggerCompound IndexKeyset Pagination
— Quote
화면이 꺼져도 시간은 흐르기 때문에, 신뢰할 수 있는 시계는 서버에 두었습니다.
프로젝트 회고