Projects yomikata

yomikata

Live · sign-in required

Manga reader for Android and the browser. Reading progress follows from tablet to phone without you doing anything for it.

Period
2025 – present
Role
Solo — concept to operations
Status
Live, behind single sign-on
Code
Private repository

The manga sit on my own server, and reading alternates: on the phone when out, on the tablet at home, both in the same series. From that follows the one requirement everything hangs on — a volume left half read on the tablet has to open at exactly that page on the phone, without anyone doing anything for it. None of the existing readers could manage that against this server: some take for granted capabilities it does not have, and the rest simply do not know what a reading position is.

yomikata is the reader for it — an Android app and a web interface, both against a backend of their own that in turn talks to the library. On top of that comes what separates a manga reader from a comic reader: reading direction is set per series, because a mixed library holds both directions and the server’s own answer is worthless here. Downloaded volumes are fully readable in flight mode and clear themselves away once they have been read. Brightness and warm filter sit in the reader itself, not three levels deep in the settings — at night the system’s lowest brightness is still too bright.

What stands out is the line the project draws. The app is built for one person with two devices, and says so: one appearance, one file format, no filters, no sorting. What several users really need — their own accounts, their own access, their own reading positions — is carried by the backend underneath, and anyone missing the light appearance reads in the browser. Simplicity over generality is not an excuse made afterwards here, it is a written-down rule.

Stack
KotlinComposeRoomRetrofit · OkHttpTypeScriptExpressSQLite (better-sqlite3)React · VitePWASingle-Sign-on (OIDC)

Decisions

ADR 014

Measure the server instead of trusting its description

The target instance speaks the API of a well-known library server, but it does not hold everything that description promises — storing a reading position, of all things, was not among it, and not for a single book. Had that only come to light during the build, it would have cost the one feature the app exists for. Rather than wait for someone else's software to be updated, the app is cut to what the server demonstrably does — measured before the first line was written.

ADR 004

The highest page wins, not the newest timestamp

Two devices report different pages for the same book, and one of the two has to give way. The usual rule — the newer one wins — would be the wrong one here: someone on page 80 on the tablet who opens the book on the phone by accident would have page 1 as the fresher entry, and would lose the progress with it. So the higher page wins, and only an explicit reset may go below it.

ADR 009

Cached is not downloaded

Pages that have been read stay on disk so that paging back is instant. That looks like a download but is not one, and a cache mistaken for an offline guarantee leads to the worst failure there is: opening a book on the train that was still there yesterday. The two stores are therefore kept apart, cleared apart and shown apart — the offline marker is worn only by what was deliberately downloaded.

ADR W13

The gatekeeper runs against a stand-in, not the real server

Three purely visual faults appeared in a single day — text that vanished against too dark a background, a card sitting opaque on top of a gradient. No test that checks whether an element is present will find that; it takes image comparison. Testing against the running instance would have been easier, but it would have touched other people's reading positions and turned red every time the server restarted — and a check that goes red for no reason teaches everyone to overlook red. The first usable run against the stand-in server found a silent data loss that four users had been living with for weeks.