Ortszeit ist in Entwicklung. Anmelden kann man sich noch nicht; wenn du Interesse hast, schreib mir.

ORTSZEIT · FORMAT · SCHEMAVERSION 1

Das portable Format

Die Dateien sind maßgeblich. Ein Blog ist ein Verzeichnis aus Markdown-Dateien mit YAML-Frontmatter und den Fotos daneben. Die Datenbank ist ein abgeleiteter Index — sie macht Ortssuche und Volltextsuche schnell, und sie lässt sich aus den Dateien wieder aufbauen.

Das ist der ganze Eigentumsanspruch, und er ist nur etwas wert, wenn das Format aufgeschrieben ist. Also hier ist es, versioniert, mit einem Deprecation-Pfad daran. Diese Seite ist der Vertrag: Wenn du ein Theme, einen Konverter oder ein Werkzeug schreibst, das ein Ortszeit-Archiv liest, bau gegen diese Seite und nicht gegen das, was ein bestimmter Export zufällig enthalten hat.

Version

ortszeit_schema: 1

Der Schlüssel steht in blog.yaml und in posts.json. Einzelne Beitragsdateien tragen ihn nicht — sie gehören zu dem Blog, in dem sie liegen.

Aufbau

blog/
  blog.yaml                          the blog itself
  posts.json                         every post again, as JSON
  trips/
    denmark-2026/
      trip.yaml                      one trip
      2026-06-12-aarhus-harbour.md   a post in that trip
      media/
        IMG_4021.jpg
  posts/                             posts that belong to no trip
    2026-05-01-a-note.md
    media/
      IMG_3980.jpg
  • Beitragsdateien heißen YYYY-MM-DD-<slug>.md, datiert nach demselben Wert wie das Feld date des Beitrags — Dateiname und Frontmatter stimmen also immer überein.
  • Jedes Beitragsverzeichnis hat sein eigenes media/. Mediendateinamen sind innerhalb eines solchen Verzeichnisses eindeutig; bei einer Kollision werden -2, -3 und so weiter an den Namensstamm gehängt.
  • Reisen ohne Beiträge werden trotzdem exportiert. Eine leere Reise gehört dir genauso.

Frontmatter eines Beitrags

---
title: Aarhus harbour
date: 2026-06-12T14:20:00+02:00
draft: false
place:
  name: Aarhus Havn
  osm: node/240109189
  lat: 56.1572
  lon: 10.2107
visibility: public
media:
  - file: media/IMG_4021.jpg
    taken_at: 2026-06-12T14:18:00+02:00
    alt: Ferry coming in past the harbour cranes
---

Rain until four, then the harbour went gold.

Feld für Feld:

Schlüssel Typ Hinweise
title String oder null Immer vorhanden, oft null. Ein Beitrag ohne Titel ist normal, nicht kaputt.
date Zeitstempel Mit Zeitzone. published_at bei einem veröffentlichten Beitrag, die Erstellungszeit, solange er Entwurf ist — der Wert passt also immer zum Dateinamen.
draft Boolean Immer vorhanden. Entwürfe werden mitexportiert: Sie sind deine Texte, und ein Archiv, das sie stillschweigend weglässt, ist kein Archiv.
place Mapping Fehlt vollständig, wenn der Beitrag keinen Ort hat. Wird nie als null geschrieben.
place.name String Der angezeigte Name.
place.osm String oder null <osm_type>/<osm_id>, z. B. node/240109189. Null, wenn der Ort aus einer Quelle ohne OpenStreetMap-Referenz kam — meistens aus einem Import.
place.lat Zahl Dezimalgrad.
place.lon Zahl Dezimalgrad. Beachte: lon, nicht lng.
visibility String public, unlisted oder password. Das ist die effektive Sichtbarkeit, bereits gegen die Reise aufgelöst — ein Leseprogramm muss keine Vererbung über zwei Dateien hinweg nachvollziehen.
media Liste Immer vorhanden, möglicherweise leer. Die Reihenfolge ist die Anzeigereihenfolge.
media[].file String Pfad relativ zum eigenen Verzeichnis des Beitrags, damit er sich für Reise-Beiträge und einzelne Beiträge gleich liest.
media[].taken_at Zeitstempel oder null Aus dem EXIF des Fotos. Null, wenn die Quelle nie eine Zeit angegeben hat.
media[].alt String oder null Alternativtext. Null, wenn leer.

Der Text ist alles nach dem schließenden ---, als reines Markdown, mit der Teilmenge aus Erste Schritte.

blog.yaml

ortszeit_schema: 1
title: Ortszeit
bio: Notes from the road.
subdomain: alice
custom_domain: null
theme: ortszeit
custom_css: ''
exported_at: 2026-06-20T09:14:03+00:00
Schlüssel Typ Hinweise
ortszeit_schema Integer Die Schemaversion dieses Archivs.
title String Blogtitel.
bio String Kurzbeschreibung. Darf leer sein.
subdomain String Der Name des Blogs unter ortszeit.app.
custom_domain String oder null Null, wenn es keine gibt.
theme String Heute ortszeit. Das Feld existiert, damit ein Theme-Ökosystem sich benennen kann.
custom_css String Darf leer sein.
exported_at Zeitstempel Wann dieses Archiv geschrieben wurde. Das einzige Feld, das vom Export handelt und nicht vom Blog.

trip.yaml

title: Denmark 2026
slug: denmark-2026
started_on: 2026-06-10
ended_on: 2026-06-24
visibility: public
co_authors:
  - Alice
Schlüssel Typ Hinweise
title String
slug String Innerhalb des Blogs eindeutig; er ist zugleich der Verzeichnisname.
started_on Datum Datum, kein Zeitstempel.
ended_on Datum oder null Null, solange die Reise offen ist.
visibility String public, unlisted oder password.
co_authors Liste von Strings Anzeigenamen.

Das Passwort einer Reise wird nie exportiert, in keinem Tarif und in keiner Form — weder das Passwort noch sein Hash. Eine Reise mit visibility: password kommt anderswo also ohne Schutz an, und jedes Importprogramm muss sie als privat behandeln statt als öffentlich. Der Importer von Ortszeit stuft sie auf unlisted herunter und sagt dir, dass du ein neues Passwort setzen sollst.

posts.json

Derselbe Inhalt noch einmal, als ein JSON-Dokument, für Werkzeuge, die lieber kein Frontmatter parsen:

{
  "ortszeit_schema": 1,
  "blog": { "ortszeit_schema": 1, "title": "Ortszeit", "...": "..." },
  "posts": [
    {
      "path": "trips/denmark-2026/2026-06-12-aarhus-harbour.md",
      "slug": "aarhus-harbour",
      "trip": "denmark-2026",
      "title": "Aarhus harbour",
      "date": "2026-06-12T14:20:00+02:00",
      "draft": false,
      "place": { "name": "Aarhus Havn", "osm": "node/240109189", "lat": 56.1572, "lon": 10.2107 },
      "visibility": "public",
      "media": [
        { "file": "media/IMG_4021.jpg", "taken_at": "2026-06-12T14:18:00+02:00", "alt": null }
      ],
      "body": "Rain until four, then the harbour went gold."
    }
  ]
}

Jeder Eintrag trägt das Frontmatter des Beitrags unverändert, dazu drei Schlüssel, die die Markdown-Datei stattdessen über ihren Ort im Baum ausdrückt:

Schlüssel Typ Hinweise
path String Der Pfad der Beitragsdatei innerhalb von blog/.
slug String Der Slug des Beitrags.
trip String oder null Der Slug der Reise, oder null bei einem Beitrag ohne Reise.
body String Der Markdown-Text.

Daten und Zeitstempel sind in JSON ISO-8601-Strings, während die YAML-Dateien echte Datums- und Zeitwerte verwenden.

Das Format lesen

Drei Regeln, damit ein heute geschriebenes Leseprogramm auch später noch funktioniert:

  1. Ignoriere Schlüssel, die du nicht kennst. Innerhalb einer Schemaversion können neue optionale Schlüssel dazukommen.
  2. Verlass dich nicht auf die Reihenfolge der Schlüssel. Der Writer schreibt sie in stabiler Reihenfolge, weil das Diffs lesbar macht — aber YAML-Mappings sind ungeordnet, und ein konformes Leseprogramm muss sie so behandeln.
  3. Unterscheide „fehlt“ von „null“. place fehlt, wenn es keinen Ort gibt. title ist vorhanden und null, wenn es keinen Titel gibt. Dieser Unterschied ist beabsichtigt und bleibt so.

Versionierung und Deprecation

ortszeit_schema ist eine ganze Zahl. Kein Datum und keine semantische Version.

Was die Version nicht erhöht: ein neuer optionaler Schlüssel, ein neuer erlaubter Wert in einem Feld, das Leseprogramme ohnehin generisch behandeln müssen, oder ein Wert, der vorher immer gefehlt hat. Leseprogramme, die sich an Regel 1 halten, sind davon nicht betroffen.

Was die Version erhöht: ein Schlüssel verschwindet, wird umbenannt, ändert seinen Typ, oder die Bedeutung eines bestehenden Werts ändert sich.

Das Versprechen, das an einer Erhöhung hängt:

  • Die neue Version steht auf dieser Seite, bevor irgendetwas sie schreibt.
  • Die vorherige Version bleibt hier dokumentiert, als veraltet markiert, mit dem Datum, ab dem sie nicht mehr geschrieben wird.
  • Der Importer von Ortszeit akzeptiert die vorherige Version mindestens zwölf Monate über dieses Datum hinaus, und Version 1 praktisch unbegrenzt — ein altes Archiv wiederherstellen zu können ist der ganze Sinn des Formats.
  • Eine Versionserhöhung wird mit dem Release angekündigt, das sie bringt, nicht danach.

Was das Format nicht enthält

Deutlich gesagt, denn eine dokumentierte Lücke ist eine Einschränkung, eine undokumentierte eine böse Überraschung:

  • Passwörter von Reisen, siehe oben.
  • Medien, die an keinem Beitrag hängen. Der Aufbau hat keinen Platz dafür, also werden sie nicht exportiert. Eine bekannte Lücke.
  • Das PDF pro Reise, das bei bezahlten Exporten zugesagt ist. Es ist spezifiziert, aber noch nicht gebaut — und es wäre ohnehin nicht Teil dieses Baums: Es ist eine Darstellung des Inhalts, nicht der Inhalt.
  • Konto-, Abo- und Kontingentstatus. Nichts davon ist deins zum Mitnehmen, alles davon ist abgeleitet.