Tudo o que faz, numa página.
Verificado no código que o executa, a 2 de setembro de 2026. Nada aqui está planeado ou a chegar.
O admin existe em inglês e italiano, por isso estas capturas são o conjunto inglês.
O esquema é o formulário.
O que escreves à esquerda é o que os editores recebem à direita.
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, não ecrãs
- required e localized são dois booleanos no campo.
- Slug a partir do título
- fields.slug({ from: 'title' }) preenche-se sozinho; select traz opções fixas.
- Também a partir do admin
- As coleções personalizadas criam-se no admin e ficam na base de dados.
Um conteúdo, quatro formas de o ler.
Escolhe a que a tua stack já fala.
As entradas públicas não pedem chave. Os documentos de back-office pedem uma chave API ou um 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' Um cliente tipado com o mesmo envelope: 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 }) Só queries, por POST. O GraphiQL está disponível em desenvolvimento.
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 }
}
} As entradas chegam às content collections do Astro no build. Nenhuma chave no 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>
))} Publicas aqui, aparece ali.
Os rascunhos ficam privados. Uma entrada publicada chega ao endpoint público num minuto, e um webhook pode reconstruir o site.
- Três estados
- draft, published, archived. As páginas acrescentam revisão, aprovação e agendamento.
- Webhook assinado
- HMAC-SHA256 sobre o corpo em x-osprey-signature. Nove eventos, segredo cifrado em repouso.
- Cabeçalhos de cache
- As leituras públicas trazem max-age=60 com stale-while-revalidate, prontas para qualquer cache à frente.
Dez línguas, uma matriz.
Cada campo localizado, cada língua, contados.
- Línguas de conteúdo
- en, it, es, de, fr, nl, pl, sv, pt, ro, definidas por workspace.
- Admin
- Inglês e italiano, trocados a partir da barra superior.
- Cobertura
- Uma matriz por página e língua, e as strings em falta num CSV.
- Entrega
- Um parâmetro de query escolhe a língua; os alternates hreflang viajam com cada entrada.
O teu domínio, em quatro passos.
Hoje pela API. A página de definições está a caminho, e esta página di-lo.
- Reivindica Faz POST do host para o endpoint de domínios. Fica pendente.
- Prova Acrescenta o registo TXT _osprey-verify.<host> com o token recebido.
- Verifica Faz POST outra vez com verify: true. O host passa para o workspace.
- Aponta CNAME para a plataforma. O certificado é emitido no primeiro pedido.
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=…" } } Os domínios personalizados dependem do plano ou do add-on de alojamento.
Um controlo que mostra o seu trabalho.
Cada linha abaixo é uma rota e um ecrã, não um roadmap.
- Papéis
- admin, editor, author, contributor, viewer
- Chaves API
- com hash, mostradas uma vez, flag só de leitura, expiração
- Registo de auditoria
- quem, o quê, quando e de onde, em cada mudança de estado
- Revisões
- histórico de páginas com diff e restauro
- Reciclagem
- as páginas apagadas esperam; restauras ou apagas de vez
- Em conjunto
- presença e edição partilhada de páginas, campo a campo
- Consentimento
- banner de cookies e registo de consentimentos com IP em hash
- Apagamento e exportação
- uma chamada anonimiza um titular; exportação a partir do admin ou da CLI
- Acesso
- OpenID Connect por workspace, ou uma palavra-passe local
- Limites de pedidos
- um bucket por família de rotas, limites nos cabeçalhos de resposta
As peças à volta.
Dois pacotes publicados, uma CLI, um servidor MCP e uma stack self-host.
- @osprey/client
- SDK tipado, renderizador de blocos React, gestor de consentimento
- @osprey/astro
- loader de conteúdo, head SEO, sincronização de traduções
- CLI
- setup, init, dev, build, generate-types, link, export
- Servidor MCP
- dezasseis ferramentas por stdio, para o agente de IA que já usas
- Self-host
- um ficheiro compose e um assistente de primeiro arranque em /setup
- Assistente de IA
- traduz falhas, preenche o SEO, escreve os alt; desligado até o ligares
O teu conteúdo. O teu servidor. Hoje.
Plano gratuito, sem cartão. Alojado na UE, ou nas tuas próprias máquinas.