Owner rulings from the admin-docs planning session: - sync-guide: dropped 'Kindle and reMarkable are under consideration' — no such plans exist, and promising support for proprietary device interfaces we will never build sets false expectations. Device posture stays as the table states it: web, Android app, KOReader anywhere (including jailbroken Kindle hardware), native Kobo the sole exception. - calibre-integration: cut 'Custom Calibre Columns (Future)' + 'Stay tuned!' — unshipped-feature promises do not belong in docs; calibre integration is a by-product of the scanner's sidecar support, not a roadmap item. The features list describing Calibre itself stays (that is Calibre's promise, not ours). - android-app: de-branded the two Kindle references per owner's legal caution — 'the Kindle app to Kindle cloud' analogy and 'quality bar is the Kindle app' are now 'any dedicated reader app to its server' / 'a first-class native reader app'; engineering substance unchanged. Governance rule going forward (codified in writing-ui-docs.md in a follow-up): no future-improvement or coming-soon language anywhere without explicit owner approval; anything found gets reported, not silently kept or silently removed.
9.7 KiB
Android App — Design & Roadmap
This document describes the planned native Android client for Bookhoard: a thin, offline-first reading app that treats the Bookhoard server as its backend. The relationship is the same as any dedicated reader app to its server: the server owns the library, sync, and conflict resolution; the app is a dedicated, mobile-first reading frontend with its own UI, designed independently of the web interface.
Status: Planning / pre-development
Companion repo: bookhoard-app (separate repository, AGPL-3.0)
🎯 Product Vision
- An amazing ereader first and foremost — rendering polish, latency, and reading UX are the product
- Mobile-first UI designed from scratch for phones; not a wrapper around the web app
- Thin client: the server remains authoritative for all sync, book matching, and conflict resolution
- v1 formats: EPUB (ebooks) and CBZ (comics/manga); PDF comes nearly free via the reader toolkit
- Android first. iOS is a real roadmap item but unscheduled — likely contributor-driven
🛠 Tech Stack
| Concern | Choice |
|---|---|
| Language | Kotlin |
| UI | Jetpack Compose + Material 3 |
| Reader engine | Readium Kotlin toolkit |
| Local database | Room |
| Networking | OkHttp / Retrofit + WebSocket |
| Background | WorkManager |
| Images | Coil |
| Settings | DataStore |
Why native Android
- The quality bar is a first-class native reader app. Page-turn latency, text layout fidelity, PDF rendering (
PdfRenderer), and comic/manga image pipelines are platform-level strengths — and they are the hard parts in a WebView, not the easy parts. - Android-first removes the "share one codebase across two platforms simultaneously" constraint that motivates hybrid stacks.
- Solo, AI-assisted development compresses the cost of native (code volume), while native's failure modes (well-documented platform APIs) are far easier to debug — alone or with AI — than cross-framework bridge/plugin bugs.
- The target audience is the self-hosted community, best reached via GitHub Releases and F-Droid rather than app-store optimization.
Alternatives considered
- Capacitor / WebView shell (the audiobookshelf-app model): excellent when a self-contained SPA already exists; a poor fit here. Bookhoard's web UI is server-rendered HTMX and cannot be packaged, comics rendering in a WebView caps the polish target, and deep offline support fights the shell.
- Flutter: strong middle ground, but no Readium port and a weaker EPUB/PDF plugin ecosystem than the native toolkits.
- Kotlin Multiplatform: only pays off with a committed near-term iOS effort. Revisit if iOS becomes active; until then it would constrain v1 for a hypothetical.
🏗 Architecture
Thin, offline-first client. The server API is the contract (see API Reference and WebSocket API).
Module layout
:app Compose UI, navigation, dependency injection
:core:domain Pure Kotlin — models, sync logic, use cases (no Android deps)
:core:data Room, Retrofit/OkHttp, downloads and file storage
:feature:reader Readium navigator integration and reading UI
Keeping :core:domain free of Android dependencies preserves optionality: a future iOS client, a KMP extraction, or a desktop client can reuse or port the domain logic without touching the UI.
Offline-first sync flow
- UI writes go to the local Room mirror first (never blocked on network)
- A WorkManager queue replays changes to the existing REST endpoints (
/api/progress,/api/media-items/:id/notes,/highlights, etc.) - Conflicts are resolved by the server's existing mechanisms — the client never invents its own merge logic
- While online, a WebSocket connection receives realtime updates pushed by other devices (web reader, KOReader)
- Books are downloaded to app storage for fully offline reading, with storage management UI
Authentication & device identity
- Primary auth: username/password login via the existing endpoints (
POST /api/auth/login+ refresh). The app is a full user client — browse, collections, ratings, and annotation management all live behind the user JWT, which device tokens cannot reach - After login, the app registers itself as a device (
device_type: mobile) and self-approves its registration using its own JWT — approval only requires a logged-in user. The phone then appears on the Devices page with sync attribution, per-device settings, and individually revocable access, with no QR ceremony - Netflix-style QR pairing as a zero-typing sign-in option: post-v1 (see below)
📖 Reader Engine
Readium provides EPUB, PDF, and CBZ through one publication model and navigator — production-hardened by real reading apps. This avoids building and maintaining three renderers.
Planned reading features:
- Custom fonts (including user-loaded), adjustable margins and line height
- Themes including OLED true-black for battery
- Paginated and scroll modes; gesture and volume-key page turns
- Keep-screen-awake while reading
- Highlights, notes, and bookmarks synced via existing APIs (including deleted-annotation restore)
- Resume to exact position using EPUB CFI, consistent with universal sync
Comics & manga UX
- RTL reading direction and double-page spreads with correct cover/single-page handling
- Per-book reading-mode overrides (a manga library can default to RTL)
- Zoom and pan; aggressive preloading of adjacent pages
- Webtoon / continuous vertical mode: post-v1
Reader settings parity with the web reader
The web reader (web/src/reader/) is the reference implementation for reading ergonomics — its font selection, reading themes, and highlight system are considered well-designed; only its desktop-oriented presentation is being replaced on mobile. The Android reader should reuse the same settings model (stored in the reader_settings table and synced via the settings endpoint) rather than inventing a parallel one:
- Fonts: the same roster of variable fonts, self-hosted under
/static/fonts/— Literata (default), Crimson Pro, Source Serif 4, EB Garamond, Libertinus Serif, Noto Serif, Charis SIL, IBM Plex Serif (FONT_MAPinweb/src/reader/reader.ts) - Typography:
font_size(default 18),line_height(1.6),margin_width,double_page_spread - Themes:
chrome_theme(defaulttokyo-night) for app chrome vsreading_theme/reading_modefor the page surface, plus the fx stack (fx_brightness,fx_contrast,fx_invert) - Navigation:
tap_zones_enabled+tap_zone_size,reading_direction,progress_mode - Highlights: per-annotation color (default
#ffd54f), matching the web palette
Settings chosen on one device should follow the user everywhere — mobile changes write back through the same sync.
🍎 iOS Posture
iOS is a real roadmap item but not near-term. The strategy is not to pre-pay for it with KMP or a cross-platform framework. Instead:
- The documented REST/WebSocket API is the sharing mechanism — a future iOS client is a new client over the same contract, never a rewrite of shared logic
- A contributor-driven Swift/SwiftUI client is welcome; the server needs no changes to support it
📦 Distribution & Licensing
- License: AGPL-3.0, matching the Bookhoard server
- Channels: GitHub Releases and F-Droid; Play Store optional later
🚧 Milestones
- Scaffold — app shell, auth + QR device pairing, library browsing, book downloads
- EPUB reading — Readium integration, CFI progress sync, offline-first reading
- Annotations — highlights/notes/bookmarks sync with offline queue
- Comics — CBZ navigator with manga modes (RTL, spreads, zoom)
- Polish — OLED themes, gestures, background sync, storage management
🔭 Post-v1 Ideas
QR pairing sign-in (Netflix-style)
"Add device" on the web (while logged in) displays a QR code; a fresh app install scans it and is fully signed in — no server URL, no password, nothing typed on the phone.
- QR is a full login: the claim endpoint returns JWT + refresh token (plus the device token for sync identity)
- Typed-code fallback (GitHub/Netflix device-flow style: app displays a short code, user enters it on the web) for phones with broken cameras or no camera
- KOReader keeps its existing flow unchanged — no typed-code pairing there; it is already as convenient as it can be
- Use the configured
BASE_URL, never a detected LAN IP — if the server is published athttps://public.domain, pairing must work identically from outside the LAN - Requires small server additions:
pair/claimendpoints backed by single-use pairing sessions with a short TTL (in-memory likependingRegistrations)
Other ideas
- Webtoon / continuous vertical reading mode
- Home-screen widgets and app shortcuts ("continue reading")
- Text-to-speech
- OPDS feed consumption from other servers
Related Documentation
- API Reference - Complete REST API
- WebSocket API - Real-time sync events
- Sync Guide - How universal sync works
- Devices API - Device registration and approval