Operations 7 min read Intermediate

Designing plan.hwmoon.com as a local-first PWA before adding cloud accounts

The first infrastructure decision record for plan.hwmoon.com: one responsive PWA, local-first storage for free users, and a staged Azure backend for Plus backup, restore, and later sync.

Hosting
Azure Static Web Apps
Client storage
IndexedDB
Backend phase
Planned Azure Functions
Person planning a mobile interface on a whiteboard, representing a local-first PWA architecture plan
자료 이미지: Photo by Christina @ wocintechchat.com M on Unsplash
On this page
  1. Product Shape
  2. Why Not m.plan.hwmoon.com
  3. Current Baseline
  4. Target Architecture
  5. Backend Build Order
  6. Storage Choice
  7. Authentication Timing
  8. Operations
  9. Production Separation
  10. Decision Summary

plan.hwmoon.com is starting as a small daily planning product, but the first infrastructure decision is not small in impact: do not make the free product depend on a database too early.

The first version should be a local-first PWA. It should work on desktop and mobile from the same URL, store daily planning data in the browser, and avoid backend cost until the product has enough daily usefulness to justify cloud features.

The architecture decision is:

Use one responsive PWA at plan.hwmoon.com. Keep free planning local. Add accounts and cloud backup only when the Plus tier is ready.

Product Shape

The product is a calm daily planner. It tracks today’s tasks, schedule, mood, and end-of-day reflection. That data is personal, frequently edited, and valuable mainly to the person using the browser in front of them.

That creates a useful constraint. The free tier does not need server storage on day one.

TierStorageCloud feature
FreeBrowser IndexedDBnone
PlusLocal storage plus encrypted cloud backupbackup and restore
Pro laterLocal storage plus cloud syncmulti-device continuity

This keeps the cost model honest. Server cost begins when the product offers server value.

Why Not m.plan.hwmoon.com

The mobile experience should not be a separate mobile subdomain for the first version.

A separate m. domain would create extra work in routing, auth, analytics, cache policy, deployment, and support. The product behavior would still be the same planner. That is not enough reason to split the surface.

The better first architecture is:

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

If Android distribution becomes important, the same PWA can be packaged later with Trusted Web Activity or Capacitor. The product keeps one URL, one content security model, and one application state model.

Current Baseline

The current baseline is intentionally simple:

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

The local gate is not real account authentication. It is only a local device lock. That distinction matters because cloud backup, account recovery, and subscription entitlement need a durable server identity.

Target Architecture

The staged target is:

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

The API should not appear because “apps need a backend.” It should appear because a paid feature needs it.

Backend Build Order

The first backend feature should be backup and restore, not real-time sync.

Backup and restore has a simpler mental model:

  1. create a versioned local export
  2. upload an encrypted snapshot
  3. list available snapshots
  4. restore a selected snapshot to a new browser or device

Sync is harder. It needs conflict resolution, per-device cursors, offline merge behavior, and a clear user experience when two devices edit the same day differently. That complexity should wait.

Storage Choice

The recommended first backend storage shape is:

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

The metadata store should hold only operational data: user ID, entitlement, device ID, backup ID, schema version, timestamp, payload size, and blob location.

It should not store task text, schedule text, or reflection text as queryable metadata. Those belong inside the encrypted backup payload.

Authentication Timing

Real authentication is necessary before paid cloud backup. It is not necessary before the local MVP proves daily value.

The practical sequence is:

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

Azure Static Web Apps authentication may be enough for early provider-based login. If email/password, advanced account recovery, or custom account flows become important, the product can move to a backend-owned auth provider later.

Operations

The MVP needs build and route confidence. The Plus backend needs service confidence.

Before backend:

  • build check
  • PWA manifest and service worker check
  • mobile viewport check
  • local export/import compatibility check
  • warning when browser storage is unavailable

After backend:

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

Operational alerts should stay quiet. Daily planner usage events do not need Slack noise. Backup failures, restore failures, deployment failures, and billing webhook failures do.

Production Separation

The first beta can use the existing development foundation resources. Paid production should have a cleaner boundary.

Recommended production shape:

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

The reason is not scale. It is privacy, permissions, cost tracking, deletion policy, and paid-user operational discipline.

Decision Summary

The first infrastructure architecture is deliberately staged:

  • one URL, not a separate mobile subdomain
  • responsive PWA first
  • IndexedDB for free local planning
  • no paid database until cloud value exists
  • auth before backup
  • backup and restore before sync
  • production separation before paid launch

This keeps plan.hwmoon.com small enough to ship and clear enough to grow. The important thing is not to build the final cloud platform early. The important thing is to make the first daily planning loop worth opening tomorrow.

Related