시스템 설계 : 캘린더 앱

발행: (2026년 1월 7일 오전 05:41 GMT+9)
5 min read
원문: Dev.to

I’m happy to help translate the article, but I need the full text you’d like translated. Could you please paste the content (excluding the source line you already provided) so I can translate it into Korean while preserving the formatting and code blocks?

기능 요구 사항

  • 이벤트 생성, 이벤트 수정, 이벤트 취소
  • 캘린더를 일간, 주간, 연간으로 보기
  • 반복 회의 설정
  • 변경 사항을 이메일로 알림 전송

Non‑Functional Requirements

  • High availability → consistency (eventual consistency for syncing events)
  • Should support 1 billion users
  • Low latency for viewing the calendar (read‑heavy > write‑heavy)

데이터 모델

  • User
  • Event
  • Recurrence

API

POST /events/

{
  "title": "Meeting title",
  "userId": "creator_id",          // creator
  "userIds": ["participant1", "participant2"], // optional list of attendees
  "startTime": "2025-01-10T15:00:00Z",
  "endTime": "2025-01-10T16:00:00Z",
  "content": {                     // JSON blob: video call link, description, etc.
    "videoCallLink": "https://example.com/meet/123",
    "description": "Discuss project status"
  },
  "recurrence": "weekly|biweekly|monthly|yearly" // optional
}

GET /events?startDay=&endDay=

요청된 날짜 범위에 해당하는 이벤트 목록을 반환합니다.

고수준 설계

(구성 요소, 캐싱 레이어, 데이터베이스 및 클라이언트 동기화 개요.)

Deep Dives

1. 일일 또는 반복 이벤트 저장

이벤트 생성 및 저장

Case 1 – Simple (One‑Time) Event
예시: 병원 예약

event_idowner_idtitlestart_time_utcend_time_utcrruletzversion
evt_101user_1Doctor Appointment2025‑01‑10 15:002025‑01‑10 16:00NULLUTC1

행이 그대로 반환되고 렌더링됩니다; 확장이 필요하지 않습니다.

Case 2 – Recurring Event (Weekly)
예시: 팀 동기화

event_idowner_idtitlestart_time_utcend_time_utcrruletzversion
evt_201user_1Team Sync2025‑01‑06 10:002025‑01‑06 11:00FREQ=WEEKLY;BYDAY=MOUTC1

GET behavior (Week view) – 기본 행을 가져와 요청된 범위에 대해서만 규칙을 확장하고, 메모리에서 발생을 생성합니다.

Case 3 – Recurring Event with Exception (One Cancellation)
예시: 1월 20일에 취소된 팀 동기화

event_exceptions 테이블:

exception_idevent_idexception_datetype
ex_301evt_2012025‑01‑20CANCELLED

GET behavior (Week of Jan 20) – 주간 규칙을 확장하고 예외와 매칭하여 해당 발생을 제외한 나머지 이벤트를 반환합니다.

저장 요약

  • 일회성 이벤트 → 1 행
  • 수년간의 주간 반복 → 1 행
  • 주간 + N 개의 예외 → 1 + N 행

결과: 최소한의 저장 공간.

2. 뷰 생성 및 저지연

사용자 흐름: 서버가 이벤트 목록을 클라이언트에 전송합니다.

최적화 – Redis 캐시

  1. 클라이언트가 이벤트를 요청합니다.
  2. 서버가 Redis를 확인합니다:
    • Cache hit → 캐시된 이벤트 반환.
    • Cache miss → DB를 조회하고 Redis에 채운 뒤 결과 반환.

장점: 빠른 읽기, DB 부하 감소.
단점: 캐시 무효화 복잡성, 최종 일관성 지연.

결론: 하이브리드 접근 방식 – 클라이언트‑사이드 확장 + 오프라인 저장을 위한 SQLite 조합이 저지연 및 오프라인 기능을 제공합니다.

3. 충돌 감지 및 잠금 전략

  • Optimistic Locking (default) – 경쟁이 적은 개인 캘린더에 적합; 서비스에서 재시도 로직 필요.
  • Pessimistic Locking – 경쟁이 높은 캘린더에 사용; 레이스 컨디션 방지를 위해 여러 행을 잠급니다.

4. 다중 디바이스 동기화 (Push & Pull)

  • Pull (Delta Sync) – 초기 시작, 재연결, 놓친 업데이트에 사용.
  • Push (SSE / Push Notifications) – 업데이트된 규칙을 가져와 로컬에서 재확장하고 SQLite와 UI를 업데이트합니다. SSE가 선호됩니다: 단방향, 가벼움, 배터리 친화적.
  • Hybrid model – 신선도는 푸시, 정확도는 풀을 조합.

5. 데이터베이스 선택: SQL vs NoSQL

SQL이 잘 맞는 이유

  • 쓰기량이 적당해 관계형 DB가 충분히 확장됩니다.
  • 트랜잭션으로 충돌 검사가 간단합니다.
  • 반복 쿼리(RRULE 확장)가 관계형 모델에 자연스럽게 들어맞습니다.
  • 강한 일관성(또는 구성 가능한 최종 일관성)을 보장하기 쉽습니다.

NoSQL 트레이드‑오프

  • 트랜잭션이 없으면 충돌 검사가 어렵습니다.
  • 반복 쿼리는 부적합합니다.
  • 기본적으로 최종 일관성이므로 정확성을 위해 추가 복잡성이 필요합니다.
  • 동일한 보장을 위해 구현 복잡도가 높아집니다.
Back to Blog

관련 글

더 보기 »

시스템 설계 빠른 가이드

System Design은 규모의 언어이며, 모든 엔지니어는 이를 구사해야 합니다. 저는 복잡한 System Design 주제를 해독하는 데 도움이 되는 1‑페이지 Quick Guide를 만들었습니다.

EP 6.3: 마스터-슬레이브 아키텍처

개요: 시스템 설계에서 Master‑Slave 또는 Leader‑Follower 아키텍처는 확장성과 고가용성을 달성하기 위해 사용되는 기본 패턴이며, 특히 ...

2015년처럼 API를 작성하지 마세요

우리는 2025년에 살고 있으며, 많은 코드베이스가 여전히 API를 단순히 “JSON을 반환하는 엔드포인트”로만 취급합니다. API 설계가 기본 CRUD 라우트를 넘어 발전하지 않았다면, 당신은 sacr…