diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 02e12cc..289dd87 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -1,13 +1,21 @@
name: Documentation
-# The docs are built on every push so a broken build is caught immediately, but
-# only published once GitHub Pages has been enabled for the repository. Until the
-# owner decides to publish, this job builds and stops.
+# Built on every push, and published from main.
#
-# And on pull requests, where the build is the only check there is: `mkdocs build
-# --strict` fails on a link to a page that does not exist, and building only after
-# the merge means finding that out on `main`. Nothing is published from a pull
-# request — the `deploy` job below runs on a manual dispatch and nothing else.
+# The publishing used to wait for a manual dispatch, with a note saying it would
+# run "once Pages is enabled". Pages was enabled — and the condition was never
+# changed, so the site was built forty times and published none of them. What it
+# showed was a Verdande from before v0.43: /links/, /beacon/ and /notifications/
+# all answered 404, months after they were written. Nothing failed, because
+# building *is* what the job was asked to do.
+#
+# The lesson is not about this line. It is that "publish later" needs something
+# that fails when later arrives — a switch that is off and silent looks exactly
+# like a switch that is on.
+#
+# Pull requests still build and never publish: `mkdocs build --strict` fails on a
+# link to a page that does not exist, and building only after the merge means
+# finding that out on `main`.
on:
push:
branches: [main]
@@ -54,9 +62,9 @@ jobs:
deploy:
needs: build
runs-on: ubuntu-latest
- # Only runs once Pages is enabled. Until then the build above still guards
- # against a broken docs tree.
- if: github.event_name == 'workflow_dispatch'
+ # From main, and by hand. Never from a pull request — a fork could otherwise
+ # publish over the site by opening one.
+ if: github.event_name != 'pull_request'
environment:
name: github-pages
url: ${{ steps.deploy.outputs.page_url }}
diff --git a/README.md b/README.md
index 3bb4cdc..839318e 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,8 @@ Which is what a to-do list is.
All six phases are built. See [What works today](#what-works-today) for what is
tested and what is not.
-Documentation: [`docs/`](docs/), built with Material for MkDocs.
+Documentation: **** — the source is in
+[`docs/`](docs/), built with Material for MkDocs and published from `main`.
## Why this exists
@@ -43,6 +44,10 @@ and an MCP endpoint so Claude can work your task list directly.
the text, which shares it with her and tells her. `#project` and
`[[another note]]` are links, and a task shows the notes that mention it. A zip of Markdown goes in — Obsidian, Bear, or Apple Notes through
the exporter in [`tools/`](tools/) — and comes back out the same shape.
+- **Notes are sealed at rest.** Title and body are encrypted in the database under
+ a key in a file beside it — the title too, because a title beside a sealed body
+ leaves the beginning of every note in the open. A copy of the file is not a copy
+ of the notes.
- **Drag where it means something.** Reorder a list or a board, file a project under
a group, drop a task on another project, or drop it on another day.
- **Sharing.** Owner, editor and viewer roles. There is no open registration:
@@ -128,6 +133,17 @@ Apple Reminders, forward mail into it, and add it to Claude as a connector.
| OpenAPI 3.1 spec, checked against the router | Done, tested |
| End-to-end smoke tests (Playwright) | Done |
| Documentation, landing page, licence | Done |
+| Notes sealed at rest: title and body encrypted in the database | Done, tested |
+| `@name` in a note shares it with that person, and tells them | Done, tested |
+| Share a project with somebody who already has an account, by name | Done, tested |
+| Invitations that have not been taken up stay visible, and can be withdrawn | Done, tested |
+| Told when a project is shared with you — and able to leave it | Done, tested |
+| Push from other programs: a webhook address per person | Done, tested |
+| Today's plan as a card on **I dag**, not only as a notification | Done, tested |
+| Search the settings, from the page or from ⌘K | Done, tested |
+| Choose which browser a link opens in | Done, tested |
+| Images in notes: open full size, copy to the clipboard | Done, tested |
+| Install count: two values, once a day, one click to stop | Done, tested |
**Not finished:** Web Push, the AI providers and the Google Calendar API calls are
implemented against their specifications and have only ever been exercised there,
diff --git a/docs/notes.md b/docs/notes.md
index 89fe064..2cf66be 100644
--- a/docs/notes.md
+++ b/docs/notes.md
@@ -138,6 +138,14 @@ Search finds a word wherever it is:
body. A word in the title is what the note is about; the same word once in a long
body is a mention.
+Two places to search from, and they now agree. The field above the list filters it
+in place. **⌘K** searches everything at once — tasks, projects, notes and the
+settings — and picking a note from it opens that note *with the rest of the matches
+still in the list beside it*. It used to drop you on the ordinary list, so the
+other results existed only in the popup you had just closed. The address carries
+the search, which also means a search worth keeping can be bookmarked or sent to
+somebody.
+
## Putting notes away
Two different things, and the difference matters:
diff --git a/site/index.html b/site/index.html
index d751bb8..3f4eff2 100644
--- a/site/index.html
+++ b/site/index.html
@@ -1326,6 +1326,64 @@
the releases page.
+ -
+ 0.47
+ Click a picture in a note and it opens at full size, with a button that
+ copies it to the clipboard. In the note it is scaled to the width of the
+ column — a photo off a phone is four thousand pixels across — so what you
+ were looking at was a thumbnail that did not look like one.
+
+ -
+ 0.47
+ Search in ⌘K, pick a note, and the rest of the matches stay in the list
+ beside it. They used to exist only in the popup you had just closed.
+
+ -
+ 0.46
+ Share a project with somebody who already has an account by picking their
+ name, rather than by spelling an email address you would have to know.
+ Invitations that have not been taken up stay visible so they do not get
+ sent twice, and can be withdrawn.
+
+ -
+ 0.46
+ You are told when a project is shared with you, and there is a
+ Leave the project button. Being let in without being
+ asked, without being told, and with no way out was three things at once.
+
+ -
+ 0.45
+ Search for a setting instead of remembering which tab it was under — in
+ the settings themselves and in ⌘K. It knows them by what they do, so
+ beacon finds the install count even though that is not its name.
+
+ -
+ 0.45
+ Today's plan is a card on I dag rather than only a
+ message in the morning that was gone if you did not read it at once. And
+ a link can be told which browser to open in.
+
+ -
+ 0.44
+ An optional AI layer, on your own key: it tidies the inbox, pulls the
+ tasks out of a meeting note, writes a morning plan, turns
+ "SV: SV: Vedr. levering uge 12" into what the mail actually asks
+ for, and answers questions about your own notes with links to what the
+ answer rests on. Every one of them is a line you accept, edit or refuse —
+ it suggests, it never writes.
+
+ -
+ 0.44
+ Administrators are told in the bell when a new version is out, once per
+ version, and the message leads to the button that restarts.
+
+ -
+ 0.43
+ Anything that can call a URL can put a task in your inbox — a shortcut on
+ your phone, a script, a service. Notes can be handed to somebody who has
+ no account yet, and writing
@Sofie in a note shares it with
+ her and tells her. Unread counts show on the app's icon in the Dock.
+
-
0.42
A sixth theme, Charcoal — a warm near-black after Apple
@@ -1362,17 +1420,6 @@
body to move it. A single note can be shared with one person, and a
[[note]] is a link you follow inline.
- -
- 0.34
- Sections can be dragged into the order the work actually happens in. The
- sidebar keeps its head still while the projects scroll.
-
- -
- 0.33
- Notes grew an archive, selection of many at once, pictures you can paste
- or drag in, a source view, and a copy button on code blocks. Search
- stopped answering by date and started answering by relevance.
-
diff --git a/web/e2e/smoke.spec.js b/web/e2e/smoke.spec.js
index b26785a..453f1ba 100644
--- a/web/e2e/smoke.spec.js
+++ b/web/e2e/smoke.spec.js
@@ -4656,11 +4656,17 @@ test('en søgning i ⌘K efterlader de træffere, den fandt', async ({ page }) =
// Gemt ved at forlade feltet, som resten af fladen gør det — der er ingen
// Gem-knap at huske.
+ //
+ // Der ventes på "Gemt", før den næste note laves. Uden det klikkes "Ny note",
+ // mens den forrige stadig er undervejs, og listen når ikke at få den med — det
+ // fejlede i CI én gang ud af tre kørsler, og bestod hver gang her på maskinen.
+ // En prøve, der er hurtigere end programmet, måler maskinen den kører på.
for (const title of ['Fyrreskov nord', 'Fyrreskov syd', 'Egeskov']) {
await page.getByRole('button', { name: 'Ny note' }).click();
const body = page.getByLabel('Notens tekst');
await body.fill(`${title}\n\nnoget om den`);
await body.blur();
+ await expect(page.getByText('Gemt', { exact: true })).toBeVisible();
await expect(page.locator('.list').getByText(title, { exact: true })).toBeVisible();
}