Lab 12.4 — System Design Whiteboard: Apple Notes Sync
Goal: produce a written system design document for “Design the iOS half of Apple Notes” — the kind of deliverable you’d submit as a take-home or paste into a senior interview transcript.
Time: 90 min writing + 30 min self-review = 2 hours.
Prereqs: Read 12.9 — System Design Scenarios. Have a markdown editor or paper handy.
The prompt
Design the iOS app architecture for Apple Notes. Specifically:
- Single-user sync across iPhone, iPad, and Mac
- Rich text + image attachments + sketches (PencilKit)
- Offline-first (full functionality without network)
- Real-time collaboration with shared notes (multiple cursors)
- 100M+ users at scale
You have 90 minutes. Write a design doc that an iOS team lead could hand to two senior engineers and have them start implementation.
Required sections
Your doc must include:
- Assumptions & clarifying questions (10 min)
- High-level architecture diagram + description (15 min)
- iOS data layer design (15 min)
- iOS state + concurrency model (10 min)
- Offline + sync strategy (15 min)
- Real-time collaboration (10 min)
- Tradeoffs & open questions (10 min)
- What I’d build first (MVP slice) (5 min)
Time-box each section. If you run out of time on one, mark it [TODO: revisit] and move on. Better incomplete than imbalanced.
Template
Use this skeleton, fill in your own answers:
# Apple Notes Sync — iOS System Design
## 1. Assumptions & clarifying questions
I'm assuming:
- Backend exists (iCloud-style CKContainer); my scope is iOS half.
- Targeting iOS 17+ (uses SwiftData, NavigationStack, @Observable).
- Single-user MVP; multi-user collaboration is V2.
Questions I'd ask the PM:
- (List 5 questions about scope, scale, conflict-resolution policy, etc.)
## 2. High-level architecture
[ASCII diagram or text description of: iOS app → Local store → Sync engine → CloudKit → other devices]
Components:
- Local persistence layer (SwiftData)
- Sync engine (background task + push notification triggered)
- UI layer (SwiftUI with @Observable view models)
- Editor (custom rich-text + PencilKit)
## 3. iOS data layer design
Models:
```swift
@Model final class Note {
var id: UUID
var title: String
var body: AttributedString // serialized as RTF
var attachments: [Attachment]
var createdAt: Date
var modifiedAt: Date
var deletedAt: Date? // tombstone
var folderID: UUID?
var serverChangeTag: String? // for sync
init(...) { ... }
}
@Model final class Folder { ... }
@Model final class Attachment { ... }
Indexes: modifiedAt DESC, folderID, deletedAt IS NULL.
Full-text search: SQLite FTS5 via SwiftData’s underlying store.
4. iOS state + concurrency
NoteListViewModel(@Observable, @MainActor) per folder.NoteEditorViewModel(@Observable, @MainActor) per open note.SyncEngine(actor) coordinates background sync.- All reads from local store (synchronous, fast).
- Writes go through SyncEngine.enqueue() for replay.
5. Offline + sync strategy
- Local-first: every write is local immediately.
- Sync triggered by: app foreground, BGAppRefreshTask, push notification, manual pull-to-refresh.
- Per-record sync via CKQueryOperation with serverChangeToken.
- Conflict resolution: last-write-wins with HLC timestamps, surface conflicts in UI as “two versions exist” banner.
- Deletes: soft via tombstone with deletedAt; hard delete after 30 days.
[Discuss: what happens when same note edited on two offline devices.]
6. Real-time collaboration (V2)
- Per-note WebSocket session for shared notes.
- Operational Transform (OT) or CRDT (e.g., Yjs port to Swift) for character-level merge.
- Presence: send cursor position; receive others’ cursors.
- Fallback to per-section locking if real-time engine unavailable.
[Discuss: tradeoff between OT and CRDT.]
7. Tradeoffs & open questions
- SwiftData vs Core Data: SwiftData chosen for iOS 17+ greenfield; risk = newer/less battle-tested.
- CloudKit vs custom backend: CloudKit for free zero-config sync; locks to Apple ecosystem.
- HLC vs CRDT: HLC + LWW simpler but loses concurrent edits; CRDT more code but auto-merges.
- PencilKit vs custom canvas: PencilKit native and free; less control over stroke data format.
Open: how to migrate from local-only V1 to collab V2 without breaking offline users mid-deploy.
8. MVP slice — what I’d build first
Week 1: Local-only notes (create/read/update/delete) with SwiftData; no sync. Week 2: Basic CloudKit sync, no conflict UI (assume single-device). Week 3: Conflict detection + manual resolution UI. Week 4: Background sync via BGAppRefreshTask + silent push. Week 5: Attachments (images). Week 6: Polish, perf testing on 5k-note libraries.
Real-time collab is V2, 2+ months out.
## Self-review checklist (30 min)
After writing, score against this rubric:
| Section | 0 (missing/weak) | 1 (acceptable) | 2 (strong) |
|---|---|---|---|
| Clarifying Qs | < 3 generic | 3–5 specific | 5+ scoped to actual gaps |
| Architecture diagram | None or unclear | Clear text description | ASCII or labeled diagram |
| Data model code | Pseudocode only | Swift with key fields | Swift with indexes + sync metadata |
| Concurrency model | "use async" | Names actors / @MainActor boundaries | Explicit concurrency-boundary justification |
| Sync triggers | Vague | Enumerated | Enumerated + battery considerations |
| Conflict resolution | Hand-waved | Named strategy | Named + UI surface + edge cases |
| Tradeoffs section | None or 1 | 2–3 named | 3+ with explicit alternatives |
| MVP slice | Missing | Listed | Time-boxed + dependencies |
Pass bar for senior level: ≥ 12/16 total, with no section at 0.
## Stretch
- Repeat the exercise for a different prompt (real-time chat, video upload pipeline).
- Send your design to a senior peer for review; ask them to grade against the rubric and find what you missed.
- Re-time it down to 60 min for tighter interview practice; then to 45 min.
## Notes
The hardest part of system design is *not* knowing the answer — it's *managing the conversation in real time*. Writing a doc removes the time pressure but builds the skeleton. Once you can write the doc cold, the live whiteboard version is just spoken version of the same content.
This lab is also good portfolio material — a polished design doc on your GitHub (gist or repo) gives recruiters a deeper signal than another sample app.
---
**End of Phase 12 labs.** Next phase covers full capstone projects bringing everything together.