Files
InkNote/CHANGELOG.md
T
marcandClaude Opus 5 1757ec9af3 Chapters: folders inside a notebook
A note is in exactly one chapter, or in none — which means the notebook
itself. Chapters sit above the loose notes; tapping one opens its own
list and the menu button becomes the way back out, which on a phone is
the only way, since the list fills the screen.

A chapter is not a wastebasket. Removing one never removes what it held:
the notes come back to the notebook, where they can be seen and filed
again. That is ON DELETE SET NULL, and it is also written out in the
delete route, because it is the promise the whole thing rests on and
should be visible where it happens rather than inferred from a schema.
The dialog says so too, with the number of notes affected, and the suite
removes a chapter holding three notes and asks the server for all three.

Three rules keep the two levels honest. A note filed into a chapter
leaves the notebook's own list, or filing it would appear to do nothing.
A chapter belongs to its notebook, so the server refuses to file a note
into a chapter of a book it is not in, and moving a note to another
notebook clears its chapter. And separators belong to the list they were
drawn in: a separator's order counts the notes before it, which means
nothing across lists.

Two bugs found while building it, both a day old and both affecting the
desktop rather than the phone they were written for:

- A submenu was clipped away. The context menu had been given
  `overflow-y: auto`, which cuts off anything flying out sideways — so
  the notebooks under "Move to..." were invisible and every click on them
  landed on the note list behind. The side was inverted too:
  `right: 100%` places a panel on the left.
- A separator was a one-pixel hairline in the border colour with faint
  grey text on near-black. Present, and on a phone effectively invisible.

And one test that never measured what it claimed. It asked whether a
dragged note had become "the most recently changed" by reading the order
on screen — but three notes made seconds apart share an `updated_at`
second, so that order is a tie broken arbitrarily. It passed on luck for
weeks and fell over on a run a fraction faster. It now compares the
timestamps themselves, before and after the drag.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 13:04:18 +02:00

323 lines
14 KiB
Markdown

# Changelog
What changed, newest first. One entry per round that went out as an image, with
the digests, so it stays possible to tell what is actually running on the server.
Digests are recorded from the registry (`docker buildx imagetools inspect`),
not from the output of `docker push`.
---
## Unreleased
**Added**
- **Chapters — folders inside a notebook.** A note is in one or in none; tapping
a chapter opens its own list, with a way back out. Removing a chapter never
removes what it held: the notes come back to the notebook, and the dialog says
so with the number affected. Separators now belong to the list they were drawn
in, so a line drawn in one chapter does not appear in another.
**Changed**
- **A notebook's design is its own.** A 45-degree stripe texture was baked into
every cover at 1.5% white — meant to be imperceptible, visibly banding on the
darker gradients, and a second pattern fighting the one actually chosen. And
the same pair of rings sat in the middle of every notebook. The mark belongs
to the design now, and the designs whose pattern already fills the face wear
none.
**Fixed**
- **A submenu was being clipped away on a wide screen.** The menu had been given
`overflow-y: auto`, which cuts off anything flying out sideways — so the list
of notebooks under *Move to…* was invisible and every click on it landed on
the note list behind. The side was also inverted: `right: 100%` places a panel
on the left.
- **A separator was effectively invisible on a phone** — a one-pixel hairline in
the border colour with faint grey text on near-black.
---
## 2026-08-12 — Two-part covers, and an app that can be installed
**Images** — web `sha256:1217b81b…`, server `sha256:3303d3dc…`
The server image changed: it takes a `cover_pattern` column, added on start.
**Changed**
- **A cover is now a colour and a pattern, chosen in turn**, rather than a list
with the combinations someone happened to write out. Every combination is
available, and each pattern is previewed over the colour in hand. Covers saved
during the day the patterns were one list are read back as the pair they were
drawn as, so nothing repaints itself.
**Fixed**
- **The install button never appeared, even over HTTPS.** Two causes, both in
this app rather than in anyone's configuration:
- `beforeinstallprompt` fires once, early — usually before React has mounted —
and is never fired again, so a listener added from inside a component simply
missed it. It is caught at the top of `index.html` now.
- The manifest is fetched **without credentials** unless the link says
otherwise. Behind a reverse proxy that authenticates in front of the app,
that request comes back as the proxy's login page and the browser reads it
as an invalid manifest — while the app itself works perfectly, because its
own requests carry the cookie. The link now says
`crossorigin="use-credentials"`.
- **The service worker could cache a proxy's login page as the application.**
Nothing checked that a response was the thing that had been asked for, so a
lapsed session could be stored as the app shell: it then "worked offline" by
showing a login screen it could never get past, curable only by clearing the
site's data by hand. Redirected and unsuccessful responses are no longer
cached, and the cache name is bumped so anything already stored under the old
rules is dropped.
---
## 2026-08-12 — Making the phone work
**Images** — web `sha256:5ea846f3…`, server unchanged at `sha256:06f94f43…`
**Fixed**
- **A note made offline lost everything written into it.** Its create reached
the server, the server named it something else, and every edit still queued
behind it went on addressing the name only that device knew — a 404, five
retries, then thrown away. The note arrived empty and untitled with no sign
anything had been lost. The queue is now repointed along with the database.
The same held for a notebook made offline.
- **The order of notes could not be changed on a phone.** The list used the
HTML5 drag API, which mobile browsers never fire from touch. It uses pointer
events now, and every row has a grip: pressing the row itself still scrolls,
and holding it still opens the menu.
- **"Move to…" opened off the side of the screen** and could not be opened at
all with a finger. It was pinned to the right of the menu and reacted only to
hover. It now opens on a tap, unfolds in place on a narrow screen, and flips
to the other side on a wide one when there is no room.
- The menu itself is placed by measuring rather than by assuming it is 220px
wide, so it can no longer hang off an edge; rows are tall enough to hit with a
thumb, and Escape closes it.
**Changed**
- **The install entry is always there.** It used to appear only when the browser
offered a prompt, so where installing was impossible there was nothing on
screen at all — no button, no reason. It now says which of the fixable causes
applies: served over plain HTTP, or a browser that wants to be asked through
its own menu.
---
## 2026-08-12 — Covers, the search box, and room to write in the margin
**Images** — web `sha256:c1222665…`, server `sha256:06f94f43…`
The server image changed: it sends the default number of versions with the
account, so the notebook dialog can name it instead of guessing.
**Added**
- **Patterned notebook covers** — ruled paper, graph paper, pinstripe, bands,
dots, cross-hatch, linen, washes, a ledger. Drawn entirely in CSS: no image
files, nothing to upload, crisp at any size, and they work offline like
everything else. Existing notebooks keep exactly the cover they had; the new
ones are appended, never inserted.
**Changed**
- **The search box in a notebook is simply there**, and the button that used to
open it is gone. A magnifying glass cost a click and having to remember that
searching was possible; the box is one line and says for itself what it does.
- **Margin notes are bigger** — the column went from 208px to 288px and a card
from three short lines to about five. Three lines is a caption, not a remark
on a passage, and the space beside the page was sitting mostly empty.
- The notebook dialog's cover grid scrolls, so the dialog cannot run past the
bottom of a laptop screen and take the *Create* button with it.
**Fixed**
- The notebook edit dialog was still part German — *"Versionen pro Notiz"*,
*"Vorgabe"* — and would not say what the server's default actually is. It now
names it (50), read from the server rather than written into the interface,
since `MAX_VERSIONS_PER_NOTE` can be changed and a hardcoded number would
quietly start lying.
---
## 2026-08-11 — Margins and a stray placeholder
**Images** — web `sha256:3a181ff3…`, server unchanged at `sha256:0832ee2b…`
**Changed**
- **Narrower margins on the sheet** — the column went from about 73 characters
to about 80, leaving roughly 8% of the paper as margin either side instead of
117px of empty page down each edge.
**Fixed**
- **"Start writing..." was printed at the foot of every page with a break after
it.** The placeholder extension styles `[contenteditable]:empty::before`, and
the spacer holding a gap open is exactly that — empty, and not editable.
---
## 2026-08-11 — Writing on paper
**Images** — web `sha256:b764a9d8…`, server unchanged at `sha256:0832ee2b…`
**Added**
- **You write on paper.** Each page is a sheet of its own, centred, with a gap
after it — the same way the PDF reader draws its pages. The sheet used to
appear only once you started drawing, which left the writing mode looking like
text floating in an empty pane, and made the space either side of the column
read as a void rather than as a margin.
- Text is broken against those sheets, so no paragraph is ever cut in half by a
gap. The breaks are decorations: nothing enters the document, reaches the
server, or appears in an export.
**Fixed**
- **A note with a drawing could not be typed in at all.** The box wrapping each
page's ink layer lay over the text and swallowed every click meant for it. The
canvas inside was already deaf to the pointer; its wrapper was not. Introduced
the same day, with per-page drawing.
---
## 2026-08-11 — Drawing on every page, and PDFs findable everywhere
**Images** — web `sha256:dc804f7b…`, server `sha256:0832ee2b…`
The server image changed this round: it takes a new column and two routes.
`docker compose pull && docker compose up -d` — the column is added on start.
**Added**
- **A PDF is searchable on every device, not only on the one that opened it.**
The device that imports the file reads it there and then — the server still has
no PDF library and never opens one — and the extracted text is stored beside
the file, encrypted, so every other device can find the document without ever
downloading it. This is what makes an archive of scanned invoices work: they
are filed and then never opened, so waiting for someone to open one meant
waiting forever.
- **A drawing runs over as many pages as the note has.** The ink used to be stuck
on page one while the writing carried on without it. Pages are numbered the way
the PDF reader numbers them, and there is always one blank page past the end to
start a new one on. The bin clears the page being looked at; undo still works on
the drawing as a whole.
- A drawing that lives entirely on page one is still stored in the old shape, so
an ordinary note is written exactly as it always was and an older client still
shows it.
**Fixed**
- **A drawing exported in a ZIP was lost on re-import.** The exporter has written
`drawings/<note>.png` since the interface was put into English; the importer
was still looking for `zeichnungen/<note>.png` and found nothing. Both names
are read now, and so are the further pages of a drawing.
---
## 2026-08-11 — The writing column
**Images** — web `sha256:ed11f034…`, server unchanged at `sha256:1648498f…`
**Changed**
- The note column is centred again. It had been pinned to the left margin so the
start of every line would always be in the same place; on a wide window that
left the whole right half of the pane as one dead block.
- A page surface was drawn behind the text to give that block a meaning, and
reverted the same day: it made the sheet sit hard against the left edge, which
was worse than the problem it solved.
---
## 2026-08-11 — Pages, typefaces, alignment
**Images** — web `sha256:3b040d99…`, server `sha256:1648498f…`
**Added**
- **Page count while writing.** The toolbar says *Page 2 of 4*, in the same words
the PDF reader uses. Pages are counted, never stored: the note stays one
document, and a test asserts no page ever reaches the stored body.
- **The typeface is a per-account setting** — serif, sans or mono, chosen under
Account → Profile. On the account rather than in the browser, so it follows you
to the phone.
- **Text alignment**, with its own TipTap extension rather than the official one,
so the schema stays in files this project owns. Left is the default and is
never written into the document. In Markdown, non-left blocks travel as
`<div align="…">` — the one form most readers still honour — and the importer
reads it back onto the paragraphs.
**Fixed**
- The Markdown exporter did not put a blank line between top-level blocks, so
consecutive paragraphs ran together in other readers.
---
## 2026-08-11 — English throughout, and the PDF toolbar
**Added**
- **Search inside a notebook**, from the note list. The sidebar's global search
was removed: searching from inside a notebook should mean searching *that*
notebook.
- **New note / Upload PDF / Import Markdown** all live under the one `+` button.
**Changed**
- The interface is English throughout. It had drifted into two languages.
- The two visibility switches — drawing and margin notes — sit together at the
far right of the PDF toolbar, because they mean the same kind of thing.
- The drawing tools appear next to the *Draw* button, not past everything else.
- A separator is renamed and removed by right-click, with a confirmation for the
removal.
**Fixed**
- Hiding the drawing also hid the margin notes. Each switch now hides only its
own thing.
---
## 2026-08-10 — Notes on passages
**Added**
- **Pinned notes in a PDF.** A remark can be attached to a passage, and is shown
in the margin beside the page — not written on top of it. On a phone, where
there is no margin, the same notes open as a bottom sheet.
- **Margin notes can be linked from the notes panel**, so a pinned remark can be
written about at length and still lead back to the passage it came from.
**Fixed**
- A grey drag indicator stayed visible in the note list after a drag. It was a
`borderTop` sitting beside a `border` shorthand in one style object.
- The server stored an overlay holding only pinned notes as `NULL`, throwing
every one of them away, because it counted strokes and nothing else.
---
## 2026-08-09 — Arranging a notebook
**Added**
- **Sorting per notebook**, remembered on the notebook itself, including an
arrangement made by hand — which comes back intact after filtering.
- **Separators** to group notes inside a hand-made arrangement.
- **Markdown import**, single files or a ZIP this app exported.
- **Moving notes between notebooks.**
**Fixed**
- Switching to Draw shrank the page from 733px to 460px. The editor was a flex
item at the default `flex: 0 1 auto`, so it was only as wide as its widest row
— the toolbar, which loses a dozen buttons in Draw.
---
## 2026-08-08 — PDFs
**Added**
- Import a PDF, read it, select its text, draw on each page, and export it with
the drawings written in.
- Notes written beside a PDF.
- Uploaded files are encrypted at rest, like note bodies already were, and stored
as deduplicated, content-addressed attachments.
- Unused attachments are freed; versions are kept by count rather than by age.
- Export as Markdown or PDF; the browser suites moved into the repository.
**Changed**
- Vector clocks were never read. Replaced with a conflict check that works.
- Public sign-up removed — an administrator creates the accounts.
---
## Earlier
TipTap editor, version history, full-text search and attachments (2026-08-07);
drawing sync with WebP/JPEG support (2026-06-21); the first syncing alpha and PWA
(2026-02-18).