Tutto quello che fa, in una pagina.
Verificato nel codice che lo esegue, il 2 settembre 2026. Niente qui è pianificato o in arrivo.
Lo schema è il form.
Quello che scrivi a sinistra è quello che gli editor trovano a destra.
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()
- Flag, non schermate
- required e localized sono due booleani sul campo.
- Slug dal titolo
- fields.slug({ from: 'title' }) si compila da solo; select porta opzioni fisse.
- Anche dall'admin
- Le collection personalizzate si creano dall'admin e vivono nel database.
Un contenuto, quattro modi di leggerlo.
Scegli quello che il tuo stack già parla.
Le voci pubbliche non chiedono chiave. I documenti di back-office vogliono una chiave API o un 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' Un client tipizzato con la stessa busta: data e 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 }) Solo query, via POST. GraphiQL è disponibile in sviluppo.
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 }
}
} Le voci finiscono nelle content collection di Astro al build. Nessuna chiave sull'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>
))} Pubblichi qui, compare là.
Le bozze restano private. Una voce pubblicata arriva all'endpoint pubblico entro un minuto, e un webhook può ricostruire il sito.
- Tre stati
- draft, published, archived. Le pagine aggiungono revisione, approvazione e programmazione.
- Webhook firmato
- HMAC-SHA256 sul corpo in x-osprey-signature. Nove eventi, segreto cifrato a riposo.
- Header di cache
- Le letture pubbliche portano max-age=60 con stale-while-revalidate, pronte per qualsiasi cache davanti.
Dieci lingue, una matrice.
Ogni campo localizzato, ogni lingua, contati.
- Lingue di contenuto
- en, it, es, de, fr, nl, pl, sv, pt, ro, impostate per workspace.
- Admin
- Inglese e italiano, si cambiano dalla barra in alto.
- Copertura
- Una matrice per pagina e lingua, e le stringhe mancanti in un CSV.
- Distribuzione
- Un parametro di query sceglie la lingua; gli alternate hreflang viaggiano con ogni voce.
Il tuo dominio, in quattro passi.
Oggi via API. La pagina nelle impostazioni è in arrivo, e questa pagina lo dice.
- Rivendica Fai POST dell'host all'endpoint dei domini. Resta in attesa.
- Dimostra Aggiungi il record TXT _osprey-verify.<host> con il token ricevuto.
- Verifica Fai di nuovo POST con verify: true. L'host passa al workspace.
- Punta CNAME verso la piattaforma. Il certificato viene emesso alla prima richiesta.
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=…" } } I domini personalizzati dipendono dal piano o dall'add-on di hosting.
Un controllo che mostra il lavoro.
Ogni riga qui sotto è una rotta e una schermata, non una roadmap.
- Ruoli
- admin, editor, author, contributor, viewer
- Chiavi API
- hash, mostrate una volta, flag di sola lettura, scadenza
- Registro audit
- chi, cosa, quando e da dove, per ogni cambio di stato
- Revisioni
- storia delle pagine con diff e ripristino
- Cestino
- le pagine eliminate aspettano; le ripristini o le cancelli per sempre
- Insieme
- presenza e modifica condivisa delle pagine, campo per campo
- Consenso
- banner cookie e registro dei consensi con IP in hash
- Cancellazione ed export
- una chiamata oscura un interessato; export dall'admin o dalla CLI
- Accesso
- OpenID Connect per workspace, oppure password locale
- Limiti di traffico
- un bucket per famiglia di rotte, limiti negli header di risposta
I pezzi intorno.
Due package pubblicati, una CLI, un server MCP e uno stack self-host.
- @osprey/client
- SDK tipizzato, renderer di blocchi React, gestore del consenso
- @osprey/astro
- loader di contenuti, head SEO, sync delle traduzioni
- CLI
- setup, init, dev, build, generate-types, link, export
- Server MCP
- sedici strumenti via stdio, per l'agente AI che usi già
- Self-host
- un file compose e una procedura guidata al primo avvio su /setup
- Assistente AI
- traduce i buchi, compila la SEO, scrive gli alt; spento finché non lo accendi
Il tuo contenuto. Il tuo server. Oggi.
Piano gratuito, senza carta. Ospitato nell'UE, o sulle tue macchine.