- Go 96.5%
- PLpgSQL 3.3%
- Shell 0.2%
Seine Flaechen ankreuzen konnte man schon, aber danach nirgends sehen, was darauf waechst -- die Auswahl war Mittel ohne Zweck. Die Seite fuehrt jetzt unter "Meine Sorten" auf, was auf den gewaehlten Bongerts steht, mit der Zahl der Baeume je Sorte, die baumreichste zuerst. Gezaehlt wird ueber die View sorten_baeume, also ueber ALLE Namen einer Sorte: ein Baum, der in treedoc "Boskop" heisst, zaehlt beim Schoener aus Boskoop mit. Gerodete Baeume stehen nicht im Cache und fehlen von selbst -- die Zahl ist eine Aussage ueber den heutigen Bestand. Nur treedoc-Baeume koennen auftauchen, die 798 OSM-Baeume tragen keinen Bongert. Darueber steht, wie viel vom Bestand ueberhaupt einen Namen traegt: heute bei vier Flaechen 236 Sorten auf 336 von 399 Baeumen, 63 ohne bestimmte Sorte. Diese Luecke ist auf einer Werkstattseite die eigentliche Auskunft -- sie sagt, wo noch Arbeit liegt. Die Spalte "Flaechen" erscheint nur bei mehreren eigenen Bongerts; sonst stuende dort in jeder Zeile eine 1. Die Erklaerung der Auswahl ist zu den Kaestchen gewandert, weil der Bestand jetzt darueber steht. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|---|---|---|
| .claude/skills | ||
| cmd | ||
| docs | ||
| internal | ||
| schema | ||
| scripts | ||
| web | ||
| .gitignore | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| config.yaml.example | ||
| go.mod | ||
| go.sum | ||
| merkmale-kalibrierung.md | ||
| README.md | ||
| treedoc-birnen-anweisung.md | ||
| verworfene-pdf-quellen.txt | ||
obstdoc
Ein Verzeichnis der Obstsorten — Apfel, Birne, Quitte, Speierling und die anderen Fruchtarten. Während treedoc den einzelnen Baum dokumentiert, dokumentiert obstdoc die Sorte und zeigt zu jeder Sorte die dokumentierten (treedoc) und die in OpenStreetMap kartierten Bäume dieser Sorte.
Das Go-Modul heißt forge.23.nu/md/obstdoc. Es ist wie
treework aufgebaut: eigener Postgres-Store, Bäume read-only über
die öffentliche treedoc-HTTP-API, optionales OSM-OAuth nur für Identität.
Datenfluss
Bearbeiten im Browser treedoc-API OSM / Overpass
│ Formulare je Abschnitt, │ │
│ mit Verlauf und Autor │ Takt-Sync + Webhook (der Server)
▼ ▼ ▼
┌──────────────────────────────────────────────────────────────────┐
│ PostgreSQL (DB: obstdoc, eigene DB — NICHT das replizierte │
│ treestore). sorten + fruchtarten + sorten_namen + baeume-Cache │
│ Der Sorte↔Baum-Link ist die VIEW sorten_baeume (abgeleitet). │
└───────────────────────────────┬──────────────────────────────────┘
▲
┌───────────────┐
│ obstdoc │ Anzeige-Server: liest die Sorten,
└───────────────┘ schreibt Baum-Cache und Bearbeitungen
│
▼ nächtlich, in Vault-Gestalt
s3://…/Sicherung/obstdoc/JJJJ-MM-TT/
(zurück mit obstdoc-auszug --einspielen)
Den Baum-Cache hält der Anzeige-Server selbst aktuell, damit obstdoc nicht davon abhängt, dass jemand ein Werkzeug startet:
- Takt — alle
sync_intervall(Vorgabe 24 h) ein Voll-Sync aus treedoc und Overpass. Das ist das Sicherheitsnetz:Repo.SaveTreein treedoc protokolliert nicht selbst, und nicht jedes CLI holt das nach — solche Änderungen melden keinen Webhook. - Zuruf —
POST /hooks/treedocnimmt treedocs Änderungsereignisse an (Signatur, ±5-Minuten-Fenster,Webhook-Idgegen Wiederholungen), antwortet sofort und zieht die Bäume 5 Sekunden nach dem letzten Ereignis neu. Das Ereignis trägt keine Daten in die Datenbank; ein verlorener oder verfälschter POST kostet Aktualität, mehr nicht. Protokoll:../treedoc/docs/webhooks.md, obstdoc-Seite:docs/treedoc-webhook-integration.md. - Archiv — hat sich am Bestand etwas geändert, rendert der Server die Sortenseiten und lädt die geänderten nach S3. Verglichen wird ein Abdruck je Quelle; ohne Änderung läuft kein Durchgang, denn er kostet einen treedoc-Aufruf je Baum. Ohne S3-Zugang in der Konfiguration bleibt das aus.
Der Kernpunkt: Namen sind uneinheitlich (Altbestand ist NFD, treedoc/OSM sind NFC;
Bäume tragen Klammer-Synonyme wie „Peter Broich (Kaiser Willhelm)"). Alle
Namensauflösung läuft über die SQL-Funktion obst_key() und die Tabelle
sorten_namen. Der Sorte↔Baum-Link ist bewusst nicht gespeichert, sondern
die View sorten_baeume — eine neue Alias-Zeile verknüpft alle betroffenen
Bäume auf einmal, nichts wird stale.
Komponenten
| Pfad | Zweck |
|---|---|
cmd/obstdoc |
HTTP-Anzeige-Server, inkl. Baum-Sync (hintergrund.go) und Webhook-Empfang (webhook.go) |
internal/vault |
Liest Notizen mit Frontmatter — seit dem Schnitt nur noch für den Rückweg aus dem Auszug |
internal/auszug |
Nächtlicher Vollabzug aller Sorten als Notizen |
internal/store |
Postgres-Store + Schema (schema.sql) |
internal/treedoc |
Read-only-Client der treedoc-API |
internal/osm |
Overpass-Client (OSM-Bäume mit Cultivar-Tag) |
internal/sync |
Baum-Cache aus treedoc + OSM aktualisieren |
internal/auth |
OSM-OAuth (identisch zu treework) |
Einrichten & Starten
# 1. Datenbank einmalig anlegen (Superuser):
# CREATE DATABASE obstdoc; \c obstdoc; CREATE EXTENSION IF NOT EXISTS postgis;
cp config.yaml.example config.yaml # db_dsn setzen
# 2. Server starten — er füllt den Baum-Cache beim Start und danach im Takt:
go run ./cmd/obstdoc # http://localhost:8768
Sorten werden im Browser bearbeitet, abschnittsweise, mit Verlauf. Wer schreiben
darf, steht in auth.schreiber; für den eigenen Rechner öffnet
OBSTDOC_SCHREIBER="*" alles, und das gehört nirgends sonst hin.
Eine leere Datenbank füllt man aus einem Auszug:
go run ./cmd/obstdoc-auszug --einspielen …/2026-08-15/Obstsorten
Den Baum-Cache baut der Server bei jedem Sync komplett neu auf
(ReplaceBaeume).
Webhook-Abonnement anlegen
Einmalig, sonst bleibt es beim Takt-Sync. Die Ziel-Adresse muss in treedocs
webhooks.allowed_hosts stehen (gepflegt in my_ansible), sonst antwortet
treedoc mit 400 — das ist der SSRF-Schutz, kein Fehler.
TOKEN=$(ssh ruby.vpn.foxel.org 'sudo /opt/treedoc/bin/treedoc-token \
--config /etc/treedoc/config.yaml --name obstdoc-setup --ttl 1h --quiet')
curl -sS -X POST https://treedoc.schnittsyndikat.de/api/tree/v1/webhooks \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"url":"https://obstdoc.schnittsyndikat.de/hooks/treedoc",
"description":"obstdoc Baum-Cache","event_types":["tree.*"]}'
Die Antwort enthält secret einmalig — als treedoc_webhook_secret in die
config.yaml, nicht ins Repo. Danach prüft
POST /api/tree/v1/webhooks/{id}/ping die Zustellung, ohne einen Baum
anzufassen.
Konfiguration (Env-Overrides)
| Variable | Zweck |
|---|---|
OBSTDOC_DB_DSN |
Postgres-DSN der obstdoc-DB |
OBSTDOC_SCHREIBER |
Freigabeliste fürs Bearbeiten (OSM-Kennungen, kommagetrennt) |
TREEDOC_BASE_URL |
treedoc-API-Basis |
OBSTDOC_TREEDOC_WEBHOOK_SECRET |
Signaturschlüssel des Webhook-Abonnements (whsec_…) |
OBSTDOC_SYNC_INTERVALL |
Abstand der Voll-Syncs, z. B. 24h; 0s schaltet ab |
OVERPASS_ENDPOINT / OVERPASS_RADIUS_KM |
OSM-Sync |
OBSTDOC_OSM_CLIENT_ID / _SECRET / OBSTDOC_SESSION_SECRET |
OSM-OAuth |