cedros-data 0.1.1

General-purpose Postgres-backed multi-site content and custom data storage
Documentation

cedros-data (server crate)

cedros-data is a single Rust crate for storing one site's content and custom data in PostgreSQL.

The crate is library-first and includes optional embedded HTTP and CLI modes in the same package.

Core guarantees

  • One required env var only: POSTGRES_URI
  • No built-in auth logic in the core data layer
  • Preserve incoming field names exactly as provided
  • JSONB compatibility mode and typed-table mode
  • Idempotent schema operations
  • Roll-forward schema evolution only (no destructive auto-drop)

Install and features

[dependencies]
cedros-data = "0.1"

Feature flags:

  • default: cli, http
  • cli: enables cedros-data binary commands
  • http: enables embedded Axum server
  • cedros-login-profile: optional compatibility profile for delegating HTTP auth/authz to cedros-login

Required environment variable

export POSTGRES_URI='postgres://user:password@localhost:5432/cedros_data'

No other environment variable is required by default.

Quick start

cd server
cargo run -- migrate
cargo run -- serve --bind-addr 127.0.0.1:8080 --allow-unauthenticated

Embedded HTTP now fails closed by default. Use --allow-unauthenticated only for local development, or enable the Cedros compatibility profile for authenticated environments.

To allow cross-origin browser admin clients, repeat --cors-origin for each trusted origin:

cargo run -- serve \
  --bind-addr 127.0.0.1:8080 \
  --allow-unauthenticated \
  --cors-origin http://localhost:3000

serve startup automatically:

  • runs base migrations
  • creates the default deployment record on fresh databases
  • bootstraps default collections and default entries for the active deployment

Rust API

use cedros_data::{CedrosData, RegisterSiteRequest};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let store = CedrosData::from_env().await?;
    store.migrate().await?;

    store.register_site(RegisterSiteRequest {
        display_name: "Docs".into(),
        metadata: serde_json::json!({}),
    }).await?;

    Ok(())
}

Primary API methods:

  • migrate()
  • register_site()
  • register_collection()
  • register_custom_schema()
  • upsert_entry()
  • query_entries()
  • export_site()
  • import_site()
  • verify_contract()
  • bootstrap_defaults()

Base schema and data model

Base migration creates:

  • site
  • collections
  • entries
  • collection_contracts
  • custom_schema_state
  • custom_schema_migrations

The active deployment has:

  • a row in site
  • a dedicated PostgreSQL schema for typed tables and custom schema objects
  • default JSONB collections:
    • pages
    • navigation
    • site_settings

Default seeded pages:

  • home
  • about
  • contact
  • docs
  • blog
  • privacy-policy
  • terms-of-service
  • not-found

Additional seeded entries:

  • navigation/main
  • site_settings/global

Singleton guarantee:

  • cedros-data stores site metadata in the singleton site table
  • runtime code always addresses the installation-scoped row with id = 1

Storage modes

  • jsonb mode:
    • flexible ingestion into shared entries table
    • preserves field names exactly
  • typed mode:
    • stores rows in deployment-specific typed tables
    • keeps JSON payload for compatibility and export/import workflows

Custom schema registration

register_custom_schema supports deployment-scoped registration of:

  • custom enum/composite types
  • custom tables and columns
  • indexes
  • unique constraints
  • foreign keys

Behavior:

  • validates schema diff before apply
  • reports additive vs breaking changes
  • applies additive roll-forward changes only
  • does not auto-drop existing objects
  • stores versioned state and generated migration statements

CLI commands

cargo run -- migrate
cargo run -- register-site --display-name "Docs"
cargo run -- register-collection --collection-name pages --mode jsonb
cargo run -- register-custom-schema --schema-file ./schema.json
cargo run -- upsert-entry --collection-name pages --entry-key home --payload-file ./home.json
cargo run -- query-entries --collection-name pages --limit 100 --offset 0
cargo run -- verify-contract --collection-name pages --samples-file ./samples.json
cargo run -- export-site --out ./docs-export.json
cargo run -- import-site --input ./docs-export.json --overwrite-contracts

verify-contract behavior:

  • reports additive and breaking changes
  • exits non-zero only on breaking changes

Embedded HTTP API

Run HTTP mode:

cargo run -- serve --bind-addr 127.0.0.1:8080

If you are not enabling the Cedros compatibility profile, add --allow-unauthenticated for local-only usage:

cargo run -- serve --bind-addr 127.0.0.1:8080 --allow-unauthenticated

CORS behavior:

  • same-origin requests remain unchanged by default
  • cross-origin browser clients require one or more explicit --cors-origin values
  • allowed methods are limited to GET, POST, PUT, and preflight OPTIONS
  • allowed headers cover the shipped admin client request shape: Authorization, Content-Type, Accept, and x-cedros-org-id

Core endpoints:

  • POST /migrate
  • POST /site
  • POST /collections
  • POST /custom-schema
  • POST /entries/upsert
  • POST /entries/query
  • GET /site/export
  • POST /import
  • POST /contract/verify

Admin endpoints:

  • GET /admin/default-pages
  • POST /admin/bootstrap
  • GET /admin/collections
  • POST /admin/collections
  • GET /admin/pages
  • PUT /admin/pages/{page_key}

Optional Cedros compatibility profile

Core cedros-data remains auth-agnostic.
The Cedros compatibility profile is opt-in and only affects HTTP mode.

cargo run --features cedros-login-profile -- serve \
  --cedros-login-profile \
  --cedros-login-verify-url http://localhost:3030/v1/auth/verify

In profile mode:

  • derives the permissions endpoint from the configured verify URL
  • authenticates and authorizes each request through the cedros-login permissions endpoint
  • uses a shared HTTP client with a 2s connect timeout and 5s total request timeout
  • resolves org scope from x-cedros-org-id header
  • enforces route-level data:* permissions before data operations
  • fails closed when org scope cannot be resolved
  • surfaces cedros-login timeouts/rate limits as gateway-style availability errors

For full route/permission details see docs/profiles.md.

Examples

  • examples/generic_blog.rs
  • examples/cedros_compat_profile.rs

Additional docs