O esquema em código. O conteúdo por HTTP.

Define coleções em TypeScript, edita-as no admin, lê-as via REST, GraphQL ou o loader Astro. Alojado na UE, ou nos teus próprios servidores.

O admin do Osprey a editar uma página publicada no próprio sítio: a página ao vivo no centro com catorze campos editáveis contornados, a lista de campos à esquerda, o seletor de língua e o botão Publicar na barra. O admin do Osprey a editar uma página publicada no próprio sítio: a página ao vivo no centro com catorze campos editáveis contornados, a lista de campos à esquerda, o seletor de língua e o botão Publicar na barra.
O admin, a editar uma página ao vivo. Uma captura, não um mockup. O admin existe em inglês e italiano, por isso estas capturas são o conjunto inglês.

Quatro coisas que podes verificar.

  • O esquema Catorze tipos de campo Texto, textarea, rich text, número, booleano, data e hora, slug, select, relação, media, grupo, array, JSON, blocos. Todos exportados pelo pacote core.
  • A leitura pública Sem chave, 404 por defeito Uma coleção lê-se sem chave só quando a sua regra de acesso admite um chamador anónimo. Tudo o resto responde 404, nunca 403.
  • As línguas Dez línguas de conteúdo Campos localizados, uma matriz de cobertura por página e língua, e as falhas num CSV.
  • As chaves Com hash, mostradas uma vez As chaves API são guardadas como hash HMAC com pepper. Vês a chave ao criá-la; o admin guarda os últimos quatro caracteres.
Cada funcionalidade, em detalhe →

De um ficheiro TypeScript a uma página na web.

Faz scroll. O mesmo conteúdo, em cada uma das suas quatro paragens.

  1. 01 · Esquema

    Defines a coleção em TypeScript.

    Slug, campos, regras de acesso. Vive no teu repositório e passa por revisão como qualquer outro código.

    content/blog-post.tsTS
    import { defineCollection, fields } from '@osprey/core'
    
    export const blogPost = defineCollection({
      slug: 'blog-post',
      access: { read: () => true },
      fields: {
        slug:        fields.slug({ from: 'title' }),
        locale:      fields.text({ required: true }),
        title:       fields.text({ required: true }),
        excerpt:     fields.textarea(),
        body:        fields.richText({ required: true }),
        publishedAt: fields.datetime(),
      },
    })
  2. 02 · Admin

    O admin lê o esquema e desenha o formulário.

    Campos obrigatórios, seletor de língua, corpo em rich text. Nada se configura duas vezes.

  3. 03 · API

    As entradas publicadas saem em JSON.

    Um GET, sem chave, com SEO, canonical e hreflang já fundidos em cada entrada.

    entriesHTTP
    GET /api/v1/collections/blog-post/entries?locale=en
    Host: cms.altovar.net
    
    200 OK
    { "data": [ {
        "id": "fdoc_16d9i3ef",
        "data":       { "title": "EU-first content infrastructure", … },
        "seo":        { "metaTitle": "EU-first content infrastructure", … },
        "canonical":  "https://…/en/eu-first-content-infrastructure",
        "alternates": { "en": …, "x-default": … }
      } ],
      "pagination": { "page": 1, "limit": 20, "total": 3 } }
  4. 04 · Site

    O teu frontend renderiza-as.

    O loader Astro vai buscar as entradas no build. O blog abaixo é construído exatamente assim, a partir deste CMS.

    Abrir o blog ao vivo →
    src/content.config.tsASTRO
    import { defineCollection } from 'astro:content'
    import { ospreyLoader } from '@osprey/astro'
    
    const blog = defineCollection({
      loader: ospreyLoader({
        collection: 'blog-post',
        baseUrl:    'https://cms.altovar.net',
        tenantId:   'altovar',
      }),
    })

O admin, no teu tema e na tua língua.

Claro ou escuro, inglês ou italiano. Cada captura deste site segue o tema que escolhes no cabeçalho: é o mesmo admin, fotografado duas vezes.

O teu conteúdo. O teu servidor. Hoje.

Plano gratuito, sem cartão. Alojado na UE, ou nas tuas próprias máquinas.