diff --git a/docs/caldav.md b/docs/caldav.md index 1d4ff1d..a21151e 100644 --- a/docs/caldav.md +++ b/docs/caldav.md @@ -1,9 +1,10 @@ # Calendar and CalDAV -Two ways to get your tasks into a calendar, one way to get a calendar into -verdande, and none of the three is the same thing. +Two ways to get your tasks into a calendar. Getting somebody else's calendar +*into* verdande is the other direction and has its own page — see +[Calendar](calendar.md). -| | [Feed](#subscribing-to-a-feed) | [CalDAV](#connecting-a-caldav-client) | [Google Calendar](#showing-a-google-calendar-in-verdande) | +| | [Feed](#subscribing-to-a-feed) | [CalDAV](#connecting-a-caldav-client) | [Calendars in](calendar.md) | |---|---|---|---| | Direction | Tasks out, read only | Tasks out, two-way | Events **in**, read only | | Works with | Anything that subscribes to a URL | Apple Reminders, Thunderbird, DAVx⁵ | A Google account | @@ -42,39 +43,10 @@ most people actually keep. ## Showing a Google calendar in verdande -The two sections above send your tasks *out*. This is the other direction: your -Google calendar drawn underneath them, so one screen answers "what does this day -already have in it". +Moved. Connecting a Google account, subscribing to an address, and what the grid +does with either now live on their own page — see [Calendar](calendar.md). -**Settings → Integrations → Google Calendar → Connect**, then tick the calendars -you want and press Save. They appear in **Calendar** in the sidebar, in Google's -own colour for each one, beside your own tasks with due dates. - -It needs the same OAuth client Gmail uses, with the Calendar API enabled and the -second redirect URI registered — see [Configuration](configuration.md#google). - -!!! warning "Read only" - verdande never writes to your Google calendar. An event cannot be dragged, - edited or ticked off here; clicking one opens it in Google, which is where it - can be changed. Your own tasks in the same grid still drag to another day as - they always have. - - Writing would need the `calendar.events` scope and an answer to what should - happen when both sides moved the same meeting — which is a synchronisation - model rather than a scope, and it is deliberately not built yet. - -!!! note "The Internal client applies here too" - An OAuth client registered as *Internal* in a Google Workspace can only be - used by accounts in that workspace, calendars included. A personal - `@gmail.com` address is refused with `org_internal`. For one personal account - the shorter road is the calendar's own secret address: in Google Calendar, - **Settings → the calendar → Integrate calendar → Secret address in iCal - format**. Nothing in verdande subscribes to one yet — it is the next piece of - this feature. - -Events are kept for ninety days back and a year forward, refreshed every fifteen -minutes and whenever you press **Fetch now**. Paging the grid past that window -says so rather than showing an empty month. +This page is the other direction: verdande's own tasks, read by something else. ## Connecting a CalDAV client diff --git a/docs/calendar.md b/docs/calendar.md new file mode 100644 index 0000000..95d26ba --- /dev/null +++ b/docs/calendar.md @@ -0,0 +1,91 @@ +# Calendar + +Your dated tasks as a grid, with other people's calendars laid under them. + +**Calendar** in the menu shows a month or a week. The week is a day: hours down the +side, and everything with a time on it in its place. Two things at ten o'clock sit +beside each other, because that is a clash you should be able to see rather than +read. + +## What is in it + +- **Your tasks**, on the day they are due — and at the time, if they have one. +- **Events from calendars you have connected**, read-only. + +Drag a task to another day to move it. Drop it on the hour column and it takes that +time; drop it in the band across the top and it keeps the day and loses the time. +Events cannot be dragged: verdande holds a copy of somebody else's calendar, and a +chip that lets itself be moved is a promise the server cannot keep. + +A project's own calendar is under **Calendar** on the project page, with the same +week and month. + +## Subscribing to a calendar + +**Settings → Integrations → Subscriptions.** Paste an address and it is fetched at +once. + +This works with anything that publishes an `.ics` file: public holidays, a club's +fixtures, a shared calendar from work, your own calendar's secret address from +Google, Apple or Fastmail. + +- **`webcal://` addresses work.** They are the same URL over https with a scheme + that makes a desktop hand it to the calendar app; it is rewritten for you. +- **Several at a time.** Unlike the Google connection, which is one account, a + subscription is one address and you can have as many as you like. +- **Read-only, refreshed every fifteen minutes.** +- The address is fetched once before it is stored, so a typo tells you now rather + than by silently never filling. + +!!! note "This is the way in for a private account" + If the instance's Google registration is *Internal*, Google refuses accounts + from outside the organisation with `org_internal` — no setting on your side + changes that. Your calendar's own secret ICS address goes through this panel + and works regardless. + +## Connecting Google Calendar + +**Settings → Integrations → Google Calendar.** It shares the OAuth client Gmail +uses, so the instance needs that registration first — see +[Configuration](configuration.md#google). + +Two things have to be true in Google Cloud, and only the owner of the registration +can do them: + +1. **Google Calendar API** is enabled for the project. +2. The calendar callback is listed as an authorised redirect URI. The exact string + is printed in the panel — copy it from there rather than typing it. Google + compares it exactly: scheme, host, path, no trailing slash. `redirect_uri_mismatch` + almost always means one of those four differs. + +Once connected, tick the calendars you want to see. The list is refreshed on every +sync, so a calendar added or renamed since last time appears under its new name. + +!!! warning "Written to the specification, not yet proven against Google" + The Google Calendar half is implemented from Google's documentation and tested + against a stand-in server. It has not been exercised against Google itself. + The subscription route above and the outgoing feed below have. + +## Your own calendar, elsewhere + +Two ways out, for two different jobs: + +- **[The ICS feed](caldav.md#subscribing-to-a-feed)** — a read-only address for Apple Calendar, + Google or Thunderbird. Your tasks appear as dated entries. +- **[CalDAV](caldav.md)** — two-way. Tick something off in Apple Reminders and it + is ticked off here. + +The feed address is a credential in itself: anybody holding it can read your tasks +without logging in, because a calendar client cannot sign in. Rotate it from +**Settings → Integrations** if it gets out. + +## What it does not do + +- **It does not write to a connected calendar.** Events are a copy. +- **It does not expand repeating events** from a subscribed file. A weekly meeting + in somebody else's calendar is stored as its first occurrence. +- **It does not resolve named time zones** from a subscribed file. An event carrying + `TZID=Europe/Copenhagen` shows the clock the file wrote, rather than one this + server has moved. +- **Only Google, and only reading**, for account connections. Everything else goes + through a subscription. diff --git a/docs/notes.md b/docs/notes.md new file mode 100644 index 0000000..75c30db --- /dev/null +++ b/docs/notes.md @@ -0,0 +1,157 @@ +# Notes + +Markdown in, Markdown out. Nothing in between. + +A note is written as rich text — headings, lists, quotations, code — and stored as +the Markdown it looks like. That is not a detail about the database: it is what +makes a note yours. Export gives you the same text you were looking at, and on the +day this program is gone, every note opens in any editor. + +## Writing + +Start typing. **The first line is the title** — always, and re-derived every time +you save, so a note you rewrite the top of is called by what it now says rather +than by what it once did. + +| Style | Written as | Shortcut | +|---|---|---| +| Title | `# ` at the start of the line | pick it in **Aa** | +| Heading | `## ` | | +| Subheading | `### ` | | +| Quote | `> ` | | +| Code block | three backticks, with an optional language | | +| Bullet and numbered lists | `- ` and `1. `, nested with Tab | | +| Bold | two asterisks around the words | ⌘B | +| Italic | one asterisk around the words | ⌘I | +| Underline | a `u` tag around the words | ⌘U | +| Strikethrough | two tildes around the words | | +| Code | one backtick around the words | | + +Every line becomes exactly one block. Markdown would normally join consecutive +lines into a paragraph; here it does not, because you typed a line and expect to +get it back. + +Press the source button in the toolbar to see the note as the file it is. Edits there are edits to the +note. + +### Pictures + +Paste one, or drag it onto the note. It is stored with the note and travels with +it in an export. Every raster format works; SVG is stored but not shown inline — +it is a document that can run script, and a note is not a place to run somebody +else's. + +### Code blocks + +A fenced block is coloured for the language it names, and guesses when it does not. +Each one carries a **Copy** button in its corner. + +## Linking + +Three kinds of reference, parsed out of the text as you write it: + +| You type | It means | +|---|---| +| `#Firma` | The project — the same `#Firma` quick add understands, not a second kind of tag | +| `[[Møde med Anders]]` | Another note, by its title | +| A pasted task link | That task | + +Links are an index over the text, rebuilt every time the note is saved. The text +stays the truth. + +**The interesting direction is backwards.** A task shows what has been written +about it, and a project shows the notes filed in it — without anybody having to +remember to attach anything. Write `#Firma` in a note and it appears on that +project's page. + +A link to something that has been deleted reads as a dead link. It is a fact about +the note, and it should not vanish because something it mentioned did. + +## Filing and sharing + +A note belongs to a project, or to nobody. + +- **In a project:** everybody who can read the project can read the note, and an + editor can change it. Choose it under **Share in** at the foot of the note. +- **In no project:** yours, and nobody else's. + +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. + +## Finding + +The list groups itself: favourites first, then **Today**, **Yesterday**, **This +week**, and then by month. Sort by created, last touched or name, and the grouping +follows — sorted by name it groups by first letter instead. + +Search finds a word wherever it is: + +- **`gron` finds `grøn`.** Unicode does not consider `ø` an accented `o`, so + stripping diacritics is not enough for Danish. A folded copy of every note is + indexed beside the original. +- **`inventory` finds `keepInventory`.** An index is built of whole words, and a + decade of notes is full of commands and identifiers that are several words in + one. When the index has nothing, the text itself is read. +- Results are ranked by how well they match, with the title weighted ten times the + body. A word in the title is what the note is about; the same word once in a long + body is a mention. + +## Putting notes away + +Two different things, and the difference matters: + +- **Archive** — this is finished and I do not want to read past it. It stays + findable and comes back whenever you ask. +- **Trash** — this was a mistake. It is gone in thirty days. + +Select several with ⌘-click and shift-click to archive or delete them together. + +## In and out + +**Export** gives you a zip of Markdown files, one per note, with the dates in a +YAML front matter block that Obsidian and Bear also read: + +```markdown +--- +created: 2019-04-02T10:15:00Z +modified: 2024-11-30T21:04:00Z +--- + +# Møde med Anders + +Han vil gerne have kaffe hver uge. +``` + +**Import** takes the same shape back. Pictures travel in the zip beside the notes, +and the links in the text are relative — so a note and its pictures must be in the +same archive, which matters when a large export is split into parts. + +Two things to know before importing: + +- **Nothing is merged.** Every run creates new notes. Importing the same archive + twice gives you two of everything. +- **The dates are read from the front matter.** Without them, a move of a thousand + notes is a pile that was all written the same evening — and the order they were + written in is half of what an archive is. + +### From Apple Notes + +`tools/apple-notes-til-markdown.py` in the repository exports Apple Notes to +exactly this shape, front matter and pictures included. It is macOS-only, because +Apple Notes is. + +For a large library, `tools/pak-noter-i-portioner.py` splits the export into +uploadable parts, keeping each note with its own pictures. + +## What is not encrypted + +Note bodies are stored as plain text. **A note holding a password or an API key is +holding it in plain text in every backup you can download.** The mailbox +credentials, OAuth tokens and AI keys are sealed; note bodies are not, and neither +are task titles, descriptions or comments. + +Encrypting them is on the list and is bigger than it sounds — the full-text index +and the folded search copy are both derived from the body, so both would have to go +and search would have to be rewritten. Until then: keep secrets somewhere built for +them. diff --git a/mkdocs.yml b/mkdocs.yml index 1260417..02ff4bb 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -50,10 +50,12 @@ nav: - Using it: - Signing in: signing-in.md - Quick add: quick-add.md + - Notes: notes.md - Filters: filters.md - Importing from Todoist: import.md - Connecting things: - - Calendar and CalDAV: caldav.md + - Calendar: calendar.md + - Feeds and CalDAV: caldav.md - Mail to task: mail.md - Mailboxes: mailboxes.md - Claude (MCP): mcp.md