•CASE STUDY

Offline Multi-Device E-Book Reader (Kindle-style)

4 min read·608 words·Intermediate

Asked at

1 candidate report in Jan 2026

How to use this case study

SDE-2 / Mid

  • Design APIs and schema for books
  • A user's library
  • Downloads
  • Syncing reading position across devices

SDE-3 / Senior

  • Go deeper on offline-first sync (queued changes, conflict rules like furthest position wins)
  • Annotations sync
  • DRM-protected downloads

Staff / Principal

  • Discuss scale (millions of devices syncing)
  • Large book files via CDN
  • Conflict resolution for notes edited on two devices

Problem RestatementProblem

Amazon asked: design an e-book reader service with APIs, a database schema and an architecture. A user buys books, reads offline, and uses several devices (phone, tablet, e-reader) for the same book. The system must sync reading position, bookmarks, highlights and notes across devices, even when devices were offline and made changes at the same time.

RequirementsRequirements

  • Library of owned books, and download of book files (DRM-protected).
  • Read fully offline.
  • Sync position ("page 142 on your phone, jump there?"), bookmarks, highlights and notes.
  • Resolve conflicts from offline edits sensibly.

ArchitectureArchitecture

Architecture diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
    D1["Phone"] -->|"sync changes"| SYNC["Sync Service"]
    D2["E-reader"] --> SYNC
    SYNC --> DB[("Reading state + annotations DB")]
    D1 -->|"download"| CDN["CDN - encrypted book files"]
    LIC["License / DRM service"] --> D1
    STORE["Store / purchases"] --> LIB[("Library - entitlements")]
    SYNC --> LIB
    SYNC -->|"push: new position"| D2

Data ModelData model

books:        book_id, title, authors, format, file_versions
library:      user_id, book_id, acquired_at, license_status
positions:    user_id, book_id, device_id, location (e.g. EPUB CFI / percent), updated_at
annotations:  annotation_id (UUID from device), user_id, book_id, type (bookmark|highlight|note),
              range_start, range_end, text, color, updated_at, deleted (tombstone), version

Locations use a stable format that doesn't depend on font size (e.g., an EPUB CFI or a character offset), since "page 142" differs per device.

Deep Dive — One book, three devices, no connectionDeep dive

Someone reads on a phone on the train, then opens a tablet at home. Both were offline, both made changes. Neither should lose anything.

Weak

Last write wins on the whole reading state

Each device uploads its state; the newest upload replaces the stored one.

Architecture diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
  PH["Phone - page 212, added 3 highlights"] --> UP1["Uploads"]
  TB["Tablet - page 96, added 1 note"] --> UP2["Uploads later"]
  UP2 --> OVER["Tablet's state overwrites"]
  OVER --> LOST["3 highlights gone, position jumps backwards to 96"]

Reading position and annotations are bundled into one blob, so a device that is merely behind erases work from a device that was ahead. Annotations are the painful loss — they are the thing readers actually create.

Good

Compare timestamps per field

Store a timestamp with the position and with each annotation, and keep the newer one.

Annotations stop destroying each other, which is the important fix. Position is still wrong: "newer" is not the same as "further". A reader who opened the tablet briefly to check a reference has the most recent position and the least progress, so the phone's page 212 is replaced by page 96.

Best

A change log per device, and different rules for different data

Architecture diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
  DEV["Device - all changes recorded in a local log"] --> SYNC["POST /sync {since_cursor, changes[]}"]
  SYNC --> SRV["Server applies changes"]
  SRV --> BACK["Returns changes from other devices since the cursor + a new cursor"]
  SRV --> POS["Reading position - stored PER DEVICE"]
  POS --> FUR["On open: if another device is further ahead, offer 'Jump to page 212?'"]
  SRV --> ANN["Annotations - merged by id, edits by timestamp"]
  ANN --> TOMB["Deletes are tombstones, so an offline device learns about them"]
  • Position is per device, and the user decides. Keeping each device's own position and offering the furthest one — Kindle's behaviour — is better than any automatic rule, because only the reader knows whether page 96 was a detour.
  • Annotations merge by id. They are independent objects, so additions from different devices simply coexist; only edits to the same annotation need a timestamp comparison.
  • Deletes need tombstones. Without one, a device that was offline when a highlight was deleted re-uploads it and resurrects it on every other device.
  • A cursor makes sync incremental and resumable. The device says what it last saw, the server returns only what changed, and an interrupted sync resumes rather than restarting.

The general rule worth stating: sync conflicts are resolved per data type, not per record. Position wants "furthest", annotations want "union", settings want "most recent" — one policy for all three is guaranteed to be wrong for two of them.

Downloads and DRM

  • Book files are encrypted and served by a CDN. The device gets a license (a key bound to the device and account) from the license service. A device limit per book or account applies.
  • Returning or refunding a book revokes the license at the next sync.

Wrap-UpWrap-up

Store the library, per-device reading positions (in font-independent locations) and annotations (client-generated IDs, versions, tombstones) on the server. Devices work offline and sync by sending their local change log and pulling changes since a cursor, with simple conflict rules: offer a jump to the furthest or most recent position, last-write-wins for edited annotations, and tombstones for deletes. Deliver encrypted books through a CDN with device-bound licenses.

More Case Studies

Frequently Asked Questions

What is the Offline Multi-Device E-Book Reader (Kindle-style) system design question?

Offline Multi-Device E-Book Reader (Kindle-style) is a system design interview question asked at FAANG companies. It covers storage, api design, collaboration, security and tests your ability to design scalable, production-ready systems. InterviewSkool's breakdown walks you through requirements, API design, architecture, and trade-offs.

Which companies ask the Offline Multi-Device E-Book Reader (Kindle-style) question?

Amazon have reportedly asked variations of this question in system design interviews. The exact wording may differ, but the core design challenges remain the same.

How should I prepare for the Offline Multi-Device E-Book Reader (Kindle-style) interview question?

Start with the problem statement and scale estimates, then design the high-level architecture. Focus on the core components, data model, and API design. InterviewSkool's breakdown covers the full solution with mermaid diagrams and trade-off analysis to help you prep efficiently.

What level is the Offline Multi-Device E-Book Reader (Kindle-style) question?

This question is suitable for SDE-2, SDE-3, and Staff engineer interviews. The level guidance on this page provides specific tips for each level — SDE-2 candidates should focus on core architecture, while Staff engineers should discuss trade-offs, monitoring, and incremental rollouts.

Practice with a Mock Interview

Apply what you learned in a live system design mock interview with InterviewSkool's AI interviewer.

Start System Design Interview →