Alles, was es kann, auf einer Seite.
Geprüft im Code, der es ausführt, am 2. September 2026. Nichts hier ist geplant oder kommt demnächst.
Der Admin gibt es auf Englisch und Italienisch, deshalb sind diese Aufnahmen der englische Satz.
Das Schema ist das Formular.
Was du links schreibst, bekommen die Redakteure rechts.
fields.text()fields.textarea()fields.richText()fields.number()fields.boolean()fields.datetime()fields.slug()fields.select()fields.relation()fields.media()fields.group()fields.array()fields.json()fields.blocks()
- Flags, keine Bildschirme
- required und localized sind zwei Booleans am Feld.
- Slug aus dem Titel
- fields.slug({ from: 'title' }) füllt sich selbst; select trägt feste Optionen.
- Auch aus dem Admin
- Eigene Collections lassen sich im Admin anlegen und in der Datenbank speichern.
Ein Inhalt, vier Wege ihn zu lesen.
Nimm den, den dein Stack schon spricht.
Öffentliche Einträge brauchen keinen Schlüssel. Back-Office-Dokumente brauchen einen API-Schlüssel oder ein Bearer-Token.
curl 'https://cms.altovar.net/api/v1/collections/blog-post/entries?locale=en'
{ "data": [ { "id": "fdoc_16d9i3ef", "locale": "en",
"data": { "title": "EU-first content infrastructure", … },
"seo": { "metaTitle": …, "metaDescription": …, "robots": "index,follow" } } ],
"pagination": { "page": 1, "limit": 20, "total": 3, "totalPages": 1 } }
# The back-office route is the same shape, with a key:
curl -H 'x-api-key: sk_…' \
'https://cms.altovar.net/api/v1/collections/blog-post/documents?limit=10' Ein typisierter Client mit derselben Hülle: data und pagination.
import { OspreyClient } from '@osprey/client'
const osprey = new OspreyClient({
baseUrl: 'https://cms.altovar.net',
tenantId: 'altovar',
})
const { data, pagination } = await osprey
.collection('blog-post')
.listEntries({ locale: 'en', limit: 10 }) Nur Queries, per POST. GraphiQL steht in der Entwicklung bereit.
POST /api/v1/graphql
x-api-key: sk_…
query Posts($limit: Int) {
documents(collectionSlug: "blog-post", status: "published", limit: $limit) {
data { id status data }
pagination { total }
}
} Einträge landen beim Build in Astro Content Collections. Kein Schlüssel am Edge.
---
import { getCollection } from 'astro:content'
const posts = (await getCollection('blog'))
.filter((p) => p.data.locale === 'en')
.sort((a, b) => b.data.publishedAt.localeCompare(a.data.publishedAt))
---
{posts.map((p) => (
<article>
<a href={'/' + p.data.slug}>{p.data.title}</a>
<p>{p.data.excerpt}</p>
</article>
))} Hier veröffentlichen, dort erscheinen.
Entwürfe bleiben privat. Ein veröffentlichter Eintrag erreicht den öffentlichen Endpunkt innerhalb einer Minute, und ein Webhook kann die Website neu bauen.
- Drei Status
- draft, published, archived. Seiten ergänzen Review, Freigabe und Zeitplanung.
- Signierter Webhook
- HMAC-SHA256 über den Body in x-osprey-signature. Neun Ereignisse, Secret verschlüsselt gespeichert.
- Cache-Header
- Öffentliche Lesezugriffe tragen max-age=60 mit stale-while-revalidate, bereit für jeden vorgeschalteten Cache.
Zehn Sprachen, eine Matrix.
Jedes lokalisierte Feld, jede Sprache, gezählt.
- Inhaltssprachen
- en, it, es, de, fr, nl, pl, sv, pt, ro, pro Workspace gesetzt.
- Admin
- Englisch und Italienisch, umschaltbar in der oberen Leiste.
- Abdeckung
- Eine Matrix pro Seite und Sprache, und die fehlenden Texte als CSV.
- Auslieferung
- Ein Query-Parameter wählt die Sprache; hreflang-Alternates reisen mit jedem Eintrag.
Deine Domain, in vier Schritten.
Heute über die API. Die Einstellungsseite ist unterwegs, und diese Seite sagt das auch.
- Beanspruchen Sende den Host per POST an den Domain-Endpunkt. Er wartet als ausstehend.
- Nachweisen Lege den TXT-Eintrag _osprey-verify.<host> mit dem erhaltenen Token an.
- Prüfen Sende erneut POST mit verify: true. Der Host wandert in den Workspace.
- Zeigen CNAME auf die Plattform. Das Zertifikat wird bei der ersten Anfrage ausgestellt.
POST /api/v1/admin/domains
Authorization: Bearer <jwt>
{ "host": "www.example.com" }
{ "status": "pending",
"verification": { "type": "TXT",
"name": "_osprey-verify.www.example.com",
"value": "osprey-verify=…" } } Eigene Domains hängen vom Plan oder vom Hosting-Add-on ab.
Kontrolle, die ihre Arbeit zeigt.
Jede Zeile unten ist eine Route und ein Bildschirm, keine Roadmap.
- Rollen
- admin, editor, author, contributor, viewer
- API-Schlüssel
- gehasht, einmal gezeigt, Nur-Lesen-Flag, Ablauf
- Audit-Log
- wer, was, wann und von wo, für jede Statusänderung
- Revisionen
- Seitenhistorie mit Diff und Wiederherstellung
- Papierkorb
- gelöschte Seiten warten; du stellst sie wieder her oder löschst sie endgültig
- Gemeinsam
- Präsenz und geteiltes Bearbeiten von Seiten, Feld für Feld
- Einwilligung
- Cookie-Banner und ein Einwilligungsprotokoll mit gehashter IP
- Löschung und Export
- ein Aufruf schwärzt eine betroffene Person; Export aus dem Admin oder der CLI
- Anmeldung
- OpenID Connect pro Workspace, oder ein lokales Passwort
- Rate-Limits
- ein Bucket pro Routenfamilie, Grenzen in den Antwort-Headern
Die Teile drumherum.
Zwei veröffentlichte Pakete, eine CLI, ein MCP-Server und ein Self-Host-Stack.
- @osprey/client
- typisiertes SDK, React-Block-Renderer, Consent-Manager
- @osprey/astro
- Content-Loader, SEO-Head, Übersetzungs-Sync
- CLI
- setup, init, dev, build, generate-types, link, export
- MCP-Server
- sechzehn Werkzeuge über stdio, für den KI-Agenten, den du schon nutzt
- Self-Host
- eine Compose-Datei und ein Einrichtungsassistent unter /setup
- KI-Assistent
- übersetzt Lücken, füllt SEO, schreibt Alt-Texte; aus, bis du ihn einschaltest
Dein Inhalt. Dein Server. Heute.
Kostenloser Plan, keine Karte. Gehostet in der EU, oder auf deinen eigenen Maschinen.