Het schema in code. De inhoud via HTTP.

Definieer collecties in TypeScript, bewerk ze in de admin, lees ze via REST, GraphQL of de Astro-loader. Gehost in de EU, of op je eigen servers.

De Osprey-admin die een gepubliceerde pagina ter plekke bewerkt: de live pagina in het midden met veertien omlijnde bewerkbare velden, de veldenlijst links, de taalkeuze en de knop Publiceren in de balk. De Osprey-admin die een gepubliceerde pagina ter plekke bewerkt: de live pagina in het midden met veertien omlijnde bewerkbare velden, de veldenlijst links, de taalkeuze en de knop Publiceren in de balk.
De admin, tijdens het bewerken van een live pagina. Een screenshot, geen mockup. De admin bestaat in het Engels en Italiaans, dus deze opnames zijn de Engelse set.

Vier dingen die je kunt nakijken.

  • Het schema Veertien veldtypen Tekst, textarea, rich text, getal, boolean, datum en tijd, slug, select, relatie, media, groep, array, JSON, blokken. Allemaal geëxporteerd door het core-pakket.
  • Het publieke lezen Zonder sleutel, standaard 404 Een collectie is alleen zonder sleutel leesbaar als haar toegangsregel een anonieme aanroeper toelaat. Al het andere antwoordt 404, nooit 403.
  • De talen Tien inhoudstalen Gelokaliseerde velden, een dekkingsmatrix per pagina en taal, en de gaten als CSV.
  • De sleutels Gehasht, één keer getoond API-sleutels worden opgeslagen als HMAC-hash met pepper. Je ziet de sleutel bij het aanmaken; de admin bewaart de laatste vier tekens.
Elke functie, in detail →

Van een TypeScript-bestand naar een pagina op het web.

Scroll. Dezelfde inhoud, bij elk van zijn vier haltes.

  1. 01 · Schema

    Je definieert de collectie in TypeScript.

    Slug, velden, toegangsregels. Het leeft in je repository en gaat door review als elke andere code.

    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

    De admin leest het schema en tekent het formulier.

    Verplichte velden, de taalkeuze, de rich-text body. Niets wordt twee keer ingesteld.

  3. 03 · API

    Gepubliceerde items komen eruit als JSON.

    Eén GET, zonder sleutel, met SEO, canonical en hreflang al samengevoegd in elk item.

    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

    Je frontend rendert ze.

    De Astro-loader haalt de items op tijdens de build. De blog hieronder is precies zo gebouwd, vanuit dit CMS.

    Open de live blog →
    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',
      }),
    })

De admin, in jouw thema en jouw taal.

Licht of donker, Engels of Italiaans. Elke opname op deze site volgt het thema dat je bovenaan kiest: het is dezelfde admin, twee keer gefotografeerd.

Jouw inhoud. Jouw server. Vandaag.

Gratis plan, geen kaart. Gehost in de EU, of op je eigen machines.