Requirements overview

This section provides an overview of the requirements specification for Papyrus, including the structure, notation, and traceability between requirements, use cases, and entities.

Requirement notation

Identifiers

  • FR-X_Y - functional requirement (e.g., FR-2_1: format conversion)

  • NFR-X_Y - non-functional requirement (e.g., NFR-4_1: startup time)

  • UC-X_Y - use case (e.g., UC-2_1: import books).

Priority levels

  • P0 - critical (v0.x).

  • P1 - high (v1.0).

  • P2 - medium (v1.x).

  • P3 - low (v2.x+).


All requirements

ID

Title

Status

Priority

FR-1_1

Account registration

open

P0

FR-1_2

Email/password login

open

P0

FR-1_3

OAuth login (Google)

open

P1

FR-1_4

Offline mode

open

P0

FR-1_5

Password recovery

open

P1

FR-1_6

Account deletion

open

P1

FR-2_1

Format conversion

open

P2

FR-2_10

Book tagging

open

P0

FR-2_11

Query language filters

open

P2

FR-2_12

ISBN barcode scanning

open

P2

FR-2_13

Metadata fetching

open

P1

FR-2_14

Physical book tracking

open

P1

FR-2_2

Manual metadata editing

open

P0

FR-2_3

Custom metadata fields

open

P2

FR-2_4

Book file export

open

P0

FR-2_5

Library data export

open

P1

FR-2_6

Book import

open

P0

FR-2_7

Full-text search

open

P1

FR-2_8

Advanced search

open

P0

FR-2_9

Shelf organization

open

P0

FR-3_1

E-book reading

open

P0

FR-3_2

Viewer customization

open

P0

FR-3_3

Reading profiles

open

P1

FR-3_4

Bookmarks

open

P0

FR-4_1

Text highlighting

open

P0

FR-4_2

Book notes

open

P0

FR-4_3

Annotation editing

open

P0

FR-4_4

Annotation export

open

P1

FR-4_5

Annotation search

open

P1

FR-5_1

Reading statistics

open

P0

FR-5_2

Statistics filtering

open

P1

FR-5_3

Cross-device sync

open

P0

FR-6_1

Reading goals

open

P1

FR-6_2

Manual goal updates

open

P1

FR-6_3

Automatic goal progress

open

P1

FR-6_4

Goal notifications

open

P2

FR-7_1

File storage backend selection

open

P0

FR-7_1_1

Metadata server configuration

open

P0

FR-7_2

File upload

open

P0

FR-7_3

OCR processing

open

P2

FR-7_4

Plugin system

open

P3

FR-7_5

OPDS catalog support

open

P2

NFR-1_1

Maximum file size

open

P0

NFR-1_2

Storage backend support

open

P0

NFR-1_3

Multi-backend configuration

open

P1

NFR-1_4

File encryption

open

P2

NFR-2_1

Online/offline parity

open

P0

NFR-2_2

Offline change indicators

open

P0

NFR-2_3

Conflict resolution

open

P1

NFR-2_4

Sync performance

open

P0

NFR-3_1

Web browser support

open

P0

NFR-3_2

Desktop operating system support

open

P0

NFR-3_3

Mobile operating system support

open

P0

NFR-3_4

E-ink device support

open

P1

NFR-4_1

Application startup

open

P0

NFR-4_2

Book opening

open

P0

NFR-4_3

Search performance

open

P0

NFR-4_4

Library scalability

open

P1

NFR-4_5

E-ink performance

open

P1

NFR-5_1

Design system

open

P0

NFR-5_2

Accessibility

open

P0

NFR-5_3

RTL and internationalization

open

P1

NFR-5_4

Localization

open

P1

NFR-5_5

E-ink usability

open

P1

NFR-6_1

Password security

open

P0

NFR-6_2

Transport security

open

P0

NFR-6_3

Two-factor authentication

open

P2

NFR-6_4

Session management

open

P0

NFR-6_5

Privacy by default

open

P0

NFR-7_1

System uptime

open

P1

NFR-7_2

Data integrity

open

P0

NFR-7_3

Network resilience

open

P0

NFR-7_4

Backup and restore

open

P1

NFR-8_1

Plugin architecture

open

P3

NFR-9_1

Code quality

open

P1

NFR-9_2

Logging and monitoring

open

P1

UC-1_1

Create user account

open

P0

UC-1_2

Login with credentials

open

P0

UC-1_3

Login with Google account

open

P1

UC-1_4

Use application offline

open

P0

UC-1_5

Recover password

open

P1

UC-1_6

Delete account

open

P1

UC-2_1

Import book files

open

P0

UC-2_2

Convert book formats

open

P2

UC-2_3

Edit book metadata

open

P0

UC-2_4

Organize books into shelves

open

P0

UC-2_5

Tag books

open

P0

UC-2_6

Search books

open

P0

UC-2_7

Export books and data

open

P0

UC-2_8

Scan ISBN barcode

open

P2

UC-2_9

Track physical book

open

P1

UC-3_1

Read books with integrated viewer

open

P0

UC-3_2

Customize reading experience

open

P0

UC-3_3

Manage reading profiles

open

P1

UC-3_4

Manage bookmarks

open

P0

UC-4_1

Create text annotations

open

P0

UC-4_2

Create book notes

open

P0

UC-4_3

Manage annotations

open

P0

UC-4_4

Export annotations

open

P1

UC-4_5

Search annotations

open

P1

UC-5_1

Track reading progress

open

P0

UC-5_2

Filter progress statistics

open

P1

UC-6_1

Create reading goals

open

P1

UC-6_2

Manage goal progress

open

P1

UC-7_1

Configure storage options

open

P0

UC-7_2

Process scanned documents

open

P2

UC-7_3

Synchronize data across devices

open

P0

UC-7_4

Browse OPDS catalog

open

P2

Functional requirements by category

Category

Scope

Description

User management

FR-1.x

Account, auth, offline mode

Book management

FR-2.x

Import, organize, search

Integrated viewer

FR-3.x

Reading, customization, profiles

Annotations and notes

FR-4.x

Highlights, notes, export

Progress tracking

FR-5.x

Statistics, sync

Goal management

FR-6.x

Goals, progress, notifications

Storage and sync

FR-7.x

Metadata server, file storage backends, OPDS

Non-functional requirements by category

Category

Scope

Description

Storage

NFR-1.x

File size, backends, encryption

Synchronization

NFR-2.x

Offline, conflicts, performance

Platform Support

NFR-3.x

Web, desktop, mobile, e-ink

Performance

NFR-4.x

Startup, open, search, scale

Usability

NFR-5.x

Design, accessibility, i18n

Security

NFR-6.x

Auth, encryption, privacy

Reliability

NFR-7.x

Uptime, integrity, backup

Extensibility

NFR-8.x

Plugin architecture

Maintainability

NFR-9.x

Code quality, logging


Dependency graphs

User management

digraph needflow { compound=true; graph [ rankdir="LR"; bgcolor="transparent"; pad="0.3"; nodesep="0.4"; ranksep="0.6"; ] node [ fontname="system-ui, -apple-system, sans-serif"; fontsize="11"; fontcolor="#333333"; style="filled,rounded"; penwidth="1.2"; color="#cccccc"; ] edge [ color="#999999"; arrowsize="0.7"; penwidth="1.0"; fontname="system-ui, -apple-system, sans-serif"; fontsize="9"; fontcolor="#777777"; ] // node definitions "UC-1_1" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Create user<br align="left"/>account</b><br align="left"/><font point-size="10">UC-1_1</font><br align="left"/>>, tooltip="UC-1_1", href="../design/use-cases.html#UC-1_1", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-1_2" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Login with<br align="left"/>credentials</b><br align="left"/><font point-size="10">UC-1_2</font><br align="left"/>>, tooltip="UC-1_2", href="../design/use-cases.html#UC-1_2", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-1_3" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Login with<br align="left"/>Google account</b><br align="left"/><font point-size="10">UC-1_3</font><br align="left"/>>, tooltip="UC-1_3", href="../design/use-cases.html#UC-1_3", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-1_4" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Use application<br align="left"/>offline</b><br align="left"/><font point-size="10">UC-1_4</font><br align="left"/>>, tooltip="UC-1_4", href="../design/use-cases.html#UC-1_4", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-1_5" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Recover<br align="left"/>password</b><br align="left"/><font point-size="10">UC-1_5</font><br align="left"/>>, tooltip="UC-1_5", href="../design/use-cases.html#UC-1_5", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-1_6" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Delete account</b><br align="left"/><font point-size="10">UC-1_6</font><br align="left"/>>, tooltip="UC-1_6", href="../design/use-cases.html#UC-1_6", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "FR-1_1" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Account<br align="left"/>registration</b><br align="left"/><font point-size="10">FR-1_1</font><br align="left"/>>, tooltip="FR-1_1", href="functional.html#FR-1_1", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-1_2" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Email/password<br align="left"/>login</b><br align="left"/><font point-size="10">FR-1_2</font><br align="left"/>>, tooltip="FR-1_2", href="functional.html#FR-1_2", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-1_3" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>OAuth login<br align="left"/>(Google)</b><br align="left"/><font point-size="10">FR-1_3</font><br align="left"/>>, tooltip="FR-1_3", href="functional.html#FR-1_3", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-1_4" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Offline mode</b><br align="left"/><font point-size="10">FR-1_4</font><br align="left"/>>, tooltip="FR-1_4", href="functional.html#FR-1_4", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-1_5" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Password<br align="left"/>recovery</b><br align="left"/><font point-size="10">FR-1_5</font><br align="left"/>>, tooltip="FR-1_5", href="functional.html#FR-1_5", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-1_6" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Account<br align="left"/>deletion</b><br align="left"/><font point-size="10">FR-1_6</font><br align="left"/>>, tooltip="FR-1_6", href="functional.html#FR-1_6", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; // edge definitions "UC-1_1" -> "FR-1_1" [arrowhead=vee]; "UC-1_2" -> "FR-1_2" [arrowhead=vee]; "UC-1_3" -> "FR-1_3" [arrowhead=vee]; "UC-1_4" -> "FR-1_4" [arrowhead=vee]; "UC-1_5" -> "FR-1_5" [arrowhead=vee]; "UC-1_6" -> "FR-1_6" [arrowhead=vee]; "FR-1_1" -> "UC-1_1" [arrowhead=vee]; "FR-1_2" -> "UC-1_2" [arrowhead=vee]; "FR-1_3" -> "UC-1_3" [arrowhead=vee]; "FR-1_4" -> "UC-1_4" [arrowhead=vee]; "FR-1_5" -> "UC-1_5" [arrowhead=vee]; "FR-1_6" -> "UC-1_6" [arrowhead=vee]; }

Book management

digraph needflow { compound=true; graph [ rankdir="LR"; bgcolor="transparent"; pad="0.3"; nodesep="0.4"; ranksep="0.6"; ] node [ fontname="system-ui, -apple-system, sans-serif"; fontsize="11"; fontcolor="#333333"; style="filled,rounded"; penwidth="1.2"; color="#cccccc"; ] edge [ color="#999999"; arrowsize="0.7"; penwidth="1.0"; fontname="system-ui, -apple-system, sans-serif"; fontsize="9"; fontcolor="#777777"; ] // node definitions "UC-2_1" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Import book<br align="left"/>files</b><br align="left"/><font point-size="10">UC-2_1</font><br align="left"/>>, tooltip="UC-2_1", href="../design/use-cases.html#UC-2_1", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-2_2" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Convert book<br align="left"/>formats</b><br align="left"/><font point-size="10">UC-2_2</font><br align="left"/>>, tooltip="UC-2_2", href="../design/use-cases.html#UC-2_2", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-2_3" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Edit book<br align="left"/>metadata</b><br align="left"/><font point-size="10">UC-2_3</font><br align="left"/>>, tooltip="UC-2_3", href="../design/use-cases.html#UC-2_3", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-2_4" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Organize books<br align="left"/>into shelves</b><br align="left"/><font point-size="10">UC-2_4</font><br align="left"/>>, tooltip="UC-2_4", href="../design/use-cases.html#UC-2_4", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-2_5" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Tag books</b><br align="left"/><font point-size="10">UC-2_5</font><br align="left"/>>, tooltip="UC-2_5", href="../design/use-cases.html#UC-2_5", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-2_6" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Search books</b><br align="left"/><font point-size="10">UC-2_6</font><br align="left"/>>, tooltip="UC-2_6", href="../design/use-cases.html#UC-2_6", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-2_7" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Export books<br align="left"/>and data</b><br align="left"/><font point-size="10">UC-2_7</font><br align="left"/>>, tooltip="UC-2_7", href="../design/use-cases.html#UC-2_7", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-2_8" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Scan ISBN<br align="left"/>barcode</b><br align="left"/><font point-size="10">UC-2_8</font><br align="left"/>>, tooltip="UC-2_8", href="../design/use-cases.html#UC-2_8", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-2_9" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Track physical<br align="left"/>book</b><br align="left"/><font point-size="10">UC-2_9</font><br align="left"/>>, tooltip="UC-2_9", href="../design/use-cases.html#UC-2_9", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "FR-2_1" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Format<br align="left"/>conversion</b><br align="left"/><font point-size="10">FR-2_1</font><br align="left"/>>, tooltip="FR-2_1", href="functional.html#FR-2_1", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-2_2" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Manual metadata<br align="left"/>editing</b><br align="left"/><font point-size="10">FR-2_2</font><br align="left"/>>, tooltip="FR-2_2", href="functional.html#FR-2_2", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-2_3" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Custom metadata<br align="left"/>fields</b><br align="left"/><font point-size="10">FR-2_3</font><br align="left"/>>, tooltip="FR-2_3", href="functional.html#FR-2_3", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-2_4" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Book file<br align="left"/>export</b><br align="left"/><font point-size="10">FR-2_4</font><br align="left"/>>, tooltip="FR-2_4", href="functional.html#FR-2_4", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-2_5" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Library data<br align="left"/>export</b><br align="left"/><font point-size="10">FR-2_5</font><br align="left"/>>, tooltip="FR-2_5", href="functional.html#FR-2_5", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-2_6" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Book import</b><br align="left"/><font point-size="10">FR-2_6</font><br align="left"/>>, tooltip="FR-2_6", href="functional.html#FR-2_6", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-2_7" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Full-text<br align="left"/>search</b><br align="left"/><font point-size="10">FR-2_7</font><br align="left"/>>, tooltip="FR-2_7", href="functional.html#FR-2_7", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-2_8" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Advanced search</b><br align="left"/><font point-size="10">FR-2_8</font><br align="left"/>>, tooltip="FR-2_8", href="functional.html#FR-2_8", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-2_9" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Shelf<br align="left"/>organization</b><br align="left"/><font point-size="10">FR-2_9</font><br align="left"/>>, tooltip="FR-2_9", href="functional.html#FR-2_9", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-2_10" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Book tagging</b><br align="left"/><font point-size="10">FR-2_10</font><br align="left"/>>, tooltip="FR-2_10", href="functional.html#FR-2_10", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-2_11" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Query language<br align="left"/>filters</b><br align="left"/><font point-size="10">FR-2_11</font><br align="left"/>>, tooltip="FR-2_11", href="functional.html#FR-2_11", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-2_12" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>ISBN barcode<br align="left"/>scanning</b><br align="left"/><font point-size="10">FR-2_12</font><br align="left"/>>, tooltip="FR-2_12", href="functional.html#FR-2_12", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-2_13" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Metadata<br align="left"/>fetching</b><br align="left"/><font point-size="10">FR-2_13</font><br align="left"/>>, tooltip="FR-2_13", href="functional.html#FR-2_13", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-2_14" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Physical book<br align="left"/>tracking</b><br align="left"/><font point-size="10">FR-2_14</font><br align="left"/>>, tooltip="FR-2_14", href="functional.html#FR-2_14", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; // edge definitions "UC-2_1" -> "FR-2_6" [arrowhead=vee]; "UC-2_2" -> "FR-2_1" [arrowhead=vee]; "UC-2_3" -> "FR-2_2" [arrowhead=vee]; "UC-2_3" -> "FR-2_13" [arrowhead=vee]; "UC-2_4" -> "FR-2_9" [arrowhead=vee]; "UC-2_5" -> "FR-2_10" [arrowhead=vee]; "UC-2_6" -> "FR-2_7" [arrowhead=vee]; "UC-2_6" -> "FR-2_8" [arrowhead=vee]; "UC-2_6" -> "FR-2_11" [arrowhead=vee]; "UC-2_7" -> "FR-2_4" [arrowhead=vee]; "UC-2_7" -> "FR-2_5" [arrowhead=vee]; "UC-2_8" -> "FR-2_12" [arrowhead=vee]; "UC-2_9" -> "FR-2_14" [arrowhead=vee]; "FR-2_1" -> "UC-2_2" [arrowhead=vee]; "FR-2_2" -> "UC-2_3" [arrowhead=vee]; "FR-2_3" -> "UC-2_3" [arrowhead=vee]; "FR-2_4" -> "UC-2_7" [arrowhead=vee]; "FR-2_5" -> "UC-2_7" [arrowhead=vee]; "FR-2_6" -> "UC-2_1" [arrowhead=vee]; "FR-2_7" -> "UC-2_6" [arrowhead=vee]; "FR-2_8" -> "UC-2_6" [arrowhead=vee]; "FR-2_9" -> "UC-2_4" [arrowhead=vee]; "FR-2_10" -> "UC-2_5" [arrowhead=vee]; "FR-2_11" -> "UC-2_6" [arrowhead=vee]; "FR-2_12" -> "UC-2_8" [arrowhead=vee]; "FR-2_13" -> "UC-2_3" [arrowhead=vee]; "FR-2_14" -> "UC-2_9" [arrowhead=vee]; }

Integrated viewer

digraph needflow { compound=true; graph [ rankdir="LR"; bgcolor="transparent"; pad="0.3"; nodesep="0.4"; ranksep="0.6"; ] node [ fontname="system-ui, -apple-system, sans-serif"; fontsize="11"; fontcolor="#333333"; style="filled,rounded"; penwidth="1.2"; color="#cccccc"; ] edge [ color="#999999"; arrowsize="0.7"; penwidth="1.0"; fontname="system-ui, -apple-system, sans-serif"; fontsize="9"; fontcolor="#777777"; ] // node definitions "UC-3_1" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Read books with<br align="left"/>integrated<br align="left"/>viewer</b><br align="left"/><font point-size="10">UC-3_1</font><br align="left"/>>, tooltip="UC-3_1", href="../design/use-cases.html#UC-3_1", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-3_2" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Customize<br align="left"/>reading<br align="left"/>experience</b><br align="left"/><font point-size="10">UC-3_2</font><br align="left"/>>, tooltip="UC-3_2", href="../design/use-cases.html#UC-3_2", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-3_3" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Manage reading<br align="left"/>profiles</b><br align="left"/><font point-size="10">UC-3_3</font><br align="left"/>>, tooltip="UC-3_3", href="../design/use-cases.html#UC-3_3", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-3_4" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Manage<br align="left"/>bookmarks</b><br align="left"/><font point-size="10">UC-3_4</font><br align="left"/>>, tooltip="UC-3_4", href="../design/use-cases.html#UC-3_4", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "FR-3_1" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>E-book reading</b><br align="left"/><font point-size="10">FR-3_1</font><br align="left"/>>, tooltip="FR-3_1", href="functional.html#FR-3_1", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-3_2" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Viewer<br align="left"/>customization</b><br align="left"/><font point-size="10">FR-3_2</font><br align="left"/>>, tooltip="FR-3_2", href="functional.html#FR-3_2", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-3_3" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Reading<br align="left"/>profiles</b><br align="left"/><font point-size="10">FR-3_3</font><br align="left"/>>, tooltip="FR-3_3", href="functional.html#FR-3_3", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-3_4" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Bookmarks</b><br align="left"/><font point-size="10">FR-3_4</font><br align="left"/>>, tooltip="FR-3_4", href="functional.html#FR-3_4", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; // edge definitions "UC-3_1" -> "FR-3_1" [arrowhead=vee]; "UC-3_2" -> "FR-3_2" [arrowhead=vee]; "UC-3_3" -> "FR-3_3" [arrowhead=vee]; "UC-3_4" -> "FR-3_4" [arrowhead=vee]; "FR-3_1" -> "UC-3_1" [arrowhead=vee]; "FR-3_2" -> "UC-3_2" [arrowhead=vee]; "FR-3_3" -> "UC-3_3" [arrowhead=vee]; "FR-3_4" -> "UC-3_4" [arrowhead=vee]; }

Annotations & notes

digraph needflow { compound=true; graph [ rankdir="LR"; bgcolor="transparent"; pad="0.3"; nodesep="0.4"; ranksep="0.6"; ] node [ fontname="system-ui, -apple-system, sans-serif"; fontsize="11"; fontcolor="#333333"; style="filled,rounded"; penwidth="1.2"; color="#cccccc"; ] edge [ color="#999999"; arrowsize="0.7"; penwidth="1.0"; fontname="system-ui, -apple-system, sans-serif"; fontsize="9"; fontcolor="#777777"; ] // node definitions "UC-4_1" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Create text<br align="left"/>annotations</b><br align="left"/><font point-size="10">UC-4_1</font><br align="left"/>>, tooltip="UC-4_1", href="../design/use-cases.html#UC-4_1", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-4_2" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Create book<br align="left"/>notes</b><br align="left"/><font point-size="10">UC-4_2</font><br align="left"/>>, tooltip="UC-4_2", href="../design/use-cases.html#UC-4_2", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-4_3" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Manage<br align="left"/>annotations</b><br align="left"/><font point-size="10">UC-4_3</font><br align="left"/>>, tooltip="UC-4_3", href="../design/use-cases.html#UC-4_3", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-4_4" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Export<br align="left"/>annotations</b><br align="left"/><font point-size="10">UC-4_4</font><br align="left"/>>, tooltip="UC-4_4", href="../design/use-cases.html#UC-4_4", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-4_5" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Search<br align="left"/>annotations</b><br align="left"/><font point-size="10">UC-4_5</font><br align="left"/>>, tooltip="UC-4_5", href="../design/use-cases.html#UC-4_5", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "FR-4_1" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Text<br align="left"/>highlighting</b><br align="left"/><font point-size="10">FR-4_1</font><br align="left"/>>, tooltip="FR-4_1", href="functional.html#FR-4_1", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-4_2" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Book notes</b><br align="left"/><font point-size="10">FR-4_2</font><br align="left"/>>, tooltip="FR-4_2", href="functional.html#FR-4_2", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-4_3" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Annotation<br align="left"/>editing</b><br align="left"/><font point-size="10">FR-4_3</font><br align="left"/>>, tooltip="FR-4_3", href="functional.html#FR-4_3", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-4_4" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Annotation<br align="left"/>export</b><br align="left"/><font point-size="10">FR-4_4</font><br align="left"/>>, tooltip="FR-4_4", href="functional.html#FR-4_4", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-4_5" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Annotation<br align="left"/>search</b><br align="left"/><font point-size="10">FR-4_5</font><br align="left"/>>, tooltip="FR-4_5", href="functional.html#FR-4_5", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; // edge definitions "UC-4_1" -> "FR-4_1" [arrowhead=vee]; "UC-4_2" -> "FR-4_2" [arrowhead=vee]; "UC-4_3" -> "FR-4_3" [arrowhead=vee]; "UC-4_4" -> "FR-4_4" [arrowhead=vee]; "UC-4_5" -> "FR-4_5" [arrowhead=vee]; "FR-4_1" -> "UC-4_1" [arrowhead=vee]; "FR-4_2" -> "UC-4_2" [arrowhead=vee]; "FR-4_3" -> "UC-4_3" [arrowhead=vee]; "FR-4_4" -> "UC-4_4" [arrowhead=vee]; "FR-4_5" -> "UC-4_5" [arrowhead=vee]; }

Progress & goals

digraph needflow { compound=true; graph [ rankdir="LR"; bgcolor="transparent"; pad="0.3"; nodesep="0.4"; ranksep="0.6"; ] node [ fontname="system-ui, -apple-system, sans-serif"; fontsize="11"; fontcolor="#333333"; style="filled,rounded"; penwidth="1.2"; color="#cccccc"; ] edge [ color="#999999"; arrowsize="0.7"; penwidth="1.0"; fontname="system-ui, -apple-system, sans-serif"; fontsize="9"; fontcolor="#777777"; ] // node definitions "UC-5_1" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Track reading<br align="left"/>progress</b><br align="left"/><font point-size="10">UC-5_1</font><br align="left"/>>, tooltip="UC-5_1", href="../design/use-cases.html#UC-5_1", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-5_2" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Filter progress<br align="left"/>statistics</b><br align="left"/><font point-size="10">UC-5_2</font><br align="left"/>>, tooltip="UC-5_2", href="../design/use-cases.html#UC-5_2", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-6_1" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Create reading<br align="left"/>goals</b><br align="left"/><font point-size="10">UC-6_1</font><br align="left"/>>, tooltip="UC-6_1", href="../design/use-cases.html#UC-6_1", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-6_2" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Manage goal<br align="left"/>progress</b><br align="left"/><font point-size="10">UC-6_2</font><br align="left"/>>, tooltip="UC-6_2", href="../design/use-cases.html#UC-6_2", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "FR-5_1" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Reading<br align="left"/>statistics</b><br align="left"/><font point-size="10">FR-5_1</font><br align="left"/>>, tooltip="FR-5_1", href="functional.html#FR-5_1", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-5_2" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Statistics<br align="left"/>filtering</b><br align="left"/><font point-size="10">FR-5_2</font><br align="left"/>>, tooltip="FR-5_2", href="functional.html#FR-5_2", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-5_3" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Cross-device<br align="left"/>sync</b><br align="left"/><font point-size="10">FR-5_3</font><br align="left"/>>, tooltip="FR-5_3", href="functional.html#FR-5_3", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-6_1" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Reading goals</b><br align="left"/><font point-size="10">FR-6_1</font><br align="left"/>>, tooltip="FR-6_1", href="functional.html#FR-6_1", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-6_2" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Manual goal<br align="left"/>updates</b><br align="left"/><font point-size="10">FR-6_2</font><br align="left"/>>, tooltip="FR-6_2", href="functional.html#FR-6_2", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-6_3" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Automatic goal<br align="left"/>progress</b><br align="left"/><font point-size="10">FR-6_3</font><br align="left"/>>, tooltip="FR-6_3", href="functional.html#FR-6_3", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-6_4" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Goal<br align="left"/>notifications</b><br align="left"/><font point-size="10">FR-6_4</font><br align="left"/>>, tooltip="FR-6_4", href="functional.html#FR-6_4", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; // edge definitions "UC-5_1" -> "FR-5_1" [arrowhead=vee]; "UC-5_2" -> "FR-5_2" [arrowhead=vee]; "UC-6_1" -> "FR-6_1" [arrowhead=vee]; "UC-6_2" -> "FR-6_2" [arrowhead=vee]; "UC-6_2" -> "FR-6_3" [arrowhead=vee]; "FR-5_1" -> "UC-5_1" [arrowhead=vee]; "FR-5_2" -> "UC-5_2" [arrowhead=vee]; "FR-6_1" -> "UC-6_1" [arrowhead=vee]; "FR-6_2" -> "UC-6_2" [arrowhead=vee]; "FR-6_3" -> "UC-6_2" [arrowhead=vee]; "FR-6_4" -> "UC-6_2" [arrowhead=vee]; }

Storage & sync

digraph needflow { compound=true; graph [ rankdir="LR"; bgcolor="transparent"; pad="0.3"; nodesep="0.4"; ranksep="0.6"; ] node [ fontname="system-ui, -apple-system, sans-serif"; fontsize="11"; fontcolor="#333333"; style="filled,rounded"; penwidth="1.2"; color="#cccccc"; ] edge [ color="#999999"; arrowsize="0.7"; penwidth="1.0"; fontname="system-ui, -apple-system, sans-serif"; fontsize="9"; fontcolor="#777777"; ] // node definitions "UC-7_1" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Configure<br align="left"/>storage options</b><br align="left"/><font point-size="10">UC-7_1</font><br align="left"/>>, tooltip="UC-7_1", href="../design/use-cases.html#UC-7_1", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-7_2" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Process scanned<br align="left"/>documents</b><br align="left"/><font point-size="10">UC-7_2</font><br align="left"/>>, tooltip="UC-7_2", href="../design/use-cases.html#UC-7_2", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-7_3" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Synchronize<br align="left"/>data across<br align="left"/>devices</b><br align="left"/><font point-size="10">UC-7_3</font><br align="left"/>>, tooltip="UC-7_3", href="../design/use-cases.html#UC-7_3", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "UC-7_4" [label=<<font point-size="12">Use Case</font><br align="left"/><b>Browse OPDS<br align="left"/>catalog</b><br align="left"/><font point-size="10">UC-7_4</font><br align="left"/>>, tooltip="UC-7_4", href="../design/use-cases.html#UC-7_4", target="_top", shape="note", style="filled,rounded,filled", fillcolor="#6FA8D4"]; "FR-7_1" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>File storage<br align="left"/>backend<br align="left"/>selection</b><br align="left"/><font point-size="10">FR-7_1</font><br align="left"/>>, tooltip="FR-7_1", href="functional.html#FR-7_1", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-7_1_1" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Metadata server<br align="left"/>configuration</b><br align="left"/><font point-size="10">FR-7_1_1</font><br align="left"/>>, tooltip="FR-7_1_1", href="functional.html#FR-7_1_1", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-7_2" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>File upload</b><br align="left"/><font point-size="10">FR-7_2</font><br align="left"/>>, tooltip="FR-7_2", href="functional.html#FR-7_2", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-7_3" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>OCR processing</b><br align="left"/><font point-size="10">FR-7_3</font><br align="left"/>>, tooltip="FR-7_3", href="functional.html#FR-7_3", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-7_4" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>Plugin system</b><br align="left"/><font point-size="10">FR-7_4</font><br align="left"/>>, tooltip="FR-7_4", href="functional.html#FR-7_4", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; "FR-7_5" [label=<<font point-size="12">Functional Requirement</font><br align="left"/><b>OPDS catalog<br align="left"/>support</b><br align="left"/><font point-size="10">FR-7_5</font><br align="left"/>>, tooltip="FR-7_5", href="functional.html#FR-7_5", target="_top", shape="box3d", style="filled,rounded,filled", fillcolor="#7C6FD4"]; // edge definitions "UC-7_1" -> "FR-7_1" [arrowhead=vee]; "UC-7_1" -> "FR-7_1_1" [arrowhead=vee]; "UC-7_2" -> "FR-7_3" [arrowhead=vee]; "UC-7_4" -> "FR-7_5" [arrowhead=vee]; "FR-7_1" -> "UC-7_1" [arrowhead=vee]; "FR-7_1_1" -> "UC-7_1" [arrowhead=vee]; "FR-7_3" -> "UC-7_2" [arrowhead=vee]; "FR-7_5" -> "UC-7_4" [arrowhead=vee]; }

Core principles

User data ownership

All user data, such as books, notes, annotations, can be exported in open formats, avoiding vendor lock-in and enabling self-hosting options for those who prefer full control over their data.

Cross-platform accessibility

Consistent experience and a full set of features across all devices and platforms, with additional platform-specific features, such as themes suitable for e-ink screens.

Offline functionality

No account or internet connection is required to use application’s core. Non-essential features, such as data synchronization and cloud file storage is optional.

Privacy first

Local-first architecture with no analytics or tracking enabled by default. A user can avoid relying on cloud services and use the system offline or with a self-hosted server instance.

Developer friendly

The system is fully open source and makes it easy to self-host the server for file storage and data sync. Documented REST API allows users to easily build their own clients and book management solutions.