Merge pull request #72 from kristianwind/dokumenter-det-der-blev-bygget
docs: skriv det ned, der er blevet bygget
This commit is contained in:
@@ -3,6 +3,11 @@ 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.
|
||||
#
|
||||
# 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.
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
@@ -10,6 +15,11 @@ on:
|
||||
- 'docs/**'
|
||||
- 'mkdocs.yml'
|
||||
- '.github/workflows/docs.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- 'mkdocs.yml'
|
||||
- '.github/workflows/docs.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
|
||||
@@ -17,6 +17,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# Taggen selv, ikke kun den commit den peger på: udgivelsesteksten
|
||||
# nedenfor står i tagbeskeden, og en overfladisk checkout henter
|
||||
# commit'en uden den.
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
@@ -60,7 +65,28 @@ jobs:
|
||||
#
|
||||
# Created after the image, so a release never announces a version that
|
||||
# failed to build.
|
||||
# Tagbeskeden ER annonceringen. Den skrives, når der tagges, på produktets
|
||||
# eget sprog og til dem, der bruger det — og indtil nu nåede den aldrig
|
||||
# frem: udgivelsen på GitHub blev fyldt med en autogenereret liste over
|
||||
# commit-overskrifter, som er skrevet til dem, der læser koden.
|
||||
#
|
||||
# Den sidste linje er et link til udgivelsen selv, og den tages af: en
|
||||
# side, der linker til sig selv, hjælper ingen.
|
||||
- id: notes
|
||||
run: |
|
||||
{
|
||||
echo 'body<<VERDANDE_EOF'
|
||||
git tag -l --format='%(contents)' "${GITHUB_REF_NAME}" \
|
||||
| sed '\#^https://github.com/.*/releases/tag/#d' \
|
||||
| sed -e :a -e '/^\n*$/{$d;N;ba' -e '}'
|
||||
echo VERDANDE_EOF
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
body: ${{ steps.notes.outputs.body }}
|
||||
# Stadig sat: den autogenererede liste lægges *under* teksten ovenfor,
|
||||
# så både den, der vil vide hvad der er nyt, og den, der vil se hvilke
|
||||
# ændringer det var, kan læse det samme sted.
|
||||
generate_release_notes: true
|
||||
make_latest: true
|
||||
|
||||
@@ -37,17 +37,32 @@ and an MCP endpoint so Claude can work your task list directly.
|
||||
- **Projects, sections, sub-tasks, labels, saved filters.** List, board and calendar
|
||||
views, and foldable groups over the projects in the sidebar.
|
||||
- **Notes, beside the work.** Rich text that is Markdown underneath — headings,
|
||||
lists, quotes, fenced code. A note is shared by filing it in a project;
|
||||
`#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
|
||||
lists, quotes, fenced code. A note is shared by filing it in a project, by
|
||||
handing it to one person — including somebody who has no account yet, who gets an
|
||||
invitation that becomes the share when they sign up — or by writing `@Sofie` in
|
||||
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.
|
||||
- **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:
|
||||
everybody arrives through an invite link, either to a project or — from
|
||||
**Settings → Brugere** — to the instance itself. Nobody's password is ever chosen
|
||||
by somebody else.
|
||||
everybody arrives through an invite link — to a project, to a single note, or
|
||||
from **Settings → Brugere** to the instance itself. Nobody's password is ever
|
||||
chosen by somebody else.
|
||||
- **Live sync.** A change made by somebody else appears without a refresh.
|
||||
- **Notifications that are worth reading.** A bell for what other people did to what
|
||||
you share — folded, so one person typing for five minutes is one line — pushed to
|
||||
your devices and counted on the app's icon in the Dock.
|
||||
- **AI that suggests and never writes.** Optional, off by default, your own key and
|
||||
your own model if you want. It tidies the inbox, pulls the tasks out of a meeting
|
||||
note, writes a morning plan, turns *"SV: SV: Vedr. levering uge 12"* into the
|
||||
action the mail asks for, and answers questions about your own notes with links to
|
||||
what the answer rests on. Every one of them arrives as a line you accept, edit or
|
||||
refuse — a model that edits your tasks directly has to be right every time to be
|
||||
worth having.
|
||||
- **Anything can put a task in the inbox.** A mail to your own forwarding address,
|
||||
or a POST of one line of text from a shortcut on your phone, a script or any
|
||||
service that can call a URL.
|
||||
- **Recurring tasks** as RRULE (RFC 5545), reminders, comments and attachments.
|
||||
- **Standards, not homegrown formats.** iCalendar and CalDAV, ICS feeds, OAuth2 with
|
||||
PKCE, OpenAPI 3.1, MCP, Web Push, Argon2id.
|
||||
|
||||
+68
-9
@@ -43,23 +43,82 @@ The key is stored on your account and is **never sent back** to the settings pag
|
||||
a page that repopulates a password field is one that will eventually leak it into a
|
||||
screenshot.
|
||||
|
||||
## The shape of all of it
|
||||
|
||||
**The model proposes; you decide.** Nothing is written until you say yes, and the
|
||||
proposal is a line in the same syntax you type yourself — `Ring til Anders i morgen
|
||||
p1 #Firma` — sitting in a field you can edit before you accept it.
|
||||
|
||||
That is not caution for its own sake. A model that edits your tasks directly has to
|
||||
be right *every* time to be worth having. One that suggests only has to be right
|
||||
often enough to save you some typing, and when it is wrong you have already seen it.
|
||||
|
||||
It is also why the suggestion is a line rather than a set of fields: there is one
|
||||
reading of "i morgen" in this program, and a suggestion goes through the same
|
||||
[quick add](quick-add.md) parser as anything you type — including after you have
|
||||
edited it by hand.
|
||||
|
||||
The model is given the names of the projects that exist and may name no others. A
|
||||
`#Projekt` it invented would create one by accident the first time you accepted it,
|
||||
and a guess must not be able to move a task somewhere you will not look for it.
|
||||
|
||||
## What it can do
|
||||
|
||||
**Split a task into sub-tasks.** On any task: *Split with AI*. It suggests two to
|
||||
seven concrete actions and creates them as sub-tasks. Written in your language.
|
||||
**Tidy up the inbox.** In the Inbox, the menu → *Ryd op i indbakken*. For each loose
|
||||
line it suggests how you would have written it if you had finished it — project,
|
||||
date, priority — with one sentence on what it read out of the task. Accept, edit, or
|
||||
skip, one line at a time.
|
||||
|
||||
**Find the tasks in a note.** Open a note → *Find opgaver i noten*. Only what
|
||||
somebody committed to or was asked to do; a heading is not a task and a topic that
|
||||
was discussed is not a task. Each suggestion quotes the words it came from, so a
|
||||
wrong one can be seen through rather than merely being wrong. The note itself is
|
||||
never edited — the task carries `[[the note's title]]` in its description instead.
|
||||
|
||||
**Today's plan, in the morning.** **Settings → Beskeder → Dagens plan**, off by
|
||||
default; pick the hour yourself. One notification about what is due today and what
|
||||
has been missed, and what to start with. The counts are done in the database and
|
||||
handed to the model as facts it may not recompute — a plan that says four tasks
|
||||
where there are three is worse than no plan. With no model configured the counts
|
||||
stand on their own, which is what you needed to know at seven in the morning anyway.
|
||||
Nothing due and nothing overdue sends nothing.
|
||||
|
||||
**Mail that becomes a task you can act on.** Where a
|
||||
[mailbox](mailboxes.md) used to produce *"Anders Jensen: SV: SV: Vedr. levering uge
|
||||
12"*, the model writes the action the mail asks for — and leaves the mail alone if
|
||||
it asks for nothing. The subject stays in the description, so a mail it misread can
|
||||
still be read. If the model is unavailable the task is named sender and subject as
|
||||
before: a model that is down must not be able to stop the post.
|
||||
|
||||
**Ask your own notes and tasks.** ⌘K, type the question, ⌘⏎. *"Hvad lovede jeg
|
||||
Anders i august?"* — search finds what contains the words, this answers the
|
||||
question, and the answer links to the notes and tasks it rests on. If nothing
|
||||
matches, it says so; a guess would be useless here, because you are asking precisely
|
||||
because you cannot remember.
|
||||
|
||||
**Split a task into sub-tasks.** On any task: *Split with AI*. Two to seven concrete
|
||||
actions, created as sub-tasks.
|
||||
|
||||
**A weekly summary.** A short note over what is outstanding: what looks urgent and
|
||||
what appears to be slipping. At most six lines — it is a prompt to think, not a
|
||||
report.
|
||||
what appears to be slipping. At most six lines — a prompt to think, not a report.
|
||||
|
||||
## What is sent
|
||||
|
||||
Only what the feature needs: for a split, the task's title and notes; for a
|
||||
summary, the titles, dates and priorities of your open tasks. Never comments,
|
||||
attachments, or anything from a project the feature was not invoked on.
|
||||
Only what the feature needs, and only when you invoke it:
|
||||
|
||||
Nothing is sent to anybody until you configure a provider. With a local model,
|
||||
nothing leaves your machine at all.
|
||||
| Feature | What leaves the instance |
|
||||
| --- | --- |
|
||||
| Tidy the inbox | The titles of the loose tasks in your inbox, the first words of their descriptions, and your project names |
|
||||
| Tasks in a note | That one note's text, and your project names |
|
||||
| Today's plan | The titles and dates of what is due or overdue today |
|
||||
| Mail to task | Sender, subject and the snippet of the mails in that sweep |
|
||||
| Ask | Your question, and the notes and tasks the search matched |
|
||||
| Split a task | That task's title and notes |
|
||||
| Weekly summary | The titles, dates and priorities of your open tasks |
|
||||
|
||||
Never comments, never attachments, never a project the feature was not invoked on,
|
||||
and never anything belonging to somebody else. Nothing is sent to anybody until you
|
||||
configure a provider, and with a local model nothing leaves your machine at all.
|
||||
|
||||
## Turning it off
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# The install count
|
||||
|
||||
verdande reports that it exists. Two values, once a day:
|
||||
|
||||
```json
|
||||
{
|
||||
"instance_id": "01a0806d-3601-7000-ad76-057f1f684881",
|
||||
"version": "v0.44.1"
|
||||
}
|
||||
```
|
||||
|
||||
That is the whole message. No IP is stored by the collector, no hostname, no
|
||||
domain, no account, no counts of anything you have made, nothing about what you
|
||||
use it for. The payload is small enough to be printed in full on the settings page,
|
||||
and it is printed there — a promise about telemetry is worth exactly as much as
|
||||
your ability to check it.
|
||||
|
||||
## On by default, off in one click
|
||||
|
||||
The alternative that was considered first was compulsory, and the argument against
|
||||
it is practical rather than principled: it cannot be enforced. The domain can be
|
||||
blocked, the binary can be patched, and a fork removes it in its first commit. So
|
||||
mandatory buys nothing over on-by-default while costing the trust the rest of this
|
||||
program works for.
|
||||
|
||||
Which is why the first administrator to sign in is **told, unprompted**, with the
|
||||
real id, the real version and the real address in front of them, and two buttons.
|
||||
On by default is only defensible if it is said out loud without being asked; a
|
||||
settings page where it is stated fully is not the same thing, because that page is
|
||||
opened by people who already suspect there is something to read.
|
||||
|
||||
**Settings → Data** afterwards: one switch. An explicit "off" survives upgrades.
|
||||
|
||||
!!! note "This disagrees with the update check, on purpose"
|
||||
|
||||
`VERDANDE_UPDATE_CHECK` is off unless you ask for it, and its reasoning is that
|
||||
a self-hosted app reaching out unbidden has broken the deal its operator made by
|
||||
self-hosting. That is the same situation as this one, and the two defaults do
|
||||
not agree. The case for treating them differently: the update check reveals an
|
||||
instance to a third party (GitHub) and returns something you can act on, while
|
||||
this returns nothing and goes to the project. Whether that is a distinction or
|
||||
an excuse is a judgement call, and it was made deliberately.
|
||||
|
||||
## What the collector cannot see, and what it can
|
||||
|
||||
A request has a source address whether or not anybody writes it down. The collector
|
||||
stores none and logs none, and the code is arranged so the address never reaches a
|
||||
function that could — the table has nowhere to put one. But the request passes
|
||||
through a reverse proxy and a tunnel on the way, and those keep their own logs.
|
||||
"We send no IP" would be a half-truth; what is true is that nothing here records
|
||||
one.
|
||||
|
||||
The ping is not authenticated either, so anybody can post a made-up id and inflate
|
||||
the count. That is an accepted trade: a token would have to ship inside every
|
||||
install anyway.
|
||||
|
||||
## Running your own count
|
||||
|
||||
Somebody running a fleet points **Settings → Data → Modtagerens adresse** at their
|
||||
own instance, and ticks **Denne instans er tælleren** there. Until that is ticked,
|
||||
`POST /api/v1/beacon` answers **404** rather than accepting quietly — an instance
|
||||
nobody made a collector must not become a bucket anyone can post into.
|
||||
|
||||
The collector's page then shows totals, active in 7 and 30 days, and a breakdown by
|
||||
version. Publishing that number at `/api/v1/beacon/count` is a second, separate
|
||||
opt-in, and it has a floor under it (25 by default): a number that *falls* cannot be
|
||||
published as a fact — a bad release, a DNS change that quietly stops the pings, or
|
||||
lost rows all look like "fewer people use this now" — and a small number mostly says
|
||||
how little it takes to move it.
|
||||
|
||||
## When it cannot reach
|
||||
|
||||
The reason is written down and shown on the settings page. A beacon that cannot
|
||||
reach its collector otherwise fails in complete silence: it tries again tomorrow,
|
||||
the page says "last sent" with a date that quietly gets older, and nobody notices.
|
||||
@@ -127,11 +127,17 @@ next time each value is written, so turning this on costs nobody a reconnection.
|
||||
|
||||
| Variable | Default | What it does |
|
||||
|---|---|---|
|
||||
| `VERDANDE_UPDATE_CHECK` | `false` | Ask GitHub whether a newer release exists. |
|
||||
| `VERDANDE_UPDATE_CHECK` | `false` | Ask GitHub whether a newer release exists, and tell the administrators when one does. |
|
||||
| `VERDANDE_PANEL_URL` | — | The Yggdrasil panel this instance runs under. |
|
||||
| `VERDANDE_PANEL_TOKEN` | — | An API token from that panel, belonging to somebody with control of this server. |
|
||||
| `VERDANDE_PANEL_SERVER_ID` | — | Which server to restart — the id in the panel's URL. |
|
||||
|
||||
With the check on, administrators are told **once per version** — in the bell, in
|
||||
push and on the app's badge — rather than having to open the settings page and
|
||||
look. The notification leads to the page where the restart button is. With the
|
||||
check off nothing is fetched and nothing is said; see
|
||||
[Notifications](notifications.md).
|
||||
|
||||
All three together let **Settings → Notifications** restart this instance,
|
||||
which is also how it picks up a new version: a container cannot replace its own
|
||||
image, so the panel recreates it and pulls `:latest` on the way. The request asks
|
||||
|
||||
+13
-2
@@ -27,8 +27,9 @@ forward mail to, and an MCP endpoint so Claude can work your task list directly.
|
||||
The calendar draws each task to its length — drag the foot to resize, the body
|
||||
to move it.
|
||||
- **Notes, beside the work.** Rich text to write in, Markdown on disk. Share a
|
||||
single note with a person, or file it in a project; `#project` and
|
||||
`[[another note]]` are links, and a task shows what has been written about it.
|
||||
single note with a person — by name, by email address, or by writing `@Sofie` in
|
||||
the text — or file it in a project; `#project` and `[[another note]]` are links,
|
||||
and a task shows what has been written about it.
|
||||
- **Delegate, and snooze.** Hand a task to somebody and it is marked with an
|
||||
arrow to them, gathered on a *Waiting on others* page. Snooze one to park it,
|
||||
greyed, at the foot of the list until a moment you pick — without touching when
|
||||
@@ -38,8 +39,18 @@ forward mail to, and an MCP endpoint so Claude can work your task list directly.
|
||||
- **Sharing** with owner, editor and viewer roles. Anyone outside your instance
|
||||
joins through an invite link.
|
||||
- **Live sync** — a change made by somebody else appears without a refresh.
|
||||
- **[Told when it matters](notifications.md).** A bell for what other people did to
|
||||
what you share, pushed to your devices and counted on the app's icon in the Dock.
|
||||
- **[AI that suggests and never writes](ai.md).** Optional, 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 as a line you accept, edit or refuse.
|
||||
- **Repeating tasks** as RRULE, comments and attachments, and reminders that go
|
||||
out as Web Push to an iPhone or a Mac.
|
||||
- **[Anything can put a task in your inbox](mail.md)** — a mail to your own
|
||||
address, or a POST from a shortcut on your phone, a script, or any service that
|
||||
can call a URL.
|
||||
- **[Your mail as an inbox](mailboxes.md).** Star a mail in Gmail, or flag one
|
||||
over IMAP in iCloud or Fastmail, and it becomes a task — and the star or flag
|
||||
comes off once it has, so a starred inbox empties as the tasks are made instead
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Opening links
|
||||
|
||||
A link in a task or a note opens in whichever browser your system opens links in.
|
||||
**Settings → Links** can try to change that — and the honest description of what it
|
||||
does is *try*.
|
||||
|
||||
## What a web page cannot do
|
||||
|
||||
Two things, and they set the limits of this feature:
|
||||
|
||||
- **It cannot see which browsers are installed.** The list is deliberately closed:
|
||||
it would be a fingerprint, distinctive enough to follow somebody from site to
|
||||
site.
|
||||
- **It cannot ask the system to use a particular one.** A link goes to the default
|
||||
browser, and there is no API that says otherwise.
|
||||
|
||||
The only handle that exists is the URL schemes browsers register for themselves —
|
||||
`firefox://open-url?url=…`, `googlechrome://…`, `microsoft-edge:…` — and there is no
|
||||
way to ask whether one exists. You can only try it.
|
||||
|
||||
## So the setting is an attempt
|
||||
|
||||
Pick Safari, Chrome, Firefox or Edge, or write your own scheme. When you click a
|
||||
link, that scheme is tried first; if nothing has happened within about half a
|
||||
second, the link opens the ordinary way.
|
||||
|
||||
The fallback is the whole reason this is safe to turn on. Without it, a setting
|
||||
that works on your phone would leave links doing nothing on your desktop.
|
||||
|
||||
In practice: **it works on a phone**, where browsers register these schemes, and
|
||||
**rarely on a Mac or a PC**, where Chrome and Firefox do not. Edge on Windows is
|
||||
the usual exception. There is a **Prøv det** button for exactly this reason — you
|
||||
cannot ask whether a scheme exists, so it is better to find out on example.dk than
|
||||
on a link you meant to follow.
|
||||
|
||||
## Writing your own
|
||||
|
||||
Three placeholders, because browsers disagree about the shape they want the address
|
||||
in:
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| `{url}` | The address as it is — `x-safari-https://example.dk` |
|
||||
| `{encoded}` | The address as a parameter value — `firefox://open-url?url=https%3A%2F%2F…` |
|
||||
| `{stripped}` | The address without the `https://` — `googlechrome://example.dk` |
|
||||
|
||||
## It belongs to the machine, not the account
|
||||
|
||||
The choice is kept in the browser you are sitting at, not on your account — the
|
||||
same rule the sidebar's width follows. `firefox://` works on the phone and does
|
||||
nothing on the Mac, so a choice that followed the account would be wrong in one of
|
||||
the two places every time.
|
||||
@@ -67,3 +67,36 @@ immediately.
|
||||
|
||||
!!! tip "Keep the address to yourself"
|
||||
Treat it like a secret. If you publish it somewhere, rotate it.
|
||||
|
||||
## Pushing from another program
|
||||
|
||||
The address above needs a mail server. When what you want is a shortcut on your
|
||||
phone, a script, or any service that can call a URL, there is a second way in:
|
||||
**Settings → Integrationer → Skub fra andre programmer** gives you an address to
|
||||
POST a line of text to.
|
||||
|
||||
```bash
|
||||
curl -X POST https://todo.example.dk/inbound/hook/<token> \
|
||||
-H "Content-Type: text/plain" \
|
||||
-d "Ring til Anders i morgen p1 #Firma"
|
||||
```
|
||||
|
||||
The body is read three ways, because those are the three you meet: plain text from
|
||||
a shortcut that just sends what was selected, JSON with a `text` field from a
|
||||
service, or a form field from a webhook form. The first line becomes the task and
|
||||
the rest sits underneath it, and the line goes through the [quick add](quick-add.md)
|
||||
parser — so "i morgen", "p1" and "#Firma" mean here what they mean in the box at the
|
||||
top of the app.
|
||||
|
||||
**The address is a key.** It has its own token rather than sharing the mail one:
|
||||
the two are the same kind of secret but they leak separately, and a URL that has
|
||||
been sitting in a shortcut on a lost phone has to be replaceable without changing
|
||||
the address other people have in their address books. A token here can do one
|
||||
thing — put a task in your inbox — which is why it is not an
|
||||
[API token](api.md), which can do everything. Change it under the same setting; the
|
||||
old one stops working at once.
|
||||
|
||||
**POST only.** A GET would be easier to call, and that is exactly the problem: a
|
||||
browser prefetch, a link check in a chat, and a revisited history entry would all
|
||||
create tasks nobody asked for.
|
||||
|
||||
|
||||
@@ -79,6 +79,37 @@ There is no folder tree. Projects, groups and labels already exist, are already
|
||||
shared and already have roles — a second hierarchy to file things in is one too
|
||||
many, and a note in a project inherits every one of those answers.
|
||||
|
||||
### Sharing one note with one person
|
||||
|
||||
Filing a note in a project is the right tool when the note belongs with a body of
|
||||
work, and the wrong one when it is just *let Sofie see this*. **Del med personer**
|
||||
at the foot of the note does the second: this note, this person, as reader or
|
||||
editor. Only the note's owner can share it.
|
||||
|
||||
Type an **email address** rather than picking a name, and one of two things
|
||||
happens. An address that already has an account is shared with straight away. One
|
||||
that does not gets an invitation — a link that creates the account and the share
|
||||
together, so the note is theirs the moment they sign up. Invitations wait in the
|
||||
panel under the note, where they can be withdrawn; that is the only way back, since
|
||||
only the token's hash is stored and a link sent to the wrong address cannot be
|
||||
looked up.
|
||||
|
||||
### Naming somebody in a note
|
||||
|
||||
Writing `@Sofie` in a note shares it with her and tells her. Naming somebody in a
|
||||
note *is* wanting them to read it, and doing it as two acts — write the name, then
|
||||
open the panel and find the person — meant the second was forgotten, and the note
|
||||
sat there addressing somebody who could not see it. The editor suggests names after
|
||||
`@`, the same way `#` suggests projects.
|
||||
|
||||
- **Only the owner's mentions share.** An editor may write the name; giving
|
||||
somebody else's note away is the owner's alone.
|
||||
- **As a reader**, which is the least that satisfies "look at this". A role you
|
||||
have raised in the panel is never lowered by a mention.
|
||||
- **Only a name that has just appeared** counts. A note is saved on every typing
|
||||
pause, so without that every save would be another share and another notification
|
||||
about the same name.
|
||||
|
||||
## Finding
|
||||
|
||||
The list groups itself: favourites first, then **Today**, **Yesterday**, **This
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
# Notifications
|
||||
|
||||
What other people did that you need to know about, and what the day has in it.
|
||||
Verdande tells you in three places at once, and they are the same thing said three
|
||||
ways: the **bell** in the header, a **push** to your devices, and the **badge** on
|
||||
the app's icon.
|
||||
|
||||
## What causes one
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| Somebody edited a note shared with you | Repeat edits fold into one line while it is unread |
|
||||
| Somebody shared a note with you | Once, when it happens |
|
||||
| Somebody named you in a note with `@` | Instead of "edited a note" — one act, one message |
|
||||
| Somebody gave you a task | Only on the change, and only to the person who got it |
|
||||
| Somebody commented | |
|
||||
| [Today's plan](ai.md), if you turned it on | In the morning, at the hour you chose |
|
||||
| A new version is out | Administrators only, once per version |
|
||||
|
||||
Not your own actions: the server does not tell anybody what they just did
|
||||
themselves. And not everything that happens — a bell that rings at every change in
|
||||
a shared project is a bell people stop looking at.
|
||||
|
||||
**Repeat edits are folded.** A note is saved on every typing pause, so one person
|
||||
writing for five minutes would otherwise be twenty identical lines. While the
|
||||
message is unread, a further edit moves it back to the top and says who touched it
|
||||
last. Once you have read it, the next edit is a new thing to be told.
|
||||
|
||||
## Push, and the badge
|
||||
|
||||
**Settings → Beskeder** turns on Web Push for the device you are sitting at, per
|
||||
device: the phone in your pocket and the laptop you have open are different
|
||||
answers, and a permission granted on one is not the other's.
|
||||
|
||||
The **badge** — the number on the icon in the Dock on a Mac, on the taskbar on a
|
||||
PC — needs the app to be installed (added to the Dock, or installed as an app in
|
||||
Chrome or Edge). Half the point of being told is being told while you are doing
|
||||
something else, and the icon is the only place the app can say anything then. It
|
||||
counts unread messages and goes down by itself as you read them. Firefox does not
|
||||
support it; nothing else changes there.
|
||||
|
||||
The sentence you see is written in your browser from *what happened* and *who did
|
||||
it*, so an English interface gets an English bell. The server's own wording is
|
||||
Danish and is used only for push, which has no dictionary to look a phrase up in.
|
||||
|
||||
## Telling you about a new version
|
||||
|
||||
If the [update check](configuration.md) is on, administrators get one notification
|
||||
per version — never one a day about the same one — and it leads to
|
||||
**Settings → Beskeder**, where the button that restarts the instance to update it
|
||||
sits. With the check off, nothing is fetched and nothing is said.
|
||||
@@ -51,6 +51,8 @@ nav:
|
||||
- Signing in: signing-in.md
|
||||
- Quick add: quick-add.md
|
||||
- Notes: notes.md
|
||||
- Notifications: notifications.md
|
||||
- Opening links: links.md
|
||||
- Filters: filters.md
|
||||
- Importing from Todoist: import.md
|
||||
- Connecting things:
|
||||
@@ -60,6 +62,8 @@ nav:
|
||||
- Mailboxes: mailboxes.md
|
||||
- Claude (MCP): mcp.md
|
||||
- AI features: ai.md
|
||||
- Privacy:
|
||||
- The install count: beacon.md
|
||||
# openapi.yaml is deliberately not in the nav: MkDocs copies it to the site as a
|
||||
# file, and api.md links to it. A nav entry expects a page to render.
|
||||
- Reference:
|
||||
|
||||
Reference in New Issue
Block a user