Wszystko, co robi, na jednej stronie.

Sprawdzone w kodzie, który to uruchamia, 2 września 2026. Nic tutaj nie jest planowane ani „wkrótce”.

Panel istnieje po angielsku i włosku, więc te zrzuty to zestaw angielski.

Schemat to formularz.

To, co piszesz po lewej, redaktorzy dostają po prawej.

  • 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()
Flagi, nie ekrany
required i localized to dwa booleany na polu.
Slug z tytułu
fields.slug({ from: 'title' }) wypełnia się sam; select niesie stałe opcje.
Także z panelu
Własne kolekcje tworzysz w panelu, a zapisują się w bazie danych.

Jedna treść, cztery sposoby czytania.

Wybierz ten, którym twój stack już mówi.

Publiczne wpisy nie wymagają klucza. Dokumenty back-office wymagają klucza API albo tokenu bearer.

shellHTTP
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'

Typowany klient z tą samą kopertą: data i pagination.

blog.tsTS
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 })

Tylko zapytania, przez POST. GraphiQL dostępny w środowisku deweloperskim.

graphqlGQL
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 }
  }
}

Wpisy trafiają do content collections Astro podczas builda. Żadnego klucza na edge.

src/pages/index.astroASTRO
---
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>
))}
Przeczytaj dokument OpenAPI →

Publikujesz tu, pojawia się tam.

Szkice zostają prywatne. Opublikowany wpis dociera do publicznego endpointu w ciągu minuty, a webhook może przebudować stronę.

Trzy statusy
draft, published, archived. Strony dodają recenzję, akceptację i harmonogram.
Podpisany webhook
HMAC-SHA256 z treści w x-osprey-signature. Dziewięć zdarzeń, sekret zaszyfrowany w spoczynku.
Nagłówki cache
Publiczne odczyty niosą max-age=60 ze stale-while-revalidate, gotowe na dowolny cache z przodu.

Dziesięć języków, jedna macierz.

Każde lokalizowane pole, każdy język, policzone.

Języki treści
en, it, es, de, fr, nl, pl, sv, pt, ro, ustawiane per workspace.
Panel
Angielski i włoski, przełączane z górnego paska.
Pokrycie
Macierz dla każdej strony i języka, a brakujące teksty w pliku CSV.
Dostarczanie
Jeden parametr zapytania wybiera język; alternatywy hreflang podróżują z każdym wpisem.

Twoja domena, w czterech krokach.

Dziś przez API. Strona ustawień jest w drodze, i ta strona to mówi.

  1. Zgłoś Wyślij POST z hostem do endpointu domen. Czeka jako oczekująca.
  2. Udowodnij Dodaj rekord TXT _osprey-verify.<host> z otrzymanym tokenem.
  3. Zweryfikuj Wyślij POST ponownie z verify: true. Host przechodzi do workspace.
  4. Skieruj CNAME na platformę. Certyfikat jest wydawany przy pierwszym żądaniu.
domainsHTTP
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=…" } }

Własne domeny zależą od planu albo od dodatku hostingowego.

Kontrola, która pokazuje swoją pracę.

Każda linia poniżej to trasa i ekran, nie roadmapa.

Role
admin, editor, author, contributor, viewer
Klucze API
hashowane, pokazane raz, flaga tylko do odczytu, wygaśnięcie
Dziennik audytu
kto, co, kiedy i skąd, przy każdej zmianie stanu
Rewizje
historia stron z diffem i przywracaniem
Kosz
usunięte strony czekają; przywracasz je albo usuwasz na dobre
Razem
obecność i wspólna edycja stron, pole po polu
Zgoda
baner cookie i dziennik zgód z hashowanym IP
Usunięcie i eksport
jedno wywołanie anonimizuje osobę; eksport z panelu albo z CLI
Logowanie
OpenID Connect per workspace, albo lokalne hasło
Limity żądań
jeden kubełek na rodzinę tras, limity w nagłówkach odpowiedzi

Elementy dookoła.

Dwa opublikowane pakiety, CLI, serwer MCP i stack do self-hostingu.

@osprey/client
typowane SDK, renderer bloków React, menedżer zgód
@osprey/astro
loader treści, head SEO, synchronizacja tłumaczeń
CLI
setup, init, dev, build, generate-types, link, export
Serwer MCP
szesnaście narzędzi przez stdio, dla agenta AI, którego już używasz
Self-host
jeden plik compose i kreator pierwszego uruchomienia pod /setup
Asystent AI
tłumaczy braki, uzupełnia SEO, pisze alt; wyłączony, dopóki go nie włączysz

Twoja treść. Twój serwer. Dziś.

Darmowy plan, bez karty. Hostowany w UE, albo na twoich własnych maszynach.