# 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
```toml
[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
```bash
export POSTGRES_URI='postgres://user:password@localhost:5432/cedros_data'
```
No other environment variable is required by default.
## Quick start
```bash
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:
```bash
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
```rust
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
```bash
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:
```bash
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:
```bash
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.
```bash
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](docs/profiles.md).
## Examples
- `examples/generic_blog.rs`
- `examples/cedros_compat_profile.rs`
## Additional docs
- [Schema + migration model](docs/schema.md)
- [Profiles and compatibility mode](docs/profiles.md)