mirror of
https://github.com/karatektus/pl_mail.git
synced 2026-10-25 01:54:10 +00:00
Correct what translating the handbook found wrong in it
Six defects, all found by somebody reading a page closely enough to
render it in another language. Each is fixed in English and in German
together, and the German markers are re-hashed only where the German
prose now says what the corrected English says — re-hashing alone would
mark a stale translation as current, which is the one thing that check
exists to prevent.
calendar-model.md claimed the materialiser honours "exactly four
things in a patch" above a table of five, and its
traps section named a different four. The truth
is five keys read, of which four are the patch
EventInstanceEditor writes; `excluded` is not a
patch field at all and is spelled by
RecurrenceRuleConverter::exclusionOverrides(),
because the one override value whose only job is
to be exactly right should not have two places
that must be right about it.
CLIENT_DEVELOPMENT.md said snooze was "not exposed over JMAP today" and
offered itself as the canonical "ask, don't work
around" case — while Thread/set has been
implementing exactly that. Somebody asked. Its
methods table was also missing Thread/set,
SearchSnippet/get and all four calendar methods,
which the same page announces two screens above.
install/docker.md described the missing blob volumes as a live
defect. They were added to compose.yaml hours
after that page was written — by the report that
found them — and nobody updated the page. It now
documents ten volumes and keeps the story as
history, with a pointer to the CHANGELOG note for
anyone upgrading past it.
providers/imap-smtp.md named a form label no interface shows. The
hardcoded labels in AccountType are overridden by
the Twig template, so the fields are "Email
address" and "Username".
settings.nav.calendars had no German, so one item in a German settings
menu rendered in English.
CONTRIBUTING.md said "four translators" where there were six.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
629d937d97
commit
b4e3cb6afb
10 files changed
+90
-99
No files matched your search
+1
-1
@@ -622,7 +622,7 @@ Two things hide the register and are worth checking for after a draft: passive v
|
||||
avoid addressing the reader at all, and "man" standing in where "du" reads better. Mixing the two
|
||||
forms is worse than either consistently, so a page converted halfway is a page not yet converted.
|
||||
|
||||
**German glossary**, so four translators do not invent four words for one thing:
|
||||
**German glossary**, so a handbook translated by several people does not invent several words for one thing:
|
||||
|
||||
| English | German |
|
||||
|---|---|
|
||||
|
||||
@@ -32,15 +32,14 @@ concept that lives in the database but not in the API, a limit that's wrong for
|
||||
|
||||
Concretely, **stop and ask before** you:
|
||||
|
||||
- reimplement server logic client-side because the API doesn't expose it (snooze is the live example
|
||||
— see [§4](#feature-parity-checklist));
|
||||
- reimplement server logic client-side because the API doesn't expose it;
|
||||
- scrape or drive the HTML / Turbo Stream routes because JMAP lacks something;
|
||||
- poll aggressively to compensate for a missing change-tracking method;
|
||||
- invent local state (custom keywords, shadow flags, local-only labels) that can't round-trip;
|
||||
- denormalise or cache something in a way that would break if the server later did it properly.
|
||||
|
||||
Things this document flags as **not implemented** — `Email/queryChanges`, anchor paging, JMAP
|
||||
Contacts, JWT issuance, snooze over JMAP, a cross-account unified query — are all *candidates for
|
||||
Contacts, JWT issuance, a cross-account unified query — are all *candidates for
|
||||
being built*, not permanent constraints. Raise the need with the maintainer and decide together
|
||||
whether it belongs in the server or the client.
|
||||
|
||||
@@ -552,6 +551,10 @@ Everything registered in [`src/Jmap/Method/`](../src/Jmap/Method/):
|
||||
| `Mailbox/get` / `Mailbox/query` / `Mailbox/changes` / `Mailbox/set` | |
|
||||
| `Email/get` / `Email/query` / `Email/changes` / `Email/set` | |
|
||||
| `Thread/get` / `Thread/changes` | |
|
||||
| `Thread/set` | plMail extension. One property, `snoozedUntil` — see §4. |
|
||||
| `SearchSnippet/get` | |
|
||||
| `Calendar/get` | `urn:plmail:params:jmap:calendars`. One account serves calendars. |
|
||||
| `CalendarEvent/get` / `CalendarEvent/query` / `CalendarEvent/set` | An id is the series, not an occurrence; `/query` requires a date window. |
|
||||
| `EmailSubmission/get` / `EmailSubmission/set` / `EmailSubmission/changes` | |
|
||||
| `Identity/get` / `Identity/set` | |
|
||||
|
||||
@@ -874,11 +877,13 @@ Ordered roughly by how much users will miss them.
|
||||
- Labels: apply, remove, create, delete. Nested labels exist in the data model; nested label *UI* is
|
||||
still on the server roadmap, so flat-with-paths is acceptable.
|
||||
- Archive = remove Inbox label. Trash = `destroy`. Both undoable.
|
||||
- Snooze — bring a conversation back later. This is a **thread-level** property
|
||||
(`MessageThread.snoozedUntil`) that exists in the database and in the web UI, but is **not exposed
|
||||
over JMAP today**. This is the canonical "ask, don't work around" case: the data and the semantics
|
||||
already exist server-side, so the fix is a small vendor extension, not a client-side reimplementation.
|
||||
A locally-tracked snooze would silently disagree with the web UI and break on reinstall.
|
||||
- Snooze — bring a conversation back later. A **thread-level** property (`MessageThread.snoozedUntil`),
|
||||
exposed as `Thread/set`, which is a plMail extension accepting that one property and nothing else.
|
||||
It goes through the same `ThreadSnoozeService` the web UI does, so a snooze set from a client and
|
||||
one set in the browser mean the same thing — which is the point, and why a locally-tracked snooze
|
||||
is still the wrong idea: it would disagree with the web UI and break on reinstall. This section
|
||||
used to say snooze was not exposed at all, and cited itself as the canonical "ask, don't work
|
||||
around" case; somebody asked.
|
||||
- Mark read/unread, star.
|
||||
|
||||
**Settings**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- translated-from: CLIENT_DEVELOPMENT.md sha1:d3361366991bf0c0c036c986fb164e5040f73b00 -->
|
||||
<!-- translated-from: CLIENT_DEVELOPMENT.md sha1:e8b507a009a17b4a74b8b3d040491e1aa38aaf35 -->
|
||||
# Einen Client für plMail bauen
|
||||
|
||||
Alles, was eine Entwicklerin (oder ein Agent) braucht, um einen *neuen* plMail-Client zu schreiben
|
||||
@@ -38,8 +38,7 @@ ein für Mobilgeräte falsch gesetztes Limit:
|
||||
|
||||
Konkret: **halt inne und frag nach, bevor du**
|
||||
|
||||
- Serverlogik clientseitig neu implementierst, weil die API sie nicht herausgibt (Zurückstellen
|
||||
ist das lebende Beispiel — siehe [§4](#checkliste-zur-funktionsgleichheit));
|
||||
- Serverlogik clientseitig neu implementierst, weil die API sie nicht herausgibt;
|
||||
- die HTML-/Turbo-Stream-Routen scrapest oder fernsteuerst, weil JMAP etwas nicht hat;
|
||||
- aggressiv pollst, um eine fehlende Methode zur Änderungsverfolgung auszugleichen;
|
||||
- lokalen Zustand erfindest (eigene Keywords, Schatten-Flags, nur lokale Label), der nicht
|
||||
@@ -48,7 +47,7 @@ Konkret: **halt inne und frag nach, bevor du**
|
||||
ordentlich täte.
|
||||
|
||||
Was dieses Dokument als **nicht implementiert** kennzeichnet — `Email/queryChanges`,
|
||||
Anchor-Paging, JMAP Contacts, JWT-Ausgabe, Zurückstellen über JMAP, eine kontoübergreifende
|
||||
Anchor-Paging, JMAP Contacts, JWT-Ausgabe, eine kontoübergreifende
|
||||
vereinigte Abfrage — sind allesamt *Kandidaten für den Bau*, keine dauerhaften Einschränkungen.
|
||||
Bring den Bedarf beim Maintainer zur Sprache und entscheidet gemeinsam, ob er in den Server oder
|
||||
in den Client gehört.
|
||||
@@ -609,6 +608,10 @@ Alles, was in [`src/Jmap/Method/`](../src/Jmap/Method/) registriert ist:
|
||||
| `Mailbox/get` / `Mailbox/query` / `Mailbox/changes` / `Mailbox/set` | |
|
||||
| `Email/get` / `Email/query` / `Email/changes` / `Email/set` | |
|
||||
| `Thread/get` / `Thread/changes` | |
|
||||
| `Thread/set` | plMail-Erweiterung. Eine Eigenschaft, `snoozedUntil` — siehe §4. |
|
||||
| `SearchSnippet/get` | |
|
||||
| `Calendar/get` | `urn:plmail:params:jmap:calendars`. Kalender liefert genau ein Konto. |
|
||||
| `CalendarEvent/get` / `CalendarEvent/query` / `CalendarEvent/set` | Eine ID ist die Serie, nicht eine Termininstanz; `/query` verlangt einen Zeitraum. |
|
||||
| `EmailSubmission/get` / `EmailSubmission/set` / `EmailSubmission/changes` | |
|
||||
| `Identity/get` / `Identity/set` | |
|
||||
|
||||
@@ -961,13 +964,15 @@ Grob danach geordnet, wie sehr Nutzerinnen sie vermissen werden.
|
||||
*Oberfläche* für verschachtelte Label steht noch auf der Server-Roadmap, flach mit Pfaden ist
|
||||
also in Ordnung.
|
||||
- Archivieren = Posteingangs-Label entfernen. Papierkorb = `destroy`. Beides rückgängig zu machen.
|
||||
- Zurückstellen — eine Konversation später zurückholen. Das ist eine Eigenschaft **auf
|
||||
Konversationsebene** (`MessageThread.snoozedUntil`), die es in der Datenbank und in der
|
||||
Web-Oberfläche gibt, die aber **heute nicht über JMAP offengelegt ist**. Das ist der
|
||||
kanonische Fall für „frag nach, bau nichts drumherum": Die Daten und die Semantik gibt es
|
||||
serverseitig bereits, die Lösung ist also eine kleine Herstellererweiterung und keine
|
||||
clientseitige Neuimplementierung. Ein lokal geführtes Zurückstellen widerspräche stillschweigend
|
||||
der Web-Oberfläche und ginge bei einer Neuinstallation kaputt.
|
||||
- Zurückstellen — eine Konversation später zurückholen. Eine Eigenschaft **auf
|
||||
Konversationsebene** (`MessageThread.snoozedUntil`), offengelegt als `Thread/set`, einer
|
||||
plMail-Erweiterung, die genau diese eine Eigenschaft annimmt und sonst nichts. Sie läuft über
|
||||
denselben `ThreadSnoozeService` wie die Web-Oberfläche, ein aus einem Client gesetztes
|
||||
Zurückstellen bedeutet also dasselbe wie eines im Browser — genau darum geht es, und genau
|
||||
deshalb ist ein lokal geführtes Zurückstellen weiterhin die falsche Idee: Es widerspräche der
|
||||
Web-Oberfläche und ginge bei einer Neuinstallation kaputt. Dieser Abschnitt sagte früher, das
|
||||
Zurückstellen sei gar nicht offengelegt, und führte sich selbst als kanonischen Fall für
|
||||
„frag nach, bau nichts drumherum" an; jemand hat nachgefragt.
|
||||
- Gelesen/ungelesen markieren, mit Stern versehen.
|
||||
|
||||
**Einstellungen**
|
||||
|
||||
+23
-37
@@ -1,4 +1,4 @@
|
||||
<!-- translated-from: install/docker.md sha1:1136c2c336cb10040b2c5e588a7cebc63fb2d930 -->
|
||||
<!-- translated-from: install/docker.md sha1:5382118760ac4e687b2aebee31c9d4910c6e6f65 -->
|
||||
# Installation mit Docker Compose
|
||||
|
||||
Der unterstützte Weg, von Anfang bis Ende: was du brauchst, was `docker compose up` tatsächlich tut,
|
||||
@@ -148,50 +148,36 @@ sollte.
|
||||
|
||||
## Speicher, und was die Standarddatei nicht dauerhaft ablegt
|
||||
|
||||
Die Compose-Datei deklariert sechs benannte Volumes:
|
||||
Die Compose-Datei deklariert zehn benannte Volumes:
|
||||
|
||||
| Volume | Enthält |
|
||||
|---|---|
|
||||
| `app_secrets` | `generated.env`, `postgres_password`, das JWT-Schlüsselpaar. Von **jedem** Anwendungsdienst eingehängt und nur lesend in `database` und `mercure` |
|
||||
| `database_data` | Den PostgreSQL-Cluster |
|
||||
| `app_secrets` | `generated.env`, `postgres_password`, das JWT-Schlüsselpaar. Von **jedem** App-Dienst eingehängt, in `database` und `mercure` nur lesend |
|
||||
| `app_attachments`, `app_raw`, `app_uploads` | Anhänge, Rohnachrichten und zwischengelagerte JMAP-Uploads. Von jedem App-Dienst eingehängt, denn die Worker schreiben sie und der Web-Container liefert sie aus |
|
||||
| `database_data` | Der PostgreSQL-Cluster |
|
||||
| `caddy_data`, `caddy_config` | Caddys TLS-Material und Zustand |
|
||||
| `mercure_data`, `mercure_config` | Zustand des Hubs |
|
||||
| `ntfy_data` | Zustand der Benachrichtigungs-Topics |
|
||||
|
||||
Diese Liste hat eine Lücke, die du kennen solltest, bevor du echte Mail hineinlegst:
|
||||
**`var/attachments`, `var/raw` und `var/uploads` liegen in der Standard-`compose.yaml` auf keinem
|
||||
Volume.** Das Dockerfile enthält bewusst kein `VOLUME /app/var/` — ein anonymes Volume dort gab
|
||||
jedem Container seine eigene Kopie, sodass Anhänge, die ein Sync-Worker schrieb, für den
|
||||
Web-Container unsichtbar waren, der sie ausliefern soll —, und die dauerhaften Pfade sind
|
||||
stattdessen pro Dienst zu deklarieren, wie es `compose.override.yaml.dist` und
|
||||
`truenas.compose.yaml` beide tun. Füge sie dem Dienst `php` und allen vier Workern hinzu, wenn
|
||||
Anhang-Downloads überleben sollen, dass ein Container neu erzeugt wird:
|
||||
Die drei Blob-Volumes fehlten bis vor Kurzem, und der Fehler war auf lehrreiche Weise lautlos. Das
|
||||
Dockerfile hat bewusst kein `VOLUME /app/var/` — ein anonymes Volume dort gab jedem Container seine
|
||||
eigene Kopie —, die dauerhaften Pfade werden also pro Dienst deklariert. Die beiden
|
||||
Deployment-Dateien, die tatsächlich jemand bearbeitet hat, `compose.override.yaml.dist` und
|
||||
`truenas.compose.yaml`, deklarierten sie. Die Standarddatei `compose.yaml`, also genau die Datei,
|
||||
zu der die README greifen lässt, nicht. Anhänge, die ein Sync-Worker schrieb, waren damit für den
|
||||
Web-Container unsichtbar, der den Download ausliefern sollte, und beide Kopien starben beim
|
||||
nächsten `docker compose up`, das einen Container neu anlegte. Nichts warf einen Fehler: Mail kam
|
||||
an, die Liste zeichnete sich, und der Download lieferte 404.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
php: &blobs
|
||||
volumes:
|
||||
- app_attachments:/app/var/attachments
|
||||
- app_raw:/app/var/raw
|
||||
- app_uploads:/app/var/uploads
|
||||
worker-ingest: *blobs
|
||||
worker-export: *blobs
|
||||
worker-maintenance: *blobs
|
||||
imap-supervisor: *blobs
|
||||
**Wenn du eine Standard-`compose.yaml` von vor dieser Korrektur betreibst, lies den
|
||||
Deployment-Hinweis in
|
||||
[CHANGELOG.md](https://github.com/karatektus/pl_mail/blob/main/CHANGELOG.md), bevor du ziehst.**
|
||||
Ein leeres Volume über ein Verzeichnis zu hängen verdeckt, was darin liegt — gelöscht wird nichts,
|
||||
aber die Dateien sind nicht mehr sichtbar, bis sie herüberkopiert sind.
|
||||
|
||||
volumes:
|
||||
app_attachments:
|
||||
app_raw:
|
||||
app_uploads:
|
||||
```
|
||||
|
||||
`truenas.compose.yaml` geht den anderen Weg: Es setzt `APP_STORAGE_DIR=var/data` und bindet ein
|
||||
einziges Host-Verzeichnis auf `/app/var/data`, sodass Anhänge, Rohnachrichten, Uploads und die
|
||||
Geheimnisse alle unter einem Pfad landen — eine Sache zum Snapshotten, eine Sache zum Sichern.
|
||||
|
||||
**Der typische Fehlerfall verläuft lautlos.** Nichts meldet einen Fehler: Mail wird abgeglichen, die
|
||||
Liste wird gerendert, und der Download eines Anhangs endet mit 404, weil die Datei in einem
|
||||
Container liegt, den der Webserver nicht sieht — oder in einem Container lag, der inzwischen ersetzt
|
||||
wurde.
|
||||
`truenas.compose.yaml` geht einen anderen Weg: Es setzt `APP_STORAGE_DIR=var/data` und bindet ein
|
||||
einziges Host-Verzeichnis an `/app/var/data`, sodass Anhänge, Rohnachrichten, Uploads und die
|
||||
Geheimnisse alle unter einem Pfad landen — eine Sache zum Snapshotten und eine zum Sichern.
|
||||
|
||||
## Alltagsbetrieb
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- translated-from: internals/calendar-model.md sha1:bf151a9ad94f1b595778248245a7ed79a2ddae60 -->
|
||||
<!-- translated-from: internals/calendar-model.md sha1:7c82dbb22e19aa9d49c9de3588e586b79b7a940a -->
|
||||
# Das Kalendermodell
|
||||
|
||||
JSCalendar in jsonb, mit den abfragbaren Teilen in Spalten herausgezogen; die Tabelle der
|
||||
@@ -195,8 +195,12 @@ stabile Art zu sagen „die, die am 3. sein sollte", nachdem sie auf den 5. gezo
|
||||
das, was eine zweite Bearbeitung derselben Instanz ihren Patch aktualisieren lässt, statt einen
|
||||
neuen danebenzustapeln.
|
||||
|
||||
Der Materialisierer beachtet in einem Patch genau vier Dinge, und
|
||||
`App\Service\Calendar\EventInstanceEditor` schreibt genau diese vier:
|
||||
Der Materialisierer liest fünf Schlüssel aus einem Override. Vier davon sind der Patch, den
|
||||
`App\Service\Calendar\EventInstanceEditor` schreibt — die vier Dinge, die eine Termininstanz
|
||||
überhaupt zeichnen kann —, und der fünfte ist gar kein Patch-Feld: `excluded` wird von
|
||||
`RecurrenceRuleConverter::exclusionOverrides()` geschrieben, denn der eine Override-Wert, dessen
|
||||
einzige Aufgabe es ist, exakt richtig zu sein, sollte keine zweite Stelle haben, die ihn richtig
|
||||
treffen muss.
|
||||
|
||||
| Schlüssel | Wirkung |
|
||||
|---|---|
|
||||
@@ -360,8 +364,9 @@ der Nutzerin. Alles, was einen Override erzeugt, muss `RecurrenceMaterialiser::z
|
||||
statt selbst eine Zone zu bestimmen.
|
||||
|
||||
**Alles, was ein Patch über `start`, `duration`, `title` und `status` hinaus sagt, wird
|
||||
ignoriert.** Der Materialisierer liest diese und sonst nichts, ein „reichhaltigerer" Patch sind
|
||||
also Daten, die die Speicherung überstehen und nie eine Ansicht beeinflussen.
|
||||
ignoriert** — diese vier plus `excluded`, das auf dem anderen Weg oben ankommt. Der
|
||||
Materialisierer liest sie und sonst nichts, ein „reichhaltigerer" Patch sind also Daten, die die
|
||||
Speicherung überstehen und nie eine Ansicht beeinflussen.
|
||||
|
||||
**Den Horizont zu verlängern ist nicht umsonst, und ihn zu verkürzen kostet Erinnerungen.** Der
|
||||
Horizont der Termininstanzen ist zugleich der Horizont der Erinnerungen — eine Erinnerung gibt es
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- translated-from: providers/imap-smtp.md sha1:23ff0340249508460944b7e7704fc313c8f01213 -->
|
||||
<!-- translated-from: providers/imap-smtp.md sha1:b4f879ff7cebf8fb604297a9d39a979025c8ea9f -->
|
||||
|
||||
# IMAP und SMTP
|
||||
|
||||
|
||||
+16
-30
@@ -133,49 +133,35 @@ running.
|
||||
|
||||
## Storage, and what the stock file does not persist
|
||||
|
||||
The compose file declares six named volumes:
|
||||
The compose file declares ten named volumes:
|
||||
|
||||
| Volume | Holds |
|
||||
|---|---|
|
||||
| `app_secrets` | `generated.env`, `postgres_password`, the JWT keypair. Mounted by **every** app service, and read-only into `database` and `mercure` |
|
||||
| `app_attachments`, `app_raw`, `app_uploads` | Attachments, raw message sources, and staged JMAP uploads. Mounted by every app service, because the workers write them and the web container serves them |
|
||||
| `database_data` | The PostgreSQL cluster |
|
||||
| `caddy_data`, `caddy_config` | Caddy's TLS material and state |
|
||||
| `mercure_data`, `mercure_config` | Hub state |
|
||||
| `ntfy_data` | Notification topic state |
|
||||
|
||||
That list has a gap worth knowing about before you put real mail in it: **`var/attachments`,
|
||||
`var/raw` and `var/uploads` are not on any volume in the stock `compose.yaml`.** The Dockerfile
|
||||
deliberately has no `VOLUME /app/var/` — an anonymous volume there gave every container its own
|
||||
copy, so attachments written by a sync worker were invisible to the web container that serves them
|
||||
— and the durable paths are instead expected to be declared per service, which
|
||||
`compose.override.yaml.dist` and `truenas.compose.yaml` both do. Add them to the `php` service and
|
||||
to all four workers if you want attachment downloads to survive a container being recreated:
|
||||
The three blob volumes were missing until recently, and the failure was silent in an instructive
|
||||
way. The Dockerfile deliberately has no `VOLUME /app/var/` — an anonymous volume there gave every
|
||||
container its own copy — and the durable paths are instead declared per service. The two
|
||||
deployment files that people actually edited, `compose.override.yaml.dist` and
|
||||
`truenas.compose.yaml`, both declared them. The stock `compose.yaml`, which is the file the README
|
||||
tells an operator to run, did not. So attachments written by a sync worker were invisible to the
|
||||
web container serving the download, and both copies died with the next `docker compose up` that
|
||||
recreated a container. Nothing errored: mail synced, the list rendered, and the download 404'd.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
php: &blobs
|
||||
volumes:
|
||||
- app_attachments:/app/var/attachments
|
||||
- app_raw:/app/var/raw
|
||||
- app_uploads:/app/var/uploads
|
||||
worker-ingest: *blobs
|
||||
worker-export: *blobs
|
||||
worker-maintenance: *blobs
|
||||
imap-supervisor: *blobs
|
||||
**If you ran a stock `compose.yaml` from before that fix, read the deployment note in
|
||||
[CHANGELOG.md](https://github.com/karatektus/pl_mail/blob/main/CHANGELOG.md) before pulling.**
|
||||
Mounting an empty volume over a directory hides what is inside it — nothing is deleted, but the
|
||||
files stop being visible until they are copied across.
|
||||
|
||||
volumes:
|
||||
app_attachments:
|
||||
app_raw:
|
||||
app_uploads:
|
||||
```
|
||||
|
||||
`truenas.compose.yaml` takes the other approach: it sets `APP_STORAGE_DIR=var/data` and binds one
|
||||
`truenas.compose.yaml` takes a different approach: it sets `APP_STORAGE_DIR=var/data` and binds one
|
||||
host directory at `/app/var/data`, so attachments, raw messages, uploads and the secrets all land
|
||||
under a single path — one thing to snapshot and one thing to back up.
|
||||
|
||||
**The failure mode is silent.** Nothing errors: mail syncs, the list renders, and an attachment
|
||||
download 404s because the file is in a container the web server cannot see — or was in a container
|
||||
that has since been replaced.
|
||||
|
||||
## Everyday operation
|
||||
|
||||
```bash
|
||||
|
||||
@@ -173,8 +173,11 @@ is the same fact in the occurrence row: the only stable way to say "the one that
|
||||
be on the 3rd" once it has been dragged to the 5th, and what makes a second edit of the same
|
||||
instance update its patch instead of stacking a new one beside it.
|
||||
|
||||
The materialiser honours exactly four things in a patch, and `App\Service\Calendar\EventInstanceEditor`
|
||||
writes exactly those four:
|
||||
The materialiser reads five keys out of an override. Four of them are the patch
|
||||
`App\Service\Calendar\EventInstanceEditor` writes — the four things an occurrence row can actually
|
||||
draw — and the fifth is not a patch field at all: `excluded` is spelled by
|
||||
`RecurrenceRuleConverter::exclusionOverrides()`, because the one override value whose only job is
|
||||
to be exactly right should not have a second place that has to be right about it.
|
||||
|
||||
| Key | Effect |
|
||||
|---|---|
|
||||
@@ -323,9 +326,9 @@ LocalDateTime in the *series'* zone; a floating event's zone is UTC, not the use
|
||||
producing an override must ask `RecurrenceMaterialiser::zoneOf()` rather than resolving a
|
||||
zone itself.
|
||||
|
||||
**Anything a patch says beyond `start`, `duration`, `title` and `status` is ignored.** The
|
||||
materialiser reads those and nothing else, so a "richer" patch is data that survives storage
|
||||
and never affects a view.
|
||||
**Anything a patch says beyond `start`, `duration`, `title` and `status` is ignored** — those
|
||||
four plus `excluded`, which arrives by the other route above. The materialiser reads them and
|
||||
nothing else, so a "richer" patch is data that survives storage and never affects a view.
|
||||
|
||||
**Extending the horizon is not free and shortening it loses alerts.** The occurrence horizon
|
||||
is also the alert horizon — an alert exists only where an occurrence row does — and
|
||||
|
||||
@@ -18,7 +18,7 @@ connection to come up, and about the handful of settings providers genuinely dis
|
||||
carry a short note about something that provider requires. The list is matched against the domain
|
||||
of the address you type, so for most mailboxes the settings arrive before you have touched the
|
||||
dropdown at all.
|
||||
2. **Account label** is what the account is called in plMail's own interface. **Email address** is
|
||||
2. **Email address** is what the account is called in plMail's own interface. **Username** is
|
||||
what the server knows you as, and is also what the provider detection reads. On most servers
|
||||
these are the same string; on some they are not, which is what the two fields are for.
|
||||
3. **Password** is the mailbox password, or — at most large providers — an application-specific
|
||||
|
||||
@@ -1680,6 +1680,7 @@ settings:
|
||||
aliases: Aliase
|
||||
app_passwords: App-Passwörter
|
||||
appearance: Darstellung
|
||||
calendars: Kalender
|
||||
general: Allgemein
|
||||
profile: Profil
|
||||
filters: Filter
|
||||
|
||||
Reference in new issue
Block a user