Operations 7 min read 중급

plan.hwmoon.com을 local-first PWA로 시작하는 인프라 설계

plan.hwmoon.com의 첫 인프라 결정 기록입니다. 하나의 반응형 PWA, 무료 사용자의 로컬 저장, Plus 백업과 복원을 위한 단계적 Azure 백엔드 설계를 정리합니다.

Hosting
Azure Static Web Apps
Client storage
IndexedDB
Backend phase
Planned Azure Functions
모바일 인터페이스를 화이트보드에 계획하는 모습. local-first PWA 아키텍처 계획을 상징한다.
자료 이미지: Photo by Christina @ wocintechchat.com M on Unsplash
이 글의 목차
  1. 제품 형태
  2. 왜 m.plan.hwmoon.com이 아닌가
  3. 현재 기준선
  4. 목표 아키텍처
  5. 백엔드 구현 순서
  6. 저장소 선택
  7. 인증 도입 시점
  8. 운영 관점
  9. 프로덕션 분리
  10. 결정 요약

plan.hwmoon.com은 작은 일일 계획 앱으로 출발하지만, 첫 인프라 결정의 영향은 작지 않다. 무료 제품을 너무 일찍 데이터베이스에 묶지 않는 것이 핵심이다.

첫 버전은 local-first PWA로 간다. 데스크톱과 모바일 모두 같은 주소에서 동작하고, 오늘의 계획 데이터는 브라우저에 저장한다. 제품이 매일 열 만한 가치가 있다는 사실이 먼저 확인된 뒤에 클라우드 기능을 붙인다.

이번 결정은 이렇게 정리할 수 있다.

plan.hwmoon.com 하나를 반응형 PWA로 운영한다. 무료 계획 데이터는 로컬에 둔다. Plus 백업 기능이 준비될 때 계정과 클라우드 저장소를 붙인다.

제품 형태

MOON Plan은 오늘의 할 일, 일정, 기분, 하루 마감 기록을 다루는 조용한 일일 계획 앱이다. 데이터는 개인적이고 자주 바뀌며, 대부분 지금 손에 든 브라우저 안에서 가치가 생긴다.

그래서 무료 버전은 첫날부터 서버 저장소가 필요하지 않다.

TierStorageCloud feature
FreeBrowser IndexedDB없음
PlusLocal storage plus encrypted cloud backup백업과 복원
Pro laterLocal storage plus cloud sync여러 기기 연속성

이 구조는 비용 모델을 솔직하게 만든다. 서버 비용은 서버가 실제 가치를 제공할 때부터 생긴다.

왜 m.plan.hwmoon.com이 아닌가

첫 버전에서는 모바일 전용 서브도메인을 만들지 않는다.

m. 도메인을 만들면 라우팅, 인증, 분석, 캐시 정책, 배포, 지원을 모두 한 번 더 관리해야 한다. 하지만 제품 동작은 여전히 같은 일일 계획 앱이다. 이 정도 차이로는 화면을 나눌 이유가 부족하다.

초기 구조는 이쪽이 낫다.

plan.hwmoon.com
  -> responsive PWA
  -> desktop web
  -> mobile web
  -> installed PWA
  -> future Android shell

나중에 Android 배포가 중요해지면 같은 PWA를 Trusted Web Activity나 Capacitor로 감싸면 된다. URL, 보안 모델, 애플리케이션 상태 모델을 하나로 유지할 수 있다.

현재 기준선

현재 기준선은 의도적으로 단순하다.

AreaCurrent choice
HostAzure Static Web Apps
Domainplan.hwmoon.com
DeployAzure DevOps pipeline
App typestatic PWA
Client dataIndexedDB
Legacy migrationlocalStorage to IndexedDB
Account gatelocal browser-profile lock

현재의 로컬 잠금은 실제 서버 계정 인증이 아니다. 브라우저 프로필 안에서만 동작하는 기기 잠금에 가깝다. 클라우드 백업, 계정 복구, 구독 권한 확인에는 지속 가능한 서버 ID가 필요하다.

목표 아키텍처

단계적으로 도달할 목표 구조는 다음과 같다.

Browser / installed PWA
  |
  | HTTPS
  v
Azure Static Web Apps: plan.hwmoon.com
  |
  | /api/* after Plus backend is enabled
  v
Azure Functions API
  |
  +--> auth identity
  +--> metadata store
  +--> encrypted backup payloads in Blob Storage
  +--> Key Vault for secrets
  +--> Application Insights for health and failures

API는 “앱에는 백엔드가 있어야 하니까” 등장하는 것이 아니다. 유료 기능이 백엔드 가치를 필요로 할 때 등장해야 한다.

백엔드 구현 순서

첫 백엔드 기능은 실시간 동기화가 아니라 백업과 복원이어야 한다.

백업과 복원은 사용자와 운영자 모두에게 이해하기 쉽다.

  1. 버전이 있는 로컬 내보내기를 만든다.
  2. 암호화된 스냅샷을 업로드한다.
  3. 사용 가능한 스냅샷 목록을 보여준다.
  4. 새 브라우저나 새 기기에서 선택한 스냅샷을 복원한다.

동기화는 더 어렵다. 충돌 해결, 기기별 cursor, 오프라인 변경 병합, 서로 다른 기기에서 같은 날짜를 수정했을 때의 UX가 필요하다. 이 복잡도는 백업과 복원이 안정된 뒤로 미루는 편이 맞다.

저장소 선택

첫 백엔드 저장소는 아래 조합을 추천한다.

DataService
User metadataAzure Table Storage 또는 Cosmos DB
Backup snapshot indexAzure Table Storage 또는 Cosmos DB
Encrypted backup payloadAzure Blob Storage
SecretsAzure Key Vault
API telemetryApplication Insights

메타데이터 저장소에는 운영에 필요한 정보만 둔다. 사용자 ID, 구독 권한, 기기 ID, 백업 ID, 스키마 버전, 시각, payload 크기, blob 위치 정도면 충분하다.

할 일 본문, 일정 본문, 회고 본문을 검색 가능한 메타데이터로 저장하지 않는다. 그 데이터는 암호화된 백업 payload 안에 있어야 한다.

인증 도입 시점

실제 인증은 유료 클라우드 백업 전에 필요하다. 하지만 로컬 MVP가 매일 쓸 만한지 확인되기 전에는 필요하지 않다.

실무 순서는 다음과 같다.

PhaseAuth state
MVPlocal device lock only
Betasign in, sign out, session check
Plusentitlement check and backup ownership
Paid productionaccount deletion and billing state handling

초기 provider 기반 로그인이면 Azure Static Web Apps 인증으로 충분할 수 있다. 이메일/비밀번호, 고급 계정 복구, 커스텀 계정 흐름이 중요해지면 별도 인증 제공자나 백엔드 소유 인증으로 이동할 수 있다.

운영 관점

MVP에는 빌드와 라우트 확신이 필요하다. Plus 백엔드에는 서비스 신뢰성이 필요하다.

백엔드 전에는 다음을 확인한다.

  • build check
  • PWA manifest and service worker check
  • mobile viewport check
  • local export/import compatibility check
  • browser storage를 사용할 수 없을 때의 경고

백엔드 이후에는 다음을 본다.

  • backup API success rate
  • restore failure alert
  • blob read/write failure alert
  • payment webhook failure alert
  • storage growth monitoring
  • resource group budget alert

운영 알림은 조용해야 한다. 일일 계획 사용 이벤트를 Slack으로 보낼 필요는 없다. 백업 실패, 복원 실패, 배포 실패, 결제 webhook 실패처럼 실제 조치가 필요한 이벤트만 알림 대상이다.

프로덕션 분리

첫 beta는 기존 개발 foundation 리소스를 활용할 수 있다. 하지만 유료 production은 경계를 분리하는 편이 낫다.

추천 production 구조는 다음과 같다.

ResourcePurpose
rg-hwmoon-plan-prod-p01Plan production boundary
swa-hwmoon-plan-prod-p01public PWA host
func-hwmoon-plan-prod-p01backend API
sthwmoonplanprodp01backup payloads and metadata
kv-hwmoon-plan-prod-p01secrets
appi-hwmoon-plan-prod-p01telemetry

이유는 규모가 아니다. 개인 계획 데이터, 권한, 비용 추적, 삭제 정책, 유료 사용자 운영 기준을 깔끔하게 분리하기 위해서다.

결정 요약

첫 인프라 아키텍처는 의도적으로 단계화한다.

  • 모바일 전용 서브도메인 없이 하나의 URL 사용
  • 반응형 PWA 먼저 구현
  • 무료 로컬 계획 데이터는 IndexedDB에 저장
  • 클라우드 가치가 생기기 전까지 유료 데이터베이스 없음
  • 백업 전에 실제 인증 도입
  • 동기화 전에 백업과 복원 안정화
  • 유료 출시 전 production 리소스 분리

이렇게 하면 plan.hwmoon.com은 출시할 만큼 작고, 확장할 만큼 명확하다. 중요한 것은 최종 클라우드 플랫폼을 미리 크게 만드는 것이 아니다. 중요한 것은 내일도 다시 열고 싶은 첫 일일 계획 루프를 만드는 것이다.

관련 글