# Ridu > Go-first content management with executable configuration, generated contracts, and one embedded runtime. Release documentation version: 0.1.1 - [Documentation map](https://riducms.com/docs/) - [Guides map](https://riducms.com/guides/) - [Complete documentation search](https://riducms.com/search/) - [Complete LLM documentation](https://riducms.com/llms-full.txt) - [Versioned complete documentation](https://riducms.com/v/0.1.1/llms-full.txt) ## Documentation - [Introduction](https://riducms.com/docs/getting-started/): Learn what Ridu provides, how an application is configured, and where to start. - [Quickstart](https://riducms.com/docs/quickstart/): Create a Ridu project with SQLite or PostgreSQL, save your first document, and read it with the generated TypeScript SDK. - [Capability status](https://riducms.com/docs/status/): See which Ridu capabilities are available, limited, experimental, or planned in the current release. - [Installation](https://riducms.com/docs/installation/): Install the CLI, choose project options, connect existing services, and recover an interrupted setup. - [Core concepts](https://riducms.com/docs/core-concepts/): See how Go configuration becomes database schema, APIs, generated types, and the admin. - [Go for TypeScript developers](https://riducms.com/docs/go-for-typescript/): Read and extend a Ridu application without having to become a Go expert first. - [Configuration](https://riducms.com/docs/configuration/): Compose the application, admin, localization, collections, globals, plugins, and runtime services. - [Collections and globals](https://riducms.com/docs/collections/): Define repeatable documents and singleton configuration, then add only the capabilities each resource needs. - [Fields](https://riducms.com/docs/fields/): Choose a field by the value you need to store and the authoring control you want. - [Conditional fields](https://riducms.com/docs/fields/conditional-fields/): Show an admin field from typed sibling or document values without confusing presentation with validation or access control. - [Text field](https://riducms.com/docs/fields/text/): Store a short string with typed length, uniqueness, localization, and admin options. - [Textarea field](https://riducms.com/docs/fields/textarea/): Store multi-line plain text as a string. - [Email field](https://riducms.com/docs/fields/email/): Store and validate an email-shaped string with a purpose-built admin control. - [Code field](https://riducms.com/docs/fields/code/): Store source text and give authors a syntax-aware editor without executing submitted code. - [Date field](https://riducms.com/docs/fields/date/): Store a day, time, or RFC 3339 timestamp with an explicit picker contract. - [Relationships, joins, and population](https://riducms.com/docs/relationships/): Reference one or many documents, model polymorphic targets, expose inverse joins, and populate safely. - [Number field](https://riducms.com/docs/fields/number/): Store a finite number with minimum, maximum, step, default, and query constraints. - [Checkbox field](https://riducms.com/docs/fields/checkbox/): Store an explicit boolean and present it as an authoring toggle. - [Select field](https://riducms.com/docs/fields/select/): Define a typed single or multiple choice with stable stored values and translated author labels. - [Content localization](https://riducms.com/docs/localization/): Store locale-specific values, configure fallback chains, query exact or all locales, and copy translations safely. - [Radio field](https://riducms.com/docs/fields/radio/): Show every singular configured choice while storing the same finite string contract as Select. - [Access control](https://riducms.com/docs/access-control/): Allow, deny, or filter operations with transaction-scoped Go rules. - [Slug field](https://riducms.com/docs/fields/slug/): Generate a required, unique URL segment from another string field while preserving author overrides. - [JSON field](https://riducms.com/docs/fields/json/): Store JSON-compatible data when the application cannot model a stable nested shape. - [Point field](https://riducms.com/docs/fields/point/): Store a portable longitude/latitude coordinate pair with bounded validation. - [Group field](https://riducms.com/docs/fields/group/): Model one nested object with child fields, generated types, and dotted query paths. - [Array field](https://riducms.com/docs/fields/array/): Model an ordered list of rows that share one child-field shape. - [Blocks field](https://riducms.com/docs/fields/blocks/): Author an ordered, discriminated list of different content shapes. - [Tabs field](https://riducms.com/docs/fields/tabs/): Organise document editing into named stored objects or presentation-only sections. - [Relationship field](https://riducms.com/docs/fields/relationship/): Reference one or many documents, including polymorphic targets, with access-aware pickers and population. - [Upload field](https://riducms.com/docs/fields/upload/): Reference documents in one upload-enabled collection with access-aware media selection. - [Row field](https://riducms.com/docs/fields/row/): Arrange direct child controls on the admin grid without changing document paths. - [Collapsible field](https://riducms.com/docs/fields/collapsible/): Group advanced controls behind an accessible disclosure without nesting their stored values. - [Hooks](https://riducms.com/docs/hooks/): Normalize input, derive values, coordinate nested work, and react after commit. - [UI field](https://riducms.com/docs/fields/ui/): Place guidance or a paired custom component in the editor without accepting or storing a document value. - [Join field](https://riducms.com/docs/fields/join/): Expose an access-controlled inverse view of documents that point to the current collection. - [Virtual field](https://riducms.com/docs/fields/virtual/): Return a typed value computed by trusted Go code without accepting or storing it. - [Plugin field](https://riducms.com/docs/fields/plugin/): Use a compiled plugin’s storage, validation, generated type, and paired admin control. - [Data access overview](https://riducms.com/docs/data-access/): Choose between the local Go API, REST, TypeScript SDK, GraphQL, and admin for a task. - [Local Go API](https://riducms.com/docs/local-api/): Read and mutate collections and globals through the full Ridu operation engine without an HTTP round trip. - [Querying data](https://riducms.com/docs/querying/): Filter, sort, paginate, select, populate, and localize collection reads through one finite query language. - [REST API](https://riducms.com/docs/rest-api/): Call Ridu’s generated HTTP contract from any language or Fetch-compatible runtime. - [Custom endpoints](https://riducms.com/docs/custom-endpoints/): Add root, collection, and global HTTP handlers with generated OpenAPI metadata. - [CORS](https://riducms.com/docs/cors/): Allow cross-origin browser clients without weakening Ridu’s HTTP boundary. - [Authentication](https://riducms.com/docs/authentication/): Configure identities, safe account provisioning, cookie sessions, password recovery, API keys, and custom request strategies. - [Editorial workflows](https://riducms.com/docs/editorial-workflows/): Choose the task guide for duplication, bulk and trash actions, document locks, preferences, drafts, versions, and scheduling. - [Model Context Protocol](https://riducms.com/docs/mcp/): Give authenticated MCP clients read-only access to selected Ridu content. - [Drafts and versions](https://riducms.com/docs/drafts-and-versions/): Keep bounded revision history, control draft visibility, restore snapshots, publish changes, and schedule collection changes. - [Browse and organize content](https://riducms.com/docs/browsing-content/): Configure useful list titles and columns, then search, filter, sort, select, and navigate collection content. - [Saved views, folders, and hierarchy](https://riducms.com/docs/saved-views-and-hierarchy/): Persist an author’s list workspace and configure folder filters or parent-child organization. - [Create and edit documents](https://riducms.com/docs/editing-documents/): Understand the schema-driven editor, validation, relationships, dirty state, revisions, and save outcomes. - [Bulk actions and trash](https://riducms.com/docs/bulk-and-trash/): Change a reviewed set atomically, recover soft-deleted documents, and permanently delete content. - [Coordinate editors with document locks](https://riducms.com/docs/document-locks/): Enable expiring edit leases, control takeover access, and keep optimistic revisions as the final write fence. - [Uploads and media](https://riducms.com/docs/uploads/): Add a media library to a Ridu project, upload files through the admin or SDK, and reference them from content. - [Localize the admin and authoring workflow](https://riducms.com/docs/admin-localization/): Configure interface catalogs, translated labels, RTL, timezones, and a separate content-locale workflow. - [Durable tasks](https://riducms.com/docs/tasks/): Run typed Go work with database-backed leases, retries, cancellation, and bounded retention. - [Generated contracts](https://riducms.com/docs/generated-contracts/): Generate and use Ridu’s manifest, OpenAPI schema, Go models, TypeScript client, and admin registry. - [The Ridu admin](https://riducms.com/docs/admin/): Browse, create, edit, localize, publish, and extend content in Ridu’s embedded admin. - [TypeScript SDK](https://riducms.com/docs/typescript-sdk/): Use Ridu’s generated, Fetch-based client from browsers, server frameworks, and tooling. - [Ridu CLI](https://riducms.com/docs/cli/): Create projects and plugins, generate contracts, run development, manage database migrations, and build releases. - [Testing](https://riducms.com/docs/testing/): Test Ridu configuration, generated contracts, database behavior, HTTP clients, and authoring flows. - [Troubleshooting](https://riducms.com/docs/troubleshooting/): Diagnose common Ridu setup, generation, migration, SDK, auth, and runtime failures by symptom. - [Adapters](https://riducms.com/docs/adapters/): Connect Ridu to databases and object-storage providers without changing CMS behavior. - [Plugins](https://riducms.com/docs/plugins/): Install, build, version, migrate, and test trusted Ridu extensions. - [MongoDB](https://riducms.com/docs/mongodb/): Create or configure a Ridu project for the supported MongoDB replica-set deployment. - [PostgreSQL](https://riducms.com/docs/postgres/): Configure, operate, and test Ridu’s official transactional store. - [SQLite](https://riducms.com/docs/sqlite/): Run Ridu with its official embedded store inside the supported single-host operating envelope. - [Rich text](https://riducms.com/docs/rich-text/): Author portable Lexical documents with bounded validation, embedded references, and safe server-side HTML rendering. - [SEO](https://riducms.com/docs/seo/): Add localized search metadata, draft-aware generators, upload selection, and a live result preview to collections and globals. - [Form Builder](https://riducms.com/docs/form-builder/): Let editors assemble reusable forms, validate and persist submissions, send templated emails, accept uploads, and connect payment callbacks. - [GraphQL](https://riducms.com/docs/graphql/): Add an optional manifest-derived GraphQL endpoint with typed resources, shared authorization, and bounded execution. - [Object storage](https://riducms.com/docs/storage/): Configure local, S3-compatible, or custom storage safely for upload bytes. - [Production](https://riducms.com/docs/production/): Build, configure, deploy, observe, drain, migrate, and recover a Ridu application. - [Migrations](https://riducms.com/docs/migrations/): Create, review, verify, and safely apply database migrations. - [Performance and footprint](https://riducms.com/docs/performance/): Review Ridu’s current runtime benchmark and measure a representative application. - [Prevent abuse](https://riducms.com/docs/preventing-abuse/): Protect a public Ridu API with access rules, authentication limits, request bounds, safe uploads, and edge rate limiting. - [Security model](https://riducms.com/docs/security/): Secure HTTP, authentication, uploads, databases, plugins, and operational access. - [Releases and compatibility](https://riducms.com/docs/releases/): Keep Ridu packages aligned, understand supported environments, and upgrade an application safely. ## Guides - [Move from Payload](https://riducms.com/guides/from-payload/): Translate a Payload project into Ridu config, normalized content, and a rehearsed production cutover. - [Coming from PocketBase](https://riducms.com/guides/from-pocketbase/): Compare Ridu with PocketBase and understand what an evaluation or migration involves. - [Build a custom field](https://riducms.com/guides/custom-fields/): Ship one exact value contract across Go, OpenAPI, TypeScript, and the Svelte admin. - [Add live preview](https://riducms.com/guides/live-preview/): Render access-checked drafts and receive unsaved form updates in a framework-agnostic frontend. ## API reference - [ridu](https://riducms.com/reference/ridu/): The ergonomic application facade for config, startup, and access decisions. - [core](https://riducms.com/reference/core/): Application contracts and the operation runtime behind the root facade. - [field](https://riducms.com/reference/field/): Type-safe field builders and presentation options. Incompatible options fail at Go compile time; semantic issues are reported by ridu.Resolve. - [query](https://riducms.com/reference/query/): Immutable filters, validated document paths, stable sorting, and relationship population controls. - [schema](https://riducms.com/reference/schema/): The immutable generated schema manifest, stable identifiers, and advanced generator/plugin contracts. - [store](https://riducms.com/reference/store/): Advanced adapter contracts for transactional documents, auth, preferences, locks, publishing, uploads, and durable tasks. - [storage](https://riducms.com/reference/storage/): Object-storage contracts used by upload collections. Implement this package only when the official local and S3 backends do not fit. - [migration](https://riducms.com/reference/migration/): Advanced, database-independent vocabulary for immutable and reviewable migration artifacts. - [migration/payload](https://riducms.com/reference/migration-payload/): Optional public import boundary for normalized Payload CMS exports; source-specific database extraction is deliberately out of scope. - [protocol (Go)](https://riducms.com/reference/go-protocol/): Advanced stable REST wire envelopes shared by the HTTP runtime, generators, SDK, admin, and transport tests. - [plugintest](https://riducms.com/reference/plugintest/): Stable backend conformance tests for third-party compiled Ridu plugins. - [postgres](https://riducms.com/reference/postgres/): The official PostgreSQL store, safe development schema sync, and immutable production migration runner. - [sqlite](https://riducms.com/reference/sqlite/): The official embedded SQLite store and its immutable, reversible migration lifecycle. - [mongodb](https://riducms.com/reference/mongodb/): The official replica-set MongoDB store, additive development index synchronization, and immutable forward-only migration lifecycle. - [graphql](https://riducms.com/reference/graphql/): An optional manifest-generated GraphQL transport over Ridu’s operation engine; importing it is what links the GraphQL runtime. - [mcp](https://riducms.com/reference/mcp/): An optional authenticated, read-only Model Context Protocol transport over explicitly selected Ridu content. - [richtext](https://riducms.com/reference/richtext/): A paired, versioned Lexical field with authoring for portable content, references, uploads, and blocks. - [seo](https://riducms.com/reference/seo/): Payload-familiar search metadata fields, authenticated draft-aware generators, and a paired Svelte admin. - [formbuilder](https://riducms.com/reference/formbuilder/): Payload-familiar dynamic form definitions, server-validated submissions, notifications, uploads, and payment callbacks. - [storage/local](https://riducms.com/reference/storage-local/): Durable filesystem object storage for development and single-host deployments. - [storage/s3](https://riducms.com/reference/storage-s3/): Dependency-free S3-compatible object storage with SigV4 requests and signed private reads. - [conformance](https://riducms.com/reference/store-conformance/): Reusable behavioral qualification suites for Ridu store adapters. - [@riducms/sdk](https://riducms.com/reference/sdk/): The generated-contract-aware Fetch client for browser and server applications. - [@riducms/protocol](https://riducms.com/reference/protocol/): Generated wire contracts and runtime guards shared by the SDK and admin. - [@riducms/plugin](https://riducms.com/reference/plugin/): Static Svelte 5 extension contracts for generated admins and plugin packages. - [@riducms/build](https://riducms.com/reference/build/): Build-time Vite, Svelte 5, and UnoCSS conventions for generated admins and plugin libraries. - [@riducms/ui](https://riducms.com/reference/ui/): Shared Svelte 5 interaction primitives and class composition for the admin and static plugins. - [@riducms/plugin-richtext](https://riducms.com/reference/plugin-richtext/): The statically bundled Svelte/Lexical half of the rich-text plugin. - [@riducms/plugin-seo](https://riducms.com/reference/plugin-seo/): The statically bundled Svelte authoring half of the official SEO plugin. - [@riducms/plugin-form-builder](https://riducms.com/reference/plugin-form-builder/): Framework-neutral public form helpers plus a separately exported static admin pairing. - [@riducms/admin](https://riducms.com/reference/admin/): The framework-owned Svelte admin mount contract and public admin client surface. - [@riducms/translations](https://riducms.com/reference/translations/): Typed admin translations, language negotiation, plurals, and Intl formatting. - [@riducms/cli/run](https://riducms.com/reference/cli-launcher/): Programmatic Node launcher for invoking the platform-specific Ridu CLI binary. - [ridu CLI](https://riducms.com/reference/cli/): The implemented project lifecycle: scaffolding, generation, migrations, development, checks, builds, diagnostics, and static plugin management. # Introduction Canonical URL: https://riducms.com/docs/getting-started/ ## What is Ridu? {#what-is-ridu} Ridu is a Go content-management framework with a built-in Svelte 5 admin. You define collections, fields, access rules, hooks, and plugins in executable Go. Ridu resolves that config into a schema manifest and derives the database plan, REST contract, TypeScript types, Fetch client, and authoring interface from it. Local Go calls, REST, the SDK, admin, tasks, and plugin transports use the same authorization, validation, hooks, transactions, population, and redaction. The built admin is embedded in the Go server, so Node.js and package managers are build-time tools. Choose PostgreSQL for networked, multi-host deployments or SQLite for a local file on one host. MongoDB requires a transaction-capable replica set and has a narrower [supported production profile](https://riducms.com/docs/mongodb/). Uploads can use local storage or S3-compatible object storage. Check [Capability status](https://riducms.com/docs/status/) for complete, limited, experimental, and planned behavior. ## The authoring model {#authoring-model} A collection is a typed Go config value: ```go title="content/posts.go" var Posts = ridu.Collection{ Slug: "posts", Fields: []field.Definition{ field.Text("title", field.Required()), field.Select("status", field.OneOf("draft", "published"), field.Default("draft"), ), }, } ``` Go checks names and option types at compile time; Ridu then validates cross-field and cross-collection rules while resolving the manifest. [Ridu for TypeScript developers](https://riducms.com/docs/go-for-typescript/) explains packages, struct literals, slices, functions, `nil`, errors, and contexts through familiar TypeScript ideas. Frontend developers consume the generated application module and can remain in TypeScript: ```ts title="src/posts.ts" import { createClient } from '~/generated/ridu.generated'; const client = createClient({ baseURL: 'https://cms.example.com' }); const page = await client.list('posts', { where: { status: { equals: 'published' } }, sort: ['-publishedAt'], limit: 12 }); for (const post of page.docs) { console.log(post.title); } ``` The generated module provides collection and field types through the Fetch SDK. Its methods return `Promise` and throw structured `RiduError` failures. ## Choose your path {#choose-path} ### I build TypeScript frontends {#typescript-path} Read [TypeScript SDK](https://riducms.com/docs/typescript-sdk/) and [Querying data](https://riducms.com/docs/querying/) first. You need Go only when you author the server schema or a compiled backend extension; a frontend consuming an existing Ridu application stays in TypeScript. ### I model content and backend behavior {#builder-path} Follow the [installation guide](https://riducms.com/docs/installation/), then read [Core concepts](https://riducms.com/docs/core-concepts/), [Configuration](https://riducms.com/docs/configuration/), [Fields](https://riducms.com/docs/fields/), [Access control](https://riducms.com/docs/access-control/), and [Hooks](https://riducms.com/docs/hooks/). The [Project structure](https://riducms.com/guides/project-structure/) guide separates files you own from committed generated contracts and disposable build state. ### I am evaluating another CMS {#evaluator-path} Use [Move from Payload](https://riducms.com/guides/from-payload/) for a concept and migration-contract map, or [Ridu for PocketBase users](https://riducms.com/guides/from-pocketbase/) for the code-defined and embedded-store trade-offs. Read [Performance and footprint](https://riducms.com/docs/performance/) for benchmark results and test conditions. ## Current limits {#not-a-compatibility-layer} See [Capability status](https://riducms.com/docs/status/) for available, limited, experimental, and planned features before choosing them for a project. ## Create an application {#create-application} Open the project wizard with your preferred launcher: ```bash title="terminal" package-manager="npm" npm create ridu@latest my-app ``` ```bash title="terminal" package-manager="bun" bun create ridu@latest my-app ``` ```bash title="terminal" package-manager="pnpm" pnpm create ridu@latest my-app ``` ```bash title="terminal" package-manager="yarn" yarn create ridu my-app ``` Choose **Starter** or **Blank**, a database, and optional agent guidance. Review the summary, then run the install and `dev` commands the initializer prints. Omit `my-app` if you prefer to name the directory inside the wizard. Direct Go installation, organization-specific Go module/npm scope flags, non-interactive automation, and recovery are covered in [Installation](https://riducms.com/docs/installation/). The CLI prints the local admin URL. On the first visit, create the initial admin account. [Installation](https://riducms.com/docs/installation/) explains requirements, generated files, and database choices. --- # Quickstart Canonical URL: https://riducms.com/docs/quickstart/ This guide takes you from an empty directory to a running CMS and a typed SDK read. The **Starter** template includes an authenticated `users` collection and a small `posts` collection. You need [Go 1.25 or newer](https://go.dev/doc/install), Node.js 20 or newer, and one package manager: npm, Bun, pnpm, or Yarn. You do not need a global `ridu` command. ## 1. Choose a database and create the project {#choose-a-database} Both paths produce the same Ridu application. Choose **SQLite** when you want the fewest moving parts on one machine. Choose **PostgreSQL** when the database will be a separate service or the application may run on more than one host.

Choose SQLite in the wizard for the shortest path to a local Ridu project. It needs no database service or Docker setup. Development data lives in .ridu/development.sqlite and is created when dev starts.

SQLite is intended for a local file on one host. Before deploying, set an absolute RIDU_SQLITE_PATH and review the SQLite production guidance.

Choose PostgreSQL in the wizard for a networked database that can run independently of the application and support multiple app hosts. The generated project includes a development service on port 54329; dev starts it with Docker or OrbStack.

If you already operate PostgreSQL, set DATABASE_URL and run dev --no-docker. Production connections must use verified TLS; the PostgreSQL guide shows the complete existing-service setup.

Start the initializer with your package manager. The positional `my-app` names the project directory; the wizard asks you to choose the **Starter** template, the database above, and optional coding-agent guidance. The remaining commands install the workspace and start development. ```bash title="terminal" package-manager="npm" npm create ridu@latest my-app cd my-app npm install npm run dev ``` ```bash title="terminal" package-manager="bun" bun create ridu@latest my-app cd my-app bun install bun run dev ``` ```bash title="terminal" package-manager="pnpm" pnpm create ridu@latest my-app cd my-app pnpm install pnpm run dev ``` ```bash title="terminal" package-manager="yarn" yarn create ridu my-app cd my-app yarn install yarn run dev ```
Non-interactive scaffolding and custom package identities
Use flags for non-interactive setup or to set the Go module and npm scope. This example selects SQLite; change `--database sqlite` to `--database postgres` for the PostgreSQL path. ```bash title="terminal" package-manager="npm" npm create ridu@latest -- \ --template starter \ --database sqlite \ --module github.com/acme/content \ --scope @acme \ --no-agent \ content ``` ```bash title="terminal" package-manager="bun" bun create ridu@latest \ --template starter \ --database sqlite \ --module github.com/acme/content \ --scope @acme \ --no-agent \ content ``` ```bash title="terminal" package-manager="pnpm" pnpm create ridu@latest \ --template starter \ --database sqlite \ --module github.com/acme/content \ --scope @acme \ --no-agent \ content ``` ```bash title="terminal" package-manager="yarn" yarn create ridu \ --template starter \ --database sqlite \ --module github.com/acme/content \ --scope @acme \ --no-agent \ content ``` The target directory must not already exist. Replace `--no-agent` with `--agent codex|claude|cursor|all` when automation should install agent guidance. See [Installation](https://riducms.com/docs/installation/#create-project) for every scaffold option and recovery behavior.
## 2. Open the admin {#open-the-admin} Keep the selected tab's `dev` command running. Wait for it to print healthy API and admin URLs, then open `http://localhost:8080/admin`. On an empty database Ridu shows the setup screen instead of a login form. Create the first user with an email address and a password. The setup operation is available only while the configured auth collection is empty. After it succeeds, the same URL shows the login screen. ![The Ridu admin dashboard showing the Users and Posts collections.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/ridu-admin-dashboard.png) ## 3. Create your first post {#create-a-post} Choose **Posts** in the sidebar, select **Create new**, and enter: | Field | Value | | ------ | ----------------- | | Title | `Hello from Ridu` | | Status | `published` | | Author | Your new user | Save the document. The list view should now contain **Hello from Ridu**. ## 4. Read it through the generated SDK {#read-with-the-sdk} Open `generated/ridu.generated.ts`, then create `scripts/read-posts.ts`: ```ts title="scripts/read-posts.ts" import { createClient } from '../generated/ridu.generated'; const baseURL = process.env.RIDU_URL ?? 'http://localhost:8080'; const email = process.env.RIDU_EMAIL; const password = process.env.RIDU_PASSWORD; if (!email || !password) { throw new Error('Set RIDU_EMAIL and RIDU_PASSWORD to the user created in the admin.'); } let sessionCookie = ''; const ridu = createClient({ baseURL, middleware: [ async (request, next) => { const headers = new Headers(request.headers); if (sessionCookie) headers.set('Cookie', sessionCookie); const response = await next(new Request(request, { headers })); const setCookie = response.headers.get('set-cookie'); const match = setCookie?.match(/(?:^|,\s*)(ridu_session=[^;,\s]+)/); const session = match?.[1]; if (session) sessionCookie = session; return response; } ] }); await ridu.login('users', { email, password }); const page = await ridu.list('posts', { where: { status: { equals: 'published' } }, select: { title: true, status: true }, sort: ['-createdAt'] }); console.log(page.docs); ``` Leave the selected tab's `dev` command running and execute the script in a second terminal: ```bash title="terminal" package-manager="npm" RIDU_EMAIL='you@example.com' \ RIDU_PASSWORD='your-password' \ npm exec tsx -- scripts/read-posts.ts ``` ```bash title="terminal" package-manager="bun" RIDU_EMAIL='you@example.com' \ RIDU_PASSWORD='your-password' \ bun scripts/read-posts.ts ``` ```bash title="terminal" package-manager="pnpm" RIDU_EMAIL='you@example.com' \ RIDU_PASSWORD='your-password' \ pnpm exec tsx scripts/read-posts.ts ``` ```bash title="terminal" package-manager="yarn" RIDU_EMAIL='you@example.com' \ RIDU_PASSWORD='your-password' \ yarn tsx scripts/read-posts.ts ``` The output includes the post you just created. The collection slug, filter operators, selected fields, and returned document shape are inferred from the generated contract; mistyping `posts`, `status`, or `published` is a TypeScript error. The middleware keeps the opaque `ridu_session` cookie in memory for this process and forwards it after login. Do not log or persist it. The typed login result does not expose the raw session token. Browser applications need no cookie middleware; call `login` once and the SDK's default `credentials: "include"` sends the `HttpOnly` cookie. Long-running service clients should use an expiring API key rather than a user's password or browser session. ## 5. Change the model {#change-the-model} Add a summary to `content/posts.go`: ```go title="content/posts.go" add={11-15} var Posts = ridu.Collection{ Slug: "posts", Access: ridu.CollectionAccess{ Create: authenticatedOnly, Read: authenticatedOnly, Update: authenticatedOnly, Delete: authenticatedOnly, }, Fields: []field.Definition{ field.Text("title", field.Required()), field.Textarea( "summary", field.MaxLength(240), field.Description("A short introduction used by post cards."), ), field.Select( "status", field.OneOf("draft", "published"), field.Default("draft"), ), field.Relationship("author", field.To("users")), richtext.Field("content"), }, } ``` Save the file while `dev` is running. Ridu regenerates the contracts, applies the additive development change, restarts the server, and refreshes the admin. Reopen the post; the **Summary** control should now be available. Run this before committing: ```bash title="terminal" package-manager="npm" npm run ridu -- doctor npm run ridu -- generate --check npm run ridu -- check ``` ```bash title="terminal" package-manager="bun" bun run ridu -- doctor bun run ridu -- generate --check bun run ridu -- check ``` ```bash title="terminal" package-manager="pnpm" pnpm run ridu doctor pnpm run ridu generate --check pnpm run ridu check ``` ```bash title="terminal" package-manager="yarn" yarn run ridu doctor yarn run ridu generate --check yarn run ridu check ``` Commit `generated/` with your Go config. `.ridu/` remains disposable local state. Create and commit migrations for production schema changes; development sync is not a deployment plan. ## If something does not start {#troubleshooting} Run the `doctor` command from the package-manager tabs above first. If the project-local launcher is not installed yet, repeat the matching `install` command from step 1 and retry. If scaffolding stopped during Go setup, follow the exact recovery commands printed by the CLI. For an occupied database port, either stop the conflicting local service or follow the existing-service command in the [PostgreSQL guide](https://riducms.com/docs/postgres/#existing-project). Next, learn [how a Ridu project is organised](https://riducms.com/guides/project-structure/), choose the right [field](https://riducms.com/docs/fields/), or read the [TypeScript SDK guide](https://riducms.com/docs/typescript-sdk/). See [Installation](https://riducms.com/docs/installation/) for other templates, existing services, and recovery. --- # Capability status Canonical URL: https://riducms.com/docs/status/ Use this page to check whether a feature fits your project before following its setup guide. ## Find a capability {#available} The matrix above links each capability to its setup guide and relevant API. Use the [documentation home](https://riducms.com/docs/) for task-oriented guides and the [API reference](https://riducms.com/reference/) for exported symbols. ## Limited capabilities {#limited} These paths work with explicit constraints: - **Generated projections.** `select` and `populate` are typed inputs, but TypeScript return types remain the collection's complete output type. Sort terms are strings rather than generated path unions. - **Query vocabulary.** There is no `notIn`, full-text search, array all-elements operator, or general geospatial query API. Direct-field distinct values are available through the Local Go API when the selected field has no document-aware read rule; broader aggregation and a public REST distinct route are not. Bulk create and general idempotency keys are absent. - **Localization boundary.** Localized storage, fallback, all-locale reads, interface translations, translated application labels, RTL authoring, timezone-aware number/date formatting, versions, and copy-locale work. Content locale and interface language remain independent, and a document's draft/published status applies to the document rather than independently to each locale. - **Task primitives.** Typed handlers, retries, leases, heartbeats, cancellation, concurrency keys, and retention work. Workflow checkpoints, declarative cron, email/import/export adapters, and an access-controlled task admin are not included. - **SQLite deployment.** SQLite is supported only as a local filesystem database on one application host for small or local workloads. Same-host processes use SQLite's file locks; Ridu makes no shared network filesystem or horizontally replicated deployment promise. Backups must be SQLite-aware or taken after quiescing WAL writers. - **MongoDB deployment.** Production support covers only generated starter and blank projects on Linux x86-64 with MongoDB Community 8.2.9, SCRAM-SHA-256, verified TLS, and a writable three-member replica set. It does not cover Atlas, DocumentDB, Cosmos DB, standalone servers, other versions/topologies/OS or architectures, arbitrary scale, network-partition matrices, or PITR. The production cutover is drain → command-scoped `verify` with the operational URL → matched database/upload snapshot → `up` with the selected app/operator URL → post-`up` `status` → start with the app URL. Use separate scoped credentials for the application, verification, and backups. See [MongoDB](https://riducms.com/docs/mongodb/). - **Multi-replica preview.** Preview grants are process-local, so multiple application replicas need process affinity for a preview session. Every preview read is still access checked. - **Large-file workflow.** Uploads are bounded and remote URLs are SSRF hardened, but resumable or direct-to-storage upload, quarantine, and malware scanning are not implemented. - **Migration overlap.** Code-only binaries with the same manifest and migration-history fingerprints can overlap. Any release with a new artifact—including a same-manifest data-only artifact—needs the adapter's coordinated drain–verify–snapshot–migrate–status–start cutover; an explicit multi-history admission contract is not implemented. This is an operational constraint to compare with the project's downtime objective, not a general production-readiness defect. - **Long-tail admin polish.** Broader tablet acceptance, related-list live refresh, plugin-isolated recovery, and known dirty-state, leave-guard, and accessibility defects remain open. ## Experimental and optional surfaces {#experimental} The [GraphQL plugin](https://riducms.com/docs/graphql/) is opt-in and supports generated schema, PostgreSQL CRUD, localization, filters, population, and bounded requests. Compatibility may still change before the plugin is marked available. The [MCP plugin](https://riducms.com/docs/mcp/) is opt-in and exposes only explicitly selected collection and global reads to authenticated clients. It preserves ordinary access predicates and field redaction. Write tools, prompts, custom resources, and source-code mutation are not currently supported. The strict in-memory store is test infrastructure, not an application database. PostgreSQL, SQLite, and MongoDB are supported in production only within their separately documented operating envelopes. The public `store.Store` contract allows custom adapters, but conformance includes transactions, auth, versions, tasks, locks, preferences, references, and cleanup—not only CRUD. ## Planned boundaries {#planned} The following features do not have a supported API: general realtime subscriptions, MFA/passkeys, general API quotas, full-text search, resumable upload, workflow checkpoints, declarative cron, task administration, and shared multi-replica preview capabilities. ## How status labels work {#labels} - **Available** means the documented workflow is supported. - **Limited** means a useful path exists with named missing behavior or an operational constraint. - **Experimental** means the feature works, but its API or compatibility may change. - **Planned** means no supported API exists. ## Evaluate Ridu for your project {#evaluate} 1. [Install Ridu](https://riducms.com/docs/installation/) and exercise the generated project. 2. Read [Core concepts](https://riducms.com/docs/core-concepts/) and [Project structure](https://riducms.com/guides/project-structure/) to understand ownership and deployment shape. 3. Check the limited capability list against your product requirements. 4. Rehearse migrations, backups, the selected database, object storage, and admin workflows with realistic data. 5. Use [Security](https://riducms.com/docs/security/), [Production](https://riducms.com/docs/production/), and [Troubleshooting](https://riducms.com/docs/troubleshooting/) as an operational readiness checklist. Evaluating another CMS? Start with [Move from Payload](https://riducms.com/guides/from-payload/) or [Ridu for PocketBase users](https://riducms.com/guides/from-pocketbase/). --- # Installation Canonical URL: https://riducms.com/docs/installation/ To build your first application, follow the [Quickstart](https://riducms.com/docs/quickstart/). Continue here for CLI launchers, scaffold flags, existing services, and recovery. ## Requirements {#requirements} - Go 1.25 or newer. - Node.js 20 or newer and one supported package manager: npm, Bun, pnpm, or Yarn. - PostgreSQL projects: Docker/OrbStack for the generated local service, or an existing PostgreSQL 17 database. - MongoDB projects: Docker/OrbStack for the generated replica set, or an existing transaction-capable replica set. Production support is limited to the exact [MongoDB profile](https://riducms.com/docs/mongodb/). - SQLite projects need no database service or Docker. Choose npm, Bun, pnpm, Yarn, or the native Go command. The generated project records its package manager in `ridu.toml`. ## Install the CLI {#install-cli} Choose the launcher you want the project to use: ```bash title="terminal" package-manager="npm" npm create ridu@latest my-app ``` ```bash title="terminal" package-manager="bun" bun create ridu@latest my-app ``` ```bash title="terminal" package-manager="pnpm" pnpm create ridu@latest my-app ``` ```bash title="terminal" package-manager="yarn" yarn create ridu my-app ``` The positional name sets the project directory. The wizard asks for the template, database, and optional coding-agent guidance; omit `my-app` when you want it to ask for the directory too. To skip the JavaScript initializer, install the native command and open the wizard directly. The native path also asks which package manager the generated project should use: ```bash title="terminal" go install github.com/riducms/ridu/cmd/ridu@latest ridu new ``` ## Choose scaffold options {#create-project} The target directory must not exist. The wizard derives `example.com/` and `@` defaults from that directory. Supply `--module` and `--scope` when those import/package identities must match names already reserved by your organization. | Choice | Values | Meaning | | --------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------- | | Template | `starter`, `blank` | Starter adds example Posts; blank keeps authentication and framework wiring only | | Database | `postgres`, `sqlite`, `mongodb` | PostgreSQL is default; SQLite is single-host embedded; MongoDB uses its bounded replica-set profile | | Package manager | `npm`, `bun`, `pnpm`, `yarn` | Owns frontend installs, lockfiles, admin commands, and plugin package changes | | Agent guidance | `codex`, `claude`, `cursor`, `all`, `none` | Installs local project guidance, or omits it | Run any launcher without project options for the interactive wizard. Native `ridu new` also asks which package manager to use. Set `RIDU_ACCESSIBLE=1` for stable plain-text prompts suitable for screen readers. Flags skip their matching prompts; use `--no-agent` to omit agent guidance.
Automate the wizard with flags
Supply every choice to run without interactive input: ```bash title="terminal" ridu new \ --template starter \ --database postgres \ --package-manager npm \ --agent codex \ --module github.com/acme/content \ --scope @acme \ content ``` JavaScript initializers accept the same arguments. npm needs the conventional separator, for example `npm create ridu@latest -- --database sqlite content`; Bun, pnpm, and Yarn forward the arguments without it.
The created project includes `go.sum` and its generated manifest, OpenAPI, Go, TypeScript, and admin plugin contracts. ## Use the project-local CLI {#project-local-cli} New projects include `@riducms/cli` as a development dependency. Install the workspace, then use its scripts: ```bash title="terminal" package-manager="npm" cd content npm install npm run ridu -- version npm run dev ``` ```bash title="terminal" package-manager="bun" cd content bun install bun run ridu -- version bun run dev ``` ```bash title="terminal" package-manager="pnpm" cd content pnpm install pnpm run ridu version pnpm run dev ``` ```bash title="terminal" package-manager="yarn" cd content yarn install yarn run ridu version yarn run dev ``` The `dev` script runs the API, selected development database, contract generation, and admin. `dev:admin` starts only Vite when another process already runs the API. Use the selected manager's `ridu` script for doctor, generation, migrations, checks, builds, and plugins. For existing generated projects, derive the npm launcher version from the framework already pinned in `go.mod`, then add the same scripts: ```bash title="terminal" package-manager="npm" RIDU_VERSION="$(go list -m -f '{{.Version}}' github.com/riducms/ridu | sed 's/^v//')" npm install --save-dev --save-exact "@riducms/cli@$RIDU_VERSION" ``` ```bash title="terminal" package-manager="bun" RIDU_VERSION="$(go list -m -f '{{.Version}}' github.com/riducms/ridu | sed 's/^v//')" bun add --dev --exact "@riducms/cli@$RIDU_VERSION" ``` ```bash title="terminal" package-manager="pnpm" RIDU_VERSION="$(go list -m -f '{{.Version}}' github.com/riducms/ridu | sed 's/^v//')" pnpm add --save-dev --save-exact "@riducms/cli@$RIDU_VERSION" ``` ```bash title="terminal" package-manager="yarn" RIDU_VERSION="$(go list -m -f '{{.Version}}' github.com/riducms/ridu | sed 's/^v//')" yarn add --dev --exact "@riducms/cli@$RIDU_VERSION" ``` Add the selected manager to `ridu.toml`. Existing version-1 projects that omit this key continue to use Bun for compatibility. ```toml title="ridu.toml" add={3} version = 1 database = "postgres" package_manager = "npm" ``` Then add manager-neutral root scripts. Keep an existing `dev:admin` script, or use the manager-specific workspace command emitted by a new scaffold. ```jsonc title="package.json" add={3,6-9} { "devDependencies": { "@riducms/cli": "X.Y.Z" }, "scripts": { "dev": "ridu dev", "ridu": "ridu", "check": "ridu check", "build": "ridu build" } } ``` Replace `X.Y.Z` with the value printed in `RIDU_VERSION`; do not leave the placeholder in the file. If you prefer a global command, install it with `npm install --global @riducms/cli@latest` or `go install github.com/riducms/ridu/cmd/ridu@latest`. Global commands can drift from older projects, so pin the project-local package for repeatable work and automation. ## Open the admin {#open-admin} Run the selected manager's `dev` script from the project directory and open the printed admin URL (normally `http://localhost:8080/admin`). PostgreSQL and MongoDB start their local services when needed; SQLite opens its local development file. On an empty auth collection, the admin shows one-time first-user setup. The [Quickstart](https://riducms.com/docs/quickstart/#open-the-admin) continues from here with the first account, document, and generated SDK read. ## Use an existing database service {#existing-database} For PostgreSQL or MongoDB, bind the URL to the command and tell development not to start Compose: ```bash title="terminal" package-manager="npm" DATABASE_URL="$DEVELOPMENT_DATABASE_URL" npm run dev -- --no-docker ``` ```bash title="terminal" package-manager="bun" DATABASE_URL="$DEVELOPMENT_DATABASE_URL" bun run dev -- --no-docker ``` ```bash title="terminal" package-manager="pnpm" DATABASE_URL="$DEVELOPMENT_DATABASE_URL" pnpm run dev --no-docker ``` ```bash title="terminal" package-manager="yarn" DATABASE_URL="$DEVELOPMENT_DATABASE_URL" yarn run dev --no-docker ``` Without an explicit MongoDB URL, development uses `mongodb://127.0.0.1:27029/ridu?directConnection=true&replicaSet=ridu-rs0`. `--no-docker` therefore requires `DATABASE_URL`/`--database-url` for MongoDB. A standalone `mongod` is not supported because Ridu operations require transactions. For SQLite development, use `--database-path ./data/content.sqlite`, `RIDU_SQLITE_PATH`, or the project-local `.ridu/development.sqlite` default. The generated production binary requires an absolute `RIDU_SQLITE_PATH` or absolute `file:` URI. See each adapter guide for setup and production limits: - [Add PostgreSQL to an existing project](https://riducms.com/docs/postgres/#existing-project) - [Add SQLite to an existing project](https://riducms.com/docs/sqlite/#existing-project) - [Add MongoDB to an existing project](https://riducms.com/docs/mongodb/#existing-project) Ridu does not provide a generic live cross-adapter migration facility. Moving existing data between adapters is an application-owned export, transform, validation, recovery, and cutover. `ridu dev --no-install` skips dependency installation, and `--no-sync` disables additive development sync. Use these options only when another tool performs the omitted step. ## Recover an interrupted installation {#recovery} If dependency setup fails, fix the reported cause, install the missing dependencies, and restart development: ```bash title="terminal" cd content go mod tidy npm install npm run ridu -- doctor npm run dev ``` The example uses npm; replace its commands with the manager recorded in `ridu.toml`. `npm run ridu -- doctor` checks Go, the selected manager, `ridu.toml`, config discovery, and adapter prerequisites without mutating production data. Continue with [Troubleshooting](https://riducms.com/docs/troubleshooting/) when a healthy scaffold still does not start. Next read [Project structure](https://riducms.com/guides/project-structure/), [Fields](https://riducms.com/docs/fields/), and [Generated contracts](https://riducms.com/docs/generated-contracts/). --- # Core concepts Canonical URL: https://riducms.com/docs/core-concepts/ You author executable Go config. Ridu resolves it into an immutable manifest, generates exact Go, OpenAPI, and TypeScript contracts, and applies one operation engine to every runtime entry point. The generated contracts are shared by the server and browser, while the application server remains a Go binary. See [Go for TypeScript developers](https://riducms.com/docs/go-for-typescript/) for the syntax and tooling. ## 1. Config is executable authoring code {#config} Your application returns a `ridu.Config`. Collections, globals, fields, access rules, hooks, tasks, storage, and compiled plugins meet here: ```go title="content/config.go" package content import "github.com/riducms/ridu" func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Admin: ridu.AdminConfig{User: "users"}, Plugins: installedPlugins(), Collections: []ridu.Collection{Users, Posts, Media}, } } ``` Field shape, labels, plugin descriptors, and admin presentation are data. Access rules, hooks, validators, task handlers, endpoint handlers, storage credentials, and database setup remain Go values and functions. Helpers, conditionals, and ordinary Go packages can participate in config. Executable functions and secrets are not serialized into the manifest. See [Configuration](https://riducms.com/docs/configuration/) for the complete surface. ## 2. Resolution produces the canonical manifest {#manifest} `ridu.Resolve` applies plugin config transforms in order, validates the model, derives stable identities, and returns `schema.Manifest`. It does not open a database or start a server: ```go title="content/config_test.go" func TestConfigResolves(t *testing.T) { manifest, err := ridu.Resolve(Config()) if err != nil { t.Fatal(err) } snapshot := manifest.Snapshot() if snapshot.Application.Name != "Acme Editorial" { t.Fatalf("application name = %q", snapshot.Application.Name) } } ``` The manifest is immutable from a consumer's point of view. `Snapshot()` returns a deep copy and `Bytes()` produces deterministic JSON. It contains the public metadata required by runtime, generation, migrations, and admin tooling. Config errors arrive together as path-aware `schema.ValidationError` issues. Change the Go config, not generated files or the manifest. ## 3. Generate contracts {#generated-contracts} `ridu generate` resolves the config and atomically writes these contracts: | Output | Consumer | | ------------------------------------- | ----------------------------------------------------------------- | | `generated/ridu.schema.json` | Review, tooling, migration history, and runtime schema inspection | | `generated/ridu.openapi.json` | REST clients and API tooling | | `generated/ridu.generated.go` | Typed local collection/global models and handles | | `generated/ridu.generated.ts` | Application-bound Fetch SDK types and methods | | `admin/src/ridu.plugins.generated.ts` | Validated static imports for paired admin plugins | Commit these generated artifacts with the config that produced them. During local work, `ridu dev` generates them whenever config or a plugin descriptor changes; review and commit the diff. Use `ridu generate` as a one-shot command when the development loop is not running. Do not hand-edit an artifact: the next generation would replace it, and `ridu generate --check` or `ridu check` fails when tracked output does not match executable config. Generated types do not authorize requests. The server validates and authorizes each request. Continue with [Generated contracts](https://riducms.com/docs/generated-contracts/) and the [TypeScript SDK](https://riducms.com/docs/typescript-sdk/). ## 4. One operation engine owns behaviour {#operation-engine} The generated Go handle, dynamic local API, REST handler, SDK, admin, and calls made through task or plugin contexts use the same operation engine. It applies access, validation, and hooks regardless of entry point. For a mutation, the useful mental model is: 1. Resolve the collection/global and begin or reuse a transaction. 2. Evaluate access and keep any filtered decision attached to the store operation. 3. Normalize input, run field access, validation, and deterministic hooks. 4. Validate final relationships and perform one semantic store mutation. 5. Compute, populate, and redact the returned document. 6. Commit, then dispatch after-commit effects. Nested local calls made from hooks reuse the outer transaction. A nested failure rolls the whole operation back, and after-commit work does not run early. For reads, updates, deletes, version history, and other filterable operations, `ridu.Where(...)` remains a predicate on the atomic store query; Ridu does not fetch a row and authorize it afterwards. > [!IMPORTANT] > Apply access rules and field redaction to local Go API calls too. Admin visibility and field > `ReadOnly` presentation do not grant or restrict permission. Read [Data access](https://riducms.com/docs/data-access/), [Access control](https://riducms.com/docs/access-control/), and [Hooks](https://riducms.com/docs/hooks/) when you need the detailed phase behaviour. ## 5. Choose a database and build {#adapters} The [PostgreSQL](https://riducms.com/docs/postgres/), [SQLite](https://riducms.com/docs/sqlite/), and [MongoDB](https://riducms.com/docs/mongodb/) adapters provide transactional persistence. Use PostgreSQL for networked, multi-host deployments and SQLite for a local file on one host. MongoDB requires a transaction-capable replica set; see its guide for the narrower supported production profile. An [object-storage adapter](https://riducms.com/docs/storage/) stores upload bytes. [Plugins](https://riducms.com/docs/plugins/) add compiled Go capabilities and statically registered admin capabilities. `ridu build` compiles the configured Go server, generated contracts, static admin, and installed plugins into one binary. Node and Bun remain build tools. Next, model a collection in [Fields](https://riducms.com/docs/fields/), or read [Testing](https://riducms.com/docs/testing/). --- # Go for TypeScript developers Canonical URL: https://riducms.com/docs/go-for-typescript/ Use Go for Ridu configuration and trusted server behaviour such as access rules and hooks. Application frontends and admin plugins remain TypeScript, and Ridu generates TypeScript contracts for your content model. ## The mental model {#mental-model} A Ridu project starts with a Go function that returns `ridu.Config`. Ridu validates the result and resolves it into a schema manifest. That manifest drives migrations, OpenAPI, generated Go models, the TypeScript client, and the admin. Map common TypeScript constructs to their Go equivalents: | TypeScript idea | Go in a Ridu project | | -------------------------------------- | ---------------------------------------------------- | | `export const posts: Collection` | `var Posts = ridu.Collection{...}` | | `{ slug: 'posts', fields: [...] }` | `ridu.Collection{Slug: "posts", Fields: ...}` | | `Field[]` | `[]field.Definition` | | `required: true` | `field.Required()` | | `async (args) => result` | `func(ctx context.Context, args T) (Result, error)` | | `undefined` or `null` | a type's zero value or, where absence matters, `nil` | | `throw new Error(...)` | return an `error` | | `AbortSignal` / request-scoped context | `context.Context` | Here is a complete collection definition: ```go title="content/posts.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) var Posts = ridu.Collection{ Slug: "posts", Fields: []field.Definition{ field.Text("title", field.Required()), field.Text("slug", field.Required(), field.Unique()), field.Select( "status", field.OneOf("draft", "published"), field.Default("draft"), ), }, } ``` The punctuation differs, but the shape is still a typed configuration object. `field.Text` and `field.Select` are constructors; calls such as `field.Required()` are typed options. Incompatible options are rejected by Go's type checker where possible, while rules that depend on the whole schema are reported when Ridu resolves the config. ## Enough Go to be productive {#enough-go} ### Packages and exports {#packages-and-exports} Every `.go` file begins with a package name. Files in the same directory normally share a package, so `content/posts.go` and `content/config.go` can use each other's variables and functions without importing one another. Imports name the external packages used by that file. Go uses capitalization instead of an `export` keyword. `Posts`, `Config`, and `Collection` are visible to other packages; `posts` is private to its package. ### Structs, slices, and zero values {#structs-slices-zero-values} A Go struct is closest to a TypeScript object with a fixed interface. A struct literal names the fields you want to set: ```go ridu.Config{ Name: "Acme Editorial", Collections: []ridu.Collection{Users, Posts}, } ``` `[]ridu.Collection` is a slice, Go's growable-list type. Go gives every field a zero value: empty strings, `false`, `0`, and `nil` for pointers and slices. Ridu's public structs document when a zero value means “use the default.” Prefer named fields as above; they remain readable as contracts grow. ### Functions and errors {#functions-and-errors} Go commonly returns a result and an error instead of throwing: ```go manifest, err := ridu.Resolve(Config()) if err != nil { return err } ``` `:=` declares local variables and infers their types. `if err != nil` handles the error. Ridu uses the same pattern for local operations, access callbacks, hooks, and startup. Many callbacks also receive `context.Context`. Treat it like request-scoped cancellation and deadline state, not a bag of global application values. Pass it to database or network work started for that operation so cancellation can propagate. ### Pointers and `nil` {#pointers-and-nil} You will sometimes see `*T`, meaning “a pointer to `T`.” Ridu uses pointers when absence has meaning. For example, a nil actor in an access request means an anonymous request; it does **not** mean an administrator. ### Formatting and tests {#formatting-and-tests} Go has one canonical formatter. Generated projects include formatting, vet, tests, generated-drift, and frontend checks behind `ridu check`. Go test files end in `_test.go`, and table-driven tests are the common equivalent of a parameterized test suite. ## What stays TypeScript {#what-stays-typescript} Ridu generates a TypeScript module containing document, create, update, select, query, and population types. It binds those contracts to the Fetch-based `@riducms/sdk`; SDK methods return `Promise` values and reject structured `RiduError` failures. The Svelte 5 admin also consumes generated contracts. Custom admin fields and views are static TypeScript/Svelte modules, while their trusted server counterpart is a compiled Go plugin. Bun builds these assets, but production serves them from the Go binary and does not need a Node or Bun server. Read [TypeScript SDK](https://riducms.com/docs/typescript-sdk/) for frontend calls, [Admin](https://riducms.com/docs/admin/) for the admin, and [Custom fields](https://riducms.com/guides/custom-fields/) for a paired extension. ## Where to put behaviour {#where-behaviour-lives} - Put collection and field definitions in small Go factory functions. - Put authorization in [access rules](https://riducms.com/docs/access-control/), not in admin visibility settings. - Put lifecycle behaviour in [hooks](https://riducms.com/docs/hooks/) and keep side effects safe for retries. - Use the [local API](https://riducms.com/docs/local-api/) for trusted Go callers; it still passes through the same authorization, validation, hooks, transaction, and redaction engine as REST. - Use the generated TypeScript module or [REST API](https://riducms.com/docs/rest-api/) from application frontends. - Treat generated schema, Go, OpenAPI, and TypeScript files as committed output. Change config and let `ridu dev` regenerate them rather than editing generated files. ## A useful learning path {#learning-path} You can learn the Go syntax as the product concepts appear: 1. Follow [Getting started](https://riducms.com/docs/getting-started/) and read the generated project. 2. Add one field with [Collections](https://riducms.com/docs/collections/) and [Fields](https://riducms.com/docs/fields/). 3. Run generation and use the new type from [TypeScript SDK](https://riducms.com/docs/typescript-sdk/). 4. Add one access rule and one hook only when the application needs them. 5. Keep [Troubleshooting](https://riducms.com/docs/troubleshooting/) nearby for compiler, generation, and runtime symptoms. The compiler reports incompatible field options, callback signatures, and returned types before the application starts. Config resolution reports schema-wide errors such as duplicate slugs or a relationship to a missing collection. --- # Configuration Canonical URL: https://riducms.com/docs/configuration/ Your content model and server behaviour begin as a typed `ridu.Config` value. Ridu resolves it into the schema used by the database, REST API, generated Go and TypeScript contracts, and the admin. Projects put the composition function in `content/config.go` by default, but you may split config across any number of Go files. ## Application config {#application-config} At minimum, a config needs a non-empty application name and one collection: ```go title="content/config.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Collections: []ridu.Collection{ { Slug: "posts", Fields: []field.Definition{ field.Text("title", field.Required()), field.Textarea("summary"), }, }, }, } } ``` Because config is Go, the compiler catches misspelled fields, wrong callback signatures, and field options used with incompatible constructors. Resolution then handles rules that require the whole application, such as duplicate slugs, missing relationship targets, invalid locale graphs, and plugin compatibility. ### Config options {#config-options} | Option | Required | What it controls | | ------------------ | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Name` | Yes | The author-facing application name shown by Ridu tooling and the admin. Whitespace is trimmed and an empty name is rejected. | | `Collections` | Yes | Repeatable document models. At least one collection is required. | | `Globals` | No | Singleton documents such as site settings or navigation. | | `Endpoints` | No | Compiled root custom endpoints below `/api`; handlers are anonymous by default. | | `Admin` | When auth is enabled | `Admin.User` selects which auth-enabled collection may enter the admin. | | `Localization` | No | Content locales, the default locale, ordered fallbacks, right-to-left metadata, and request-visible locales. The zero value disables content localization. | | `Hooks` | No | Application-wide failure hooks. Collection and global lifecycle hooks live on the resource they affect. | | `Plugins` | No | Compiled extensions, applied in declaration order. | | `AfterCommit` | No | A dispatcher for collection and global hooks that run after a successful transaction. | | `Storage` | When uploads are enabled | The object backend for upload bytes. It can instead be supplied lazily with `ridu.WithUploadStorage`. | | `StorageNamespace` | When uploads are enabled | A stable application-owned prefix for objects in a shared backend. | See the [`ridu.Config` reference](https://riducms.com/reference/ridu/config/) for every field. ## How Ridu reads config {#source-of-truth} Ridu does not parse Go files looking for collections. The project entry calls your `Config()` function, so access rules, hooks, computed fields, and plugin constructors execute as Go code. The CLI finds that entry through `ridu.toml`: ```toml title="ridu.toml" version = 1 database = "postgres" # or "sqlite" or "mongodb"; credentials remain runtime-owned package_manager = "npm" # or "bun", "pnpm", or "yarn" entry = "./cmd/server" admin = "./admin" schema = "./generated/ridu.schema.json" client = "./generated/ridu.generated.ts" openapi = "./generated/ridu.openapi.json" # Optional after enabling the GraphQL plugin: # generated.graphql.schema = "./generated/ridu.graphql" migrations = "./migrations" assets = "./internal/adminassets/dist" plugins = "./ridu.plugins.json" plugin_go = "./content/ridu_plugins.generated.go" ``` `ridu generate`, `ridu dev`, and migration commands run the configured entry to resolve the current schema. Plugin transforms run in declaration order before Ridu validates the application and creates the schema manifest. Hooks, access rules, computed resolvers, storage, and endpoint handlers remain in the Go runtime. Change `content/*.go` rather than generated JSON. The development loop regenerates the manifest and other derived files. ## Compose a larger application {#compose-configuration} As the application grows, declare static collections and globals as focused package variables. Their filenames and package layout are yours to choose. ```go title="content/config.go" package content import "github.com/riducms/ridu" func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Admin: ridu.AdminConfig{User: "users"}, Plugins: installedPlugins(), Collections: []ridu.Collection{Users, Posts, Media}, Globals: []ridu.Global{SiteSettings}, } } ``` For example, the `Posts` collection can live beside it with its imports and behaviour close to the model it belongs to: ```go title="content/posts.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" "github.com/riducms/ridu/plugins/richtext" ) var Posts = ridu.Collection{ Slug: "posts", Admin: ridu.CollectionAdmin{ UseAsTitle: "title", DefaultColumns: []string{"title", "status"}, Group: "Editorial", }, Fields: []field.Definition{ field.Text("title", field.Required()), field.Select( "status", field.OneOf("draft", "published"), field.Default("draft"), ), richtext.Field("content"), }, } ``` Ridu defensively copies these declarations before plugins transform or validate the configuration. Treat exported collection variables as definitions rather than shared application state: use a function instead when construction needs options, runtime values, fallible setup, or a fresh caller-owned mutable value. `ridu add` and `ridu plugin remove` update `installedPlugins()`, Go dependencies, and matching admin imports together. Add application-local plugins directly to `Config.Plugins`. See [Collections and globals](https://riducms.com/docs/collections/) for capabilities and lifecycle behaviour, and [Fields](https://riducms.com/docs/fields/) for the complete field vocabulary. ## Configure the admin identity {#admin-config} `Config.Admin` selects which auth collection owns admin sessions. It does not enable authentication by itself. Set `Auth: true` on the collection, then name that collection in `Admin.User`: ```go title="content/config.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Admin: ridu.AdminConfig{User: "users"}, Collections: []ridu.Collection{ { Slug: "users", Auth: true, Fields: []field.Definition{ field.Text("email", field.Required(), field.Unique()), }, }, Posts, }, } } ``` If several collections enable auth, only the selected collection gains admin access. Ridu rejects an absent, unknown, or non-auth-enabled `Admin.User` whenever any auth collection exists. An application without auth collections may leave `Admin` at its zero value. Collection list columns, labels, groups, descriptions, and live preview belong to `ridu.CollectionAdmin`; global presentation belongs to `ridu.GlobalAdmin`. Those values shape the admin but do not grant authorization. See [Admin](https://riducms.com/docs/admin/) and [Authentication](https://riducms.com/docs/authentication/) for those separate concerns. Admin interface language is separate from content locale. Configure `Admin.Localization` with the allowed BCP-47 languages, default language, browser-safe IANA timezones (or fixed offsets), and the default timezone. English, French, and Arabic catalogs ship with Ridu. Editors can persist their choice from the account screen; the whole interface, accessibility text, plural rules, formatting, and right-to-left layout update together. Application, resource, field, choice, relationship, language, and timezone labels can provide `LabelTranslations` maps without changing stable IDs. ## Add content localization {#localization} Localization is opt-in. Once it is configured, mark individual fields with `field.Localized()`; ordinary fields continue to store one shared value. ```go title="content/config.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" "github.com/riducms/ridu/schema" ) func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Localization: ridu.LocalizationConfig{ DefaultLocale: "en", Locales: []ridu.Locale{ {Code: "en", Label: "English"}, { Code: "fr", Label: "Français", FallbackLocales: []schema.LocaleCode{"en"}, }, { Code: "ar", Label: "العربية", RTL: true, FallbackLocales: []schema.LocaleCode{"en"}, }, }, }, Collections: []ridu.Collection{ { Slug: "posts", Fields: []field.Definition{ field.Text("title", field.Required(), field.Localized()), field.Text("slug", field.Required(), field.Unique()), }, }, }, } } ``` Every configured locale needs a unique valid code and non-empty label. `DefaultLocale` must name one of them. Fallbacks are enabled by default and follow each locale's ordered `FallbackLocales`; unknown locales, self-fallbacks, duplicates, and cycles fail resolution. Set `DisableFallback: true` when reads must return only the exact requested locale. `Localization.AvailableLocales` can reduce the locales shown to a particular admin request using its actor and local API. It is executable request policy, so it is not serialized into the public manifest and does not weaken locale validation or authorization. See the localization options in the [schema reference](https://riducms.com/reference/schema/locale-code/). ## Register plugins {#plugins} Plugins are compiled Go values. Ridu checks compatibility and applies config transforms in declaration order. Runtime callbacks and secrets remain in the binary. ```go title="content/config.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/plugins/graphql" "github.com/riducms/ridu/plugins/richtext" ) func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Plugins: []ridu.Plugin{ richtext.New(), graphql.New(graphql.Options{MaxDepth: 10}), }, Collections: []ridu.Collection{Users, Posts}, } } ``` When a plugin contributes an admin package, generation emits a static import and verifies its key, API version, and pairing version against the backend descriptor. Production never downloads or installs plugin code dynamically. See [Plugins](https://riducms.com/docs/plugins/) for installation, removal, and authoring. ## Configure root hooks and after-commit dispatch {#hooks-and-after-commit} `Config.Hooks` contains application-wide failure observation. Put operation lifecycle behaviour on the collection or global that owns it; those resource hooks have the document, original values, actor, locale, and local API in their context. ```go title="content/config.go" package content import ( "log/slog" "github.com/riducms/ridu" "github.com/riducms/ridu/core" ) func reportRootFailure(ctx ridu.HookContext) error { slog.Error( "ridu operation failed", "operation", ctx.Operation, "error", ctx.Error, ) return nil } func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Hooks: core.RootHooks{ AfterError: []ridu.Hook{reportRootFailure}, }, Collections: []ridu.Collection{Users, Posts}, } } ``` Resource `AfterCommit` hooks run only after the document transaction succeeds. Without a custom dispatcher Ridu runs them immediately. Set `Config.AfterCommit` to an implementation of `ridu.AfterCommitDispatcher` when the application needs one place to schedule, instrument, or otherwise control committed effects. The dispatcher receives operation and resource identity plus the callback to run; an error at this point cannot roll the committed document back. See [Hooks](https://riducms.com/docs/hooks/) for the full lifecycle and transaction boundaries. ## Configure upload storage {#upload-storage} Upload collections store document metadata in the document-store adapter and file bytes in an object-storage adapter. Every upload-enabled application also needs a stable `StorageNamespace`; do not derive it from `Config.Name`, because the display name can change. For runtime-created clients, prefer `ridu.WithUploadStorage`. Its factory is evaluated only when the server starts, not while the CLI resolves config: ```go title="cmd/server/main.go" add={12,24-32} package main import ( "context" "log" "os" "example.com/acme/content" "github.com/riducms/ridu" "github.com/riducms/ridu/adapters/postgres" "github.com/riducms/ridu/adapters/storage/s3" "github.com/riducms/ridu/storage" "github.com/riducms/ridu/store" ) func main() { err := ridu.Execute( content.Config(), ridu.WithStore(func(ctx context.Context) (store.Store, error) { return postgres.Open(ctx, os.Getenv("DATABASE_URL")) }), ridu.WithAddress(":8080"), ridu.WithUploadStorage(func(context.Context) (storage.Backend, error) { return s3.New(s3.Config{ Endpoint: os.Getenv("S3_ENDPOINT"), Region: os.Getenv("S3_REGION"), Bucket: os.Getenv("S3_BUCKET"), AccessKey: os.Getenv("S3_ACCESS_KEY"), SecretKey: os.Getenv("S3_SECRET_KEY"), }) }), ) if err != nil { log.Fatal(err) } } ``` The content config still declares the namespace and upload collection: ```go title="content/config.go" package content import "github.com/riducms/ridu" func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", StorageNamespace: "acme-content", Collections: []ridu.Collection{Users, Posts, Media}, } } ``` `ridu.Resolve` validates the serializable upload schema. Runtime construction additionally checks that upload storage is present and that the document store supports every enabled capability. See [Uploads](https://riducms.com/docs/uploads/) and [Object storage](https://riducms.com/docs/storage/) for backend and privacy options. ## Server entry {#server-entry} `ridu.Execute` joins config to runtime services. A PostgreSQL server entry looks like this: ```go title="cmd/server/main.go" package main import ( "context" "log" "os" "example.com/acme/content" "example.com/acme/internal/adminassets" "github.com/riducms/ridu" "github.com/riducms/ridu/adapters/postgres" "github.com/riducms/ridu/store" ) func main() { err := ridu.Execute( content.Config(), ridu.WithStore(func(ctx context.Context) (store.Store, error) { return postgres.Open(ctx, os.Getenv("DATABASE_URL")) }), ridu.WithAddress(":8080"), ridu.WithHandlerOptions(ridu.HandlerOptions{ AdminAssets: adminassets.FS(), AllowedOrigins: []string{ "https://www.example.com", }, }), ) if err != nil { log.Fatal(err) } } ``` SQLite-selected projects import `adapters/sqlite` and open `RIDU_SQLITE_PATH`; see [SQLite](https://riducms.com/docs/sqlite/). MongoDB-selected projects import `adapters/mongodb`, open `DATABASE_URL`, and verify the resolved index plan before serving; see [MongoDB](https://riducms.com/docs/mongodb/). Use `ridu.New(config, store)` for tests, embedded use, or a custom HTTP process. It still applies access, validation, and hooks. Build production applications with `ridu build`; a direct `go build` omits the migration-history fingerprint, so `/readyz` fails with an official adapter. ## Validate before runtime {#validate-before-runtime} Use `ridu.Resolve` in focused tests to validate config and inspect the immutable manifest without opening a database: ```go title="content/config_test.go" package content import ( "errors" "testing" "github.com/riducms/ridu" "github.com/riducms/ridu/schema" ) func TestConfigResolves(t *testing.T) { manifest, err := ridu.Resolve(Config()) if err != nil { var validation *schema.ValidationError if errors.As(err, &validation) { for _, issue := range validation.Issues { t.Logf("%s [%s]: %s", issue.Path, issue.Code, issue.Message) } } t.Fatal(err) } if manifest.Snapshot().Application.Name != "Acme Editorial" { t.Fatal("resolved the wrong application config") } } ``` Schema validation errors carry a stable `Code`, exact `Path`, and actionable `Message`. One pass can report several independent issues, which is more useful than fixing a large config one failure at a time. Runtime-only capability checks—such as requiring `store.AuthStore` for auth collections or object storage for uploads—run when the application is bound to its backends. ## Develop and review generated contracts {#generation-workflow} While `ridu dev` is running, saving a config change automatically resolves it, regenerates every derived contract, synchronizes safe additive database changes, and restarts the application. Before committing, verify that the generated files are current: ```bash title="terminal" npm run ridu -- generate --check npm run ridu -- check ``` If the development loop is not running, `npm run ridu -- generate` performs the same generation as a one-shot command. It resolves the Go config once, then atomically updates the canonical manifest, OpenAPI document, generated Go models and handles, application-bound TypeScript client, and static admin plugin registry. `ridu check` fails when committed generated output has drifted. ```text title="Configuration flow" content/*.go ↓ Config() ridu.Resolve + plugin transforms ↓ immutable manifest schema · OpenAPI · Go types · TypeScript SDK · admin forms ``` For a database change, generation describes the desired application but does not silently define a production migration. Create and review an immutable migration artifact separately: ```bash title="terminal" npm run ridu -- migrate create --name add-post-summary npm run ridu -- migrate verify ``` Apply that reviewed artifact with `migrate up` during deployment. `ridu dev` handles local schema sync. See [Ridu CLI](https://riducms.com/docs/cli/) for the development and release commands. --- # Collections and globals Canonical URL: https://riducms.com/docs/collections/ Collections hold many documents—posts, products, people, media. Globals hold exactly one logical document—site settings, navigation, or a home-page composition. Both use the same fields, access, validation, hooks, localization, and field redaction. `ridu.Collection` and `ridu.Global` are typed Go config values. Their serializable shape becomes generated Go and TypeScript contracts, OpenAPI, and the admin model. ## Define a collection {#define-a-collection} A collection slug is its durable public address in REST, generated clients, relationships, and the admin. Presentation belongs in `Labels` and `Admin`; runtime behaviour belongs in fields, access, hooks, and explicit capabilities. ```go title="content/articles.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) var Articles = ridu.Collection{ Slug: "articles", Labels: ridu.CollectionLabels{ Singular: "Article", Plural: "Articles", }, Admin: ridu.CollectionAdmin{ UseAsTitle: "title", DefaultColumns: []string{"title", "category", "summary"}, Group: "Editorial", Description: "Long-form stories published on the site.", }, Fields: []field.Definition{ field.Text("title", field.Required()), field.Textarea("summary"), field.Relationship("category", field.To("categories")), field.Group("seo", field.Fields( field.Text("slug", field.Required()), )), }, Indexes: []ridu.CollectionIndex{ {Fields: []string{"category", "seo.slug"}, Unique: true}, }, } ``` Register the value in `ridu.Config.Collections`. Config resolution rejects unknown relationship targets, invalid admin fields, duplicate slugs, and unsupported index paths. ## Collection configuration map {#collection-config} | Property | Purpose | | ------------------------------------- | ------------------------------------------------------------------------------------------------ | | `Slug` | URL-safe public resource name. It is used by APIs and relationships, not just the admin. | | `Labels` | Optional singular/plural author-facing names. Ridu derives readable defaults from the slug. | | `Admin` | Navigation, list, hierarchy, folder, and live-preview presentation. It never grants access. | | `Fields` | Stored, layout, computed, relationship, upload, and plugin field definitions. | | `Indexes` | Ordered compound store indexes; use field-level `Unique()` for one-field uniqueness. | | `Auth`, `AuthConfig` | Make documents identities and configure passwords, sessions, recovery, API keys, and strategies. | | `Upload`, `UploadConfig` | Make documents file records backed by `Config.Storage`. | | `Versions`, `VersionConfig` | Record snapshots and optionally enable draft authoring. | | `Trash` | Replace ordinary delete with recoverable trash, restore, and permanent-delete operations. | | `LockDocuments`, `DocumentLockConfig` | Persist editor locks and controlled takeover for coordinated authoring. | | `Access`, `FieldAccess` | Authorize resource operations and redact or reject individual field paths. | | `Hooks`, `FieldHooks` | Run deterministic lifecycle callbacks, including transaction-reusing nested local calls. | | `Computed` | Resolve virtual response fields after storage without persisting them. | See [Fields](https://riducms.com/docs/fields/) for every builder and option. A field's name is part of stored and generated contracts; its label and description affect presentation only. ## Admin metadata is presentation {#admin-metadata} `CollectionAdmin` configures browsing and editing without changing API authorization: | Property | Current behaviour | | ---------------- | ---------------------------------------------------------------------------------------------------------------- | | `UseAsTitle` | Names a direct field used as the document label in lists, relationships, and upload flows. | | `DefaultColumns` | Names unique direct fields shown by a fresh list workspace. Authors can persist their own workspace preferences. | | `Group` | Groups the collection in admin navigation. | | `Description` | Adds author-facing context for the resource. | | `FolderField` | Names a singular, non-polymorphic relationship used to filter a collection into folders. | | `ParentField` | Names a singular relationship back to the same collection and enables the hierarchy view. | | `LivePreview` | Configures the editor preview URL and optional named viewport sizes. | `UseAsTitle`, columns, folder, and parent fields must name existing direct fields. Folder relationships may target another collection; a parent relationship must target the collection itself. Live-preview URL templates accept `{id}`, `{collection}`, and `{field:path.to.value}` placeholders. Read [Admin](https://riducms.com/docs/admin/) and [Editorial workflows](https://riducms.com/docs/editorial-workflows/) for the authoring experience. > [!IMPORTANT] > Admin visibility and capability responses are interface hints, never authorization. Every API > request independently evaluates collection and field access inside its store transaction. ## Compound indexes {#indexes} Use `CollectionIndex` when the tuple, rather than one field, is indexed or unique: ```go Indexes: []ridu.CollectionIndex{ {Fields: []string{"tenant", "seo.slug"}}, {Fields: []string{"tenant", "externalID"}, Unique: true}, }, ``` An index contains 2–32 unique, ordered paths. Paths can pass through non-repeated groups and end at a supported scalar or a singular, non-polymorphic relationship/upload reference. Arrays, blocks, rich text, objects, has-many references, and polymorphic references are not index terminals. Official stores use PostgreSQL-style `NULLS DISTINCT` semantics: a unique tuple can appear more than once when any component is null or absent. Localized values are unique per exact locale, not across a fallback result. Trashed documents leave the active unique set; restoring one can fail with `conflict` if another active document has claimed its tuple. ## Opt-in capabilities {#capabilities} A collection supports create, duplicate, find, list, update, delete, filtering, pagination, selection, population, access evaluation, hooks, and generated contracts. Flags add features: | Configuration | Adds | Required runtime contract | | --------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | `Auth: true` | Password credentials, sessions, account lockout, recovery/verification, optional API keys, custom request strategies | Store implements `store.AuthStore`; the production server also expects auth maintenance support | | `Upload: true` | Server-owned file metadata, validation, image variants, delivery, regeneration, and cleanup | `Config.Storage`, `StorageNamespace`, and upload-aware store capabilities | | `Versions: true` | `_revision`, `_status`, retained snapshots, restore, and scheduled collection publishing | Store implements `store.VersionTransaction`; scheduling needs durable task or publish-job support | | `Trash: true` | Soft delete, trash-only reads, restore, permanent delete, empty trash, and cleanup of owned state | Store implements the trash and reference-cleanup contracts | | `LockDocuments: true` | Inspect/acquire/release locks and authorized takeover | Store implements `store.DocumentLockStore` | All three official database adapters supply these store capabilities; MongoDB does so inside its [bounded production profile](https://riducms.com/docs/mongodb/). Application construction fails if an adapter cannot support an enabled feature. Continue with [Authentication](https://riducms.com/docs/authentication/), [Uploads](https://riducms.com/docs/uploads/), [Drafts and versions](https://riducms.com/docs/drafts-and-versions/), and [Editorial workflows](https://riducms.com/docs/editorial-workflows/) for each feature. ## Access, hooks, and computed output {#runtime-behaviour} `CollectionAccess` has independent `Admin`, `Create`, `Read`, `ReadVersions`, `Update`, `Publish`, `Unpublish`, `Delete`, and `Unlock` rules. A nil `ReadVersions` rule falls back to `Read`; nil `Publish`, `Unpublish`, and `Unlock` rules fall back to `Update`. Read and mutation rules can return `ridu.Where(...)`, which the store must combine atomically with the caller's filter. `FieldAccess` and `FieldHooks` maps use authored paths such as `seo.slug`. Repeated field occurrences also receive a concrete runtime path. `Computed` values are response-only and can be limited with local API output selection. Learn the order and transaction boundaries in [Access control](https://riducms.com/docs/access-control/) and [Hooks](https://riducms.com/docs/hooks/). ## Globals {#globals} Globals use singleton routes and generated singleton handles. Reading a global before its first write returns a schema-shaped value with defaults; the first update persists the row under the global slug. ```go title="content/globals.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) var SiteSettings = ridu.Global{ Slug: "site-settings", Label: "Site settings", Admin: ridu.GlobalAdmin{ Group: "Settings", Description: "Site-wide identity and support details.", }, Fields: []field.Definition{ field.Text("siteName", field.Required()), field.Email("supportEmail"), }, Access: ridu.GlobalAccess{ Read: publicRead, Update: administratorsOnly, }, } ``` Register it in `ridu.Config.Globals`. A global has no collection-style create, duplicate, list, delete/trash, auth, upload, document-lock, folder, hierarchy, or compound-index configuration. Its supported surface is smaller: | Concern | Collection | Global | | --------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | Cardinality | Many documents with generated IDs | One document whose ID is its slug | | Base operations | Create, duplicate, find/list, update, delete, bulk | Read and update | | Access | `CollectionAccess` per CRUD/version/admin/lock operation | `GlobalAccess.Read`, `ReadVersions`, `Update`, `Publish`, and `Unpublish` | | Admin | Title, columns, folders, hierarchy, group, description, preview | Group, description, preview | | Optional capabilities | Auth, upload, versions/drafts, trash, locks | Versions/drafts only | | Versions | Per-document history, publish/unpublish, restore, scheduling | Singleton history, publish/unpublish, restore; scheduled global publishing is not implemented | For a missing singleton, a filtered `GlobalAccess.Update` decision cannot match a row; the first update therefore requires an unconditional `Allow`. Once persisted, filtered read/update/version decisions are applied atomically to the row or each snapshot. ## Renames and migrations {#renames} Rename the authored slug or field name, regenerate, then run `ridu migrate create`. PostgreSQL migration creation presents compatible remove/add pairs for confirmation and records accepted continuity in the immutable artifact. SQLite requires a named compiled transform to rewrite stored canonical JSON. Do not maintain hand-authored public schema IDs or edit generated manifests to force a rename. This changes the public field from `title` to `headline`; the migration must preserve the stored value: ```go title="content/articles.go" remove={2} add={3} Fields: []field.Definition{ field.Text("title", field.Required()), field.Text("headline", field.Required()), }, ``` Review the resulting storage and API change—especially relationships, indexes, auth identities, localized fields, and removed capabilities—before applying it. See [PostgreSQL migrations](https://riducms.com/docs/migrations/), [SQLite](https://riducms.com/docs/sqlite/), and [Generated contracts](https://riducms.com/docs/generated-contracts/). --- # Fields Canonical URL: https://riducms.com/docs/fields/ Fields are the building blocks of a Ridu document. One Go definition drives operation-engine validation, storage, migrations, generated Go and TypeScript types, REST/OpenAPI contracts, and the control rendered in the admin. ## Field anatomy {#field-anatomy} The constructor chooses the value kind, its first argument becomes the document property, and typed options refine validation and presentation: ```go title="content/posts.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) var Posts = ridu.Collection{ Slug: "posts", Fields: []field.Definition{ field.Text("title", field.Required()), field.Select( "status", field.Choices( field.Choice{Value: "draft", Label: "Draft"}, field.Choice{Value: "published", Label: "Published"}, ), field.Default("draft"), ), }, } ``` `title` and `status` are public paths in JSON, generated clients, queries, access maps, hooks, and migrations. Labels and descriptions are author-facing metadata and never rename stored data. ![A clean overview of representative Ridu field controls: text, select, array, relationship, tabs, and rich text.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/ridu-admin-field-showcase.png) ### Names are data contracts {#field-names} A field name starts with a lowercase letter, contains letters/numbers/underscores, and is unique among siblings. `id`, `createdAt`, `updatedAt`, and `deletedAt` are framework-owned. Nested names form paths such as `seo.description`; runtime issue paths include row indexes such as `links.2.label`. Treat a field rename as an API and data migration. Change `field.Label` when only author copy should change. ## Choose a built-in field {#built-in-fields} Start with the value shape consumers should receive, then choose its authoring control. | Group | Field pages | Value | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------ | | Scalar and choice | [Text](https://riducms.com/docs/fields/text/), [Textarea](https://riducms.com/docs/fields/textarea/), [Email](https://riducms.com/docs/fields/email/), [Code](https://riducms.com/docs/fields/code/), [Date](https://riducms.com/docs/fields/date/), [Number](https://riducms.com/docs/fields/number/), [Checkbox](https://riducms.com/docs/fields/checkbox/), [Select](https://riducms.com/docs/fields/select/), [Radio](https://riducms.com/docs/fields/radio/), [Slug](https://riducms.com/docs/fields/slug/) | Strings, numbers, booleans, and finite choices | | Structured | [JSON](https://riducms.com/docs/fields/json/), [Point](https://riducms.com/docs/fields/point/), [Group](https://riducms.com/docs/fields/group/), [Array](https://riducms.com/docs/fields/array/), [Blocks](https://riducms.com/docs/fields/blocks/), [Tabs](https://riducms.com/docs/fields/tabs/) | JSON values, objects, repeated rows, and discriminated lists | | Relationship and media | [Relationship](https://riducms.com/docs/fields/relationship/), [Upload](https://riducms.com/docs/fields/upload/) | Stable document references or populated documents | | Layout | [Row](https://riducms.com/docs/fields/row/), [Collapsible](https://riducms.com/docs/fields/collapsible/), [UI](https://riducms.com/docs/fields/ui/) | No stored property; these organise the editor | | Computed and plugin | [Join](https://riducms.com/docs/fields/join/), [Virtual](https://riducms.com/docs/fields/virtual/), [Plugin](https://riducms.com/docs/fields/plugin/) | Response-only output or a compiled plugin contract | ### Scalar fields {#scalar-fields} Use Text for a short string, Textarea for multi-line plain text, Code for a syntax-aware editor, and Email for server-validated addresses. Date keeps an explicit string format. Number and Checkbox use JSON number/boolean values. Select and Radio generate unions from configured values; Select can also be multiple. Slug adds deterministic source generation, required/unique/indexed behavior, and manual overrides to ordinary text storage. ### Slugs {#slugs} ```go field.Text("title", field.Required()), field.Slug("slug", "title"), ``` Slugs are required, unique, indexed, non-localized strings. Generated values follow the source until an author supplies a manual value. Read [Slug](https://riducms.com/docs/fields/slug/) for ASCII normalization and migration implications. ## Field options {#field-options} Constructors accept narrow option interfaces, making many invalid combinations a Go compile error. Compatibility that depends on the concrete kind—for example `Language` on anything except Code—is reported by `ridu.Resolve` with an exact config path. | Option | Purpose | | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | `Label`, `Description`, `Placeholder` and translation variants | Author copy without changing data paths | | `Required` | Reject missing, null, and kind-specific empty values | | `Default`, `DefaultChoices` | Write supported create defaults | | `Unique`, `Index` | Declare scalar/reference storage invariants or query indexes | | `Localized` | Store an independent content value per configured locale | | `ReadOnly`, `Hidden`, `Sidebar`, `Columns`, `Tab` | Change admin presentation, never authorization | | `ShowWhen`, `ShowWhenCondition` | Reactively display controls from typed sibling/document predicates | | [`AdminComponent`](#custom-components) | Select an exact renderer from a statically paired plugin | | Kind-specific options | Length/range, choices, relationship targets, nested fields, rows, blocks, joins, and editor hints | `ShowWhen` is presentation only. Hidden values remain in the form and still pass through validation, access, hooks, and writes. Use application validation/hooks for a cross-field invariant and field access for security. ### Custom components {#custom-components} Use `field.AdminComponent` when the stored value and server behavior of a built-in field are right, but its authoring control is not. The selected Svelte component replaces the field editor without changing storage, validation, access, hooks, migrations, REST, OpenAPI, or generated types: ```go title="content/posts.go" field.Text( "headline", field.Required(), field.AdminComponent( "editorial-tools", "Headline", json.RawMessage(`{"showCharacterCount":true}`), ), ) ``` Register the exact renderer in the statically paired admin package: ```ts title="admin/src/index.ts" import { ADMIN_PLUGIN_API_VERSION, defineAdminPlugin, defineFieldPlugin } from '@riducms/plugin'; import HeadlineField from './headline-field.svelte'; const headlineField = defineFieldPlugin({ type: 'text', key: 'editorial-tools', componentKey: 'Headline', component: HeadlineField, canRender: (field) => field.admin.component?.plugin === 'editorial-tools' && field.admin.component.component === 'Headline' }); export const editorialToolsAdminPlugin = defineAdminPlugin({ apiVersion: ADMIN_PLUGIN_API_VERSION, key: 'editorial-tools', pairingVersion: 1, fields: [headlineField] }); ``` The component receives `FieldComponentProps`: the resolved schema field, the narrow form controller, admin translations, and an optional authoring host for document lookup, the reference browser, and plugin requests. Read and write through `form.get(field.path)` and `form.set(field.path, value)`, register the path, respect `field.admin.readOnly`, and render `form.issuesFor(field.path)`. Component config is public deterministic manifest metadata, so never place secrets or executable policy in it. The paired backend plugin and admin package must use the same plugin key, admin API version, and pairing version; generation or startup rejects a missing or incompatible pair. Use a [UI field](https://riducms.com/docs/fields/ui/) for presentation that stores no value. Use a [Plugin field](https://riducms.com/docs/fields/plugin/) and the complete [custom-field guide](https://riducms.com/guides/custom-fields/) when the value shape, validation, generated types, or query behavior is itself new. Ridu's component surface is deliberately smaller than Payload's current field-component API: | Authoring need | Ridu contract | | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | | Replace the edit control | `field.AdminComponent` plus an exact `FieldPlugin` renderer | | Add presentation-only editor UI | `field.UI` with an optional paired renderer | | Customize array or block row headings | `field.RowLabelComponent` plus a registered row-label component | | Customize a collection list cell | Admin plugin `listCells`, scoped to an exact collection and field | | Field-specific filter or version diff | No public custom renderer yet | | Separate label/description/error slots | No independent slots; the replacement field component renders these through its schema metadata and form issues | | Before/after-input component slots | No independent slots; compose the additional UI inside the replacement field component | | Server-rendered admin components | Not supported; admin extensions are statically bundled Svelte components and production has no JavaScript server | Custom components are presentation, not authorization. Ridu evaluates visibility and field access before rendering, but authoritative validation and access remain in Go and apply to every transport. ### Defaults and validation {#validation-and-defaults} Built-in kinds validate through the operation engine for Local API, REST, SDK, admin, tasks, and plugin transports. Defaults run on create, not update. Core fields do not accept an arbitrary `Validate` callback; normalize input in `BeforeValidate`, enforce cross-field business rules in hooks, or create a typed [Plugin field](https://riducms.com/docs/fields/plugin/) with a server validator. ## Read sibling values {#sibling-data} A sibling is another field under the same parent. At the collection root, every other root field is a sibling. Inside a Group, Array row, or Block, only fields in that object or row are siblings. Use the API that matches the behavior you are implementing: | Where you need the value | Read it from | Scope | | -------------------------- | ----------------------------- | ---------------------------------------------------------------------------- | | Virtual resolver | `ctx.Document.Values["name"]` | The current root document | | Field-access rule | `ctx.SiblingData["name"]` | The nearest parent object or repeated row | | Admin visibility condition | `field.Sibling("name", ...)` | The nearest parent object or repeated row | | Collection or field hook | `ctx.Data["name"]` | Submitted root data; persisted update values are under `ctx.Original.Values` | Values use Ridu's typed [`store.Value`](https://riducms.com/reference/store/value/) vocabulary. For example, `ctx.SiblingData["membersOnly"].BooleanValue()` returns the boolean and whether the stored value is actually a boolean; `StringValue()`, `NumberValue()`, `ObjectValue()`, and `Values()` handle the other shapes. See [Conditional fields](https://riducms.com/docs/fields/conditional-fields/) for `field.Sibling` paths, operators, and compound presentation rules; [Virtual fields](https://riducms.com/docs/fields/virtual/#sibling-data) for deriving response values; and [field access](https://riducms.com/docs/access-control/#sibling-data) for row-scoped authorization. Reading a sibling does not itself enforce a rule: conditions are presentation, while access and hooks run on the server. ## Nested fields {#nested-fields} Use [Group](https://riducms.com/docs/fields/group/) for one known object, [Array](https://riducms.com/docs/fields/array/) for ordered rows with one shape, and [Blocks](https://riducms.com/docs/fields/blocks/) for an ordered union. Named [Tabs](https://riducms.com/docs/fields/tabs/) also create an object; unnamed tabs affect only presentation. ```go field.Group("seo", field.Fields( field.Text("title"), field.Textarea("description"), )), field.Array("links", field.Fields( field.Text("label", field.Required()), field.Text("url", field.Required()), ), field.MaxRows(12)), ``` Nested fields generate typed contracts, validate precise paths, support migrations and queries, and render structured controls. Prefer them over JSON when the shape is known. ## Authoring layout {#authoring-layout} Rows, collapsibles, unnamed tabs, and UI fields organise authors without nesting stored values. Named tabs and Groups do create a stored boundary. `ReadOnly` and `Hidden` are also presentation, not authorization. ```go field.Row( field.Text("firstName", field.Columns(6)), field.Text("lastName", field.Columns(6)), ), field.Collapsible("advanced", true, field.JSON("providerMetadata"), ), ``` The stored paths remain `firstName`, `lastName`, and `providerMetadata`. ## Relationships {#relationships} [Relationship](https://riducms.com/docs/fields/relationship/) stores one/many references to one or several collection targets. [Upload](https://riducms.com/docs/fields/upload/) is the focused reference to one upload-enabled collection. Option filters narrow author choices and are revalidated on the server, but target read access is still required. Population replaces stored references with access-checked target documents only when requested. Use [Join](https://riducms.com/docs/fields/join/) for an inverse view rather than keeping two ID lists synchronized. See [Relationships, joins, and population](https://riducms.com/docs/relationships/) for cardinality, delete behavior, atomic join mutation, and read limits. ## Upload and rich-text fields {#plugin-fields} An Upload field references a media document; it does not accept raw bytes. Create the media through the admin, multipart REST, or generated SDK upload methods. The official [Rich-text plugin](https://riducms.com/docs/rich-text/) uses a Plugin field with a portable versioned document, Go validation, generated types, and a statically paired Svelte/Lexical editor. ## Joins and computed fields {#joins-and-virtual-fields} Join and [Virtual](https://riducms.com/docs/fields/virtual/) values appear in generated output but never mutation input. A Join reads inverse relationships through target access. A Virtual calls a matching trusted `Computed` resolver and validates its result against `ValueString`, `ValueNumber`, `ValueBoolean`, or `ValueJSON`. Both run only when selected output needs them. ## Localization {#localized-fields} `Localized` requires application content locales. Put it on one scalar/reference when only that value varies, or on Group/Array/Blocks when the complete structure varies per locale. Container localization prevents fallback from mixing descendant values from different locale objects. Admin-interface translations for labels, descriptions, choices, blocks, tabs, and row names use their `*Translations` metadata and are independent from stored content localization. See [Content localization](https://riducms.com/docs/localization/). ## Field access and hooks {#field-access-and-hooks} `Collection.FieldAccess` maps canonical paths to executable read/write decisions; `Collection.FieldHooks` maps paths to lifecycle hooks. Presentation never substitutes for either. Filtered collection access remains in the atomic store query, while field read rules redact denied values after a document is admitted. Use `BeforeValidate` to normalize, `BeforeChange` for transaction-bound derived stored values, and `AfterChange` only when an external effect can safely be retried. Continue with [Access control](https://riducms.com/docs/access-control/) and [Hooks](https://riducms.com/docs/hooks/). ## Evolve a field safely {#schema-evolution} Adding an optional field is usually additive. Renames, kind/cardinality changes, removed choices or block types, narrowed relationship targets, new required constraints, and removed fields can need a data transform or coordinated migration. Run `ridu migrate create`, review the artifact, verify it against an isolated target, and rehearse production data before applying it. Never use development sync as a substitute for a deployment plan. ## Modelling patterns {#modelling-patterns} | Need | Prefer | | ------------------------------------------------------- | -------------------------------------------------------- | | Short or multi-line plain text | Text or Textarea | | Formatted portable document | Official Rich text plugin | | One known object / repeated one-shape rows / mixed rows | Group / Array / Blocks | | Fixed values / managed records | Select / Relationship | | Media reference | Upload to an upload-enabled collection | | Editor organisation without API nesting | Row, Collapsible, unnamed Tabs, Columns | | Derived response value | Root Virtual plus `Computed` resolver | | Reusable new value kind | Compiled Plugin field with exact generated/admin pairing | Prefer the narrowest shape that represents the domain. See the individual field pages for behavior and the [`field` API reference](https://riducms.com/reference/field/) for signatures. --- # Conditional fields Canonical URL: https://riducms.com/docs/fields/conditional-fields/ Use a field condition when one authoring control should appear only after another value makes it relevant. Conditions react immediately in the admin. They do not remove data, reject API input, or grant access. `field.Sibling` creates one typed condition. Attach it to the field being shown with `field.ShowWhenCondition`: ```go field.Text( "videoURL", field.ShowWhenCondition( field.Sibling("format", field.ConditionEquals, "video"), ), ) ``` Read that expression as: “show `videoURL` when the `format` field beside it equals `video`.” ## Start with string equality {#show-when} `field.ShowWhen(path, value)` is the concise form for one sibling string equality. This complete collection reveals `videoURL` when an author chooses the Video format: ```go title="content/posts.go" focus={19} package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) var Posts = ridu.Collection{ Slug: "posts", Fields: []field.Definition{ field.Text("title", field.Required()), field.Select( "format", field.OneOf("article", "video"), field.Default("article"), ), field.Text( "videoURL", field.ShowWhen("format", "video"), ), }, } ``` Use `ShowWhen` for this common string case. Use `Sibling` with `ShowWhenCondition` for booleans, numbers, several accepted values, negation, or combined rules. ## Understand sibling scope {#sibling-scope} A sibling path starts at the parent of the field being shown: - A root field reads another root field. - A field inside a Group reads from that Group. - A field inside an Array or Block reads from its own row, not another row. - A sibling path can descend through non-repeating Groups, such as `settings.kind`. - It cannot cross through an Array or Blocks field. Ridu rejects that path while resolving the configuration. The following condition is attached to `answers.explanation`. For the third answer row, `field.Sibling("settings.kind", ...)` reads `answers.2.settings.kind`. The separate `field.Document("archived", ...)` predicate always reads the root `archived` field: ```go title="content/questions.go" focus={18-21} package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) var Questions = ridu.Collection{ Slug: "questions", Fields: []field.Definition{ field.Checkbox("archived", field.Default(false)), field.Array("answers", field.Fields( field.Group("settings", field.Fields( field.Select("kind", field.OneOf("lesson", "question", "note")), )), field.Textarea( "explanation", field.ShowWhenCondition(field.All( field.Sibling("settings.kind", field.ConditionOneOf, "lesson", "question"), field.Not(field.Document("archived", field.ConditionEquals, true)), )), ), )), }, } ``` At the document root, `Sibling("status", ...)` and `Document("status", ...)` read the same value. Prefer `Sibling` when the rule should remain relative if those fields later move together into a Group or repeated row. Use `Document` when the rule intentionally depends on a root setting. ## Choose an operator {#operators} The comparison value must have the same scalar type as the referenced field. Ridu checks paths, types, and operand counts before the application starts. | Operator | Meaning | Values | | -------------------------- | ------------------------------------------------- | ----------- | | `field.ConditionEquals` | The current value equals the supplied value | Exactly one | | `field.ConditionNotEquals` | The current value differs from the supplied value | Exactly one | | `field.ConditionOneOf` | The current value equals any supplied value | One or more | Strings, booleans, and numbers are supported. For example: ```go field.Sibling("featured", field.ConditionEquals, true) field.Sibling("score", field.ConditionNotEquals, 0) field.Sibling("status", field.ConditionOneOf, "draft", "review") ``` Combine predicates with `field.All`, `field.Any`, and `field.Not`. `All` and `Any` require at least two children; `Not` wraps exactly one. ## Conditions are presentation only {#server-enforcement} A hidden field keeps its current form value and can still be submitted through REST, the SDK, or the Local API. This prevents toggling a controller field from silently deleting work, but it also means a condition is never a security or validation rule. Use the corresponding server contract when behavior must be enforced: | Requirement | Server-side API | | ---------------------------------------- | ------------------------------------------------------ | | Allow or redact a field based on its row | `ctx.SiblingData` in a `ridu.FieldAccess` rule | | Reject an invalid combination | `BeforeValidate` or a typed plugin-field validator | | Normalize or clear a submitted value | `BeforeValidate` through `ctx.Data` | | Derive a response-only value | A Virtual field resolver through `ctx.Document.Values` | See [reading sibling values](https://riducms.com/docs/fields/#sibling-data) for those contexts and the complete [row-scoped field access example](https://riducms.com/docs/access-control/#sibling-data). ## Troubleshooting {#troubleshooting} - If a nested condition reads the wrong value, confirm that the controlling field shares the same Group, Array row, or Block with the field being shown. Use `field.Document` for a root value. - If a condition never matches, check that the comparison type matches the referenced field. The boolean `true` is different from the string `"true"`. - If `ShowWhen` cannot express the comparison, switch to `ShowWhenCondition` and a typed `Sibling` predicate. - If an API caller can still write the hidden field, add field access or a hook. That behavior is intentional. See [`field.Sibling`](https://riducms.com/reference/field/condition-sibling/), [`field.Document`](https://riducms.com/reference/field/condition-document/), [`field.ShowWhenCondition`](https://riducms.com/reference/field/show-when-condition/), and [`field.ShowWhen`](https://riducms.com/reference/field/show-when/) for their exact signatures. --- # Text field Canonical URL: https://riducms.com/docs/fields/text/ Use `field.Text` for a short, unformatted string: a title, name, reference code, or single-line summary. It produces a `string` in generated Go, TypeScript, REST, and OpenAPI contracts and a single-line control in the admin. ## In the admin {#admin-behavior} ![A populated Title text field in the Ridu admin, with its required marker and field description.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/text.png) _Changing its label affects only the editor; changing `title` changes the stored and API path._ ## Smallest working example {#example} ```go title="content/posts.go" field.Text("title", field.Required()) ``` The document property is `title`. Authors see a label derived from that name unless you provide `field.Label("Post title")`. ## Validation and options {#options} ```go title="content/products.go" field.Text( "sku", field.Required(), field.MinLength(3), field.MaxLength(32), field.Unique(), field.Index(), field.Description("The identifier used by fulfilment."), ) ``` `MinLength` and `MaxLength` count the submitted string. `Required` rejects missing, null, and empty values. `Unique` is collection-wide and should describe a real business invariant; `Index` is for a field you regularly filter or sort. `Default`, `Localized`, `ReadOnly`, `Hidden`, `Sidebar`, `Columns`, conditions, labels, descriptions, placeholders, and a paired `AdminComponent` are also compatible. Presentation options do not grant access. Protect sensitive strings with field access rules even when the admin hides or disables the control. ## Querying and localization {#querying} Text fields support string operators such as equality, containment, and `like`, plus sorting and selection. Use the canonical field path (`title` or `seo.title`) in Local API and REST queries; the generated SDK exposes that path in its `where` type. `field.Localized()` stores one value per configured content locale. Required and unique checks are evaluated per locale, and reads obey the request's locale and fallback chain. Do not add `Localized` merely to translate the admin label—use `LabelTranslations` for interface copy. ## Common mistakes {#troubleshooting} - Use [Textarea](https://riducms.com/docs/fields/textarea/) for multi-line plain text and [Rich text](https://riducms.com/docs/rich-text/) for formatted documents. - A field rename changes stored data and generated APIs. Create a reviewed migration instead of changing the string literal casually. - `ReadOnly` and `Hidden` affect only the admin. They do not prevent API writes. - For an automatically generated URL identifier, use [Slug](https://riducms.com/docs/fields/slug/) rather than rebuilding slug hooks around a plain text field. See [`field.Text`](https://riducms.com/reference/field/text/) and the shared [field options](https://riducms.com/docs/fields/#field-options). --- # Textarea field Canonical URL: https://riducms.com/docs/fields/textarea/ Use `field.Textarea` for multi-line **plain text** such as a synopsis, internal note, or address. It stores a string—the line breaks are part of that string—and renders a larger text control in the admin. ## In the admin {#admin-behavior} ![A populated Summary textarea in the Ridu admin showing a focused multi-line plain-text control.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/textarea.png) _Line breaks remain part of one string; the control does not create rich-text structure._ ## Smallest working example {#example} ```go title="content/posts.go" field.Textarea("summary", field.MaxLength(280)) ``` Create and update inputs accept `summary: string`; optional fields may be omitted. Reads return the same plain string through REST, the Local API, and the generated SDK. ## A realistic configuration {#options} ```go title="content/reviews.go" field.Textarea( "editorNote", field.Required(), field.MinLength(10), field.MaxLength(2_000), field.Placeholder("Explain what must change before publication…"), field.Sidebar(), ) ``` Textarea fields accept the common string options: `Required`, `MinLength`, `MaxLength`, `Default`, `Localized`, `Unique`, `Index`, and the shared admin options. Use uniqueness only for a genuine invariant; long prose is rarely an appropriate indexed or unique key. Localization stores an independent string per content locale. Admin-language translations for the label, description, or placeholder are separate and do not localize content. ## Constraints and querying {#querying} String filters work as they do for [Text](https://riducms.com/docs/fields/text/), including equality, containment, `like`, selection, and sorting. Long text queries are not relevance-ranked search. Build a search index outside this field when your application needs stemming, ranking, or language analysis. Textarea does not parse Markdown or HTML and does not sanitize it for rendering. Escape plain text in your frontend. If authors need formatting, links, uploads, or structured blocks, use the [Rich-text plugin](https://riducms.com/docs/rich-text/) or [Blocks](https://riducms.com/docs/fields/blocks/). ## Common mistakes {#troubleshooting} - Do not store an object or arbitrary array in a textarea; use [JSON](https://riducms.com/docs/fields/json/) or model the shape with fields. - `MaxLength` limits characters accepted by Ridu; it does not visually truncate the control. - Hiding a note in the admin is not a field access rule. See [`field.Textarea`](https://riducms.com/reference/field/textarea/) and [access control](https://riducms.com/docs/access-control/). --- # Email field Canonical URL: https://riducms.com/docs/fields/email/ Use `field.Email` when a document property is an email address. It retains a string value contract but adds server-side email-shape validation and an email control in the admin. ## In the admin {#admin-behavior} ![A populated Contact email field in the Ridu admin.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/email.png) _The email input and server share shape validation; the stored value remains a string._ ## Smallest working example {#example} ```go title="content/contacts.go" field.Email("contactEmail", field.Required()) ``` The operation engine validates requests from every transport, not only values entered in the admin. Invalid input produces a `422 validation` response with an issue at `contactEmail`. ## Options and behavior {#options} ```go title="content/teams.go" field.Email( "billingEmail", field.Required(), field.Unique(), field.Description("Invoices and payment notices are sent here."), ) ``` Email supports common string-field presentation, default, localization, uniqueness, and indexing options. Use `Unique` when one address must identify at most one document in that collection. An email field does not send mail, verify ownership, or make a collection authenticate users; those are separate application and [authentication](https://riducms.com/docs/authentication/) concerns. Email values can be selected, sorted, and queried with the string filter vocabulary. A localized email is valid when each locale genuinely needs a different address; translating the label uses `LabelTranslations` instead. ## Common mistakes {#troubleshooting} - Syntactic validation does not confirm that an inbox exists or belongs to the actor. Use a verification workflow for that claim. - Normalize addresses according to your product policy before relying on uniqueness. Ridu does not invent provider-specific equivalence rules such as stripping dots or `+` suffixes. - A collection with an `email` field is not automatically an auth collection. Set `Auth: true` and configure its access and account workflows. See [`field.Email`](https://riducms.com/reference/field/email/) and [Authentication](https://riducms.com/docs/authentication/). --- # Code field Canonical URL: https://riducms.com/docs/fields/code/ Use `field.Code` for source text, templates, queries, or configuration where syntax-aware authoring is useful. It stores a string; Ridu does not execute, compile, or trust the value. ## In the admin {#admin-behavior} ![A populated TypeScript Source code field in the Ridu admin.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/code.png) _Language changes highlighting only; stored source remains an unexecuted string._ ## Smallest working example {#example} ```go title="content/snippets.go" field.Code("source", field.Language("typescript"), field.Required()) ``` `Language` is an editor hint. It does not validate that the source parses and does not transform the returned string. ## Options and constraints {#options} Code accepts string length constraints, a string default, localization, indexing/uniqueness, and the common admin options. Only Code accepts `field.Language`; applying it to Text or Textarea is a configuration error reported by `ridu.Resolve`. ```go title="content/templates.go" field.Code( "template", field.Language("html"), field.MaxLength(50_000), field.Description("Rendered by the application after its own validation."), ) ``` Queries use the string operators. Localization can be useful for locale-specific templates, but be explicit about fallback behavior when a missing translation would change execution or presentation. ## Security and troubleshooting {#troubleshooting} - Treat code values as untrusted content. Never pass them to `eval`, a shell, a template engine, or a database without an application-owned parser, allowlist, and resource bounds. - Syntax highlighting is not syntax validation. Add a hook or plugin validator when valid source is a business requirement. - Use [JSON](https://riducms.com/docs/fields/json/) when machines need structured configuration rather than source text, and Rich text when authors need formatted prose. See [`field.Code`](https://riducms.com/reference/field/code/) and [`field.Language`](https://riducms.com/reference/field/language/). --- # Date field Canonical URL: https://riducms.com/docs/fields/date/ Use `field.Date` for a calendar day, wall-clock time, or absolute timestamp. Date values remain strings on the wire so their format and timezone meaning stay explicit. ## In the admin {#admin-behavior} ![A populated Publication date field beside its open September 2026 calendar in the Ridu admin.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/date.png) _Picker appearance also selects the wire format; this day-and-time value is stored as an RFC 3339 timestamp._ ## Choose the value shape {#example} ```go title="content/events.go" field.Date( "startsAt", field.Required(), field.PickerAppearance(field.DatePickerDayAndTime), ) ``` | Appearance | Accepted value | Use it for | | ---------------------- | --------------------- | ------------------------------------------------- | | `DatePickerDayOnly` | `YYYY-MM-DD` | Birthdays, release days, and other calendar dates | | `DatePickerDayAndTime` | RFC 3339 timestamp | An instant such as `2027-06-10T09:30:00Z` | | `DatePickerTimeOnly` | `HH:mm` or `HH:mm:ss` | A local opening time without a date | The selected appearance controls both server validation and the admin control. Omitting it uses the default; set it when consumers depend on one shape. ## Options, querying, and localization {#options} Date supports `Required`, string defaults, localization, uniqueness/indexing, and common admin options. Filters and sorts compare normalized accepted date strings. Use RFC 3339 with an explicit offset for day-and-time values; convert for display in the consumer rather than removing timezone information before storage. A localized date is appropriate only when the underlying content really differs by locale. A single event instant usually should not be localized merely because each audience formats it differently. ## Common mistakes {#troubleshooting} - Do not send a JavaScript `Date` object directly. Serialize a day/time string matching the chosen appearance. - A day-only value has no timezone. Do not convert it through midnight UTC and accidentally move it to another day. - Time-only values need an application-owned timezone and recurrence model if they represent store hours or schedules. See [`field.Date`](https://riducms.com/reference/field/date/), [`field.PickerAppearance`](https://riducms.com/reference/field/picker-appearance/), and [querying](https://riducms.com/docs/querying/). --- # Relationships, joins, and population Canonical URL: https://riducms.com/docs/relationships/ Relationship fields store forward references. Join fields derive the inverse view by querying a target collection. Population replaces stored references with authorized target documents in an operation response. This distinction determines storage, mutation, and read cost. ## Store one relationship {#one} ```go field.Relationship("author", field.To("users"), field.Required(), field.OnDelete(field.ReferenceDeleteRestrict), ) ``` The stored value is the target document ID. The target collection must exist, and writes validate that the selected document exists, passes target read access, and satisfies any option filter. A required reference cannot use nullify-on-delete because automatic cleanup would create a value ordinary validation rejects. ## Store many or polymorphic relationships {#many-polymorphic} Use `ToMany` for a list to one collection, or combine `ToAny` and `HasMany` for a polymorphic list: ```go field.Relationship("reviewers", field.ToMany("users")) field.Relationship("subjects", field.ToAny("posts", "media"), field.HasMany(), ) ``` A polymorphic wire value carries both the target collection and document ID so an ID collision between collections is unambiguous. Generated TypeScript keeps that discriminated shape. Singular and list cardinality are schema contracts; changing them requires a reviewed migration. Relationship and upload references can be localized. The selected locale controls which forward reference is read or changed, and population uses the same locale/fallback chain. ## Narrow author choices {#option-filters} Option filters derive server-validated predicates from the current document. A category can, for example, limit an editor picker to users with a matching category: ```go field.Relationship("editor", field.To("users"), field.FilterOptionRules( field.OptionFilter("category", field.FilterEquals, "category"), ), ) ``` Add more rules for multiple conditions, or use `OptionFilterFor` for polymorphic targets. Supported comparisons are equals, not-equals, like, contains, and ordered greater/less variants. The admin uses these predicates when listing choices, and the operation engine revalidates them on write. They never grant target read access. A target must pass both ordinary authorization and the option predicate; hiding a picker is not security. ## Choose delete behavior {#delete-behavior} `OnDelete` controls current documents when a target is permanently deleted: | Action | Behavior | | ------------------------- | ------------------------------------------------------------- | | `ReferenceDeleteNullify` | Clear a singular value or remove matching members from a list | | `ReferenceDeleteRestrict` | Reject the target deletion while a surviving reference exists | Cascade is not supported. Required references resolve to restrict. Version snapshots are immutable and are not rewritten when a current target is deleted; restoring old content can therefore expose a historical reference that must still pass current validation and access rules. Soft deletion moves the target into trash rather than applying permanent-delete cleanup. Plan retention and restore behavior before choosing nullify versus restrict. ## Add an inverse join {#inverse-join} Suppose each post stores `category`. A category can display the posts that point back to it without duplicating IDs: ```go ridu.Collection{ Slug: "categories", Fields: []field.Definition{ field.Text("name", field.Required()), field.Join("posts", "posts", "category", field.JoinLimit(20), field.JoinColumns("title", "status", "updatedAt"), field.JoinDefaultSort("-updatedAt"), field.JoinAllowCreate(true), ), }, } ``` Join fields are read-only computed output and are supported on collections, not globals. The target path must be a compatible relationship back to the source collection. `JoinLimit` is between 1 and 100. Columns, default sort, and inline-create preference configure the admin table; they do not authorize target reads or creates. Reads query the target collection through its access rule, hooks, localization, and redaction. Callers can omit expensive join output with the local API's `OutputFields` selection. ## Mutate a join atomically {#mutate-join} The join itself is derived, so changing membership updates the target documents' forward field. Use the delta operation: ```ts const result = await client.mutateJoin('categories', category.id, 'posts', { additions: ['post_123', 'post_456'], removals: ['post_789'] }); console.log(result.added, result.removed, result.doc.posts); ``` One request accepts between 1 and 100 unique target IDs. The same ID cannot appear in both deltas. Ridu locks and rechecks the source and targets, requires source-field visibility plus target update access, runs every target update through normal validation/hooks, and rolls the complete set back on failure. A concurrent reparent produces `conflict` rather than silently stealing membership. ## Populate forward references {#population} Without population, a relationship returns its stored ID/reference. Ask for target documents only when the response needs them: ```ts const post = await client.find('posts', 'post_123', { populate: { author: { depth: 1, select: { name: true, avatar: true } } } }); ``` Population batches work, reapplies target access and field redaction, respects localization, and supports nested relationships under groups, arrays, and blocks. The operation-wide limits are 64 explicit paths, depth 5, 256 expanded schema paths, and 4,096 materialized related documents. See [Querying data](https://riducms.com/docs/querying/#populate) for REST encoding and cost controls. ## Migration implications {#migrations} Removing or narrowing a target list, changing cardinality, removing a relationship, or shrinking a nested root can leave current values or version snapshots that later bind to reused identities. Ridu's migration planner rejects these unsafe reference-shape changes. Add targets additively where possible. For destructive changes, use an application-owned data transition, verify it on restored data, then create the schema artifact. Confirmed collection/field renames use stable identity and schema-addressed rewrites. Read [PostgreSQL migrations](https://riducms.com/docs/migrations/) before evolving live relationships. See [Fields](https://riducms.com/docs/fields/) for all constructors and the [`field` reference](https://riducms.com/reference/field/) for exact typed options. --- # Number field Canonical URL: https://riducms.com/docs/fields/number/ Use `field.Number` for a finite JSON number: a price, score, quantity, percentage, or measurement. Generated TypeScript uses `number`; numeric strings are not accepted. ## In the admin {#admin-behavior} ![A populated Priority number field in the Ridu admin with bounded numeric input.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/number.png) _Bounds constrain the editor and server; the API accepts JSON numbers, not numeric strings._ ## Smallest working example {#example} ```go title="content/products.go" field.Number("price", field.Required(), field.Min(0)) ``` Submitting `"19.99"` as a string is invalid. Send `19.99` as a JSON number. ## Bounds and increments {#options} ```go title="content/reviews.go" field.Number( "rating", field.Required(), field.Min(1), field.Max(5), field.Step(0.5), field.Default(3), ) ``` `Min` and `Max` include their boundary. `Step` declares the allowed increment and informs the admin control. All submitted values must be finite; `NaN` and infinities are not JSON values and are rejected before storage. Number also supports localization, uniqueness/indexing, conditions, and the shared presentation options. Number filters include equality and ordered comparisons, and numeric fields can be sorted. A localized number has an independent value per content locale; use it for genuinely locale-specific content such as a regional price, not display formatting. ## Common mistakes {#troubleshooting} - JSON numbers are floating-point values at the TypeScript boundary. For currency that requires exact minor units, store an integer amount (for example cents) and document that unit. - A placeholder such as `0` is not a default. Use `field.Default(0)` when the value must be written on create. - `Step` is a value constraint, not a rounding instruction. Normalize application calculations before submission. See [`field.Number`](https://riducms.com/reference/field/number/) and [query operators](https://riducms.com/docs/querying/). --- # Checkbox field Canonical URL: https://riducms.com/docs/fields/checkbox/ Use `field.Checkbox` for a boolean property such as `featured`, `archived`, or `requiresReview`. The document value is the JSON boolean `true` or `false`, and the admin shows a checkbox/toggle control. ## In the admin {#admin-behavior} ![A checked Feature this example checkbox in the Ridu admin.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/checkbox.png) _The control writes a JSON boolean, so API callers must send `true` or `false` rather than form strings._ ## Smallest working example {#example} ```go title="content/posts.go" field.Checkbox("featured", field.Default(false)) ``` Use a boolean default when callers that omit the property should receive a concrete initial value. Without `Required` or a default, omission and an explicit `false` have different create-input meanings. ## Conditional authoring {#options} ```go title="content/posts.go" field.Checkbox("sponsored", field.Default(false)), field.Text( "sponsorName", field.ShowWhenCondition( field.Sibling("sponsored", field.ConditionEquals, true), ), ), ``` Conditions only change what the admin displays. A hidden `sponsorName` still exists in submitted data and remains subject to validation, access, and hooks. Enforce a cross-field business rule in validation or a hook when `sponsorName` must be empty unless `sponsored` is true. Read [Conditional fields](https://riducms.com/docs/fields/conditional-fields/) for sibling scope, typed operators, root-document conditions, compound expressions, and server-side enforcement. Checkbox supports `Required`, boolean `Default`, localization, indexing/uniqueness where meaningful, and common presentation options. Query it with boolean equality rather than the strings `"true"` or `"false"`. ## Common mistakes {#troubleshooting} - HTML form libraries often submit strings or omit unchecked controls. Convert them to an explicit boolean before calling the SDK. - `ReadOnly` does not prevent an API mutation. Use field access for server authorization. - Do not use a checkbox for three states. Model an explicit [Select](https://riducms.com/docs/fields/select/) choice when `unknown` is a real business value. See [`field.Checkbox`](https://riducms.com/reference/field/checkbox/) and the shared [field options](https://riducms.com/docs/fields/#field-options). --- # Select field Canonical URL: https://riducms.com/docs/fields/select/ Use `field.Select` when a value must come from a finite set. It renders a dropdown for one choice and a multi-select when you add `field.Multiple()`. Generated TypeScript narrows input and output to the configured string values instead of a free-form `string`. ## In the admin {#admin-behavior} ![An open multiple Status select in the Ridu admin showing In review and Published as selected choices.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/select.png) _The menu displays labels; stored and generated values use the configured choice keys._ ## Smallest working example {#example} ```go title="content/posts.go" field.Select( "status", field.OneOf("draft", "review", "published"), field.Default("draft"), ) ``` `OneOf` derives labels from the stored values. Use `Choices` when author-facing labels should differ: ```go title="content/posts.go" field.Select( "visibility", field.Choices( field.Choice{Value: "public", Label: "Everyone"}, field.Choice{Value: "members", Label: "Signed-in members"}, ), ) ``` Values are stable data; labels and `LabelTranslations` are presentation. Changing `members` to `registered` is a data/API migration, while changing its label is not. ## Multiple choices {#multiple} ```go title="content/posts.go" field.Select( "channels", field.OneOf("web", "email", "social"), field.Multiple(), field.DefaultChoices("web", "email"), ) ``` Multi-selects store an ordered list of unique configured values. Use `DefaultChoices` rather than the scalar `Default`. `Radio` cannot be multiple. ## Validation, queries, and localization {#options} At least one non-empty unique choice is required. Defaults must be in the choice list. Select also supports `Required`, localization, indexing/uniqueness where appropriate, conditions, and common admin options. Query single choices with scalar equality/inequality and multi-selects with the generated list-aware operators. Localizing the field stores different selected values per content locale; translating choice labels alone uses `Choice.WithLabelTranslations`. ## Common mistakes {#troubleshooting} - Do not use labels as API values. Submit the exact `Value` string. - Adding a choice is additive; removing or renaming a value requires a migration for existing data. - Use [Relationship](https://riducms.com/docs/fields/relationship/) when choices are managed documents rather than a fixed list compiled into config. See [`field.Select`](https://riducms.com/reference/field/select/), [`field.Choices`](https://riducms.com/reference/field/choices/), and [`field.Multiple`](https://riducms.com/reference/field/multiple/). --- # Content localization Canonical URL: https://riducms.com/docs/localization/ Ridu localizes authored content, not its application code. A field opts into locale-specific stored values while unlocalized fields remain shared. The selected locale flows through reads, writes, filters, counts, sorting, relationships, access rules, hooks, drafts, versions, duplication, and the admin. Content locale and admin interface language are independent. Content localization controls stored values and request projection. `Admin.Localization` controls statically bundled interface catalogs, translated application labels, text direction, and the timezone used for `Intl` date/number formatting. An editor may author French content while using the English interface. ## Configure locales {#configure} Declare an ordered locale list and a default locale on the application config: ```go title="content/config.go" func Config() ridu.Config { return ridu.Config{ Name: "Editorial", Localization: ridu.LocalizationConfig{ DefaultLocale: "en", Locales: []ridu.Locale{ {Code: "en", Label: "English"}, {Code: "fr", Label: "Français", FallbackLocales: []schema.LocaleCode{"en"}}, {Code: "ar", Label: "العربية", RTL: true, FallbackLocales: []schema.LocaleCode{"en"}}, }, }, Collections: []ridu.Collection{Posts}, } } ``` Locale codes are case-sensitive stable identifiers. Resolution rejects empty or duplicate codes, unknown defaults and fallback targets, self-fallback, cycles, and request-reserved tokens such as `all`, `*`, `false`, `none`, and `null`. Fallback is enabled by default. Set `DisableFallback: true` globally when exact-locale reads should be the default; individual requests can still provide their own explicit chain. ## Mark fields as localized {#localized-fields} Use `field.Localized()` on scalar, relationship, upload, nested, or plugin fields that support stored content: ```go title="content/posts.go" add={5,7,10} var Posts = ridu.Collection{ Slug: "posts", Fields: []field.Definition{ field.Text("slug", field.Required(), field.Unique()), field.Text("title", field.Required(), field.Localized()), field.Group("seo", field.Fields( field.Text("title", field.Localized()), field.Text("canonicalURL"), )), field.Relationship("editor", field.To("users"), field.Localized()), }, } ``` Putting `Localized()` on a group, array, or blocks field localizes the complete parent value. Localized descendants under an unlocalized parent are independently localized. Ridu preserves array and block row identity when another locale is edited. A required localized field is validated for the locale being written; one mutation does not need to provide every translation. Locale-scoped unique fields enforce uniqueness within each locale. ![A focused Ridu Article editor in the French content locale, showing inherited English title and summary values beside shared relationship and upload fields.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/ridu-admin-localization.png) _The interface remains English while the content locale is French. “Inherited from English” shows the fallback source before an author writes a French value._ ## Read one locale {#read-one} An omitted locale selects the configured default. The SDK accepts a locale and either an explicit fallback chain or `false` for an exact read: ```ts const french = await client.find('posts', 'post_123', { locale: 'fr', fallbackLocale: ['en'] }); const exactFrench = await client.find('posts', 'post_123', { locale: 'fr', fallbackLocale: false }); ``` REST uses `locale=fr` and `fallback-locale=en` (or the camel-case `fallbackLocale` alias). The local Go API uses `ridu.LocaleOptions` or the locale fields on list/find/mutation options. Fallback happens after the target document passes access filtering. It cannot expose a value from an unauthorized row or reintroduce a redacted field. The REST document includes `_localization.sources`, keyed by authored field path, so an editor or frontend can distinguish an exact value from an inherited fallback. An empty string remains visible in an exact read but counts as missing when fallback is enabled. ## Read every locale {#read-all} Use `locale: 'all'`, REST `locale=all` (or `*`), or `AllLocales: true` to receive locale-keyed values for localized fields. Shared fields keep their ordinary shape: ```json title="All-locales response fragment" { "id": "post_123", "slug": "hello-ridu", "title": { "en": "Hello, Ridu", "fr": "Bonjour, Ridu", "ar": "مرحباً Ridu" } } ``` All-locale reads apply field access inside every locale and population branch. Ordinary create and update requests cannot target `all`; write one selected locale or use the dedicated copy operation. Generated TypeScript distinguishes a literal `locale: 'all'` call from a single-locale call. When a runtime variable may contain either shape, the result remains the corresponding union and consumer code must narrow it rather than casting an all-locale result to a single-locale document. ## Write without erasing translations {#write} Writing one locale changes only that locale's localized values. Unlocalized values update normally, and stored values for other locales are preserved: ```ts await client.update('posts', 'post_123', { title: 'Bonjour, Ridu' }, { locale: 'fr', revision: 7 }); ``` Filters, counts, sort, relationships, uploads, versions, drafts, restore, duplicate, trash, and publishing all use the same selected locale contract. Historical version snapshots retain the localized state needed for a faithful restore. ## Copy a locale {#copy-locale} Copying is an explicit mutation rather than a read-and-write performed in the browser: ```ts await client.copyLocale('posts', 'post_123', { from: 'en', to: 'fr' }, { revision: 7 }); ``` Ridu checks source read access, destination write access, validation, and optimistic concurrency in one transaction. The local API exposes `CopyLocale`; REST uses `POST /api/collections/{collection}/{id}/copy-locale`. Globals have matching local, REST, and SDK operations. ## Limit locales per author {#available-locales} `AvailableLocales` is an executable Go callback that can reduce the locale list shown to one authenticated admin user. It receives the actor, exact auth collection, context, and local API. The callback is never serialized into the manifest. This is presentation availability, not authorization. API requests still validate against the configured locale set, and field/collection access rules remain responsible for protecting values. Returning an unknown, duplicate, or empty locale list fails closed with `locale_availability_failed`. ## Configure the admin interface language {#admin-language} Ridu publishes complete English, French, and Arabic catalogs in `@riducms/translations`. Declare the languages and editor timezones in Go, then statically pass matching catalogs to `mountAdmin`. The Go manifest carries only deterministic language/timezone metadata; translated message catalogs remain compiled TypeScript modules. ```go title="content/config.go" Admin: ridu.AdminConfig{ User: "users", Localization: ridu.AdminLocalizationConfig{ Languages: []ridu.AdminLanguage{ {Code: "en", Label: "English"}, {Code: "fr", Label: "Français"}, {Code: "ar", Label: "العربية", RTL: true}, }, DefaultLanguage: "en", TimeZones: []ridu.AdminTimeZone{ {ID: "UTC", Label: "UTC"}, {ID: "Europe/Paris", Label: "Paris"}, }, DefaultTimeZone: "UTC", }, }, ``` Install the direct admin dependency if the project does not already declare it: ```bash title="terminal" package-manager="bun" bun add --cwd admin @riducms/translations ``` ```bash title="terminal" package-manager="npm" npm install --workspace admin @riducms/translations ``` ```bash title="terminal" package-manager="pnpm" pnpm --dir admin add @riducms/translations ``` ```bash title="terminal" package-manager="yarn" yarn --cwd admin add @riducms/translations ``` ```ts title="admin/src/main.ts" import { mountAdmin } from '@riducms/admin'; import { ar, en, fr } from '@riducms/translations'; import { createClient, type RiduConfig } from '../../generated/ridu.generated'; import { adminPlugins } from '@/plugins'; mountAdmin({ target: document.getElementById('app')!, clientFactory: () => createClient({ baseURL: window.location.origin }), plugins: adminPlugins, languages: [en, fr, ar] }); ``` Configured Go language codes must have matching static catalogs, including the same RTL setting; the admin fails closed on a missing or conflicting catalog. `defineTranslationLanguage` and `extendTranslationLanguage` support complete application-owned catalogs. Admin plugins may ship namespaced translated messages without mutating Ridu's core catalog. Fields, choices, blocks, tabs, collection/global labels, application name, and timezone labels have typed `*Translations` metadata. The active interface language selects that metadata while preserving the canonical fallback text. Authors choose language and timezone in their account settings; Ridu stores the preference and uses `Intl` plural, number, relative-time, and date formatting. ## Admin behavior and current boundary {#admin} The admin remembers an author's locale preference, shows each fallback source, preserves dirty state across locale switches, requires an explicit decision before saving inherited content, and sets right-to-left editing direction for RTL locales, including rich text. Locale-specific draft status is not a Ridu contract: a document's draft/published status applies to the document rather than independently to each locale. Interface language does not automatically translate application-authored content, and content locale does not override the editor's selected interface language or timezone. See [Querying data](https://riducms.com/docs/querying/) for locale-aware filters and population, [Access control](https://riducms.com/docs/access-control/) for locale context in rules, and the [`core` reference](https://riducms.com/reference/core/) for exact Go fields. --- # Radio field Canonical URL: https://riducms.com/docs/fields/radio/ Use `field.Radio` for a small set of mutually exclusive choices that authors should see without opening a dropdown. Its stored and generated contract is the same singular string union as [Select](https://riducms.com/docs/fields/select/); only the admin control differs. ## In the admin {#admin-behavior} ![A Tone radio field in the Ridu admin with Friendly selected from three visible choices.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/radio.png) _Labels remain interface copy; the document stores one configured choice value._ ## Smallest working example {#example} ```go title="content/posts.go" field.Radio( "priority", field.OneOf("low", "normal", "high"), field.Default("normal"), ) ``` For clearer author copy, configure explicit choices: ```go title="content/events.go" field.Radio( "attendance", field.Choices( field.Choice{Value: "remote", Label: "Join online"}, field.Choice{Value: "venue", Label: "Attend at the venue"}, ), field.Required(), ) ``` Radio supports singular `Default`, `Required`, localization, indexing/uniqueness, conditions, and common presentation options. It does not accept `Multiple` or `DefaultChoices`; use Select for multiple values. Queries and generated types use stored values, never labels. Choice labels may be translated for the admin without localizing the content value. Add `field.Localized()` only when different locales may select different business values. ## Common mistakes {#troubleshooting} - Too many radio choices create a slow form. Switch to Select or a Relationship picker as the set grows. - Renaming a `Choice.Value` is a data migration. Changing `Label` is safe presentation copy. - `ShowWhen` can improve the form but cannot enforce a cross-field rule or access policy. See [`field.Radio`](https://riducms.com/reference/field/radio/) and [Select](https://riducms.com/docs/fields/select/) for the full choice contract. --- # Access control Canonical URL: https://riducms.com/docs/access-control/ ## Access decisions {#decisions} A collection rule receives the actor, operation, target ID, submitted data, locale, and local API. Return `ridu.Allow()` or `ridu.Deny()` for any rule. Return `ridu.Where(expression)` only where Ridu can attach a document predicate to an atomic document read, version-history read, update, delete, or unlock query. Keep reusable rules in an ordinary Go file beside your content model. This example allows anyone to read, requires a session to create, and builds an ownership predicate from the authenticated document ID. ```go title="content/access.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/query" "github.com/riducms/ridu/store" ) func publicRead(ridu.AccessContext) (ridu.AccessDecision, error) { return ridu.Allow(), nil } func signedIn(ctx ridu.AccessContext) (ridu.AccessDecision, error) { if ctx.Actor == nil { return ridu.Deny(), nil } return ridu.Allow(), nil } func ownDocuments(path query.Path) ridu.AccessRule { return func(ctx ridu.AccessContext) (ridu.AccessDecision, error) { if ctx.Actor == nil { return ridu.Deny(), nil } return ridu.Where( query.Equal(path, query.String(ctx.Actor.ID)), ), nil } } func actorHasRole(actor *store.Document, allowed ...string) bool { if actor == nil { return false } role, ok := actor.Values["role"].StringValue() if !ok { return false } for _, candidate := range allowed { if role == candidate { return true } } return false } ``` ## Collection rules {#collection-rules} Attach those rules to the collection operation they protect. The path supplied to `ownDocuments` is the stored relationship field, so an author can update or delete only rows whose `author` ID matches their own document ID. ```go title="content/posts.go" add={24-30} package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" "github.com/riducms/ridu/query" ) func Posts() ridu.Collection { authorPath, err := query.NewPath("author") if err != nil { panic(err) } return ridu.Collection{ Slug: "posts", Fields: []field.Definition{ field.Text("title", field.Required()), field.Relationship("author", field.To("users"), field.Required()), field.Textarea("internalNotes"), }, Access: ridu.CollectionAccess{ Create: signedIn, Read: publicRead, Update: ownDocuments(authorPath), Delete: ownDocuments(authorPath), }, FieldAccess: postFieldAccess(), } } ``` This example keeps `Posts` as a function because it performs fallible path construction before it can return the collection. Ordinary static collection definitions should be package variables. ## Field access {#field-access} Field rules return a boolean. A denied write is rejected; a denied read is redacted from the returned document. Presentation options such as `field.ReadOnly()` are not authorization. Field-access map keys are authored field paths. `postFieldAccess()` is called by `Posts()` above, keeping the policy readable without hiding it in an anonymous collection literal. ```go title="content/field_access.go" package content import "github.com/riducms/ridu" func postFieldAccess() map[string]ridu.FieldAccess { return map[string]ridu.FieldAccess{ "internalNotes": { Create: func(ctx ridu.FieldAccessContext) (bool, error) { return actorHasRole(ctx.Actor, "admin"), nil }, Read: func(ctx ridu.FieldAccessContext) (bool, error) { return actorHasRole(ctx.Actor, "editor", "admin"), nil }, Update: func(ctx ridu.FieldAccessContext) (bool, error) { return actorHasRole(ctx.Actor, "admin"), nil }, }, } } ``` Here only administrators may create or update `internalNotes`; editors may read it. Omitting the `Create` rule would leave that write allowed by default, even if `Update` were restricted. ## Read sibling values in a field rule {#sibling-data} `ctx.SiblingData` contains the values beside the field currently being authorized. For a root field, that is the document's root value map. For a nested field, Ridu narrows it to that field's Group, Array row, or Block instance. This collection makes a link URL visible to everyone unless the checkbox in the same row marks it as members-only: ```go title="content/pages.go" focus={20-24} package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) var Pages = ridu.Collection{ Slug: "pages", Fields: []field.Definition{ field.Array("links", field.Fields( field.Text("label", field.Required()), field.Text("url", field.Required()), field.Checkbox("membersOnly", field.Default(false)), )), }, FieldAccess: map[string]ridu.FieldAccess{ "links.url": { Read: func(ctx ridu.FieldAccessContext) (bool, error) { membersOnly, _ := ctx.SiblingData["membersOnly"].BooleanValue() if !membersOnly { return true, nil } return ctx.Actor != nil, nil }, }, }, } ``` The map key remains the authored path `links.url`. When Ridu evaluates a particular row, `ctx.RuntimePath` is concrete—for example, `links.2.url`—and `SiblingData` is that row's `label`, `url`, and `membersOnly` values. It is a detached snapshot: changing it does not change the document. Use a hook when you intend to mutate submitted data. See [`ridu.FieldAccessContext`](https://riducms.com/reference/ridu/field-access-context/) for the current value, document, original document, locale, and transaction-reusing Local API available alongside sibling data. --- # Slug field Canonical URL: https://riducms.com/docs/fields/slug/ Use `field.Slug` for a URL-safe identifier derived from another string field. It uses text storage and generated `string` contracts, but is always required, collection-wide unique, and indexed. ## In the admin {#admin-behavior} ![A generated Slug field in the Ridu admin, populated from the document title.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/slug.png) _The value follows source edits until an author overrides it; **Generate slug** restores source-driven updates._ ## Smallest working example {#example} ```go title="content/posts.go" field.Text("title", field.Required()), field.Slug("slug", "title"), ``` When `slug` is omitted on create, Ridu derives it from `title`. Generated slugs follow later source edits. Once an author submits a different slug, that manual value remains stable. The admin's **Generate slug** action returns it to source-derived behavior. The source can be a direct string or a string beneath non-repeated groups, for example `seo.pageTitle`. It cannot traverse an array or blocks list. ## Normalization contract {#normalization} Ridu applies the same fixed normalization in the server and admin: ASCII letters become lowercase, digits and underscores remain, whitespace and hyphen runs become one hyphen, and other characters are removed. Requests that bypass the admin are normalized too. Use `field.NormalizeSlug` when application code needs the same result. ```go title="slug_test.go" got := field.NormalizeSlug(" Hello, Ridu! ") // got == "hello-ridu" ``` ## Constraints and migrations {#constraints} Slug fields cannot declare a default or `Localized`. Their source chain cannot be localized either. For locale-specific URLs, model separate explicit fields and routing rules. Labels, descriptions, conditions, and compatible string presentation options still work. A slug rename can break inbound URLs even when the database migration succeeds. Preserve redirects in the consuming application and decide whether old values must remain reserved. ## Common mistakes {#troubleshooting} - Do not duplicate `Required`, `Unique`, or `Index`; `Slug` already owns those guarantees. - Empty normalization (for example a title containing only removed characters) is invalid; require a usable source or let the author enter a manual value. - Do not expect Unicode transliteration. Normalization is ASCII and deterministic. See [`field.Slug`](https://riducms.com/reference/field/slug/) and [`field.NormalizeSlug`](https://riducms.com/reference/field/normalize-slug/). --- # JSON field Canonical URL: https://riducms.com/docs/fields/json/ Use `field.JSON` for JSON-compatible data whose shape is genuinely open or controlled by another system. It accepts null, booleans, finite numbers, strings, arrays, and objects and generates `unknown` in TypeScript so consumers must narrow the value before use. ## In the admin {#admin-behavior} ![A populated Metadata JSON editor in the Ridu admin with formatted object data.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/json.png) _Authors edit open JSON; generated TypeScript exposes `unknown`, requiring consumers to narrow it._ ## Smallest working example {#example} ```go title="content/integrations.go" field.JSON( "providerMetadata", field.Description("Opaque metadata returned by the connected provider."), ) ``` The admin provides a JSON authoring control and the operation engine rejects malformed/non-JSON values from every transport. ## When to model the shape instead {#model-the-shape} Prefer [Group](https://riducms.com/docs/fields/group/) when the object has known properties, [Array](https://riducms.com/docs/fields/array/) for repeated known rows, or [Blocks](https://riducms.com/docs/fields/blocks/) for an authored union. Explicit fields produce better validation, migrations, generated types, filters, access paths, and admin controls. JSON supports `Required`, `Localized`, conditions, and common presentation options. It does not accept scalar `Default`, length, numeric, choice, or relationship options. Define a plugin field when an open-looking value still needs a reusable validator and generated type. ## Querying and localization {#querying} Select or omit the JSON property as one value. The query API does not support JSON path operators. Promote fields you must filter or sort into the content model. `Localized` stores the whole JSON value independently per locale. Partial locale fallback applies to the field value, not recursively to individual object keys. ## Common mistakes {#troubleshooting} - Do not use JSON to avoid modelling a stable business object; consumers then lose generated contracts and path-aware validation. - JSON does not accept functions, `undefined`, `Date`, `Map`, circular values, `NaN`, or infinity. - Treat provider metadata as untrusted input even after JSON decoding. See [`field.JSON`](https://riducms.com/reference/field/json/) and [Generated contracts](https://riducms.com/docs/generated-contracts/). --- # Point field Canonical URL: https://riducms.com/docs/fields/point/ Use `field.Point` for one geographic coordinate. The portable value is a two-number array in **longitude, latitude** order: `[longitude, latitude]`. ## In the admin {#admin-behavior} ![A populated Location point field in the Ridu admin with longitude and latitude controls.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/point.png) _Separate inputs write a `[longitude, latitude]` tuple; coordinate order is part of the API._ ## Smallest working example {#example} ```go title="content/venues.go" field.Point( "location", field.Required(), field.Description("Drag the marker to the venue entrance."), ) ``` ```json title="document.json" { "location": [-0.1276, 51.5072] } ``` Longitude must be finite and between `-180` and `180`; latitude must be finite and between `-90` and `90`. Ridu rejects an array with the wrong length, reversed object-shaped coordinates, numeric strings, `NaN`, or infinities. ## Options and queries {#options} Point supports `Required`, `Localized`, conditions, descriptions, labels, layout options, and a paired custom admin component. It does not accept numeric `Min`, `Max`, or `Step`: coordinate bounds are part of the field contract. Select the point as one property. The Ridu query API does not expose raw PostGIS or MongoDB driver handles. Add an indexed search integration for radius, polygon, or route queries. Localization stores a separate coordinate pair per locale. This is unusual but useful when the content itself represents locale-specific offices; presentation formatting alone does not require localization. ## Common mistakes {#troubleshooting} - The order is longitude first. `[51.5072, -0.1276]` points somewhere else. - A Point is not a postal address, accuracy reading, or geometry collection. Model those as sibling fields or a Group. - Validate whether `0,0` is meaningful to your application; it is geographically valid and Ridu will not treat it as missing. See [`field.Point`](https://riducms.com/reference/field/point/) and [custom fields](https://riducms.com/guides/custom-fields/). --- # Group field Canonical URL: https://riducms.com/docs/fields/group/ Use `field.Group` for one object with a known shape: SEO metadata, an address, dimensions, or a reusable cluster of settings. Children become a nested type in generated Go and TypeScript contracts. ## In the admin {#admin-behavior} ![An expanded Search preview group in the Ridu admin with populated SEO title and description fields.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/group.png) _Grouped controls become one nested object, with child paths such as `seo.title`._ ## Smallest working example {#example} ```go title="content/posts.go" field.Group( "seo", field.Fields( field.Text("title", field.MaxLength(60)), field.Textarea("description", field.MaxLength(160)), ), ) ``` ```json title="document.json" { "seo": { "title": "A concise search title", "description": "A concise search description." } } ``` At least one child field is required. Child names must be unique within the group and form canonical paths such as `seo.title` and `seo.description`. ## Validation, queries, and localization {#options} Group supports `Required`, `Localized`, conditions, and common presentation options. Each child keeps its own validation, access, hooks, and admin metadata. Query nested stored children with their dotted path; the generated SDK exposes those canonical keys in its `where` contract. The group container also supports an `exists` filter. Localize individual children when only those values vary. Put `Localized` on the Group when the entire object varies as one locale value. A localized container falls back as a container instead of mixing child values from different locale objects. ## Common mistakes {#troubleshooting} - Use [Array](https://riducms.com/docs/fields/array/) when there can be several objects and [Blocks](https://riducms.com/docs/fields/blocks/) when rows have different shapes. - A Group changes the API path. Use [Row](https://riducms.com/docs/fields/row/) or [Collapsible](https://riducms.com/docs/fields/collapsible/) to organise controls without adding an object wrapper. - Renaming the group or a child is a stored-data and API migration. See [`field.Group`](https://riducms.com/reference/field/group/) and [`field.Fields`](https://riducms.com/reference/field/fields/). --- # Array field Canonical URL: https://riducms.com/docs/fields/array/ Use `field.Array` for an ordered list whose rows all have the same known shape: navigation links, credits, opening hours, or product variants. ## In the admin {#admin-behavior} ![An expanded Links array in the Ridu admin with two ordered, populated rows.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/array.png) _Rows can be reordered in the editor; the document preserves that order and one shared row shape._ ## Smallest working example {#example} ```go title="content/pages.go" field.Array( "links", field.Fields( field.Text("label", field.Required()), field.Text("url", field.Required()), ), field.MinRows(1), field.MaxRows(12), field.RowLabel("label"), ) ``` ```json title="document.json" { "links": [{ "label": "Documentation", "url": "/docs/" }] } ``` At least one child definition is required. `MinRows` may be zero, `MaxRows` must be at least one, and the minimum cannot exceed the maximum. `RowLabel` names a direct stored child used for an accessible row heading. ## Authoring and generated contracts {#options} Authors can add, reorder, duplicate, and remove rows within configured bounds. `ArrayRowLabels` changes singular/plural interface copy. A paired `RowLabelComponent` can render richer headings, but keep `RowLabel` as its text fallback and remember that a component changes presentation only. Generated types preserve the ordered row array. Validation issues include concrete indexes such as `links.2.url`. Nested queries use canonical paths such as `links.label`; the array container supports `exists`. Localize a child for per-row localized values or the Array container when each locale owns an independent list and ordering. Container localization prevents descendant locale mixing. ## Common mistakes {#troubleshooting} - Use [Blocks](https://riducms.com/docs/fields/blocks/) for a list of different row types. - Row order is data. Reordering can be meaningful even when every child value stays the same. - `RowLabel` must point to a direct stored child, not a nested path or presentation field. - An array can grow request and document size quickly; set a realistic `MaxRows`. See [`field.Array`](https://riducms.com/reference/field/array/), [`field.MinRows`](https://riducms.com/reference/field/min-rows/), and [`field.RowLabel`](https://riducms.com/reference/field/row-label/). --- # Blocks field Canonical URL: https://riducms.com/docs/fields/blocks/ Use `field.Blocks` for an ordered list that may contain different authored shapes: a page-builder layout, email sections, or a portable content stream. Every row stores a stable `blockType` discriminator and the fields declared by that block type. ## In the admin {#admin-behavior} ![An expanded Page layout Blocks field in the Ridu admin with populated Callout and Quote blocks.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/blocks.png) _Each row can use a different configured shape; `blockType` preserves its type in stored data and generated unions._ ## Smallest working example {#example} ```go title="content/pages.go" field.Blocks( "layout", field.BlockTypes( field.BlockType("hero", "Hero", field.Text("heading", field.Required()), field.Textarea("summary"), ), field.BlockType("quote", "Quote", field.Textarea("text", field.Required()), field.Text("source"), ), ), ) ``` ```json title="document.json" { "layout": [ { "blockType": "hero", "heading": "Build with Ridu" }, { "blockType": "quote", "text": "Content is structured data." } ] } ``` At least one block type is required. Keys must be unique lowercase kebab-case. A direct block child cannot be named `blockType` because Ridu owns that discriminator. ## Contracts, queries, and authoring {#options} Generated TypeScript exposes a discriminated union, so narrowing on `blockType` gives the exact fields for that row. Authors choose a block type, edit it, reorder the list, and may use a paired `RowLabelComponent` for richer row headings. Nested query paths include the block key, for example `layout.quote.source`; the container supports `exists`. Put `Localized` on a child for translated values within a shared layout or on Blocks when each locale owns its complete block selection and order. ## Common mistakes {#troubleshooting} - A block key is a persisted API discriminator. Renaming/removing one requires a reviewed data migration and consumer update. - Use [Array](https://riducms.com/docs/fields/array/) when every row has the same shape; it produces a simpler contract. - Blocks store structured content. Handle every generated union member in the frontend. See [`field.Blocks`](https://riducms.com/reference/field/blocks/), [`field.BlockType`](https://riducms.com/reference/field/block-type/), and [Generated contracts](https://riducms.com/docs/generated-contracts/). --- # Tabs field Canonical URL: https://riducms.com/docs/fields/tabs/ Use `field.Tabs` to divide a long editor into focused sections. A **named** tab stores its children under an object property; an **unnamed** tab changes only the admin layout and leaves child paths at their current level. ## In the admin {#admin-behavior} ![A Tabs field in the Ridu admin with the Content tab active and Settings available beside it.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/tabs.png) _Unnamed tabs alter layout only; named tabs add an object boundary to document paths._ ## Named and unnamed tabs {#example} ```go title="content/pages.go" field.Tabs( field.UnnamedTab("Content", field.Text("title", field.Required()), field.Blocks("layout", field.BlockTypes(/* … */)), ), field.NamedTab("seo", "Search & sharing", field.Text("title", field.MaxLength(60)), field.Textarea("description", field.MaxLength(160)), ), ) ``` The resulting document has root `title` and `layout` properties plus a nested `seo` object. Choose named tabs when the object boundary is meaningful to API consumers; choose unnamed tabs when only the authoring experience needs separation. Tab labels and `LabelTranslations` are admin-interface copy. They do not localize content. Configure `Localized` on stored child fields or on another nested container according to the value that actually varies. ## Constraints and common mistakes {#troubleshooting} - Every tab needs a label and fields. Named tab names must obey field-name rules and be unique at that level. - Presentation-only tabs do not grant access or change validation. Hidden fields still pass through the operation engine. - Changing an unnamed tab to a named tab changes document paths and requires a migration. Changing only its label does not. - For a few direct fields, the concise `field.Tab("Label")` option may be enough. Use Tabs when you want an explicit ordered set of sections or stored named objects. See [`field.Tabs`](https://riducms.com/reference/field/tabs/), [`field.NamedTab`](https://riducms.com/reference/field/named-tab/), and [`field.UnnamedTab`](https://riducms.com/reference/field/unnamed-tab/). --- # Relationship field Canonical URL: https://riducms.com/docs/fields/relationship/ Use `field.Relationship` when one document refers to another. Ridu validates target existence and read access at write time, stores stable references, and can populate authorized target documents in read responses. ## In the admin {#admin-behavior} ![A populated Author relationship field in the Ridu admin referencing the documentation user.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/relationship.png) _The picker shows the target label; stored data contains a reference that can be populated on read._ ## One target or many {#example} ```go title="content/posts.go" field.Relationship( "author", field.To("users"), field.Required(), field.OnDelete(field.ReferenceDeleteRestrict), ) ``` A singular relationship to one collection stores its document ID. Use `ToMany("users")` for an ordered list. Use `ToAny("posts", "media")` for a polymorphic relationship; its wire value carries both `relationTo` and `id`, so equal IDs in different collections are unambiguous. Add `HasMany()` for a polymorphic list. ## Narrow the author picker {#option-filters} ```go title="content/posts.go" field.Relationship( "reviewer", field.To("users"), field.FilterOptionRules( field.OptionFilter("team", field.FilterEquals, "editorialTeam"), ), ) ``` Option filters drive the admin picker **and** are revalidated on the server. They are not access rules: a candidate must pass target read access and every configured predicate. Static rules use `OptionFilterValue`; polymorphic rules can use `OptionFilterFor`. ## Deletion, querying, and localization {#behavior} `ReferenceDeleteNullify` clears an optional singular value or removes list members when the target is permanently deleted. `ReferenceDeleteRestrict` blocks that deletion while a current reference exists. Required references always restrict. Version snapshots remain immutable. Filter by IDs/reference shapes, select the stored reference, or request bounded `populate` through the Local API/SDK. Population reapplies target access, field redaction, localization, and depth limits. `Localized` stores an independent reference per content locale. ## Common mistakes {#troubleshooting} - The target collection must be declared, and upload-only semantics belong in [Upload](https://riducms.com/docs/fields/upload/). - Changing singular/many shape or removing a target is a destructive data-contract migration. - Picker visibility never replaces authorization. - Use [Join](https://riducms.com/docs/fields/join/) for the inverse view; do not duplicate both sides as manually synchronized ID lists. See [`field.Relationship`](https://riducms.com/reference/field/relationship/) and the complete [relationship and population guide](https://riducms.com/docs/relationships/). --- # Upload field Canonical URL: https://riducms.com/docs/fields/upload/ Use `field.Upload` when a document refers to media stored as an upload-enabled collection document. The file bytes belong to the configured storage backend; this field stores the media document reference. ## In the admin {#admin-behavior} ![A populated Cover upload field in the Ridu admin showing the selected field-guide image.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/upload.png) _The control selects a media document; the field stores its reference while bytes remain in object storage._ ## Define the target and field {#example} ```go title="content/media.go" var Media = ridu.Collection{ Slug: "media", Upload: true, Fields: []field.Definition{ field.Text("alt", field.Required()), }, } ``` ```go title="content/posts.go" field.Upload( "heroImage", field.To("media"), field.Required(), field.OnDelete(field.ReferenceDeleteRestrict), ) ``` An Upload must target exactly one existing collection with `Upload: true`. Use `HasMany()` or the `ToMany("media")` shorthand for a gallery. ## Authoring, filtering, and reads {#options} The admin provides an access-aware media picker. `FilterOptionRules` can narrow candidates by metadata such as MIME type or a current-document value, and the server revalidates the rule on write. Upload also supports `Required`, `Localized`, delete behavior, conditions, and common presentation options. Without population, reads return the stored ID/reference. Request population when a response needs the media document and its server-owned filename, MIME, dimensions, sizes, or authored `alt` data. Target access and redaction still apply. This field does not upload bytes by itself. Create media through the generated SDK's `upload` or `uploadFromURL` methods, the multipart REST endpoint, or the admin, then select the resulting document. ## Common mistakes {#troubleshooting} - Setting `field.To("media")` does not make `media` upload-enabled. - Never submit or expose raw storage object keys as if they were media references. - Required uploads cannot use nullify-on-delete. Decide retention and permanent deletion behavior before authors build references. - Database and object storage must be backed up and restored as one recovery point. See [`field.Upload`](https://riducms.com/reference/field/upload/) and [Uploads and media](https://riducms.com/docs/uploads/) for ingestion, image variants, delivery, cleanup, and storage ownership. --- # Row field Canonical URL: https://riducms.com/docs/fields/row/ Use `field.Row` to place related controls on one responsive admin grid row. Row is presentation-only: its children remain at their existing document level and `Row` itself produces no stored property. ## In the admin {#admin-behavior} ![A Row layout in the Ridu admin placing populated First name and Last name controls side by side.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/row.png) _The controls share a responsive row but remain top-level properties in JSON._ ## Smallest working example {#example} ```go title="content/people.go" field.Row( field.Text("firstName", field.Columns(6)), field.Text("lastName", field.Columns(6)), ) ``` The document shape is `{ firstName, lastName }`, not `{ row: { … } }`. `Columns` accepts values from 1 through 12. On narrow screens the admin preserves readable controls instead of forcing an unusable desktop grid. ## When to use Row {#when-to-use} Rows are useful for short fields that authors understand together: first/last name, latitude and longitude labels, or a status beside a date. Keep long text, rich text, arrays, and other dense controls full width unless the actual authoring task benefits from the pairing. Each child keeps its own validation, hooks, access, conditions, localization, and generated contract. Query the child by its normal path. A Row can appear within a tab or other supported layout, but it should not be mistaken for a stored nested container. ## Common mistakes {#troubleshooting} - Column totals do not create server validation. They only describe layout. - Use [Group](https://riducms.com/docs/fields/group/) when the API should contain a nested object. - Changing Row layout does not require a data migration; renaming or moving its child fields does. - Do not hide an authorization-sensitive field by squeezing it out of the layout—use field access. See [`field.Row`](https://riducms.com/reference/field/row/) and [`field.Columns`](https://riducms.com/reference/field/columns/). --- # Collapsible field Canonical URL: https://riducms.com/docs/fields/collapsible/ Use `field.Collapsible` to keep optional or advanced controls available without making the default editor overwhelming. It changes presentation only; children stay at their current document path. ## In the admin {#admin-behavior} ![An opened Advanced collapsible in the Ridu admin with populated Internal name and Editor notes controls.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/collapsible.png) _Collapsing changes only presentation; child values remain at their existing document paths._ ## Smallest working example {#example} ```go title="content/pages.go" field.Collapsible( "advancedSettings", true, field.Text("canonicalURL", field.Label("Canonical URL")), field.JSON("providerMetadata"), ) ``` The second argument controls whether the disclosure starts collapsed. The document has root `canonicalURL` and `providerMetadata` properties; there is no `advancedSettings` object. Child fields retain their own labels, descriptions, validation, access, conditions, and generated contracts. Opening or closing the disclosure never changes submitted values. ## When to use it {#when-to-use} Collapsibles work well for infrequent metadata and power-user settings. Do not put required fields or the primary task behind a closed disclosure without a clear error path—the author should be able to find and correct validation issues. Use [Group](https://riducms.com/docs/fields/group/) when children need a stored object boundary, and [Tabs](https://riducms.com/docs/fields/tabs/) when a long form needs peer sections rather than optional detail. ## Common mistakes {#troubleshooting} - Collapsed is not hidden. Values are still read, submitted, validated, and authorized. - Moving existing fields into a Collapsible is presentation-only; changing their names or nesting is a migration. - Keep the label meaningful to screen-reader and keyboard users; do not rely on an icon alone. See [`field.Collapsible`](https://riducms.com/reference/field/collapsible/) and [Admin field layout](https://riducms.com/docs/admin/#field-layout). --- # Hooks Canonical URL: https://riducms.com/docs/hooks/ ## The lifecycle {#lifecycle} Hooks run as part of the same operation engine used by REST, the local API, the SDK, and the admin. Within a phase, each `[]ridu.Hook` runs in slice order. Choose the narrowest phase that owns the work: normalize before validation, derive before persistence, and leave external effects until after commit. | Phase | When it runs | Good for | | ----------------------------- | ----------------------------------------- | ------------------------------------------------- | | `BeforeDuplicate` | After the source is copied | Resetting slugs and copy-only fields | | `BeforeValidate` | Before field validators | Trimming and normalizing input | | `BeforeChange` | After validation, before persistence | Derived values and audit fields | | `BeforeOperation` | Immediately before storage | Last transactional preparation | | `BeforeRead` | Before documents are read | Request-scoped read setup | | `BeforeDelete` | After the original is loaded | Dependent transactional cleanup | | `AfterChange` / `AfterDelete` | After persistence, inside the transaction | Writes that must commit or roll back together | | `AfterRead` | Before field-level redaction | Decorating the returned document | | `AfterOperation` | After the operation, before commit | General transactional follow-up | | `AfterError` | When the resource operation fails | Metrics and contextual logging | | `AfterCommit` | Only after commit succeeds | Email, webhooks, indexing, and cache invalidation | ## Read HookContext {#hook-context} Application code should use [`ridu.HookContext`](https://riducms.com/reference/ridu/hook-context/). It is the ergonomic alias of [`core.HookContext`](https://riducms.com/reference/core/hook-context/), so both names describe the same value. | Value | What it contains | | ----------------------- | ------------------------------------------------------------------------------------------- | | `Operation` | The create, duplicate, read, update, delete, publish, or unpublish operation | | `Actor` | The authenticated document, or `nil` for an anonymous operation | | `Data` | Mutable incoming values during write phases | | `Document` | The current result once the phase has one | | `Original` | The persisted value before update or delete | | `Context` | Cancellation, deadline, and the active transaction boundary | | `Local` | Nested operations through the normal engine; pre-commit phases reuse the active transaction | | `Error` | The original failure while `AfterError` runs | | `Locale` / `AllLocales` | The locale view selected for this operation | Fields are [`store.Value`](https://riducms.com/reference/store/value/) values rather than `any`. Read strings with [`StringValue()`](https://riducms.com/reference/store/value-string-value/) and write them with [`store.String(...)`](https://riducms.com/reference/store/string/). ## Normalize before validation {#normalize-input} `BeforeValidate` is the right place to make user input canonical. The validator sees the value written back to `ctx.Data`. ```go title="content/posts.go" add={18-22} func trimString(name string) ridu.Hook { return func(ctx ridu.HookContext) error { value, exists := ctx.Data[name] if !exists { return nil } text, valid := value.StringValue() if valid { ctx.Data[name] = store.String(strings.TrimSpace(text)) } return nil } } var Posts = ridu.Collection{ Slug: "posts", FieldHooks: map[string]ridu.CollectionHooks{ "title": { BeforeValidate: []ridu.Hook{trimString("title")}, }, }, } ``` ## Derive values before persistence {#derive-values} Use `BeforeChange` when a value should be derived from already-valid input and written in the same transaction. Inspect `Operation` when behaviour differs between create and update. ```go title="content/posts.go" func recordLastEditor(ctx ridu.HookContext) error { if ctx.Actor == nil { return nil } if ctx.Operation != ridu.OperationCreate && ctx.Operation != ridu.OperationUpdate { return nil } ctx.Data["lastEditedBy"] = store.String(ctx.Actor.ID) return nil } var Posts = ridu.Collection{ Hooks: ridu.CollectionHooks{ BeforeChange: []ridu.Hook{recordLastEditor}, }, } ``` ## Keep related writes atomic {#nested-operations} During a transactional phase such as `AfterChange`, `ctx.Local` runs nested work through normal access rules, validation, and hooks while reusing the outer transaction. If the nested call fails, return its error and the outer operation rolls back too. ```go title="content/posts.go" func writeAuditEntry(ctx ridu.HookContext) error { if ctx.Document == nil { return nil } _, err := ctx.Local.Create( ctx.Context, "audit-log", store.Values{ "document": store.String(ctx.Document.ID), "operation": store.String(string(ctx.Operation)), }, ctx.Actor, ) return err } var Posts = ridu.Collection{ Hooks: ridu.CollectionHooks{ AfterChange: []ridu.Hook{writeAuditEntry}, }, } ``` ## Cross the transaction boundary {#after-commit} Use `AfterCommit` for work that must not happen when the database rolls back. The write is already durable: a returned error is reported as a committed-hook failure and cannot roll the document back. Configure `Config.AfterCommit` with a dispatcher when effects need retries or a durable worker boundary. ```go title="content/posts.go" func reindexPost(ctx ridu.HookContext) error { if ctx.Document == nil { return nil } return search.Enqueue(ctx.Context, ctx.Document.ID) } var Posts = ridu.Collection{ Hooks: ridu.CollectionHooks{ AfterCommit: []ridu.Hook{reindexPost}, }, } ``` ## Observe failures without hiding them {#handle-errors} `AfterError` runs outside the failed transaction and receives the original failure on `ctx.Error`. Use it for context-rich logging and metrics; returning `nil` does not turn the failed operation into a success. ```go title="content/posts.go" func countFailure(ctx ridu.HookContext) error { metrics.OperationFailure( string(ctx.Operation), string(ctx.CollectionID), ) log.Printf("ridu operation failed: %v", ctx.Error) return nil } var Posts = ridu.Collection{ Hooks: ridu.CollectionHooks{ AfterError: []ridu.Hook{countFailure}, }, } ``` See [`ridu.CollectionHooks`](https://riducms.com/reference/ridu/collection-hooks/) for every phase and [`ridu.Hook`](https://riducms.com/reference/ridu/hook/) for the callback contract. --- # UI field Canonical URL: https://riducms.com/docs/fields/ui/ Use `field.UI` for contextual guidance or a statically paired admin component that does not own a document value. UI fields never appear in stored data, generated inputs, REST bodies, or SDK output. ## In the admin {#admin-behavior} ![An Author guidance UI field in the Ridu admin showing presentation-only help.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/ui.png) _The guidance appears only in the admin; no `guidance` property enters storage, inputs, or SDK output._ ## Built-in guidance {#example} ```go title="content/posts.go" field.UI( "publishingGuide", field.Label("Before you publish"), field.Description("Check the preview, links, and search description."), ) ``` The name is a presentation identity, not a JSON property. Use translated labels and descriptions when the admin interface supports several languages. ## Pair a custom component {#custom-component} ```go title="content/posts.go" field.UI( "contentScore", field.AdminComponent( "acme-editorial", "ContentScore", json.RawMessage(`{"minimum":80}`), ), ) ``` The plugin must be registered with its paired static admin package. The component name must match an exported registration and config must be a deterministic JSON object because it enters the public manifest. Generation and startup reject a missing pair. Custom UI is presentation, not trusted execution or authorization. Read data through the provided admin/SDK contracts and keep server invariants in access, validation, hooks, or plugin endpoints. ## Common mistakes {#troubleshooting} - Do not expect a UI field to submit a value. Build a paired custom renderer for a stored field, or a [Plugin field](https://riducms.com/docs/fields/plugin/), when data belongs in the document. - Do not place secrets in component config; the manifest is public to authorized tooling and admin clients. - A component hidden or disabled in the admin cannot protect an API operation. See [`field.UI`](https://riducms.com/reference/field/ui/), [`field.AdminComponent`](https://riducms.com/reference/field/admin-component/), and [Build a custom field](https://riducms.com/guides/custom-fields/). --- # Join field Canonical URL: https://riducms.com/docs/fields/join/ Use `field.Join` for the inverse side of a singular relationship. It queries documents that point to the current document instead of storing a second synchronized ID list. ## In the admin {#admin-behavior} ![A populated Articles in this category Join field in the Ridu admin showing the related article row.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/join.png) _The table is computed from forward relationships, so the category stores no duplicate list of post IDs._ ## Smallest working example {#example} ```go title="content/categories.go" var Categories = ridu.Collection{ Slug: "categories", Fields: []field.Definition{ field.Text("name", field.Required()), field.Join("posts", "posts", "category"), }, } var Posts = ridu.Collection{ Slug: "posts", Fields: []field.Definition{ field.Text("title", field.Required()), field.Relationship("category", field.To("categories")), }, } ``` The constructor arguments are the output field name, target collection, and target relationship path. That path must identify a singular, non-polymorphic relationship back to the source collection. ## Configure the admin view {#options} ```go title="content/categories.go" field.Join( "posts", "posts", "category", field.JoinLimit(20), field.JoinColumns("title", "status", "updatedAt"), field.JoinDefaultSort("-updatedAt"), field.JoinAllowCreate(true), ) ``` `JoinLimit` is between 1 and 100. Columns, sorting, and inline-create availability describe the admin table; target read/create access still applies. Joins must live at a collection root and are not supported on globals. The value appears in generated output but never in create/update input. Reads apply target access, hooks, localization, and field redaction. Select output fields to omit an expensive join when a consumer does not need it. Use SDK `mutateJoin` for an explicit atomic addition/removal; it updates the target documents' forward relationships through validation and access. ## Common mistakes {#troubleshooting} - Do not create and manually synchronize a second forward relationship. - `JoinAllowCreate(true)` is an affordance, not permission. - Changing the target/on path can be a relationship-shape migration even though the Join itself is response-only. See [`field.Join`](https://riducms.com/reference/field/join/) and [Relationships and joins](https://riducms.com/docs/relationships/#inverse-join). --- # Virtual field Canonical URL: https://riducms.com/docs/fields/virtual/ Use `field.Virtual` when trusted Go code derives a response value from a document or another access-controlled read. Virtual values appear in generated output contracts but are never accepted as create/update data and are not stored. ## In the admin {#admin-behavior} ![A read-only Computed label virtual field in the Ridu admin showing a value resolved by Go code.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/virtual.png) _The admin renders resolver output as read-only; create and update inputs never accept or persist it._ ## Define the field and resolver {#example} ```go title="content/people.go" focus={18-20} package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" "github.com/riducms/ridu/store" ) var People = ridu.Collection{ Slug: "people", Fields: []field.Definition{ field.Text("firstName", field.Required()), field.Text("lastName", field.Required()), field.Virtual("displayName", field.ValueString), }, Computed: map[string]ridu.Computed{ "displayName": func(ctx ridu.ComputedContext) (store.Value, error) { first, _ := ctx.Document.Values["firstName"].StringValue() last, _ := ctx.Document.Values["lastName"].StringValue() return store.String(first + " " + last), nil }, }, } ``` ### Read sibling values {#sibling-data} Virtual fields are root fields, so their sibling values live in `ctx.Document.Values`. In the example, `displayName` reads the stored `firstName` and `lastName` siblings with `StringValue()`. The second return value reports whether the value is actually a string; the example can ignore it because both source fields are required Text fields. Use `BooleanValue()` or `NumberValue()` for other scalar siblings, `ObjectValue()` for a Group or named Tabs value, and `Values()` for an Array or Blocks value. A Relationship or Upload sibling contains its stored reference shape—an ID, ID list, or polymorphic object—not an automatically populated document. Use `ctx.Local` when the resolver also needs to read that related document through its normal access rules. Choose `ValueString`, `ValueNumber`, `ValueBoolean`, or `ValueJSON`. The resolver must return the matching `store.Value`. Missing resolvers fail startup; a mismatched runtime value fails the operation. Virtual fields must live at a collection or global root. Resolvers receive the operation, actor and auth collection, current document, locale selection, context, and access-controlled Local API. Use that Local API for additional reads. ## Cost, access, and selection {#behavior} Unselected virtual fields do not run. Consumers should select only expensive computed output they need. A resolver is trusted application code, so bound its work and avoid network calls on every list row unless caching and failure behavior are defined. The output remains subject to field read visibility. ## Common mistakes {#troubleshooting} - Do not try to filter or sort by a value that is never stored. Materialize/index a real field when the database must query it. - Avoid nondeterministic or secret-bearing output unless an access rule permits it. - A Virtual is not an admin-only UI element; use [UI](https://riducms.com/docs/fields/ui/) for presentation with no response value. See [`field.Virtual`](https://riducms.com/reference/field/virtual/) and [`ridu.Computed`](https://riducms.com/reference/core/computed/). --- # Plugin field Canonical URL: https://riducms.com/docs/fields/plugin/ `field.Plugin` is the low-level constructor for a compiled field extension. Most applications use a plugin-owned helper such as `richtext.Field`; that helper serializes valid config and prevents callers from mistyping the plugin key. ## In the admin {#admin-behavior} ![The official Rich text plugin field in the Ridu admin with populated portable editor content.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/fields/plugin.png) _The Svelte control authors the value; its paired Go plugin defines server validation and the stored shape._ ## Prefer the plugin helper {#example} ```go title="content/posts.go" import "github.com/riducms/ridu/plugins/richtext" richtext.Field("content", field.Required()) ``` The matching plugin must also be present in `Config.Plugins`, and its paired admin package must be statically registered when the field needs a custom control. Run `ridu add …` to install both sides and update their registration. ## Low-level constructor {#low-level} ```go title="color/field.go" func Field(name string, config Config, options ...field.PluginOption) field.Definition { encoded, err := json.Marshal(config) if err != nil { panic(err) } return field.Plugin(name, Key, encoded, options...) } ``` Plugin config must be deterministic public JSON. Never put secrets, callbacks, or request-specific data in it. If config properties contain collection slugs, declare those exact property names with `CollectionReferenceKeys` so schema-addressed migration checks can follow renames safely. Define Go/TypeScript/OpenAPI mappings, runtime validation, admin pairing, and any supported query type in the plugin descriptor. Without those mappings generated values fall back to `json.RawMessage`/`unknown`; without a server validator a pretty control is not a finished field. Only common safe options such as required, localized, labels, descriptions, layout, and conditions are accepted by `PluginOption`. ## Common mistakes {#troubleshooting} - Do not call `field.Plugin` directly when the package provides a typed helper. - Installing only the npm control or only the Go package creates an incomplete pair. - Config is schema metadata, not the stored value. - Test a custom field through resolution, generation, storage, Local API/REST, and the admin. See [`field.Plugin`](https://riducms.com/reference/field/plugin/), [Plugin system](https://riducms.com/docs/plugins/), and the complete [custom field guide](https://riducms.com/guides/custom-fields/). --- # Data access overview Canonical URL: https://riducms.com/docs/data-access/ Ridu offers several ways into one operation engine. Choosing a transport changes how you express a request, not the access rules, validation, hooks, transactions, relationship population, or field redaction applied to it. ## Choose a surface {#choose-surface} | Surface | Use it when | Contract | | --------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------ | | [Local Go API](https://riducms.com/docs/local-api/) | Backend code already runs inside the Ridu process | Dynamic `store.Values` or generated Go structs; no HTTP round trip | | [REST API](https://riducms.com/docs/rest-api/) | Any HTTP-capable client needs the canonical wire API | Generated OpenAPI plus stable success/error envelopes | | [TypeScript SDK](https://riducms.com/docs/typescript-sdk/) | A browser, SvelteKit app, Bun/Node service, or test uses Fetch | Exact generated collection/input/query types over `Promise` | | [GraphQL plugin](https://riducms.com/docs/graphql/) | A project needs GraphQL selection sets or tooling | Optional generated SDL over the same engine | | [Admin](https://riducms.com/docs/admin/) | Content authors need the built-in interface | Schema-driven forms and lists using the generated SDK | Prefer the local API for Go code inside the application and the generated SDK for TypeScript. REST is the durable interoperability boundary. GraphQL is opt-in, and excluding the plugin keeps its implementation out of the compiled binary. ## The shared operation pipeline {#operation-pipeline} Every collection read or mutation follows the same ordering: 1. identify the collection, actor, locale, requested draft/trash mode, and operation; 2. evaluate collection access and keep any filtered decision as an atomic store predicate; 3. run before-operation and before-validation hooks; 4. validate field values, relationships, access, uniqueness, and optimistic revision input; 5. execute the store work in one transaction, including nested local calls; 6. run after-change/read hooks, population, computed or join output, and field redaction; 7. commit, then dispatch registered after-commit effects. Local calls are not privileged. Passing a `nil` actor means anonymous, not superuser. Admin visibility is presentation metadata and never grants an operation. ## Collections and globals {#resources} Collections hold repeatable documents and expose create, list, count, find, update, duplicate, delete, and capability operations. Enabled capabilities add uploads, trash, versions, drafts, publishing, scheduling, locks, and bulk mutations. Globals are singleton documents. They expose read and update rather than collection-style create or delete, and can opt into versions, drafts, publishing, scheduling, localization, live preview, and field-level access. See [Collections and globals](https://riducms.com/docs/collections/) for modeling differences. ## One request in Go and TypeScript {#same-request} Inside the Go process: ```go title="Go local API" statusPath, err := query.NewPath("status") if err != nil { return err } page, err := app.Local().List(ctx, "posts", ridu.ListOptions{ Page: 1, Limit: 20, Where: query.Equal(statusPath, query.String("published")), Actor: currentUser, }) if err != nil { return err } ``` From a generated TypeScript client: ```ts title="TypeScript SDK" const page = await client.list('posts', { page: 1, limit: 20, where: { status: { equals: 'published' } } }); ``` The representations differ, but access predicates and caller filters remain separate until the store combines them into one atomic query. Neither client can fetch a denied row and filter it afterward. ## Documents, pages, and errors {#responses} Documents carry an ID and timestamps in addition to authored fields. Enabled features add values such as `_revision`, `_status`, upload metadata, or localization source metadata. Generated contracts describe these fields. List results use a page envelope with `docs` and nested `pagination` information including current page, limit, total documents, total pages, and next/previous state. REST failures use one stable error envelope; the SDK converts it to `RiduError` with `code`, `status`, `requestId`, `issues`, and structured `details`. Branch on the code and issue path, never on human wording. ## Concurrency and side effects {#concurrency} Version-enabled documents expose an integer revision. Send it with mutations—through `ExpectedRevision`, the SDK `revision` option, or REST `If-Match`—to reject stale writes with a conflict rather than overwrite another author. Document locks coordinate the admin editing experience but do not replace authorization or optimistic revisions. Hooks that send email, enqueue external work, or delete remote objects should register an after-commit effect. Transaction hooks may run again when the surrounding operation is retried; an after-commit dispatcher sees only committed work. Continue with [Querying data](https://riducms.com/docs/querying/), then choose the [Local Go API](https://riducms.com/docs/local-api/), [REST API](https://riducms.com/docs/rest-api/), or [TypeScript SDK](https://riducms.com/docs/typescript-sdk/) task guide. --- # Local Go API Canonical URL: https://riducms.com/docs/local-api/ `app.Local()` is the in-process data API for Go handlers, task code, application services, access rules, and hooks. It avoids serialization and an HTTP round trip, but it is not a privileged store handle: access, field redaction, validation, relationships, hooks, versions, transactions, and localization are the same engine used by REST, the SDK, GraphQL, and the admin. ## Dynamic values {#dynamic-values} The dynamic surface uses `store.Values`, a map whose values have a finite JSON-shaped vocabulary. Construct values with `store.String`, `Number`, `Boolean`, `Object`, `List`, and `Null` rather than passing `any`. ```go title="service/posts.go" package service import ( "context" "github.com/riducms/ridu" "github.com/riducms/ridu/query" "github.com/riducms/ridu/store" ) func RecentPosts(ctx context.Context, app *ridu.App, actor *store.Document) (store.Page, error) { post, err := app.Local().Create(ctx, "posts", store.Values{ "title": store.String("Hello, Ridu"), "summary": store.String("An in-process write."), }, actor) if err != nil { return store.Page{}, err } title, _ := post.Values["title"].StringValue() _ = title categoryPath, err := query.NewPath("category") if err != nil { return store.Page{}, err } categorySort, err := query.NewSort(categoryPath, query.Ascending) if err != nil { return store.Page{}, err } return app.Local().List(ctx, "posts", ridu.ListOptions{ Page: 1, Limit: 20, Where: query.Equal(categoryPath, query.String("news")), Sort: []query.Sort{categorySort}, Actor: actor, }) } ``` Values returned from the store are detached snapshots. A string relationship value is an ID; when that path is explicitly populated, it becomes a `store.Populated` document value. See [Querying data](https://riducms.com/docs/querying/) for expressions, selection, sorting, and bounded population. ## Pass the caller, not a bypass flag {#actors} The final `actor` argument, or `Actor` in an options struct, is the authenticated document supplied to access rules and hooks. `nil` means anonymous. It never means superuser, and the local API has no access-override option. When an application has more than one auth collection, a document ID is not a complete identity. Carry the collection slug as well: ```go session, err := app.Session(ctx, rawSessionToken) if err != nil { return err } post, err := app.Local().FindWithOptions(ctx, "posts", postID, ridu.FindOptions{ Actor: &session.User, ActorCollection: session.Collection, }) ``` All option-bearing reads, mutations, and capability checks accept `ActorCollection`. Transport code should preserve the exact `ridu.AuthIdentity` established by authentication and copy both `Actor` and `Collection` into local options. Concise actor-only methods remain convenient for an application's trusted internal work. Identity-sensitive application services such as scheduling, preferences, previews, account unlocks, and document locks accept `AuthIdentity` directly. ## Read and write options {#options} The short methods accept an actor and optional `LocaleOptions`. Use the `WithOptions` forms when a request needs more control: | Type | Controls | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | `FindOptions` | `Select`, relationship `Populate`, computed/join `OutputFields`, draft visibility, exact actor identity, trash-only mode, and locale projection | | `ListOptions` | All find controls plus `Where`, one-based `Page`, `Limit`, and ordered `Sort` | | `MutationOptions` | Exact actor identity, optimistic `ExpectedRevision`, returned population/output fields, draft status, and write locale | | `CapabilityOptions` | Candidate `Data`, exact actor identity, trash mode, and locale for a side-effect-free permission summary | | `LocaleOptions` | Locale, replacement fallback chain, fallback disablement, or all-locales reads for concise methods | `Select` projects stored fields. `OutputFields` independently controls computed fields and inverse joins: nil resolves all, while a non-nil empty slice resolves none. `Populate` changes the returned shape only; it does not change what is validated or saved. `AllLocales` is read-only for ordinary create/update calls—write one locale at a time or use `CopyLocale`. `Draft` is a pointer so omitted, true, and false stay distinct. For reads, true includes drafts and false restricts results to published documents. For creates, true requests draft and false requests published status. Updates do not accept status intent: edit drafts with `Update`, and use `PublishChanges` or `Unpublish` for lifecycle transitions. The omitted defaults are covered in [Drafts and versions](https://riducms.com/docs/drafts-and-versions/). ## Collection operation map {#collection-operations} | Task | Local API methods | | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | Create or copy | `Create`, `CreateWithOptions`, `Duplicate`, `DuplicateWithOptions` | | Read | `Find`, `FindWithOptions`, `List` | | Inspect permission | `Capabilities` returns operation and field booleans without exposing rule code or filtered predicates | | Update | `Update`, `UpdateWithOptions`, `UpdateRevision` | | Maintain inverse joins | `MutateJoin`, `MutateJoinWithOptions` atomically add/remove source IDs | | Publish state | `Publish`, `Unpublish` and their option-bearing forms | | Localization | `CopyLocale`, `CopyLocaleWithOptions` | | Version history | `Versions`, `Version`, restore/preserve-status, and restore-as-draft forms | | Delete | `Delete`; trash-enabled resources also have restore, permanent delete, and `EmptyTrash` | | Bulk | Bounded update, publish, unpublish, delete, restore-deleted, and permanent-delete methods | | Migration import | `Import` preserves a source ID, status, and timestamps while still running ordinary access, validation, hooks, relationships, versions, and transactions | Capability results are suitable for deciding which controls to show. They are not a lease or authorization token; run the requested operation and handle its result. Import is intended for trusted migration code, not ordinary end-user creation. Upload collections use the storage-aware methods on `App` rather than dynamic `Create` for file-bearing documents. Bulk operations accept 1–100 explicit IDs and commit every item or none. The current Go bulk, `EmptyTrash`, and `Import` signatures are actor-only: they do not accept `ActorCollection` or an `AuthIdentity`. In a multi-auth application, use the REST/SDK bulk transport—which preserves the transport's exact identity—or reserve these local methods for application-owned callers whose identity cannot be ambiguous. Individual option-bearing local methods are the exact-identity path. ## Globals use singleton methods {#globals} Globals do not pretend to be one-row collections. Use `Global`/`GlobalWithOptions` to read and `UpdateGlobal`/`UpdateGlobalWithOptions` to create-or-update the singleton. Version-enabled globals also expose publish, unpublish, copy-locale, version reads, and restore methods. ```go settings, err := app.Local().UpdateGlobalWithOptions( ctx, "site-settings", store.Values{"siteName": store.String("Acme")}, ridu.MutationOptions{ Actor: actor, ActorCollection: "users", ExpectedRevision: currentRevision, }, ) ``` There are no global create/list/delete/trash, auth, upload, or lock methods. A never-persisted global reads as a schema-shaped singleton with defaults; its first update persists it. ## Generated typed handles {#typed-handles} `ridu generate` writes output, create, and update structs plus typed collection and global handles. Bind a generated definition to the same local engine: ```go title="service/typed-posts.go" posts := generated.PostsCollection.With(app.Local()) post, err := posts.Create(ctx, generated.PostCreate{ Title: "Hello, Ridu", Summary: "Checked by Go's compiler", }, actor) if err != nil { return err } page, err := posts.List(ctx, core.TypedListOptions{ Page: 1, Limit: 20, Actor: actor, ActorCollection: "users", }) ``` Typed collection handles currently cover create, import, find, list, update, revision-aware update, and delete. Typed global handles cover find, update, publish, unpublish, restore, and restore-as-draft. Use the dynamic local API for advanced operations that are not on a generated handle. The typed layer JSON-encodes generated input and decodes the result; it changes compile-time ergonomics, not runtime semantics or authorization. Generated mutation fields are presence-aware. Nullable fields use `*core.Input[T]`: nil omits the key, `core.Set(value)` sends a concrete value, and `core.Null[T]()` sends explicit JSON `null`. Non-null slices, maps, fallback `json.RawMessage` fields, and plugin-owned Go types whose JSON nullability cannot be proven use `core.NonNullInput[T]`: construct a required value with `core.NonNull(value)`, or an omittable default/update value with `core.SetNonNull(value)`. Encoding rejects nil or otherwise null-encoding wrapped values. Other non-null fields that are optional only in an update or because a server default exists use `*T`. Generated mutation wrappers are write-only, not general-purpose JSON-unmarshal contracts. `TypedListOptions` excludes population and all-locale reads because those operations change relationship and localized field shapes; use the dynamic local API when you need either. Except for typed `List`, these generated methods currently take an actor document rather than an options struct, so they cannot carry `ActorCollection`, locale selection, draft intent, or returned population. In a multi-auth or option-rich operation, keep the generated input/output types where useful but call the dynamic `WithOptions` method so the exact identity and request semantics are not lost. ## Optimistic revisions {#optimistic-writes} Versioned documents and globals expose `_revision`. Pass the revision you last observed through `ExpectedRevision`, `UpdateRevision`, or the expected-revision argument on publish, unpublish, and restore. Zero means no revision fence; a stale positive revision returns a `conflict` operation error instead of replacing a newer edit. ```go updated, err := app.Local().UpdateWithOptions(ctx, "posts", post.ID, values, ridu.MutationOptions{ Actor: actor, ActorCollection: "users", ExpectedRevision: post.Revision, }) ``` Document locks coordinate editors but do not replace this fence. Prefer revisions on every interactive write. ## Nested calls and transactions {#nested-transactions} `HookContext.Local`, `AccessContext.Local`, and `FieldAccessContext.Local` expose the same API. Calls made during a pre-commit operation phase automatically reuse the outer store transaction. The nested operation still runs its own access, validation, hooks, version snapshot, and redaction; if it fails, the transaction becomes rollback-only even when a hook tries to swallow the error. After-commit and after-error callbacks run outside the completed/failed transaction, so their local calls start a new transaction. An after-commit error means the original document is already durable and must not be blindly retried. Guard operations that call back into the same hooked resource: Ridu bounds total nesting and repeated operation frames, but `operation_recursion` is a safety net, not workflow design. Ridu does not currently expose caller-controlled begin/commit/rollback or savepoints. Put atomic related writes in transactional hook phases and use an after-commit dispatcher or durable task for external effects. See [Hooks](https://riducms.com/docs/hooks/). ## Structured errors {#errors} Local failures can be inspected as `*ridu.OperationError`. Branch on `Code`, HTTP-shaped `Status`, and validation `Issues`; do not parse `Message`. ```go import "errors" post, err := app.Local().UpdateRevision(ctx, "posts", id, patch, revision, actor) if err != nil { var operationErr *ridu.OperationError if errors.As(err, &operationErr) { switch operationErr.Code { case "conflict": return reloadAndAskTheAuthor(operationErr) case "validation": return showFieldIssues(operationErr.Issues) case "access_denied", "not_found": return hideUnavailableDocument() } } return err } _ = post ``` `not_found` may hide a row rejected by filtered access. `Committed` marks an error from work after a successful commit; `CommitAttempted` marks an ambiguous commit outcome. Those flags matter when reconciling external objects or deciding whether retrying a mutation is safe. The complete methods and option members are in the [Go API reference](https://riducms.com/reference/ridu/). --- # Querying data Canonical URL: https://riducms.com/docs/querying/ Ridu uses one query vocabulary across the local Go API, REST, SDK, access rules, and store adapters. ## Filter with `where` {#where} Generated TypeScript clients expose only paths from your application schema: ```ts const page = await client.list('posts', { where: { and: [ { status: { equals: 'published' } }, { or: [{ title: { contains: 'ridu' } }, { 'author.name': { like: 'Ada Lovelace' } }] } ] } }); ``` | TypeScript operator | Go operator | Meaning | | --------------------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------- | | `equals` | `query.Equal` | exact scalar equality | | `notEquals` | `query.NotEqual` | scalar inequality | | `in` | `query.In` | value equals one member of a non-empty list | | `exists` | `query.Compare(path, query.OperatorExists, query.Boolean(...))` | field is present or absent | | `greaterThan`, `greaterThanEqual` | `query.GreaterThan`, `query.GreaterThanEqual` | ordered string/number comparison | | `lessThan`, `lessThanEqual` | `query.LessThan`, `query.LessThanEqual` | ordered string/number comparison | | `contains` | `query.Contains` | case-insensitive substring match | | `like` | `query.Like` | case-insensitive match for every whitespace-delimited search word | | `and`, `or`, `not` | `query.And`, `query.Or`, `query.Not` | recursive logical composition | `and` and `or` require at least two children; `not` requires exactly one. HTTP `where` accepts at most 100 comparison expressions, nesting depth 16, and 100 values in one `in` expression. A query path has at most 64 segments and 4,096 bytes. Invalid shapes fail with `bad_query` before storage. ### Current query limits {#limits} There is currently no `notIn`, full-text ranking, array all-elements operator, or general geospatial comparison. The Local Go API supports distinct values for one direct singular stored field; relationship-path population, custom aggregate ordering, and a public REST distinct route remain outside that focused contract. A point field can be stored, returned, and rendered without implying a radius or bounding-box query API. ## Nested and repeated paths {#paths} Paths use authored field names separated by dots, such as `seo.title`. Blocks include their stable block key in the schema path. Runtime array indexes are not part of a path: one nested path applies to matching rows. The resolver validates a path against the schema and rejects layout-only, non-sortable, or incompatible fields for the requested operation. Filters do not populate relationships first. They operate on persisted fields according to the schema/store contract. Population is a separate output step and re-authorizes every target. ## Sort stably {#sort} Pass repeated sort terms in priority order. Prefix a path with `-` for descending order: ```ts const page = await client.list('posts', { sort: ['-publishedAt', 'title'] }); ``` REST repeats the query key: `?sort=-publishedAt&sort=title`. The HTTP API accepts at most 16 unique sort fields. Nested repeated structures, groups, arrays, blocks, JSON, and opaque plugin fields are not sortable. The store appends `id` as the final tie-breaker when needed, which keeps page ordering deterministic when authored values are equal. Generated SDK sort terms are validated strings today, not path unions; the server remains the authority for whether a field can be sorted. ## Paginate and count {#pagination} REST list requests default to page 1 and limit 10. Both values must be positive; the HTTP maximum limit is 100. SDK page results keep metadata under `pagination`: ```ts const { docs, pagination } = await client.list('posts', { page: 2, limit: 25 }); console.log(pagination.totalDocs); console.log(pagination.totalPages); console.log(pagination.hasNextPage); ``` Use `client.count('posts', { where })` when you only need the authorized total. Counts use the same caller filter, access predicate, locale, draft, and trash semantics as lists. Go applications can use `LocalAPI.Distinct` for a paginated, ascending set of values from one direct scalar, singular relationship, singular upload, or `id` field. The caller filter and collection read predicate stay combined in the adapter query, and field read access is checked before values are selected. A selected field with a configured read-access rule is rejected: Ridu rules may depend on each document and cannot be safely reduced to one aggregate predicate. ## Select output fields {#select} `select` projects top-level authored fields while retaining framework identity fields: ```ts const post = await client.find('posts', 'post_123', { select: { title: true, summary: true, author: true } }); ``` HTTP selection is a JSON object and accepts at most 256 entries. Selecting a relationship does not populate it; it remains an ID or polymorphic reference unless `populate` is also requested. Selection changes the runtime response, but the current TypeScript method still returns the collection's complete output type. Projection-dependent result inference is planned, so code must not assume an unselected field exists at runtime merely because its static property is present. ## Populate relationships {#populate} Population replaces relationship or upload references with access-checked target documents: ```ts const page = await client.list('posts', { populate: { author: { depth: 1, select: { name: true, avatar: true } }, 'sections.quote.source': true } }); ``` Each target read re-applies collection access, field redaction, localization, and nested population rules. Missing or denied targets do not become an authorization side channel. Population supports at most 64 explicitly requested paths, maximum depth 5, 256 recursively expanded schema paths, and a shared budget of 4,096 materialized related documents per operation. These are request-wide ceilings, not per row. REST also accepts `depth=1` to expand every root reference field. Do not combine `depth` and `populate`; use explicit population for production queries that need predictable shape and cost. As with `select`, current SDK return types are not narrowed or expanded according to the population object yet. ## Query localized and trashed content {#modes} List, find, count, sort, filter, and population use the selected content locale. SDK requests accept `locale` and `fallbackLocale`; REST uses `locale` and `fallback-locale` (with `fallbackLocale` as an alias). `locale=all` returns locale-keyed values and makes ordinary mutations read-only. See [Localization](https://riducms.com/docs/localization/) for exact fallback and copy-locale behavior. Trash-enabled collections keep deleted documents out of ordinary queries. Set the dedicated trash mode to list only deleted documents; there is no mixed live-and-deleted query. Restore and permanent delete are separate, access-checked operations described in [Editorial workflows](https://riducms.com/docs/editorial-workflows/). ## Access filters remain atomic {#access-filters} An access rule may allow, deny, or return a query predicate. Ridu combines a filtered access decision with the caller's `where` inside the store request for reads, updates, deletes, duplicate, and other target operations. It never reads an unauthorized page and removes rows afterward. See [Access control](https://riducms.com/docs/access-control/) for the operation matrix. Use the [`query` Go reference](https://riducms.com/reference/query/) for constructors and types, or continue with the [TypeScript SDK](https://riducms.com/docs/typescript-sdk/) and [REST API](https://riducms.com/docs/rest-api/) representations. --- # REST API Canonical URL: https://riducms.com/docs/rest-api/ Ridu generates an OpenAPI document from the resolved application manifest. The tables below are the framework route families; your `generated/ridu.openapi.json` is authoritative for the concrete collection, global, auth, upload, version, and plugin routes enabled by your config. A browser frontend on another origin must configure the HTTP boundary before calling these routes. See [CORS](https://riducms.com/docs/cors/) for exact origins, credentials, custom headers, proxy trust, and preflight errors. Server-to-server clients do not need CORS. ## Collection routes {#collection-routes} `{collection}` is the authored collection slug and `{id}` is the public document ID. | Task | Method and path | Availability or input | | ---------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | List / create | `GET, POST /api/collections/{collection}` | JSON create for ordinary collections. An auth collection must use `create-user`; an upload collection uses multipart or `remote-upload`. | | Read / update / delete | `GET, PATCH, DELETE /api/collections/{collection}/{id}` | `PATCH` accepts `If-Match`. With trash enabled, delete moves the row to trash. | | Count | `GET /api/collections/{collection}/count` | Accepts the same filter, locale, and trash context as list. | | Duplicate | `POST /api/collections/{collection}/{id}/duplicate` | JSON object contains optional field overrides; unavailable for auth collections. | | Copy locale | `POST /api/collections/{collection}/{id}/copy-locale` | Body `{ "from": "en", "to": "fr" }`; accepts `If-Match`. | | Mutate inverse join | `PATCH /api/collections/{collection}/{id}/joins/{field}` | Body `{ "additions": [...], "removals": [...] }`; only writable joins. | | Bulk operations | `POST /api/collections/{collection}/bulk` | Body `{ action, ids, data? }`; 1–100 unique non-empty IDs. | Bulk `action` is exactly one of `update`, `publish`, `unpublish`, `delete`, `restoreDeleted`, or `deletePermanent`. `data` is required only by `update`. Capability and access checks still run per document; this route is not a permission bypass. ### Trash {#trash} These routes exist only for a trash-enabled collection: | Method and path | Task | | --------------------------------------------------------- | --------------------------------------- | | `GET /api/collections/{collection}?trash=true` | List only trashed documents. | | `POST /api/collections/{collection}/{id}/restore-deleted` | Restore one document. | | `DELETE /api/collections/{collection}/{id}/permanent` | Permanently delete one document. | | `DELETE /api/collections/{collection}/trash` | Permanently empty the collection trash. | ### Versions and scheduling {#versions} These routes exist only when collection versions are enabled; draft/publish actions additionally depend on the configured version capability. | Method and path | Task | | ------------------------------------------------------------ | ---------------------------------------------------------- | | `GET /api/collections/{collection}/{id}/versions` | List snapshots. | | `GET /api/collections/{collection}/{id}/versions/{revision}` | Read one positive integer revision. | | `POST /api/collections/{collection}/{id}/publish` | Publish the current document. | | `POST /api/collections/{collection}/{id}/unpublish` | Return the current document to draft. | | `POST /api/collections/{collection}/{id}/restore/{revision}` | Restore a snapshot; add `?draft=true` to restore as draft. | | `GET, POST /api/collections/{collection}/{id}/schedule` | List jobs or schedule publication with `{ "runAt": "…" }`. | | `DELETE /api/collections/{collection}/{id}/schedule/{jobId}` | Cancel a scheduled publication. | Publishing, unpublishing, restoring, and scheduling accept `If-Match` for optimistic concurrency. ### Uploads {#uploads} Upload-enabled collections add these transports: | Method and path | Content | | -------------------------------------------------- | --------------------------------------------------------------------------------- | | `POST /api/collections/{collection}` | `multipart/form-data` with required `file` and optional `data` JSON-object field. | | `POST /api/collections/{collection}/remote-upload` | JSON `{ "url": "https://…", "data": { … } }`. | | `PATCH /api/collections/{collection}/{id}/image` | JSON focal point and optional crop coordinates; accepts `If-Match`. | | `GET, HEAD /api/uploads/{collection}/{object-key}` | Access-checked object delivery. | Multipart requests are limited to the collection’s maximum file size plus framing allowance. Remote-host, redirect, MIME, image-dimension, spool, and storage policies come from the configured upload backend. Object responses are always private and non-cacheable; HTML, SVG, and XML-like active content is forced to download with a sandbox policy. ## Globals and schema {#globals-and-schema} | Method and path | Task | | ----------------------------------------------- | --------------------------------------------------- | | `GET /api/schema` | Read the canonical public manifest envelope. | | `GET, PATCH /api/globals/{global}` | Read or update a global; update accepts `If-Match`. | | `POST /api/globals/{global}/copy-locale` | Copy localized values; accepts `If-Match`. | | `GET /api/globals/{global}/versions` | List global versions. | | `GET /api/globals/{global}/versions/{revision}` | Read a global revision. | | `POST /api/globals/{global}/publish` | Publish a versioned global. | | `POST /api/globals/{global}/unpublish` | Unpublish a versioned global. | | `POST /api/globals/{global}/restore/{revision}` | Restore a global revision; accepts `If-Match`. | | `GET /healthz` | Process liveness. | | `GET /readyz` | Configured dependency and migration readiness. | Global scheduled publishing is not implemented. Version routes are absent when versions are not configured. ## Authentication and account routes {#authentication} Auth-collection feature flags determine which routes are generated. | Method and path | Task | | ---------------------------------------------------- | ----------------------------------------------------------- | | `GET /api/auth/{collection}/bootstrap` | Check whether one-time first-admin setup is available. | | `POST /api/auth/{collection}/create-user` | Create a user with `{ "data": { … }, "password": "…" }`. | | `POST /api/auth/{collection}/login` | Authenticate with email and password. | | `POST /api/auth/{collection}/forgot-password` | Request recovery when enabled. | | `POST /api/auth/{collection}/reset-password` | Consume a recovery token when enabled. | | `POST /api/auth/{collection}/request-verification` | Request verification when enabled. | | `POST /api/auth/{collection}/verify` | Consume a verification token when enabled. | | `POST /api/auth/{collection}/{id}/unlock` | Clear login-attempt lock state when enabled and authorized. | | `GET /api/auth/me` | Read the current session identity. | | `POST /api/auth/refresh` | Rotate/refresh the current session. | | `POST /api/auth/logout`, `POST /api/auth/logout-all` | Revoke the current or all actor sessions. | | `POST /api/auth/change-password` | Change password and revoke the current cookie session. | | `GET /api/auth/sessions` | List sessions for the current actor. | | `DELETE /api/auth/sessions/{id}` | Revoke one session. | | `GET, POST /api/auth/api-keys` | List API-key metadata or create a key when enabled. | | `DELETE /api/auth/api-keys/{id}` | Revoke an API key. | Login establishes the HttpOnly, SameSite=Lax `ridu_session` cookie. Cookie-authenticated browser requests must include credentials. A raw session token uses `Authorization: Session `; `Authorization: JWT ` remains accepted for compatibility. An API key uses `Authorization: Bearer `. API-key creation specifically requires cookie authentication, and the returned secret cannot be retrieved from a later list call. ## Access, preferences, and document locks {#coordination} | Method and path | Task | | ----------------------------------------------------------- | ---------------------------------------------------------------------------- | | `POST /api/access/collections/{collection}` | Resolve operation and field capabilities for optional `{ id, data, trash }`. | | `POST /api/access/collections/{collection}/selection` | Resolve an access-checked `{ where?, trash? }` to at most 100 IDs. | | `POST /api/access/globals/{global}` | Resolve global capabilities for optional `{ data }`. | | `GET, PUT, DELETE /api/preferences/{key}` | Read, set (`{ value }`), or delete an actor preference. | | `DELETE /api/preferences` | Reset all preferences for the actor. | | `GET, POST, DELETE /api/collections/{collection}/{id}/lock` | Inspect, acquire (`{ takeover? }`), or release an editor lock. | Capability responses help build interfaces. Every later operation independently re-runs access rules and storage predicates, so a cached capability response is never authorization. ## Preview routes {#preview} | Method and path | Task | | ------------------------------------------------------- | -------------------------------------------------------------------- | | `POST /api/preview/collections/{collection}/{id}/token` | Mint a short-lived collection preview token. | | `GET /api/preview/collections/{collection}/{id}` | Read preview content with the preview token as Bearer authorization. | | `POST /api/preview/globals/{global}/token` | Mint a global preview token. | | `GET /api/preview/globals/{global}` | Read a global preview. | | `POST /api/preview/token/revoke` | Revoke `{ "token": "…" }`. | Preview tokens are resource-bound credentials, not general API keys. See [Live preview](https://riducms.com/guides/live-preview/) for iframe URL and update-channel handling. ## Plugin routes {#plugins} Application-authored root, collection, and global routes appear in the same generated OpenAPI document. Their handlers own arbitrary request and response shapes, and they are not authenticated automatically. See [Custom endpoints](https://riducms.com/docs/custom-endpoints/) for mounting, path parameters, actor/LocalAPI context, limits, route precedence, and raw SDK calls. Compiled plugins contribute concrete method/path pairs to the generated OpenAPI document. Generic namespaced endpoints use `/api/plugins/{plugin-key}/{endpoint}`; a plugin transport may instead declare its exact path, such as the official GraphQL transport. Only declared methods are accepted, request bodies are bounded, and plugin errors use the same Ridu envelope. Inspect your generated OpenAPI file and the installed plugin's reference module, such as [`graphql`](https://riducms.com/reference/graphql/), for its available routes. ## Query-string encoding {#queries} Collection list and count routes reject unknown query parameters. | Parameter | Encoding and limit | | ----------------- | --------------------------------------------------------------------------------------------------------------------------- | | `page` | Positive integer; default `1`, maximum `1,000,000`. | | `limit` | Positive integer; default `10`, maximum `100`. | | `sort` | Repeat the parameter for each field; prefix a field with `-` for descending order. | | `where` | URL-encoded JSON query expression. | | `select` | URL-encoded JSON selection object. | | `populate` | URL-encoded JSON population object. | | `depth` | Integer from `0` to `5`; expands eligible relationship roots uniformly. Cannot be combined with `populate`. | | `trash` | Exactly `true` or `false`; `true` requires trash capability. | | `locale` | Locale code, `all`, or `*`. | | `fallback-locale` | One locale, a comma-separated chain, or `false`. `fallbackLocale` is an accepted alias, but the two names may not conflict. | ```ts title="raw-fetch.ts" const query = new URLSearchParams({ page: '1', limit: '20', where: JSON.stringify({ status: { equals: 'published' } }), select: JSON.stringify({ title: true, author: true }), locale: 'fr', 'fallback-locale': 'en' }); query.append('sort', '-createdAt'); query.append('sort', 'title'); const response = await fetch(`${origin}/api/collections/posts?${query}`, { credentials: 'include' }); ``` Exact operators and resource paths come from the generated contract; see [Querying data](https://riducms.com/docs/querying/). ## Requests, responses, and limits {#requests-responses} JSON input is strict: request objects reject unknown fields, duplicate keys, trailing data, excessive structural complexity, and bodies over the configured server limit (1 MiB by default). Send `Content-Type: application/json` for JSON and `multipart/form-data` for direct uploads. Successful resource reads use Ridu envelopes such as `{ "doc": … }`, `{ "docs": …, "pagination": … }`, or capability-specific envelopes. `204` is not the generic delete shape; delete operations return a JSON `{ id, deleted: true }` envelope. Every response includes `X-Request-ID`; include it when reporting a failure. CORS permits `Accept`, `Authorization`, `Content-Type`, and `If-Match` by default when an origin is allowed. `If-Match` accepts a quoted or unquoted positive revision. Host allowlists, CORS, rate limits, request timeouts, upload admission, and plugin-specific body limits may reject a request before its handler runs. ## Errors {#errors} Failures use one stable JSON envelope. Validation errors use HTTP 422 and put field-addressable problems in `issues`; conflicts use HTTP 409. Do not branch on message text. ```json title="response.json" { "error": { "code": "validation", "status": 422, "message": "document validation failed", "requestId": "req_…", "issues": [{ "code": "required", "path": "title", "message": "title is required" }] } } ``` The generated OpenAPI file is the language-neutral authority for enabled paths and schemas. The [protocol reference](https://riducms.com/reference/protocol/) lists the shared envelopes and stable error-code union; the [SDK reference](https://riducms.com/reference/sdk/) lists the typed Fetch methods. Prefer the [TypeScript SDK](https://riducms.com/docs/typescript-sdk/) when TypeScript is available—it performs query encoding and success-envelope checks for you. --- # Custom endpoints Canonical URL: https://riducms.com/docs/custom-endpoints/ Custom endpoints add application-specific HTTP behavior beside Ridu’s generated REST API. Declare them on `ridu.Config`, a `ridu.Collection`, or a `ridu.Global`; Ridu keeps their public method, path, and summary in the v1 manifest and generated OpenAPI document while the compiled Go handler stays runtime-only. ## Mounting and paths {#mounting} The config location determines the route prefix: | Declaration | Mounted route | | --------------------------- | ------------------------------------------ | | `ridu.Config.Endpoints` | `/api` | | `ridu.Collection.Endpoints` | `/api/collections/` | | `ridu.Global.Endpoints` | `/api/globals/` | `Path` starts with `/`. A complete segment beginning with `:` captures one decoded value, so `/:id/tracking` exposes `id`. Configured static segments and parameter names cannot contain whitespace, percent escapes, traversal, query strings, fragments, partial parameters, or empty segments. A path of `/` targets the scope root, and requests may include one trailing slash. Root endpoints require a static first segment and cannot enter the reserved `/collections/…` or `/globals/…` namespaces; declare those handlers on the resource. Captured values must be non-empty and cannot decode to `/` or `\`. When multiple methods share a path shape, use the same parameter name in each declaration so the generated OpenAPI path remains unambiguous. Supported methods are `CONNECT`, `DELETE`, `GET`, `HEAD`, `OPTIONS`, `PATCH`, `POST`, and `PUT`; config resolution accepts any case and stores uppercase metadata. Collection and global endpoint matching stays inside its known resource scope. Within one scope, custom endpoints run before a built-in route for the same method. This supports a wrapper or replacement such as `GET /count`; a custom endpoint registered for a different method does not hide the built-in method. ## Add a collection endpoint {#collection-endpoint} This Payload-familiar tracking route is available at `GET /api/collections/orders//tracking`: ```go title="content/orders.go" package content import ( "encoding/json" "net/http" "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) var Orders = ridu.Collection{ Slug: "orders", Fields: []field.Definition{ field.Text("reference", field.Required()), }, Endpoints: []ridu.Endpoint{{ Method: http.MethodGet, Path: "/:id/tracking", Summary: "Read order tracking", Handler: func(ctx ridu.EndpointContext) { if ctx.Actor == nil { http.Error(ctx.Writer, "authentication required", http.StatusUnauthorized) return } id := ctx.RouteParams["id"] // The same value is also available through ctx.Request.PathValue("id"). ctx.Writer.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(ctx.Writer).Encode(map[string]string{ "id": id, "status": "in-transit", }) }, }}, } ``` The typed `Collection` or `Global` field identifies the owning scope without parsing the URL. ## Use the authenticated local API {#local-api} `EndpointContext.Local` is the application’s Local API. Pass both actor fields into options so collection/global access, validation, hooks, transactions, and field redaction remain authoritative: ```go title="content/order-endpoint.go" order, err := ctx.Local.FindWithOptions( ctx.Request.Context(), "orders", ctx.RouteParams["id"], ridu.FindOptions{ Actor: ctx.Actor, ActorCollection: ctx.ActorCollection, }, ) if err != nil { // Translate the operation failure to the endpoint's chosen public response. http.Error(ctx.Writer, "order unavailable", http.StatusNotFound) return } ``` The endpoint chooses its own response envelope. Return JSON, text, an empty response, or a bounded stream as the route contract requires. Ridu still applies host and origin checks, CORS preflight, request IDs and deadlines, identity resolution, panic recovery, and error reporting. ## Root and global endpoints {#root-and-global} Root endpoints belong on the top-level config: ```go title="content/config.go" return ridu.Config{ Name: "Acme Editorial", Endpoints: []ridu.Endpoint{{ Method: http.MethodPost, Path: "/revalidate/:site", Summary: "Revalidate a frontend site", Handler: revalidateSite, }}, Collections: []ridu.Collection{Orders}, Globals: []ridu.Global{SiteSettings}, } ``` That route mounts at `POST /api/revalidate/:site`. A global declaration with `Path: "/refresh"` on `site-settings` mounts at `/api/globals/site-settings/refresh`. ## Body limits, cancellation, and errors {#safety} `MaxBodyBytes: 0` inherits `ridu.HandlerOptions.MaxBodyBytes` (1 MiB by default). A positive value sets a tighter route limit through `http.MaxBytesReader`. A negative value opts trusted streaming code out of that byte limit; pair it with explicit work, duration, and downstream bounds. Use `ctx.Request.Context()` for every dependency call. It carries client cancellation and the framework request deadline. `ctx.RequestID` matches the `X-Request-ID` response header. Call `ctx.ReportError(err, "stable_code")` when the endpoint writes its own public failure response but an internal dependency error should reach `HandlerOptions.RequestError` and request observations. The trusted error is never copied into Ridu’s panic response. An authentication-like endpoint should call `ctx.AdmitAuthAttempt` before work that aliases or repeated requests can amplify. ## Call a custom endpoint from TypeScript {#typescript} Custom endpoints own arbitrary request and response shapes, so the SDK exposes raw Fetch rather than pretending they share collection envelopes: ```ts title="tracking.ts" const response = await ridu.request(`/api/collections/orders/${encodeURIComponent(id)}/tracking`, { method: 'GET' }); if (!response.ok) throw new Error(`tracking failed: ${response.status}`); const tracking = (await response.json()) as { id: string; status: string }; ``` `request` accepts only a same-origin absolute-path reference. It retains configured credentials, default and per-call headers, middleware, `AbortSignal`, and `keepalive`, but returns the raw `Response` for every status and does not add a content type or parse an envelope. Use it for custom endpoints; keep ordinary content work on the generated typed methods. ## OpenAPI and generation {#openapi} The v1 manifest contains each custom endpoint’s uppercase method, Payload-style path, and optional summary. Generation converts named segments to OpenAPI path parameters, for example `/:id/tracking` to `/{id}/tracking`. The request and response schemas remain endpoint-owned, so the generated operation documents unconstrained `2XX` and default responses. OpenAPI has no standard `CONNECT` Path Item operation, so Ridu records that method under the valid `x-ridu-connect` vendor extension. With `ridu dev` running, saving the config regenerates `generated/ridu.openapi.json`; inspect and commit that file. Use `ridu generate` only when you need the same update as a one-shot command, such as in CI. Executable handlers, body-limit choices, actor data, and secrets never enter the manifest. Invalid methods, paths, duplicates within one scope, or missing handlers fail config resolution before the server starts. --- # CORS Canonical URL: https://riducms.com/docs/cors/ Ridu accepts same-origin browser requests without extra configuration. Configure CORS only when JavaScript running on one origin—such as `https://app.example.com`—calls a Ridu API on another, such as `https://cms.example.com`. CORS is a browser boundary, not authentication or authorization. Ridu still authenticates the caller, applies access rules, validates input, and redacts fields after the browser is allowed to send the request. Server-to-server calls do not need CORS configuration. ## Do I need CORS? {#when-needed} An origin is the exact combination of scheme, hostname, and port. | Client arrangement | Configuration | | ------------------------------------------------------------------ | -------------------------------------------------------- | | Embedded Ridu admin calling its own API | None; it is same-origin | | Frontend and API on the same scheme, hostname, and port | None | | Browser frontend on a different subdomain, domain, scheme, or port | Add the frontend's exact origin | | Server-rendered backend or worker calling Ridu | None; authenticate the request instead | | Live-preview page on another origin | Configure CORS and the separate preview message boundary | Do not add the CMS origin merely because it is the request destination. `AllowedOrigins` contains the origins where calling browser code runs. Ridu also accepts a request whose `Origin` exactly matches the API's effective request origin. ## Configure a generated application {#generated-application} Generated servers read a comma-separated `RIDU_ALLOWED_ORIGINS` value: ```sh title="terminal" export RIDU_ALLOWED_ORIGINS='https://app.example.com,https://staff.example.com' ``` Use complete origins with no path, query, fragment, credentials, or trailing slash. Ridu canonicalizes host casing and default ports, but it does not support `*` or wildcard subdomains. List each trusted browser origin. For local frontend development, add the exact dev-server port: ```sh title="terminal" RIDU_ALLOWED_ORIGINS='http://localhost:5173' ridu dev ``` `ridu dev` automatically allows its admin dev server. A separate application dev server still needs its own origin. In production, set `RIDU_ALLOWED_ORIGINS` in the environment that starts the Ridu binary—for example in your container, service manager, or hosting provider. ## Where `WithHandlerOptions` goes {#handler-options} ### Projects created by `ridu new` {#generated-handler-options} Set `RIDU_ALLOWED_ORIGINS`; the generated `cmd/server/main.go` already passes its comma-separated values to `HandlerOptions.AllowedOrigins`. You do not need to edit the Go entrypoint for ordinary origin configuration. ### Custom `ridu.Execute` entrypoints {#custom-execute} If the application did not come from `ridu new`, pass `WithHandlerOptions` directly to `ridu.Execute`, beside `WithStore` and `WithAddress`: ```go title="cmd/server/main.go" add={8-12} func main() { err := ridu.Execute( content.Config(), ridu.WithStore(func(ctx context.Context) (store.Store, error) { return postgres.Open(ctx, os.Getenv("DATABASE_URL")) }), ridu.WithAddress(":8080"), ridu.WithHandlerOptions(ridu.HandlerOptions{ AllowedOrigins: []string{ "https://app.example.com", }, }), ) if err != nil { log.Fatal(err) } } ``` `WithHandlerOptions` is an execute option, not a top-level statement or collection setting. ### Application-owned HTTP servers {#custom-handler} If you create the application with `ridu.New` and own `http.Server` yourself, do not use `WithHandlerOptions`. Pass the value to `app.Handler` where you construct the HTTP handler: ```go title="cmd/server/main.go" app, err := ridu.New(content.Config(), backend) if err != nil { log.Fatal(err) } handler := app.Handler(ridu.HandlerOptions{ AllowedOrigins: []string{"https://app.example.com"}, AllowedRequestHeaders: []string{ "X-Workspace-ID", }, }) log.Fatal(http.ListenAndServe(":8080", handler)) ``` When you construct `http.Server` yourself, check application readiness before accepting traffic; `ridu.Execute` performs that check before binding automatically. `AllowedOrigins` and `AllowedHosts` solve different problems. Origins identify browser callers; hosts restrict the public hostnames accepted by the API. Do not add a hostname to one list merely because it appears in the other. See the complete [`HandlerOptions` reference](https://riducms.com/reference/ridu/handler-options/) for request, readiness, proxy, cookie, and worker controls. ## Allow a custom request header {#custom-request-headers} Skip this section unless your browser request sends a header outside Ridu's defaults. Ridu already allows `Accept`, `Authorization`, `Content-Type`, and `If-Match`. For example, if the browser sends `X-Workspace-ID`, add `AllowedRequestHeaders` inside the existing `HandlerOptions` block in `cmd/server/main.go`: ```go title="cmd/server/main.go" add={4-6} ridu.WithHandlerOptions(ridu.HandlerOptions{ AdminAssets: adminassets.FS(), AllowedOrigins: envList("RIDU_ALLOWED_ORIGINS"), AllowedRequestHeaders: []string{ "X-Workspace-ID", }, AllowedHosts: envList("RIDU_ALLOWED_HOSTS"), }) ``` Add only headers that your frontend actually sends. Invalid HTTP header names are ignored, and a preflight asking for an unlisted header fails closed with `cors_header_denied`. ## Cookies and the TypeScript SDK {#credentials} `@riducms/sdk` defaults to Fetch credentials mode `include`, so allowed cross-origin responses carry `Access-Control-Allow-Credentials: true` and echo the exact allowed origin. Plain Fetch calls must opt into credentials when they use Ridu's session cookie: ```ts title="browser.ts" const response = await fetch('https://cms.example.com/api/auth/me', { credentials: 'include' }); ``` Set `SecureCookies` in production; `ridu.Execute` does so unless disabled. The session cookie is `SameSite=Lax`. Separate origins that remain on the same site—for example two HTTPS subdomains—can use the cookie flow. A genuinely cross-site embedded application should put the API on a same-site origin or use an application-owned bearer flow; CORS alone cannot make the browser send an ineligible cookie. ## Preflights and allowed methods {#preflight} Ridu answers a valid preflight with status `204`, credentialed origin headers, and the allowed methods and headers. You can test the boundary independently of application code: ```sh title="terminal" curl -i -X OPTIONS 'https://cms.example.com/api/schema' \ -H 'Origin: https://app.example.com' \ -H 'Access-Control-Request-Method: GET' \ -H 'Access-Control-Request-Headers: Authorization, Content-Type' ``` The browser allow-list is `GET`, `HEAD`, `POST`, `PUT`, `PATCH`, `DELETE`, and `OPTIONS`. That includes cross-origin preference writes at `PUT /api/preferences/{key}` when the origin, requested headers, authentication cookie, and ordinary route authorization all pass. ## Proxies and HTTPS {#proxies} Same-origin comparison uses the API's effective scheme and host. When TLS terminates at a reverse proxy, configure only that proxy's immediate network in `TrustedProxyCIDRs` (or `RIDU_TRUSTED_PROXY_CIDRS`). Ridu trusts forwarded scheme and client-address headers only from those networks. Without correct proxy trust, a browser may send `Origin: https://cms.example.com` while the Go process sees an untrusted HTTP request. Ridu treats those as different origins instead of trusting a spoofable forwarded header. Keep `AllowedHosts` aligned with the public API hostname as a separate host-header defense. ## Diagnose a blocked request {#troubleshooting} Use the browser network panel to inspect the preflight and the API response, then match the stable Ridu error: | Error | Meaning | | -------------------- | ------------------------------------------------------------------------------ | | `origin_denied` | The origin is malformed, not listed, or differs from the effective scheme/host | | `cors_method_denied` | The preflight requested a method outside the browser allow-list | | `cors_header_denied` | The preflight requested an unlisted or invalid header | Common mistakes are including a trailing slash, allowing the API rather than the browser origin, forgetting a local dev-server port, adding a custom header only on the frontend, or terminating HTTPS at an untrusted proxy. A failed `GET` or `HEAD` may appear only as a browser CORS error because Ridu withholds the allow-origin response header; mutating requests and rejected preflights also return a structured `403`. For session-specific failures, continue with [Authentication](https://riducms.com/docs/authentication/). For preview iframes and `postMessage`, also follow [Live preview](https://riducms.com/guides/live-preview/#cross-origin): its origin, source-window, and channel checks are separate from CORS. --- # Authentication Canonical URL: https://riducms.com/docs/authentication/ Ridu models an identity as a document in an auth-enabled collection. That keeps roles, profiles, access rules, field redaction, hooks, and generated types in the same content model while private password hashes, session tokens, API keys, and recovery tokens stay in store-owned credential records. Secrets never become fields, manifest data, hook input, or ordinary API output. ## Define an auth collection {#auth-collections} Set `Auth: true` and provide a required, unique, non-localized `email` field. It can be an Email or Text field; `email` is the built-in password strategy's fixed identity name. `Config.Admin.User` selects which auth collection is allowed to establish an admin identity. ```go title="content/users.go" package content import ( "time" "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Admin: ridu.AdminConfig{User: "users"}, Collections: []ridu.Collection{Users}, } } var Users = ridu.Collection{ Slug: "users", Auth: true, AuthConfig: ridu.AuthConfig{ SessionDuration: 7 * 24 * time.Hour, MaxLoginAttempts: 5, LockDuration: 15 * time.Minute, Password: ridu.PasswordPolicy{ MinLength: 12, MaxBytes: 72, BcryptCost: 12, }, PasswordReset: ridu.PasswordResetConfig{ TokenDuration: time.Hour, Send: sendPasswordReset, }, Verify: &ridu.VerifyEmailConfig{ TokenDuration: 24 * time.Hour, Send: sendVerification, }, APIKeys: true, }, Fields: []field.Definition{ field.Email("email", field.Required(), field.Unique()), field.Select("role", field.OneOf("admin", "editor", "author"), field.Default("author"), ), }, } ``` An auth collection requires a store implementing `store.AuthStore`. Production execution also expects `store.AuthMaintenanceStore` so expired sessions and keys are pruned; all three official database adapters implement both. MongoDB availability remains inside its [bounded production profile](https://riducms.com/docs/mongodb/). ## Provision users safely {#provisioning} Auth users must be created atomically with a password credential. Generic REST, multipart, remote-upload, and duplicate creation reject auth collections and direct callers to `/api/auth/{collection}/create-user`. In TypeScript, use the generated SDK: ```ts const user = await ridu.createAuthUser( 'users', { email: 'editor@example.com', role: 'editor' }, 'a long application-chosen password' ); ``` The dynamic Go local API can create or import an auth collection document, but that alone does not create a password credential and the document cannot log in. Use `CreateAuthUser` for a login-capable account. When importing existing users, attach passwords with trusted `SetPassword` provisioning code. The transport creation path has this first-run rule: 1. If `CollectionAccess.Create` is omitted, one anonymous request may create the first active user only in `Config.Admin.User`. 2. After that first user, anonymous creation is denied. Other auth collections are never opened by the implicit bootstrap rule. 3. If you define `CollectionAccess.Create`, that rule decides every creation request. Use it to provide public registration or restrict provisioning to administrators. When the configured admin collection is eligible, opening `/admin` redirects to the `/admin/create-first-user` setup screen. It renders the collection fields, creates the account through the same atomic operation, and signs the new administrator in. Once an active user exists, the setup route closes and the normal login screen takes over. Automation can check the boolean `GET /api/auth/{collection}/bootstrap` response before calling `create-user`; the database transaction remains the authority if two callers race. The one-time operation can set fields whose Create access normally requires an authenticated actor, because no actor exists before the first administrator. Schema validation, hooks, password policy, and the atomic transaction still run. Every later create uses the authored field access rules normally. The first admin bootstrap credential is marked verified so a broken or not-yet-configured delivery system cannot lock the initial operator out. Later users in a verification-enabled collection must consume a verification token before login. Go application code uses `app.CreateAuthUser`/`CreateAuthUserWithOptions`; HTTP adapters use `CreateAuthUserForTransport` to include the one-user bootstrap behaviour. All forms create the document and credential atomically and run create access, validation, hooks, and version logic. `app.AuthInitialized` reveals only whether an active auth document exists, not any user data. `app.SetPassword` is a trusted application operation for an existing user; it revokes existing sessions and should not be exposed as an unauthorised arbitrary-user endpoint. ## Exact identity with multiple auth collections {#multiple-auth} An application can define `users`, `staff`, `customers`, or other auth collections, but document IDs are not globally unique. Ridu therefore represents a transport identity as both a collection slug and an actor document: ```go type AuthIdentity struct { Collection schema.CollectionSlug Actor store.Document } ``` Sessions return the same pair as `AuthSession.Collection` and `AuthSession.User`. Preserve both in `FindOptions.ActorCollection`, `MutationOptions.ActorCollection`, access/hook context, audit data, and upload inputs when using the trusted local API. Application services for scheduled work, preferences, previews, account unlocks, and document locks accept `AuthIdentity` directly and reload the actor from that exact collection. `Config.Admin.User` chooses the admin login collection; it does not disable the other collections for API authentication. `CollectionAccess.Admin` on that collection can still deny a particular authenticated user from entering the admin. ## Browser sessions {#sessions} Password login creates an opaque server-stored session and sets a `ridu_session` cookie. The cookie is `HttpOnly`, `SameSite=Lax`, scoped to `/`, and expires at the session's absolute expiry. Set `HandlerOptions.SecureCookies` for HTTPS; `ridu.Execute` enables secure cookies unless `RIDU_SECURE_COOKIES=false` is set. The generated Fetch client includes credentials. For a separate browser origin, list the exact origin in `HandlerOptions.AllowedOrigins`; Ridu then emits credentialed CORS responses. SameSite=Lax still does not make a cross-site embedded authentication design work—deploy the API on a same-site origin or choose an application-owned bearer flow. ```ts title="src/auth.ts" await ridu.login('users', { email: 'editor@example.com', password: 'correct horse battery staple' }); const current = await ridu.session(); console.log(current.collection, current.user, current.expiresAt); const sessions = await ridu.sessions(); await ridu.revokeSession(sessions.find((item) => !item.current)!.id); await ridu.refreshSession(); await ridu.logout(); ``` `refreshSession` atomically rotates the bearer token and invalidates the old token; it does not extend the original absolute expiry. `logout` is idempotent and revokes the current token. `logoutAll` revokes every session for the identity. Session listings expose only safe metadata—ID, created/last-seen/expiry times, IP address, user agent, and whether it is current. For non-cookie clients, send a raw session as `Authorization: Session `. `JWT` remains an accepted compatibility scheme, but the token is opaque and is not a JWT. Application code can use `LoginWithOptions` to record a normalized client IP and user agent, and `Session`, `RotateSession`, `Sessions`, `RevokeSession`, `Logout`, and `LogoutAll` to manage the same lifecycle. ## Password policy and lockout {#password-policy} Zero-valued auth config resolves to secure defaults: | Setting | Default and boundary | | --------------------- | ---------------------------------------------------------- | | `SessionDuration` | 24 hours; configured values must be at least one minute | | `Password.MinLength` | 8 Unicode code points | | `Password.MaxBytes` | 72 UTF-8 bytes, bcrypt's safe input ceiling | | `Password.BcryptCost` | bcrypt default cost (10); accepted range is 4–16 | | `MaxLoginAttempts` | 5; set `-1` to disable account lockout | | `LockDuration` | 10 minutes; configured lockout must be at least one second | Ridu uses length rules rather than mandatory character classes. Add application-specific breached password or product rules with `Password.Validate`; return a user-safe explanation. Raising the bcrypt cost transparently upgrades an older hash after successful login. Credential failures use one `access_denied` response—unknown identity, wrong password, lockout, deleted/inaccessible user, and concurrent credential changes do not reveal which fact was true. Password hashing is admission-bounded, and HTTP login has an additional identity/client-window rate limiter configured with `HandlerOptions.AuthRateLimit` and `AuthRateWindow`. `app.ForceUnlock` and the SDK `forceUnlock` clear failed-attempt state only after collection update access authorizes the caller. Changing a password verifies the current password, applies the new policy, and revokes every session and API key for that user. The browser cookie is cleared by the HTTP endpoint. A trusted `SetPassword` also revokes sessions; use the reset flow for an untrusted user who has forgotten the current password. ## Password reset and email verification {#recovery-verification} Recovery is enabled only when `PasswordReset.Send` is non-nil. Verification is enabled when `Verify` is non-nil and also needs its `Send` callback. Ridu creates a random, single-use token, stores only its digest, and gives the raw token once to the trusted callback: ```go func sendPasswordReset(ctx context.Context, note ridu.PasswordResetNotification) error { return mailer.SendReset(ctx, note.User.ID, resetURL(note.Collection, note.Token), note.ExpiresAt) } ``` The callback owns email/SMS delivery and link construction. Never log the token or place it in a long-lived job payload without equivalent secret handling. A callback error prevents a success response, so enqueue durably before returning if delivery must survive process failure. `RequestPasswordReset` is a successful no-op for an unknown identity. `RequestVerification` is a successful no-op for unknown or already-verified identities. These behaviours prevent account enumeration. A reset token is consumed exactly once; resetting replaces the password, clears lockout, and revokes all sessions and API keys in one auth-store transaction. A verification token is likewise single-use. Invalid or expired tokens return `invalid_auth_token`. The SDK exposes `requestPasswordReset`, `resetPassword`, `requestVerification`, and `verifyEmail`; the framework admin includes the matching account flows. ## API keys {#api-keys} Set `AuthConfig.APIKeys: true` to allow an authenticated session to mint independent bearer keys. Creation requires cookie/session authentication and `AuthConfig.Access.APIKey` permission. ```ts const created = await ridu.createAPIKey({ name: 'content sync', expiresAt: '2026-12-31T23:59:59Z' }); saveInSecretManager(created.key); // shown once ``` Send the secret as `Authorization: Bearer `. Listing keys returns metadata only; the raw key cannot be recovered. Keys can be revoked individually, expire automatically, and are all revoked by password change/reset. API keys authenticate as their current owner document and exact auth collection; they do not freeze the user's role or bypass later content access checks. ## Custom request strategies {#custom-strategies} `AuthConfig.Strategies` integrates a proxy assertion, signed header, or application-owned identity provider without creating a browser session: ```go Strategies: []ridu.AuthStrategy{{ Name: "trusted-proxy", Authenticate: func(ctx ridu.AuthStrategyContext) (ridu.AuthStrategyResult, error) { values := ctx.Headers["X-Authenticated-User"] if len(values) != 1 { return ridu.AuthStrategyResult{Authenticated: false}, nil } userID, err := verifyProxyAssertion(values[0]) if err != nil { return ridu.AuthStrategyResult{}, err } return ridu.AuthStrategyResult{Authenticated: true, UserID: userID}, nil }, }}, ``` Strategies run after cookie sessions, bearer API keys, and session authorization headers, then in configured collection/declaration order. Return `Authenticated: false` when the request does not belong to the strategy; a matched result must return a user ID in that strategy's collection. Ridu reloads the user through normal read access, then applies login access and before/after-login hooks. `AuthStrategyContext.Headers` uses canonical HTTP header names. Validate the external credential completely—Ridu does not know a proxy header is trustworthy. The transport treats an invalid credential or strategy error as no authenticated actor; protected content must therefore deny anonymous access. Call `AuthenticateExternalIdentity` directly when application code needs the exact failure and collection identity. ## Auth access and hooks {#auth-rules-hooks} Authentication-specific policy lives beside the collection: | Contract | Operations | | -------------------------- | ----------------------------------------------------------------------------------------------------------- | | `AuthAccess.Login` | Password and matched external-strategy login | | `AuthAccess.PasswordReset` | Forgot/reset-password lifecycle | | `AuthAccess.Verification` | Request/consume verification lifecycle | | `AuthAccess.APIKey` | Create, list, and revoke API keys | | `AuthAccess.Session` | List/revoke sessions and logout-all management | | `AuthHooks` | Before/after login, logout, refresh, forgot password, password reset, verification, API key, plus `AfterMe` | Nil auth rules allow their operation. Auth hooks receive `AuthContext` with operation, collection stable ID, safe user/identity metadata, IP/user agent, and a local API—but never passwords or raw tokens. Before hooks can reject. If an after-login or after-refresh hook fails, Ridu revokes the newly issued credential before returning `auth_hook_failed`. Authentication only establishes an actor. The collection and field access rules for the next document operation still run. An auth access callback error becomes `auth_access_failed` (500); a false decision becomes `access_denied` (403). Disabled optional flows return `auth_feature_disabled` (404), invalid credentials/authentication return a generic `access_denied` (401), and invalid recovery tokens return `invalid_auth_token` (400). Treat messages as human diagnostics and branch on stable codes. For host/origin/proxy hardening, request audit events, and production cookie settings, continue with [Security and trust boundaries](https://riducms.com/docs/security/) and [REST API](https://riducms.com/docs/rest-api/). Exact Go methods and structures are in the [Go API reference](https://riducms.com/reference/ridu/). --- # Editorial workflows Canonical URL: https://riducms.com/docs/editorial-workflows/ Start with the authoring task you need: | Task | Guide | | ----------------------------------- | ----------------------------------------------------------------------- | | Find, filter, sort, and select work | [Browse and organize content](https://riducms.com/docs/browsing-content/) | | Reopen a useful list workspace | [Saved views, folders, and hierarchy](https://riducms.com/docs/saved-views-and-hierarchy/) | | Use the schema-driven form | [Create and edit documents](https://riducms.com/docs/editing-documents/) | | Change many records or recover one | [Bulk actions and trash](https://riducms.com/docs/bulk-and-trash/) | | Coordinate concurrent editors | [Document locks](https://riducms.com/docs/document-locks/) | | Publish, restore, or schedule | [Drafts and versions](https://riducms.com/docs/drafts-and-versions/) | | Translate content | [Localization](https://riducms.com/docs/localization/) | | Preview unsaved changes | [Live preview](https://riducms.com/guides/live-preview/) | ## Duplicate a document {#duplicate} Duplicate runs a create lifecycle from an authorized source snapshot and accepts create-style overrides: ```ts const copy = await client.duplicate('posts', original.id, { title: `${original.title} (copy)`, slug: 'hello-ridu-copy' }); ``` Ridu checks source read access, redacts denied fields, validates the new input, applies create access and hooks, assigns a new ID/timestamps, and writes in one transaction. Unique values usually need an override. Localized documents retain their locale data according to the duplicate contract; use the dedicated [copy-locale operation](https://riducms.com/docs/localization/#copy-locale) to translate one existing document in place. ## Run atomic bulk actions {#bulk} Bulk edit, publish, unpublish, delete, trash restore, and permanent delete accept a bounded reviewed selection and commit atomically. Follow [Bulk actions and trash](https://riducms.com/docs/bulk-and-trash/#bulk-actions) for admin steps, SDK examples, the 100-document limit, and rollback behavior. ## Enable trash {#enable-trash} Set `Trash: true` on a collection when normal deletion should be recoverable. With `ridu dev` running, saving that change regenerates contracts and safely prepares the local development store; create the reviewed migration before deployment. [Bulk actions and trash](https://riducms.com/docs/bulk-and-trash/#enable-trash) covers the active/trash workspaces, restore behavior, and the difference between soft and permanent deletion. ## Permanently delete {#permanent-delete} Permanent deletion and **Empty trash** are destructive, bounded operations. Read [Permanently delete content](https://riducms.com/docs/bulk-and-trash/#permanent-delete) before using them with uploads, references, or retained version history. ## Coordinate editors with document locks {#locks} Enable expiring authoring leases with `LockDocuments: true`. [Document locks](https://riducms.com/docs/document-locks/) explains refresh, read-only behavior, separately authorized takeover, SDK integration, and why `_revision` remains the final write fence. ## Persist author preferences {#preferences} Authenticated users have namespaced JSON preferences for saved list views, columns, navigation state, locale choice, and application/plugin UI: ```ts await client.setPreference('posts:list:default', { columns: ['title', 'status', 'updatedAt'], sort: ['-updatedAt'] }); const view = await client.preference('posts:list:default'); await client.deletePreference('posts:list:default'); ``` Keys are 1–200 characters and use lowercase letters, numbers, `:`, `.`, `_`, or `-`. Preference ownership includes the exact auth collection as well as user ID, so identical document IDs in two auth collections cannot share state accidentally. `resetPreferences` removes every preference for the current identity. Preferences are convenience state, never authorization. A saved filter or hidden column cannot expand the current user's capabilities. ## Ask what the actor can do {#capabilities} Use collection/global capability endpoints to enable an action before the user clicks it, and `resolveFilteredSelection` to turn the current authorized filter into a bounded bulk target set. Capability responses contain booleans and non-secret presentation information; they never serialize access callbacks or filtered predicates. Always handle a denied operation anyway. State or access can change between capability evaluation and mutation, and the server is the authority. For revision history, drafts, publishing, restore, autosave, and scheduling, continue with [Drafts and versions](https://riducms.com/docs/drafts-and-versions/). See [The Ridu admin](https://riducms.com/docs/admin/) for the full authoring surface and [Access control](https://riducms.com/docs/access-control/) for the rule matrix. --- # Model Context Protocol Canonical URL: https://riducms.com/docs/mcp/ Ridu's optional MCP plugin lets coding agents and other Model Context Protocol clients discover and read selected CMS content. It is a compiled Go plugin served by the application binary at `/api/mcp`; no Node server or separate authorization layer is introduced. ## Use it in a new project {#new-project} Start with a generated project, enable API keys on the auth collection that will own agent identities, and add `ridumcp.New` below. MCP is a Go-only transport: there is no npm/admin half to install or pair. ## Add it to an existing project {#existing-project} Import `github.com/riducms/ridu/plugins/mcp` from the project's published Ridu module and register it in executable config. Run `go mod tidy`; do not add a JavaScript MCP server or a second content API. Choose the smallest explicit resource allowlist and a least-privileged auth user before issuing a key. ## Enable selected resources {#enable} ```go title="content/config.go" import ridumcp "github.com/riducms/ridu/plugins/mcp" func Config() ridu.Config { return ridu.Config{ // ... Plugins: []ridu.Plugin{ ridumcp.New(ridumcp.Config{ Collections: []ridumcp.Resource{ {Slug: "posts", Description: "Published editorial posts."}, }, Globals: []ridumcp.Resource{{Slug: "site-settings"}}, DefaultLimit: 20, MaxLimit: 100, }), }, } } ``` Only listed resources become tools. Configuration with an unknown resource or colliding normalized tool name fails application startup. Saving the config while `ridu dev` is running regenerates the tool contract before restarting the application. Complete and verify the installation: ```bash title="terminal" go mod tidy npm run dev ``` The transport alone adds no adapter tables, so it does not need a migration. If enabling API keys or the same change alters the resolved resource schema, prepare the selected adapter's reviewed migration before deployment. Run `npm run ridu -- check` before committing. Test `initialize`, `tools/list`, and one allowed read with an expiring key; also confirm that an anonymous request, an unlisted collection, and a field denied to that actor are rejected. ## Authenticate the client {#authenticate} Enable API keys on the relevant auth collection, create an expiring key for a least-privileged user, and send it as a bearer token: ```json title="mcp.json" { "mcpServers": { "Ridu": { "type": "http", "url": "https://cms.example.com/api/mcp", "headers": { "Authorization": "Bearer ridu__" } } } } ``` Anonymous requests receive `401`, unsupported methods receive `405`, and request body and result sizes are bounded. Keep keys out of source control, set expirations, and revoke keys that are no longer used. ## Authorization and tools {#tools} Each collection contributes `ridu_find_collection_` with pagination, selection, locale, fallback, all-locale, and draft inputs. Each global contributes `ridu_find_global_` with selection and localization inputs. Every call enters the ordinary Local API and operation engine with the API key's owning actor. Filtered collection access remains in the store query, field access redacts values, and localization and draft rules are unchanged. Tool annotations describe read-only behavior; they are not the security boundary. The current plugin does not provide create, update, delete, prompts, custom resources, or edits to Go config. Those require an explicit per-key side-effect capability and audit contract before Ridu can expose them safely. See the [`plugins/mcp` API reference](https://riducms.com/reference/mcp/) for the exact exported configuration types. --- # Drafts and versions Canonical URL: https://riducms.com/docs/drafts-and-versions/ Versions and drafts are related but separate. `Versions: true` records immutable snapshots and adds optimistic revisions. `VersionConfig.Drafts: true` makes unpublished status part of the ordinary authoring workflow. You can keep history without enabling draft creation. ## Enable revision history {#enable-versions} ```go title="content/posts.go" package content import ( "time" "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) var Posts = ridu.Collection{ Slug: "posts", Versions: true, VersionConfig: ridu.VersionConfig{ Drafts: true, MaxPerDocument: 100, AutosaveInterval: 30 * time.Second, }, Fields: []field.Definition{ field.Text("title", field.Required()), field.Textarea("summary"), }, } ``` Versioned output includes `_revision` and `_status` (`draft` or `published`). The Go store model exposes the same values as `Document.Revision` and `Document.Status`. | Setting | Current behaviour | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Drafts` | Defaults false. When true, ordinary creates default to draft and draft-specific create/update/restore behaviour is enabled. | | `MaxPerDocument` | Defaults to 100. Every mutation prunes the oldest snapshots beyond this positive per-document limit. | | `AutosaveInterval` | Defaults to 30 seconds when zero; a configured value must be at least one second. It controls the admin's draft-save and published-edit checkpoint timer. | The server does not mutate documents on a timer. For a dirty draft, autosave is the admin calling the same update endpoint, so access, validation, hooks, revisions, and conflicts still apply. A dirty published document is checkpointed in browser storage instead: a background update would make those edits public. Reload restores that checkpoint until the author chooses **Publish changes**. Zero currently selects the 30-second default rather than disabling this timer. Every accepted create, duplicate, update, publish, unpublish, and restore saves the canonical stored document in the same transaction. Reads and delete/trash operations do not create versions. Relationship population, computed output, and field redaction are response shapes and are not copied into the stored snapshot. ## Draft write semantics {#draft-writes} `MutationOptions.Draft` has three states: | Configuration/request | Create | Existing update | | ----------------------------------------------- | ---------------------------------------- | -------------------------------------------------------- | | Versions disabled | Ordinary unversioned document | Ordinary unversioned update | | Versions enabled, drafts disabled, `Draft: nil` | Published | Rejected for the published row; use `PublishChanges` | | Drafts enabled, `Draft: nil` | Draft | Updates a draft; published rows require `PublishChanges` | | `Draft: &true` | Draft; rejected when drafts are disabled | Rejected; use the unpublish lifecycle | | `Draft: &false` | Published | Rejected; use the publish lifecycle | In REST/SDK calls, the equivalent write option is `draft: true` or `draft: false`. Publishing and unpublishing are clearer lifecycle operations than changing status as part of an unrelated update, because they run the publish/unpublish hook operation and are easier to audit. The low-level Go and REST version surface is present on any versioned resource. Treat publish/unpublish as a draft workflow and configure `Drafts: true`; restore-as-draft rejects a versioned resource whose draft support is disabled, and the admin/GraphQL draft actions are driven by that setting. ## Draft read semantics {#draft-reads} `FindOptions.Draft` and `ListOptions.Draft` are also three-state: | Read option | Result set | | ----------------------------- | ------------------------------------------------------------------ | | `Draft: &false` | Published documents only | | `Draft: &true` | Published and draft documents; this is not “drafts only” | | `Draft: nil`, anonymous actor | Published only | | `Draft: nil`, non-nil actor | No status filter; collection/field access still decides visibility | This default gives public anonymous local reads the published view while letting an authenticated author see a draft when access allows it. For application code, do not rely on actor presence as an implicit content mode—set `Draft` at preview, public-rendering, and background-job boundaries. REST and the generated SDK likewise require `draft: true` for draft reads. A draft is not a security boundary. Collection and field access always run, and requesting draft content does not grant permission. Preview tokens provide a separate, short-lived, target-scoped read path for a configured live preview; they do not weaken normal collection routes. See [Editorial workflows](https://riducms.com/docs/editorial-workflows/). ## Publish and unpublish {#publish-unpublish} Publish changes status to `published`; unpublish changes it to `draft`. Both are mutations: they run their dedicated collection access rule (falling back to `Update` only when omitted), update field access, validation, field and collection change/operation hooks, optimistic revision checks, snapshotting, and after-commit work. `PublishChanges` and the SDK's `publishChanges` atomically apply edited values through that same publish lifecycle instead of performing an ordinary update. Body-bearing publish and unpublish operations require both `Update` and their dedicated lifecycle permission. Status-only transitions require only the dedicated permission. An ordinary update of a published versioned row returns `publish_required`; Ridu never silently turns a generic update into a live publication. ```go published, err := app.Local().Publish( ctx, "posts", post.ID, post.Revision, actor, ) if err != nil { return err } draft, err := app.Local().Unpublish( ctx, "posts", post.ID, published.Revision, actor, ) ``` The generated TypeScript client exposes the same intent: ```ts const published = await ridu.publish('posts', id, { revision: post._revision }); const republished = await ridu.publishChanges( 'posts', id, { title: 'Edited and published atomically' }, { revision: published._revision } ); await ridu.unpublish('posts', id, { revision: republished._revision }); ``` `ExpectedRevision`/`revision` is optional at the API level; zero or omission means no fence. For an editor, always send the last observed positive revision. A stale revision returns `conflict` (409) instead of overwriting a newer save. ## Read version history {#version-history} `LocalAPI.Versions` returns retained versions newest first; `Version` reads one positive revision. Each `store.Version` has its own ID, document ID, revision, status, creation time, and snapshot. Version history is not a raw database escape hatch: - `CollectionAccess.ReadVersions` runs independently; when nil, it falls back to `Read`. - A filtered decision is applied to every stored snapshot, so a caller can see only the historical states that match its predicate. - Current field access, computed output, after-read hooks, localization projection, and redaction apply before a snapshot is returned. - Reading a single revision narrows the authorized history before running its output lifecycle. This means changing a field-access rule can hide a value in old snapshots without rewriting stored history. It also means an ownership predicate can expose different revisions to old and new owners. ## Restore without rewriting history {#restore} A restore does not move a pointer backward or delete later revisions. Ridu loads the authorized snapshot, then runs its values through the publish lifecycle when the selected snapshot is published, or the unpublish lifecycle when it is draft. Because the transition carries values, it requires Update plus the matching lifecycle permission and runs current validation, relationship checks, hooks, localization, and optimistic concurrency. The restored document receives the next revision and the restore itself becomes a new snapshot. ```go versions, err := app.Local().Versions(ctx, "posts", post.ID, actor) if err != nil { return err } restored, err := app.Local().Restore( ctx, "posts", post.ID, versions[len(versions)-1].Revision, post.Revision, actor, ) ``` `Restore` preserves the selected snapshot's status. `RestoreAsDraft` copies its values but forces draft status and therefore requires drafts to be enabled. `RestoreVersionWithOptions` exposes the same choice plus exact actor identity, returned population/output selection, revision fence, and locale controls. Restore first requires version-read permission, then Update plus Publish or Unpublish according to the resulting status. For localized resources, the snapshot is restored as a canonical all-locale value set so one locale cannot accidentally splice old data over another. The response can still be projected to the requested locale. ## Schedule collection publishing {#scheduling} Scheduled publishing is durable for versioned collection documents: ```go job, err := app.SchedulePublish( ctx, "posts", post.ID, time.Date(2026, 9, 1, 9, 0, 0, 0, time.UTC), post.Revision, identity, ) ``` Scheduling requires publish capability immediately. If the expected revision is zero, Ridu captures the current revision so a later edit makes the job stale rather than publishing unexpected content. The requesting auth collection and user ID are persisted, not a stale copy of the user document. At execution, the worker reloads that exact user, re-evaluates current publish access, and applies the stored revision fence through the normal publish operation. A deleted user, changed role, removed collection, stale revision, or failed hook leaves an actionable failed scheduled task rather than silently publishing. `ScheduledPublishes` lists queued/running/failed items; `CancelScheduledPublish` cancels or dismisses one after rechecking publish permission. `ridu.Execute` runs the durable task worker. `HandlerOptions.TaskInterval` and `TaskBatch` tune its polling. Directly embedded applications can call `RunScheduledPublishes` from their own worker boundary. Scheduled publishing currently targets collection documents only. Globals support immediate publish/unpublish and version restore, but not scheduled global publishing. ## Versioned globals {#globals} Globals accept the same `Versions` and `VersionConfig` fields. A missing draft-enabled global reads as a schema-shaped draft with defaults; its first `UpdateGlobal` persists revision 1. Use: - `Global`/`GlobalWithOptions` and `UpdateGlobal`/`UpdateGlobalWithOptions`; - `PublishGlobal` and `UnpublishGlobal`; - `GlobalVersions` and `GlobalVersion`; - `RestoreGlobal`, `RestoreGlobalAsDraft`, or `RestoreGlobalVersionWithOptions`. `GlobalAccess.ReadVersions` falls back to `Read`; `GlobalAccess.Publish` and `Unpublish` each fall back to `Update` when omitted. A filtered update cannot initialize a missing singleton because there is no row to match, so its first write needs an unconditional allow decision. Retention, autosave, redaction, restore-as-new-revision, and optimistic conflicts otherwise match collection behaviour. ## Common surprises {#failures} | Symptom | Explanation | | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | Anonymous `Find` cannot see a new document | Draft-enabled creates default to draft; publish it or request authorized draft visibility. | | `Draft: &true` returns published documents too | True means include drafts, not draft-only. Add an authored status field if the product needs another workflow filter. | | Old snapshot has a redacted/missing field | Current field access and after-read lifecycle apply to history reads. | | Restore returns `access_denied` | Restore needs both access to that snapshot and update access to the current document. | | Restore/publish/update returns `conflict` | The expected revision is stale; reload instead of silently retrying with zero. | | Only 100 snapshots remain | Zero `MaxPerDocument` resolves to the 100-version default; raise it if storage policy allows. | | Setting autosave to zero does not stop it | Zero resolves to the current 30-second default; the admin server-saves drafts and locally checkpoints published edits. | | Scheduled job failed after an editor role changed | Execution rehydrates and reauthorizes the original exact identity by design. | Version and publishing methods are listed in the [Local Go API](https://riducms.com/docs/local-api/) and exact Go signatures are in the [Go API reference](https://riducms.com/reference/ridu/). For browser and wire forms, see the [TypeScript SDK](https://riducms.com/docs/typescript-sdk/) and [REST API](https://riducms.com/docs/rest-api/). --- # Browse and organize content Canonical URL: https://riducms.com/docs/browsing-content/ Open a collection list to search, filter, sort, select, and organize documents. Available columns, workflow and locale states, and actions come from the resolved schema and the current actor's capabilities. ## Give the list a useful default {#configure} ```go title="content/posts.go" ridu.Collection{ Slug: "posts", Admin: ridu.CollectionAdmin{ UseAsTitle: "title", DefaultColumns: []string{"title", "status", "author", "updatedAt"}, Group: "Editorial", Description: "Draft, review, and publish site articles.", }, Fields: []field.Definition{ field.Text("title", field.Required()), field.Select("status", field.OneOf("draft", "review", "published")), field.Relationship("author", field.To("users")), }, } ``` `UseAsTitle` and `DefaultColumns` must name compatible direct fields. They change presentation only; the API path remains `/api/collections/posts`, and every list request still evaluates collection and field access. ## Work in the list {#use-the-list} Open **Posts** in the admin, then use the toolbar to: 1. search the configured title field; 2. add typed filters and combine them with the current locale/workflow state; 3. sort by a supported field and choose the page size; 4. show or hide ID, timestamps, status, nested group paths, relationships, and uploads; and 5. select the current page or resolve a bounded filtered selection for bulk work. The URL owns page, search, sort, filter, locale, folder, hierarchy, and trash state. Reloading or sharing an allowed URL reproduces the workspace rather than resetting to hidden component state. Per-user column/page-size choices and saved views use authenticated preferences. Relationship and upload cells resolve readable labels through access-checked requests. A redacted field stays redacted in the table even if another user saved it as a visible column. ![A Posts list in the Ridu admin showing one published post with search, filter, column, saved-view, sort, and selection controls.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/ridu-admin-posts-list.png) ## Empty, failed, and large result sets {#troubleshooting} - Clear the current search, filters, folder, locale, and trash mode before assuming content is gone. - A list can be empty because the collection access rule contributed a database predicate. The admin cannot reveal the number of inaccessible documents. - Bulk resolution accepts at most 100 unique IDs. Narrow the filter or work in reviewed batches. - A field absent from column/filter/sort choices may be a presentation field, unsupported nested shape, computed output, or denied by field access. Continue with [Saved views and hierarchy](https://riducms.com/docs/saved-views-and-hierarchy/) and [Bulk actions and trash](https://riducms.com/docs/bulk-and-trash/). See [Querying data](https://riducms.com/docs/querying/) for the same portable filter vocabulary outside the admin. --- # Saved views, folders, and hierarchy Canonical URL: https://riducms.com/docs/saved-views-and-hierarchy/ Saved views preserve an author's list workspace. Folder and parent fields add relationships that the list can use for organization. Neither feature changes access. ## Save a list workspace {#saved-views} Configure filters, columns, sort, locale, folder, and list/hierarchy mode in a collection list, then choose **Save view**. Give it a descriptive name such as “French posts ready for review.” Applying the view restores those inputs; deleting it removes only the preference, never documents. Preferences are owned by the exact auth collection and user ID. They remain private convenience state and cannot preserve access that the actor later loses. The SDK also exposes `preference`, `setPreference`, `deletePreference`, and `resetPreferences` for application/admin extensions. ## Add folders and hierarchy {#configure} ```go title="content/pages.go" var Folders = ridu.Collection{ Slug: "folders", Admin: ridu.CollectionAdmin{UseAsTitle: "name"}, Fields: []field.Definition{ field.Text("name", field.Required()), }, } var Pages = ridu.Collection{ Slug: "pages", Admin: ridu.CollectionAdmin{ UseAsTitle: "title", FolderField: "folder", ParentField: "parent", }, Fields: []field.Definition{ field.Text("title", field.Required()), field.Relationship("folder", field.To("folders")), field.Relationship("parent", field.To("pages")), }, } ``` `FolderField` must be a direct singular, non-polymorphic relationship. The toolbar then lists readable folders, filters pages by the chosen ID, and links to the folder collection for management. `ParentField` must be a direct singular relationship back to the same collection and enables the hierarchy/list switch. Save the config with `ridu dev` running. It regenerates contracts, safely synchronizes the additive development schema, and reloads the admin. Create a few folders and parent/child pages, then verify list, hierarchy, filter, saved-view, and SDK reads. Before deployment, create, review, and verify the selected adapter's migration. ## Constraints and troubleshooting {#troubleshooting} - Folder and parent values are relationship fields. Target existence, read access, delete behavior, localization, and migration safety still apply. - A saved folder ID can become unavailable; the view must not reveal or resurrect it. - Parent cycles are a content-model concern. Add validation when your application requires a strict acyclic tree. - Trash mode uses its own workspace; deleted parents are not shown as live nodes. See [Collections](https://riducms.com/docs/collections/#admin-metadata) for metadata contracts and [Relationships](https://riducms.com/docs/fields/relationship/) for reference behavior. --- # Create and edit documents Canonical URL: https://riducms.com/docs/editing-documents/ Ridu's document editor supports built-in scalar and nested fields, relationships/uploads, layout fields, localization, joins/virtual output, and statically registered plugin fields. ## Create the first document {#create} Open a collection and choose **Create new**. Required markers, descriptions, placeholders, conditions, choice labels, row bounds, and field access come from resolved config. Saving applies access, defaults, validation, hooks, persistence, and response redaction. Server issues return to exact paths, including nested row indexes. Fix those inputs and submit again; a rejected operation does not partially persist other fields. ## Edit safely {#edit} The form tracks dirty values and warns before an accidental navigation. Relationships/uploads open an access-aware browser with search, pagination, filters, selection, and permitted inline work. Array/block rows preserve stable editing identity during reorder. A resolved schema change is reconciled without silently submitting removed or incompatible values. Version-aware updates carry the visible `_revision`. A competing write returns `conflict` rather than overwriting the newer document. Refresh/review the latest state and reapply the intended change; do not blindly replay stale input. Available actions are capability-driven: save, save draft, publish, unpublish, duplicate, copy-locale, delete/trash, preview, and lock takeover appear only where resource config and the proposed document allow them. The server always rechecks the action when invoked. ![A Post editor showing a published status, selected author, populated rich text, document tabs, and a successful-create notice.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/ridu-admin-post-editor.png) ## Presentation is not authorization {#access} `ReadOnly`, `Hidden`, conditions, tabs, and plugin controls affect the editor. They cannot protect a field from raw REST/SDK input. Use `FieldAccess` for read/create/update security and hooks/validation for business invariants. ## If saving fails {#troubleshooting} - Follow the field-addressed validation issue instead of editing generated contracts. - `denied` means collection or field access rejected the current actor/context. - `conflict` means the revision changed; reload and reconcile. - A reference can disappear from its picker because target read access or option filters changed. - A failed post-commit side effect must be made observable/retryable; it cannot roll back a commit that already succeeded. Continue with [Drafts, versions, and scheduling](https://riducms.com/docs/drafts-and-versions/), [Document locks](https://riducms.com/docs/document-locks/), [Uploads](https://riducms.com/docs/uploads/), and [Live preview](https://riducms.com/guides/live-preview/). --- # Bulk actions and trash Canonical URL: https://riducms.com/docs/bulk-and-trash/ Use a bulk action when the same reviewed change belongs on several documents. Enable trash when an ordinary delete should be recoverable. ## Enable recoverable deletion {#enable-trash} Trash is configured per collection: ```go title="content/posts.go" ridu.Collection{ Slug: "posts", Trash: true, Fields: []field.Definition{ field.Text("title", field.Required()), }, } ``` Save the change with `ridu dev` running. It regenerates contracts, safely synchronizes the development store, and refreshes the admin. Deleting a document now moves it out of ordinary reads and into the collection's **Trash** workspace. A collection without `Trash: true` hard-deletes instead. Before deployment, create, review, and verify the selected adapter's migration. ## Change a reviewed selection {#bulk-actions} In a collection list, select rows or choose all results matching the current authorized filters. The available actions depend on collection configuration and the current actor: - **Edit** applies one partial value set; - **Publish** and **Unpublish** run their dedicated version lifecycles; - **Delete** moves documents to trash when enabled, otherwise it permanently deletes them; - **Restore** returns selected trashed documents to the active collection; and - **Delete permanently** removes selected trashed documents. One request accepts 1–100 unique IDs. Ridu authorizes and validates every target, locks the set, runs the per-document hooks, and commits all results together. If one document fails, the whole batch rolls back. Narrow a filter when **Select all** resolves more than 100 documents. The generated SDK exposes the same operations: ```ts title="review-posts.ts" const selected = ['post_01', 'post_02'] as const; await ridu.bulkUpdate('posts', selected, { category: 'news' }); await ridu.bulkPublish('posts', selected); await ridu.bulkDelete('posts', selected); const deleted = await ridu.list('posts', { trash: true }); await ridu.bulkRestoreDeleted( 'posts', deleted.docs.map((post) => post.id) ); ``` The admin has no generic bulk create/import action. Use a purpose-built task or import program with idempotency, progress, and error handling. ## Restore a document {#restore} Open **Trash** from the collection header, select a document, and choose **Restore**. Restore runs current access, validation, relationship, uniqueness, field, and hook rules; it can fail when the old values no longer satisfy today's model. ```ts await ridu.restoreDeleted('posts', post.id); ``` The document returns to ordinary list/API reads only after the restore commits. Its retained upload objects remain available throughout trash and restore. ## Permanently delete content {#permanent-delete} `deletePermanent`, `bulkDeletePermanent`, and **Empty trash** cannot be undone by Ridu. They apply reference restrict/nullify behavior and remove related sessions, credentials, versions, tasks, preferences, locks, and reference state. Upload object cleanup runs after the database commit so a failed transaction cannot remove bytes still referenced by content. Prefer selected permanent deletion when the target set needs review. **Empty trash** is a confirmed, collection-wide action, but it is still bounded to 100 accessible documents per atomic request. If there are more, delete in reviewed batches. ```ts await ridu.deletePermanent('posts', post.id); await ridu.bulkDeletePermanent('posts', selected); await ridu.emptyTrash('posts'); ``` Back up the database and object storage as one recovery point before a large cleanup. Historical version snapshots are separate records and are not rewritten merely because a referenced target is deleted. ## Troubleshooting {#troubleshooting} | Symptom | What to check | | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | Trash is missing from the collection | Confirm `Trash: true` and keep `ridu dev` running so the manifest and safe additive development schema are refreshed. | | A bulk action is absent | Check the resource capability, document state, and current actor's evaluated access. | | Select all reports too many documents | Add a narrower search/filter. Atomic selection and mutation are limited to 100 unique IDs. | | Restore returns a validation error | The trashed values no longer pass current schema, uniqueness, relationship, localization, or field-access rules. | | Permanent delete is denied or restricted | Check `Delete` access and references whose delete policy prevents removal. | Continue with [Browse and organize content](https://riducms.com/docs/browsing-content/), [Drafts and versions](https://riducms.com/docs/drafts-and-versions/), and [Uploads and media](https://riducms.com/docs/uploads/). Exact methods are documented under [`RiduClient.bulkUpdate`](https://riducms.com/reference/sdk/ridu-client-bulk-update/), [`RiduClient.bulkRestoreDeleted`](https://riducms.com/reference/sdk/ridu-client-bulk-restore-deleted/), and [`LocalAPI.BulkDelete`](https://riducms.com/reference/core/local-api-bulk-delete/). --- # Coordinate editors with document locks Canonical URL: https://riducms.com/docs/document-locks/ Document locks coordinate authors who open the same collection document. An active lease makes the second editor's form read-only and identifies the current owner; an authorized editor can take it over. Locks improve the authoring experience, but they do not grant update access and do not replace optimistic revision checks. ## Enable locks {#configure} ```go title="content/posts.go" package content import ( "time" "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) var Posts = ridu.Collection{ Slug: "posts", LockDocuments: true, DocumentLockConfig: ridu.DocumentLockConfig{ Duration: 5 * time.Minute, }, Fields: []field.Definition{ field.Text("title", field.Required()), }, } ``` Zero duration uses five minutes. A custom duration must be at least ten seconds. Save this change with `ridu dev` running; it regenerates contracts, safely synchronizes the development store, and reloads the admin. The selected store must implement Ridu's document-lock contract; all official database adapters do. Before deployment, create, review, and verify the adapter migration. ## What authors experience {#admin-behavior} When an authorized author opens an existing post, the admin acquires a persisted lease and refreshes it while the editor remains active. Leaving the route releases an owned lease; an abandoned lease expires after the configured duration. If another author owns the active lease, the form becomes read-only and shows the owner's label and expiry. **Take over** appears only when the current actor has unlock capability. A successful takeover replaces the previous lease; it does not save or discard either editor's local form state. Locking applies to existing collection documents. Create forms and globals do not acquire document leases. ## Authorize takeover separately {#access} Update access is required to acquire or refresh a lock. `CollectionAccess.Unlock` controls takeover of another editor's lease and falls back to `Update` when omitted. Define it when takeover should be limited to a smaller role: ```go Access: ridu.CollectionAccess{ Update: canEditPosts, Unlock: administratorsOnly, }, ``` Reading lock state returns not-found behavior when the document itself is not readable, so lock metadata cannot reveal a hidden document. The server re-evaluates access for acquisition and takeover; showing or hiding the admin button is only presentation. ## Use locks outside the admin {#sdk} Custom authoring clients can use the generated SDK: ```ts title="edit-lease.ts" let state = await ridu.acquireDocumentLock('posts', post.id); if (!state.owned && state.canTakeOver) { state = await ridu.acquireDocumentLock('posts', post.id, true); } if (!state.owned) { throw new Error(`This post is being edited by ${state.lock?.ownerLabel ?? 'another author'}.`); } try { await ridu.update('posts', post.id, { title: 'Reviewed title' }, { revision: post._revision }); } finally { await ridu.releaseDocumentLock('posts', post.id); } ``` Long-lived clients must refresh an owned lease before it expires. Reacquiring the same lock refreshes it. Browser unload delivery is best-effort, so expiry must remain the recovery path. Always send the last observed `_revision` for versioned updates. A lock can expire, be taken over, or be bypassed by a non-authoring client; the revision fence is what prevents a stale write from overwriting a newer committed document. ## Document locks are not account locks {#account-locks} An auth account can also be locked after repeated failed sign-ins. That is a separate authentication feature controlled by `AuthConfig.MaxLoginAttempts` and `AuthConfig.LockDuration`. An authorized administrator uses **Force unlock** or `RiduClient.forceUnlock`; document-lock takeover does not change account state. ## Troubleshooting {#troubleshooting} | Symptom | What to check | | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------- | | No lock appears | Confirm `LockDocuments: true`, keep `ridu dev` running, and open an existing collection document rather than a create form. | | The form remains read-only | The lease belongs to another identity. Wait for expiry or ask an actor with `Unlock` access to take over. | | Take over is missing | The actor lacks evaluated unlock capability, or the lease is already owned/expired. | | Lock calls return `not_found` | The collection has no lock support, the document is absent, or read access hides it. | | Save still returns `conflict` | Another committed write changed `_revision`. Refresh and reapply the intended edit; the lease is not a concurrency bypass. | See [Create and edit documents](https://riducms.com/docs/editing-documents/), [Access control](https://riducms.com/docs/access-control/), and the exact [`RiduClient.acquireDocumentLock`](https://riducms.com/reference/sdk/ridu-client-acquire-document-lock/) and [`App.AcquireDocumentLock`](https://riducms.com/reference/core/app-acquire-document-lock/) contracts. --- # Uploads and media Canonical URL: https://riducms.com/docs/uploads/ Uploads in Ridu are documents with files attached. The document lives in your selected database and contains fields such as alt text and a caption. The file bytes live in a separate object-storage backend. Ridu joins the two into one media-library experience in the admin and generated SDK. This guide adds a private `media` library to an existing starter project, stores files under `.ridu/uploads` during development, and adds a `heroImage` picker to posts. When you finish, an author can upload an image once and reuse it from any post. > [!NOTE] > An **upload collection** accepts file bytes and creates media documents. An **Upload field** only > stores a reference to one of those documents. Add both when content such as a post needs a media > picker. ## Before you start {#prerequisites} You need a generated Ridu project and a user who can sign in to its admin. The examples use the starter project's existing `authenticatedOnly` access function. If your project started from the blank template, define an auth collection and equivalent access rule first. The local backend below is appropriate for development and one application process on a durable disk. The [production storage](#production-storage) section shows the S3-compatible replacement. ## 1. Define the media library {#upload-collection} Create `content/media.go`: ```go title="content/media.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) var Media = ridu.Collection{ Slug: "media", Labels: ridu.CollectionLabels{Singular: "Asset", Plural: "Media"}, Admin: ridu.CollectionAdmin{ Group: "Content", UseAsTitle: "alt", }, Upload: true, UploadConfig: ridu.UploadConfig{ MaxFileSize: 10 << 20, // 10 × 2²⁰ = 10,485,760 bytes (10 MiB) MimeTypes: []string{"image/jpeg", "image/png"}, Private: true, ImageSizes: []ridu.ImageSize{ {Name: "card", Width: 1200, Height: 630, Fit: "cover"}, {Name: "thumb", Width: 320, Height: 320, Fit: "cover"}, }, }, Fields: []field.Definition{ field.Text( "alt", field.Label("Alt text"), field.Required(), field.Description("Describe the image for people who cannot see it."), ), field.Textarea("caption", field.Label("Caption")), }, Access: ridu.CollectionAccess{ Create: authenticatedOnly, Read: authenticatedOnly, Update: authenticatedOnly, Delete: authenticatedOnly, }, } ``` The `media` collection now accepts images up to 10 MiB. JPEG and PNG originals are retained, and Ridu generates `card` and `thumb` JPEG variants. `Fit: "cover"` fills the requested dimensions by cropping around the image's focal point; use `"contain"` when the complete image must remain visible. Ridu adds the following server-owned fields to every upload document: | Field | Meaning | | ----------------------------- | ---------------------------------------------------------------- | | `filename`, `mimeType` | Sanitized filename and MIME type detected from the file bytes | | `filesize`, `width`, `height` | Original byte size and image dimensions | | `url` | Access-checked delivery path for the original | | `sizes.card`, `sizes.thumb` | URL, dimensions, MIME type, and byte size for each image variant | | `focalX`, `focalY` | Image focal point as percentages from `0` through `100` | Clients cannot forge these values with an ordinary JSON create. They submit the file and authored fields such as `alt`; Ridu derives the file metadata. ## 2. Register the collection {#register-collection} Add a stable storage namespace and `Media` to `content/config.go`. The surrounding starter config is included so the insertion points are clear: ```go title="content/config.go" add={9,14} package content import "github.com/riducms/ridu" func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Admin: ridu.AdminConfig{User: "users"}, StorageNamespace: "acme-editorial", Plugins: installedPlugins(), Collections: []ridu.Collection{ Users, Posts, Media, }, } } ``` `StorageNamespace` owns one application's objects inside the backend. Use 3–64 lowercase letters, digits, underscores, or hyphens. Keep it unchanged if the display name or collection slug changes, and do not share it with another application using the same storage location. ## 3. Connect local storage {#storage-ownership} Keep the storage setup in the generated `cmd/server/main.go`. First add the local-storage and storage-contract imports alongside the existing SQLite imports: ```go title="cmd/server/main.go" add={14,17} package main import ( "context" "log" "net/url" "os" "path/filepath" "strconv" "strings" "time" "example.com/acme/internal/adminassets" localstorage "github.com/riducms/ridu/adapters/storage/local" "github.com/riducms/ridu" "github.com/riducms/ridu/adapters/sqlite" "github.com/riducms/ridu/storage" "github.com/riducms/ridu/store" ) ``` Then create the backend lazily inside `runtimeOptions`. This example uses SQLite; keep your PostgreSQL or MongoDB `WithStore` block unchanged and add the same highlighted `WithUploadStorage` block after it. ```go title="cmd/server/main.go" add={6-12} func runtimeOptions(applicationConfig ridu.Config) []ridu.ExecuteOption { return []ridu.ExecuteOption{ ridu.WithStore(func(ctx context.Context) (store.Store, error) { return sqlite.Open(ctx, sqliteDatabasePath()) }), ridu.WithUploadStorage(func(_ context.Context) (storage.Backend, error) { root := os.Getenv("RIDU_UPLOAD_PATH") if root == "" { root = ".ridu/uploads" } return localstorage.New(root) }), ridu.WithAddress(env("RIDU_ADDRESS", ":8080")), ridu.WithHandlerOptions(ridu.HandlerOptions{ AdminAssets: adminassets.FS(), // Keep the remaining generated handler options here. }), // Keep the generated WithServerOptions block here. } } ``` The factory runs only when the application server starts. Commands that resolve config—such as generation and offline migration creation—do not need the upload directory or cloud credentials. For local development the default `.ridu/uploads` directory is already disposable project state. Set an absolute `RIDU_UPLOAD_PATH` when the files must survive a process working-directory change. ## 4. Add a media picker to posts {#reference-upload} Add `field.Upload` to the starter `Posts` collection. The target is the `media` collection slug, not a filesystem path or storage bucket: ```go title="content/posts.go" add={24} package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" "github.com/riducms/ridu/plugins/richtext" ) var Posts = ridu.Collection{ Slug: "posts", Access: ridu.CollectionAccess{ Create: authenticatedOnly, Read: authenticatedOnly, Update: authenticatedOnly, Delete: authenticatedOnly, }, Fields: []field.Definition{ field.Text("title", field.Required()), field.Select( "status", field.OneOf("draft", "published"), field.Default("draft"), ), field.Upload("heroImage", field.To("media")), field.Relationship("author", field.To("users")), richtext.Field("content"), }, } ``` This stores one media document ID in `heroImage`. Add `field.Required()` when every post must have an image, or `field.HasMany()` when the field should be a gallery. Read the focused [Upload field guide](https://riducms.com/docs/fields/upload/) for filtering and delete behavior. ## 5. Run in development {#generate-and-run} Run the project-local development loop from the project root. `ridu dev` resolves the updated Go config, regenerates contracts, applies the safe additive development schema change, and starts the API and admin. These four tabs are the same command; use the package manager selected when the project was created. ```bash title="terminal" package-manager="npm" npm run dev ``` ```bash title="terminal" package-manager="bun" bun run dev ``` ```bash title="terminal" package-manager="pnpm" pnpm run dev ``` ```bash title="terminal" package-manager="yarn" yarn run dev ``` The server should pass upload-storage readiness and print the admin URL. If it reports `upload storage is unavailable`, the `WithUploadStorage` option is missing or the configured directory cannot be created. ## 6. Upload and reuse an image in the admin {#admin-workflow} Open `/admin`, sign in, and choose **Media** under **Content**. Select **Create new**, choose an image, enter its alt text, and save. Ridu uploads the original, detects its metadata, generates both image sizes, and creates the media document. Now open a post. The new **Hero image** field opens a media picker containing the document you just created. Selecting it stores that media document's ID on the post; it does not copy the file. ![A Ridu Media document editor showing the asset preview, detected file metadata, authored alt text, image variants, and document actions.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/ridu-admin-upload.png) _The preview, generated sizes, and authored fields belong to one media document. The original and variant bytes remain in the configured storage backend._ ## Upload from application code {#sdk-upload} The generated TypeScript module knows that `media` accepts uploads and which authored fields it expects. This complete helper creates the application-bound client, uploads a browser `File`, and returns a URL that works whether the SDK returned a relative or absolute delivery path: ```ts title="src/lib/media.ts" import { createClient } from '../../generated/ridu.generated'; const baseURL = 'http://localhost:8080'; const ridu = createClient({ baseURL }); export async function uploadHero(file: File, alt: string) { const asset = await ridu.upload('media', file, { data: { alt, caption: 'Uploaded from the website' } }); return { id: asset.id, originalURL: new URL(asset.url, baseURL).toString(), cardURL: new URL(asset.sizes.card.url, baseURL).toString(), width: asset.width, height: asset.height }; } ``` Pass the resulting media ID when creating or updating a post: ```ts title="src/features/posts/create-post.ts" import { uploadHero } from '../../lib/media'; import { createClient } from '../../../generated/ridu.generated'; const ridu = createClient({ baseURL: 'http://localhost:8080' }); export async function createPost(file: File) { const hero = await uploadHero(file, 'The Ridu team outside the studio'); return ridu.create('posts', { title: 'Studio notes', status: 'draft', heroImage: hero.id }); } ``` In a browser, the SDK sends the current session cookie by default. For another browser origin, configure [CORS and credentialed cookies](https://riducms.com/docs/cors/). Server-side callers can supply an API-key `Authorization` header when their application uses service credentials.
Use the multipart REST endpoint directly
The SDK call above sends `multipart/form-data` to `POST /api/collections/media`. A non-TypeScript client can send the same request. This example assumes `cookies.txt` contains an authenticated Ridu session: ```bash title="terminal" curl --fail-with-body \ --cookie cookies.txt \ --form 'file=@./hero.jpg' \ --form 'data={"alt":"The Ridu team outside the studio","caption":"Homepage hero"}' \ http://localhost:8080/api/collections/media ``` The `file` part is required. `data` is an optional JSON object containing only application-authored fields. Do not set the multipart `Content-Type` header manually; the client must add its boundary.
## Import a public remote image {#remote-url} Use `uploadFromURL` when Ridu should fetch a public HTTP(S) image and turn it into a normal media document: ```ts title="src/lib/import-media.ts" import { createClient } from '../../generated/ridu.generated'; const ridu = createClient({ baseURL: 'https://cms.example.com' }); export async function importLaunchGraphic() { return ridu.uploadFromURL('media', 'https://images.example.com/launch.png', { data: { alt: 'Launch graphic', caption: 'Imported from the campaign image service' } }); } ``` The server blocks non-HTTP schemes, private and loopback destinations, unsafe redirects, oversized responses, and content that fails the collection's MIME rules. This is a guarded import operation, not a general server-side proxy. Application-specific host allowlists, moderation, malware scanning, and quarantine need a trusted pre-ingestion service or plugin. ## Change the focal point and regenerate sizes {#images} Image uploads start at `{ focalX: 50, focalY: 50 }`, the center of the original. Authors can adjust the focal point in the media editor. Application code can do the same and regenerate every named size: ```ts title="src/lib/update-crop.ts" import { createClient } from '../../generated/ridu.generated'; const ridu = createClient({ baseURL: 'https://cms.example.com' }); export async function keepSubjectInFrame(assetID: string, revision: number) { return ridu.updateUploadImage('media', assetID, { focalX: 40, focalY: 35 }, { revision }); } ``` Coordinates are percentages from `0` through `100`, not decimal fractions or source pixels. Pass the current `_revision` so an older editor cannot overwrite a newer crop. Optional `cropX`, `cropY`, `cropWidth`, and `cropHeight` values use the same percentage coordinate system. ## Deliver files safely {#delivery} `asset.url` and each `asset.sizes[name].url` point at Ridu's access-checked delivery endpoint. Build an absolute URL with `new URL(asset.url, baseURL)` when a frontend and CMS use different origins. Because the example collection sets `Private: true`, the request must carry an authenticated actor who can read the media document. Ridu also reapplies field redaction before delivery. Framework delivery sends `Cache-Control: private, no-store`, including for collections where `Private` is false, because collection read access may still depend on the actor or document. If a public CDN is required, create an application-owned publication or copy boundary instead of exposing Ridu's internal `objectKey`. A backend that implements `storage.URLSigner` can issue a short-lived direct download only after the application has made the relevant access decision. ## Use S3-compatible storage in production {#production-storage} For more than one application replica, replace the local backend with an S3-compatible backend so every replica sees the same objects. The collection and `field.Upload` definitions do not change. In `cmd/server/main.go`, replace the `localstorage` import with `s3storage "github.com/riducms/ridu/adapters/storage/s3"`, then replace the local `WithUploadStorage` option: ```go title="cmd/server/main.go" ridu.WithStore(func(ctx context.Context) (store.Store, error) { return postgres.Open(ctx, os.Getenv("DATABASE_URL")) }), ridu.WithUploadStorage(func(_ context.Context) (storage.Backend, error) { return s3storage.New(s3storage.Config{ Endpoint: os.Getenv("S3_ENDPOINT"), Region: os.Getenv("S3_REGION"), Bucket: os.Getenv("S3_BUCKET"), AccessKey: os.Getenv("S3_ACCESS_KEY"), SecretKey: os.Getenv("S3_SECRET_KEY"), MaxSpoolBytes: 256 << 20, // 256 × 2²⁰ = 268,435,456 bytes (256 MiB) SpoolDirectory: "/var/tmp/ridu-spool", }) }), ridu.WithAddress(env("RIDU_ADDRESS", ":8080")), ``` Use HTTPS for production endpoints. Size the private spool directory for concurrent uploads and back it with ephemeral disk; S3 signing may need to spool a non-seekable request before upload. See [Object storage](https://riducms.com/docs/storage/#s3-storage) for timeouts, local emulators, signed URLs, and the backend contract. ## Prepare the schema change for deployment {#deploy-schema} `ridu dev` applies additive development synchronization only. Before deploying the media collection, create a migration, review its plan, verify the complete history, and run the project check. Do this after the local workflow above succeeds—not before `ridu dev`. ```bash title="terminal" package-manager="npm" npm run ridu -- migrate create --name add-media npm run ridu -- migrate plan npm run ridu -- migrate verify npm run ridu -- check ``` ```bash title="terminal" package-manager="bun" bun run ridu -- migrate create --name add-media bun run ridu -- migrate plan bun run ridu -- migrate verify bun run ridu -- check ``` ```bash title="terminal" package-manager="pnpm" pnpm run ridu migrate create --name add-media pnpm run ridu migrate plan pnpm run ridu migrate verify pnpm run ridu check ``` ```bash title="terminal" package-manager="yarn" yarn run ridu migrate create --name add-media yarn run ridu migrate plan yarn run ridu migrate verify yarn run ridu check ``` Commit the migration and changed files under `generated/`. Apply the reviewed history with `migrate up` against the deployment database as an operator step, then require `migrate status` and application readiness to pass. The [Migrations guide](https://riducms.com/docs/migrations/) covers adapter-specific connection and safety options. ## Delete, reconcile, and back up media {#cleanup} Soft-deleting a media document retains its objects so it can be restored. Permanent deletion removes objects only after the database transaction commits and only when no live, trashed, or versioned document still owns them. Database metadata and object storage cannot share one transaction. `App.ReconcileUploads` reports old unreferenced objects without deleting them; after reviewing that report, `App.CleanupUploads` performs the destructive pass. Use a grace period of at least five minutes and longer than the slowest upload or import in your deployment. Storage listings must provide trustworthy non-zero modification times or cleanup fails closed. Back up the database and its upload namespace to a matched recovery point. Restoring only the database can leave missing files; restoring only object storage can leave unreferenced objects. After a restore, check representative media URLs and checksums before running report-only reconciliation. ## Current limitations {#limits} Ridu does not yet provide resumable transfers, direct browser-to-storage sessions, quarantine, malware scanning, or a general raw-object endpoint. Each document can own at most 65 original and derived object keys. ## Troubleshooting {#troubleshooting} | Symptom | What to check | | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | `upload storage is unavailable` | Register `ridu.WithUploadStorage(...)` and make sure the directory, bucket, and credentials are available to the server process. | | `unknown upload collection "media"` | Add `Media` to `Config.Collections`, keep `Upload: true`, and save while `ridu dev` is running; prepare the immutable migration before deployment. | | MIME or size validation fails | Compare the actual file bytes with `MimeTypes` and `MaxFileSize`; Ridu sniffs content rather than trusting the browser's MIME header. | | The media picker is empty | Upload a media document first, confirm the Upload field targets `media`, and check that the signed-in actor can read that document. | | A browser upload is unauthorized | Sign in first; for a separate frontend origin, allow the exact CORS origin and credentials. | | A private `` does not load | Use the Ridu delivery URL, preserve credentials where appropriate, and check the collection's read rule. Do not use `objectKey` as a URL. | | An image variant is missing | Confirm the original is a supported image, the size name exists in `ImageSizes`, and the requested variant is read from `asset.sizes..url`. | | A create timed out or returned an uncertain 5xx | Refresh or query the media collection before retrying so a committed upload is not duplicated. | Continue with the [Upload field guide](https://riducms.com/docs/fields/upload/), [Object storage](https://riducms.com/docs/storage/), [TypeScript SDK](https://riducms.com/docs/typescript-sdk/#uploads), or the [`storage` API reference](https://riducms.com/reference/storage/). --- # Localize the admin and authoring workflow Canonical URL: https://riducms.com/docs/admin-localization/ Ridu separates two choices: the **content locale** selects stored/fallback values, while the **interface language** translates admin controls and application labels. An editor can author Arabic content with the French interface and a Europe/Paris display timezone. ## Configure interface choices {#configure} Declare languages/timezones in `Admin.Localization` and pass matching static catalogs to `mountAdmin`. Ridu publishes complete English, French, and Arabic catalogs in `@riducms/translations`: ```ts title="admin/src/main.ts" import { ar, en, fr } from '@riducms/translations'; mountAdmin({ target, clientFactory: () => createClient({ baseURL: window.location.origin }), plugins: adminPlugins, languages: [en, fr, ar] }); ``` The matching Go config declares canonical language codes, labels, RTL state, IANA timezone IDs, and defaults. A configured language without a matching static catalog—or conflicting RTL metadata— fails closed. Authors persist interface language and timezone in their account preferences. Application name, collections/globals, fields, choices, blocks, tabs, row labels, groups, and timezones support typed translated labels. Plugin messages use namespaced build-validated catalogs. Dates, numbers, plurals, and relative time use the active language/timezone through `Intl`. ## Author localized content {#content-locale} The global content-locale switcher controls exact/fallback values, list filters, relationships, versions, and copy-locale operations. The admin shows the fallback source, protects dirty changes during a locale switch, and uses RTL editing direction where configured. Interface language never changes stored content, and content locale never changes interface copy automatically. ## Verify the workflow {#verify} 1. switch English/French/Arabic interface catalogs and confirm direction/labels; 2. switch timezones and confirm one stored timestamp formats differently without mutating it; 3. edit one localized field in two content locales and verify the fallback source; 4. reload/sign in again and confirm account preferences; and 5. read exact and `locale: 'all'` shapes through the generated SDK. The complete Go configuration, catalog installation, fallback rules, APIs, and limitations are in [Content localization](https://riducms.com/docs/localization/#admin-language). --- # Durable tasks Canonical URL: https://riducms.com/docs/tasks/ Ridu tasks are typed Go handlers with database-backed scheduling, retries, and leases. PostgreSQL supports workers on multiple hosts. SQLite tasks are limited to one application host, and MongoDB tasks follow its [bounded production profile](https://riducms.com/docs/mongodb/). Use the local API from handlers when content operations need access rules, validation, hooks, transactions, and redaction. ## Define and register a task {#define} ```go title="content/tasks.go" package content import ( "time" "github.com/riducms/ridu" ) type EmailInput struct { MessageID string `json:"messageID"` To string `json:"to"` } type EmailOutput struct { ProviderID string `json:"providerID"` } var SendEmail = ridu.NewTask( "send-email", func(task ridu.TaskContext, input EmailInput) (EmailOutput, error) { providerID, err := send(task.Context, input.MessageID, input.To) if rateLimited(err) { return EmailOutput{}, ridu.RetryTaskAfter( "email_rate_limited", err, time.Minute, ) } if invalidAddress(err) { return EmailOutput{}, ridu.AbortTask("email_address_invalid", err) } return EmailOutput{ProviderID: providerID}, err }, ridu.TaskQueue("email"), ridu.TaskRetries(5, time.Second, time.Hour, ridu.TaskBackoffExponential), ridu.TaskTimeout(2*time.Minute), ridu.TaskRetention(30*24*time.Hour), ) ``` Register the definition in executable config: ```go title="content/config.go" func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Tasks: []ridu.TaskDefinition{SendEmail}, } } ``` Only a value returned by `ridu.NewTask` can implement `TaskDefinition`. Persisted JSON can select a registered slug and provide validated data; it cannot provide executable code. Duplicate, reserved, missing-handler, and invalid retry-policy definitions fail config validation. ## Enqueue and inspect work {#enqueue} Use the same typed definition from trusted Go code: ```go receipt, err := SendEmail.Enqueue(ctx, app, EmailInput{ MessageID: requestID, To: "author@example.com", }, ridu.TaskEnqueueOptions{ RunAt: time.Now().Add(5 * time.Minute), ConcurrencyKey: "author@example.com", }) if err != nil { return err } result, err := SendEmail.Result(ctx, app, receipt.ID) ``` `RunAt` schedules future admission. `Queue` can override the definition's queue. A concurrency key serializes active leases for that key within one queue. Optional `Target` and `RequestedBy` references attach lifecycle-safe collection/document identities; hard deletion removes tasks that refer to the deleted identity. `Result` returns typed output plus state, attempts, retained failure code and message, and completion time. `HasOutput` distinguishes a successful zero value from work that has not succeeded. `Cancel` atomically stops queued work and fences a running lease so a stale heartbeat or completion cannot win afterward. ## Delivery is at least once {#at-least-once} > [!WARNING] > A handler can complete an external side effect and crash before recording success. Tasks use > at-least-once delivery. Use a stable idempotency key for email, payments, webhooks, object > writes, and other external effects. Every claim has an opaque lease token. Heartbeats extend it; an expired lease can be reclaimed; and completion, failure, release, and cancellation require the current token. A process stopping gracefully cancels cooperative handlers and returns leases immediately. A handler that ignores `task.Context` can delay drain, but its stale lease remains fenced and can be recovered after expiry. `TaskContext.Local` is the local API. If work represents a user, persist a stable user reference and choose the actor when making the call. A nil actor is not an administrator. ## Recover a commit-to-enqueue gap {#admission-reconciliation} If application state commits before its task is admitted, attach a bounded recovery scan to the task definition: ```go ridu.TaskAdmissionReconciler(func(ctx context.Context, app *ridu.App) error { return reconcilePendingExports(ctx, app) }) ``` Ridu runs the reconciler before every task claim cycle, including the first cycle at startup. Implementations must be idempotent and safe across concurrent application instances. A failure is reported through `HandlerOptions.JobError`, while work that is already queued remains eligible to run. Use this only to repair durable admission gaps; it is not a cron scheduler. For a document-backed admission queue, use `LocalAPI.ListWindow` over one direct, unique, indexed, non-localized text field. It supports a bounded half-open range, not arbitrary filters, population, versions, or trash. Put pending and terminal records in separate key ranges and move each examined record forward with a compare-and-set. ## Retry, abort, and timeout {#failure-policy} Return an ordinary error to use the definition's retry policy. Use the helpers when provider semantics are known: | Handler result | Outcome | | --------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `nil` error | Store the typed output and mark the task succeeded. | | `ridu.RetryTask(code, err)` | Queue another attempt using fixed, linear, or exponential definition backoff. | | `ridu.RetryTaskAfter(code, err, delay)` | Queue another attempt after at least the supplied delay, useful for provider rate limits. | | `ridu.AbortTask(code, err)` | Mark a terminal failure and retain it until the configured retention expires. | | Attempt timeout | Cancel the handler context and retry as `task_timeout` while attempts remain. Cancellation is cooperative. | The first execution counts toward `TaskRetries`' maximum attempts. Linear and exponential growth is deterministic and capped by the configured maximum delay. ## Bounds and sensitive data {#bounds} Inputs and outputs are strict JSON for their registered Go types. Unknown fields are rejected, and both payloads are capped at 1 MiB. Store large files in an upload backend and enqueue a small stable reference. Task inputs, outputs, error messages, target identities, and requester identities are database records. Do not put credentials, bearer tokens, or other secrets in them. Error text, attempts, timeouts, retry delays, claim/prune batches, concurrency keys, and retention are bounded by the runtime. ## Failure codes {#failure-codes} Application-defined codes such as `email_rate_limited` belong to your runbook. Ridu also exposes stable boundary and persisted-state codes: | Code | Where it appears | Meaning | | ------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `task_not_registered` | local error or terminal state | The typed definition is not registered in this running application, or persisted work names a slug the binary does not contain. | | `task_unavailable` | local error | The application/store cannot provide the durable-task runtime. | | `task_input_invalid` | local error or terminal state | Input could not be strictly decoded, encoded, or admitted within its bound. | | `task_output_invalid` | local error | Retained output does not match the exact typed definition. | | `task_output_too_large` | terminal state | A handler returned more than the 1 MiB output limit. | | `task_not_found` | local error | The ID is absent or belongs to another typed task definition. | | `task_store_failed` | local error | A store claim, read, mutation, or prune operation failed. | | `task_lease_lost` | local error | Another lease state won; the stale attempt cannot commit. | | `task_timeout` | retry or terminal state | The attempt exceeded its configured timeout. | | `task_handler_panicked` | retry state | Ridu contained a handler panic without persisting the panic value and applied retry policy. | | `task_attempts_exhausted` | terminal state | Lease recovery found work beyond its maximum attempts. | | `worker_shutdown` | queued state | Graceful shutdown released the task for immediate recovery. | Monitor terminal codes and sustained retries by queue and slug. A diagnostic sink can receive the underlying causes, so redact sensitive data there too. ## Worker operation {#worker} `ridu.Execute` starts the worker when registered tasks or versioned collections require it. `HandlerOptions` configures polling interval, claim batch, queues, lease duration, heartbeat interval, and prune batch; zero values use defaults. PostgreSQL supports multiple workers across hosts. SQLite supports same-host processes only. MongoDB remains limited to its documented replica-set profile. Scheduled publishing uses the reserved `ridu-schedule-publish` task. Use the scheduling API; do not register that task yourself. ## Limits {#availability} Tasks do not provide workflow graphs, declarative cron, a job admin, email or webhook adapters, exactly-once external effects, or a sandbox for untrusted handlers. See [Hooks](https://riducms.com/docs/hooks/) for after-commit dispatch, [Drafts and versions](https://riducms.com/docs/drafts-and-versions/) for scheduled publishing, [Security](https://riducms.com/docs/security/) for trusted-code boundaries, and [Production](https://riducms.com/docs/production/) for worker drain and monitoring. --- # Generated contracts Canonical URL: https://riducms.com/docs/generated-contracts/ `ridu generate` resolves the application config into a manifest and generated contracts. It does not touch the database, and it installs the output set atomically. Commit generated contracts. They are reviewable application interfaces, not disposable caches. ## Why Ridu executes config {#execute-config} A Go configuration can call functions, compose packages, and register compiled plugins. Parsing Go source would see syntax, not the values the program actually produces, so the CLI runs the project's configured command to resolve it. The project command resolves `ridu.Config`, applies plugin transforms, validates the graph, and returns a deterministic snapshot. Generation does not connect to the database, initialize runtime storage, start the HTTP server, or make application network requests. Protocol or framework version mismatches fail with an upgrade diagnostic instead of guessing at a schema. Executable access callbacks, hooks, task handlers, storage credentials, and secrets remain runtime-only; they are never serialized into the manifest. ## Files in one generation {#outputs} The default generated project writes: | Path | What it contains | Commit it? | | ------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------- | | `generated/ridu.schema.json` | Canonical, versioned manifest with stable IDs, resources, fields, capabilities, plugin metadata, and digests | Yes | | `generated/ridu.openapi.json` | REST paths, request/response schemas, auth, locale parameters, and stable error envelopes | Yes | | `generated/ridu.generated.go` | Output/create/update structs and typed local collection/global handles | Yes | | `generated/ridu.generated.ts` | Exact document/input/query/select/populate types and the generated client factory | Yes | | `admin/src/ridu.plugins.generated.ts` | Validated static imports for official or packaged admin plugins | Yes | | `.ridu/…` | Project-command builds, staging files, caches, and intermediate admin output | No | `ridu.toml` can change the structural paths, but it cannot contain database credentials, access rules, or schema definitions. See [Project structure](https://riducms.com/guides/project-structure/) for the directory map. Keep `@riducms/sdk` and packages referenced by generated TypeScript field types in the root `package.json`. Keep an admin plugin in `admin/package.json` as well when the generated admin registry imports its runtime module. ## Canonical manifest {#manifest} The manifest is the contract shared by migrations, runtime plugins, generators, the admin, and tooling. Its serialization is deterministic: equivalent resolved configuration produces identical bytes and digests regardless of map iteration order. Stable resource and field identities let a migration distinguish a rename from an unrelated drop and create. Human-facing slugs and labels can change while committed identity records continuity. Plugin contributions are namespaced and versioned. A built-in field may carry `admin.component` with a paired plugin key, exact component key, and deterministic object configuration. This is public presentation metadata, not a new value type: storage, validation, migrations, OpenAPI, and generated Go/TypeScript values continue to follow the built-in field kind. Executable callbacks and credentials remain outside the manifest. The manifest describes that an access rule exists and which operation it protects, but never its function body or decision. The admin can use this metadata to hide an unavailable action only as a presentation; every operation re-evaluates authorization on the server. ## Generated Go API {#go} The Go file contains distinct types for stored output, create input, and partial update input. A generated collection handle binds those types to the same dynamic local operation engine: ```go posts := generated.PostsCollection.With(app.Local()) created, err := posts.Create(ctx, generated.PostCreate{ Title: "Hello, Ridu", Status: "draft", }, actor) if err != nil { return err } page, err := posts.List(ctx, core.TypedListOptions{Page: 1, Limit: 20, Actor: actor}) ``` Generated handles do not bypass access, hooks, validation, transactions, localization, or redaction. Dynamic filters keep using the shared [`query` package](https://riducms.com/reference/query/); generated document and mutation shapes remove field-name maps from ordinary application code. Nullable create/update fields use `*core.Input[T]`: leave the pointer nil to omit the field, call `core.Set(value)` to send a concrete value (including `false`, `0`, or an empty slice), and call `core.Null[T]()` to send explicit JSON `null`. A non-null slice, map, or fallback `json.RawMessage` cannot safely use its raw Go type because a nil value would encode as null. The same conservative rule applies to plugin-owned named Go types, whose underlying type and custom marshaling cannot be proven from the manifest. Required fields of those shapes therefore use `core.NonNullInput[T]` and `core.NonNull(value)`; their omittable default/update forms use `*core.NonNullInput[T]` and `core.SetNonNull(value)`. JSON encoding rejects a nil or otherwise null-encoding wrapped value. Other non-null fields that are omittable in an update or because they have a server default use `*T`. Both wrappers are write-only typed local-API arguments: `core.Input` and `core.NonNullInput` are not general-purpose JSON-unmarshal contracts. The non-null wrapper prevents JSON null; ordinary required/minimum-length validation still decides whether an empty concrete collection is valid. Typed list handles accept `core.TypedListOptions`; population and all-locale reads remain on the dynamic local API because they change field value shapes at runtime. ## Generated TypeScript API {#typescript} The generated module extends the neutral `@riducms/sdk` runtime with application-specific types: - output, create, and update shapes for every collection and global; - collection/global/auth/upload/version-capability slug unions; - field-aware `where`, `select`, and `populate` inputs; - one `RiduConfig` map connecting slugs to all those types; - a `createClient` wrapper that supplies the exact config without repeated generics; - type-only module augmentation for raw SDK inference in programs with one generated config. Conditional admin presentation does not narrow generated TypeScript inputs. Create and update types remain ordinary flat field contracts, including each field's required, default, and null behavior. Hidden fields can still be submitted, and conditions do not perform runtime validation or authorization; enforce active-shape rules in application validation when needed. ```ts import { createClient } from '~/generated/ridu.generated'; const client = createClient({ baseURL: 'https://cms.example.com' }); const post = await client.create('posts', { title: 'Generated contracts', status: 'draft' }); ``` A TypeScript program that contains zero generated configs—or more than one—does not select an automatic default. Import the intended generated wrapper, or pass its `RiduConfig` explicitly to the raw SDK. This avoids whichever package happened to load first silently choosing your API. Selection and population inputs are typed, but they do not yet transform the method's output type. Sort terms also remain strings. Treat the runtime projection as authoritative and see [Querying data](https://riducms.com/docs/querying/) for that current boundary. ## OpenAPI and other consumers {#openapi} The OpenAPI document is generated from the same snapshot as the TypeScript module. Use it for API inspection, non-TypeScript client generation, request fixtures, or gateway tooling. Do not hand-edit it: the next generation replaces it. When `generated.graphql.schema` is configured, the compiled GraphQL plugin also emits its exact runtime SDL for GraphQL clients, editor tooling, and API review. The admin loads the runtime schema and generated SDK contract, while its plugin registry imports static code selected at build time. GraphQL derives its SDL from the same manifest and executable plugin options. ## Atomic writes and drift checks {#atomic} `ridu generate` writes the outputs as one set. If generation or installation fails, the previous contract set remains intact. Byte-identical output keeps its timestamp. Use the non-writing mode in CI: ```bash npm run ridu -- generate --check ``` It fails when an expected file is missing or byte-different. During ordinary local development, keep the complete loop running: ```bash npm run dev ``` It regenerates contracts on config changes and synchronizes safe additive development schema changes. After the behavior works, review the generated files: ```bash git diff -- generated admin/src/ridu.plugins.generated.ts ``` If the change affects stored schema, create the immutable artifact and run the project checks before deployment: ```bash npm run ridu -- migrate create --name describe-the-change npm run ridu -- check ``` Generation describes the target API; migration creation records the reviewed, immutable database transition from the previous manifest. A migration is not required for ordinary local development. Read [Migrations](https://riducms.com/docs/migrations/) before changing an existing schema. ## Common failures {#failures} | Symptom | Likely cause | Next step | | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | | Project command cannot compile | Invalid Go config or incompatible package versions | Run `go test ./...`; fix the first compiler error | | Handshake version mismatch | CLI and application framework do not share the project-command contract | Use the CLI release pinned to the project | | Manifest validation fails | Duplicate slug/name, invalid option combination, unknown relationship target, localization cycle, or plugin conflict | Follow the structured path in the error | | `--check` reports drift | Config or generator version changed without committed outputs | Run generation locally and review all artifacts together | | Raw SDK types fall back to defaults | No generated config, or multiple generated configs, are in the TypeScript program | Import/use the generated wrapper explicitly | | Generated plugin import fails | Registry metadata and installed Go/admin packages disagree | Use `ridu plugin` commands; do not patch the generated registry | The [Troubleshooting](https://riducms.com/docs/troubleshooting/) guide covers recovery in more detail. Exact generator, manifest, and project-handshake types are in the [Go API reference](https://riducms.com/reference/schema/) and [CLI reference](https://riducms.com/reference/cli/). --- # The Ridu admin Canonical URL: https://riducms.com/docs/admin/ Ridu includes a Svelte 5 admin. Your application provides a Vite entry, theme, and plugin imports. Production assets are static files embedded in the Go binary, so the authoring UI does not require Node, Bun, SvelteKit, or a separate JavaScript server at runtime. ## How the admin is configured {#framework-owned-shell} At startup the admin reads the canonical manifest, current identity, and access capabilities. That single contract drives navigation, collection columns, field layout, localization, resource features, and plugin pairing. The generated Fetch SDK is its transport; REST, local Go calls, and the admin therefore enter the same validation, access, hooks, versioning, and transaction engine. The authenticated shell includes: - dashboard, grouped collection/global navigation, breadcrumbs, command-menu navigation and create shortcuts; - login plus configured recovery and verification screens; - profile, password, session, and API-key account workflows; and - responsive navigation, page titles, loading progress, notifications, confirmation dialogs, and safe redirects back to the originally requested admin route. Admin visibility is not authorization. Hidden navigation or a read-only field only describes the current interface; the server re-evaluates collection, document, and field access on every request. See [Access control](https://riducms.com/docs/access-control/) and [Authentication](https://riducms.com/docs/authentication/). ## Find and organize content {#lists} Collection list routes support title search, pagination, stable sorting, typed filters, selectable columns, page-size preferences, saved views, workflow status, and locale switching. ID, created, updated, and status metadata can be selected independently. Nested group paths can be columns, filters, and sort keys when the schema permits them; relationship and upload cells resolve readable labels through access-checked requests. When a collection declares a folder relationship, authors can filter by folder and switch to a hierarchical view. Trash-enabled collections have a separate trash workspace. List state is kept in the URL and actor preferences, so filtered and saved workspaces remain navigable rather than living only in component memory. Authors can select the current page or resolve all filtered results. Bulk edit, publish, unpublish, delete, restore, and permanent delete are performed as one access-checked server request. The atomic maximum is 100 documents; narrow a filter when it resolves to more. Bulk create/import is not a generic admin workflow today—use an application task or purpose-built importer. ## Create and edit documents {#documents} The schema-driven document route handles collections and globals. It renders scalar fields, relationships, uploads, groups, arrays, blocks, rows, tabs, collapsibles, joins, localization, and statically registered custom fields. It reconciles a manifest change without silently submitting removed or incompatible values. The form controller owns nested values, registration, client validation, dirty state, field access, server issues, conditional presentation, localized inheritance, and submit state. Save, save draft, publish, unpublish, duplicate, delete/trash, and copy-locale controls appear only when the resource and evaluated access allow them. Optimistic revisions turn a competing write into a visible conflict instead of overwriting it. Relationship and upload fields open an access-aware reference browser with debounced search, pagination, filters, multi-selection, and inline create/edit where permitted. Upload collections also provide direct and SSRF-guarded remote ingestion, a retryable bulk-upload queue, media preview, metadata editing, replacement, and persisted crop/focal-point controls. ```go title="content/posts.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) var Posts = ridu.Collection{ Slug: "posts", Versions: true, VersionConfig: ridu.VersionConfig{ Drafts: true, }, Admin: ridu.CollectionAdmin{ UseAsTitle: "title", DefaultColumns: []string{"title", "author", "status"}, Group: "Editorial", Description: "Stories published across Acme properties", LivePreview: ridu.LivePreviewConfig{ URL: "https://www.example.com/preview/posts/{id}", Breakpoints: []ridu.PreviewBreakpoint{ {Name: "mobile", Label: "Mobile", Width: 390, Height: 844}, {Name: "desktop", Label: "Desktop", Width: 1440, Height: 900}, }, }, }, Fields: []field.Definition{ field.Text("title", field.Required()), field.Relationship("author", field.To("users")), field.Select("status", field.OneOf("draft", "published")), }, } ``` ## Versions, locks, and preview {#editorial} Version-enabled resources have history and revision-detail routes. Authors can compare field-level changes, show only modified values, restore a revision, and publish or unpublish. Collections also show durable scheduled publications and allow an authorized author to schedule or cancel them. Global scheduling is not implemented. Document locks warn when another editor owns the record, make the form read-only, and allow an authorized takeover. Account login-attempt locks are separate: authorized users can force-unlock an auth document from its document actions. Configured live preview opens an isolated iframe panel with named viewport breakpoints. The admin mints a short-lived resource-bound preview grant and posts subsequent form updates through the framework preview protocol. Preview grants are process-local today, so multi-replica deployments need affinity for the preview session. Read [Live preview](https://riducms.com/guides/live-preview/) before integrating the receiving site. Every create/edit/global route also has a stable API view. Its URL can be linked directly and survives reload, which is useful when comparing the current authoring state with JSON consumers. ## Field layout {#field-layout} `Label`, `Description`, `Columns`, `Tab`, `ShowWhen`, `ReadOnly`, rows, tabs, and collapsibles affect authoring presentation. They do not grant access or rename stored paths. ```go title="admin-layout.go" package content import "github.com/riducms/ridu/field" func profileFields() []field.Definition { return []field.Definition{ field.Row( field.Text("firstName", field.Columns(6)), field.Text("lastName", field.Columns(6)), ), field.Collapsible("SEO", true, field.Text("metaTitle"), field.Textarea("metaDescription"), ), } } ``` Use [Fields](https://riducms.com/docs/fields/) for the complete vocabulary and [Rich text](https://riducms.com/docs/rich-text/) for the official paired editor plugin. ## Extend the admin {#extend-the-admin} Admin plugins are published TypeScript/Svelte packages, imported statically into the generated registry. Backend partners are compiled Go packages. The generator and startup resolver validate the stable plugin key, admin API version, plugin-owned pairing version, exported symbol, route list, and asset list before exposing extensions. There is no runtime package installation or dynamic code download in production. Use `defineAdminPlugin` to register only the surface you need: ```ts title="src/admin.ts" import { ADMIN_PLUGIN_API_VERSION, defineAdminPlugin } from '@riducms/plugin'; import EditorialPanel from './EditorialPanel.svelte'; import ReviewRoute from './ReviewRoute.svelte'; export const admin = defineAdminPlugin({ apiVersion: ADMIN_PLUGIN_API_VERSION, key: 'editorial-tools', pairingVersion: 1, fields: [], dashboard: [{ key: 'queue', component: EditorialPanel, position: 'after' }], routes: [ { path: 'editorial/review', component: ReviewRoute, navigation: { label: 'Review queue', group: 'Editorial' } } ] }); ``` Plugins can provide exact namespaced message catalogs with `defineAdminMessages`. Every extension receives `i18n`, and route, list-cell, and document-view registrations can use translated `labelKey` values. Missing locale keys and changed placeholders fail the TypeScript build. The public extension families are: | Need | Contract | | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | | Custom stored field UI | `FieldPlugin` receives the exact schema field, narrow `FieldForm`, and optional authoring host for document lookup/reference browsing. | | Authenticated page | `routes`; each relative path must match the compiled backend descriptor. Navigation is optional. | | Dashboard composition | `dashboard` panels before/after the default, or one collision-checked replacement. | | Shell composition | `login`, `account`, `navigation`, `logoutButton`, `branding`, `shell`, and ordered `providers`. | | Core route composition | `views` can wrap/replace collection list/create/edit, global, or not-found surfaces and receive a narrow refresh/notification host. | | Resource details | `listCells`, `documentActions`, and read-only/operational `documentViews`. | | Static companion modules | `assets`, validated against the backend descriptor and imported by the generated registry. | Replacement components receive the framework `defaultView` as a Svelte snippet, so a plugin can wrap the working screen instead of recreating it. Hosts expose focused operations such as refresh, login/logout, document-change notification, and toasts; they do not leak the admin’s internal stores. Extension keys and scoped replacement targets are collision-checked for deterministic composition. Start with [Plugins](https://riducms.com/docs/plugins/) and [Custom fields](https://riducms.com/guides/custom-fields/). Exact contracts are in the [`@riducms/plugin` reference](https://riducms.com/reference/plugin/); reusable primitives are documented in [`@riducms/ui`](https://riducms.com/reference/ui/), and generated alias behavior in [`@riducms/build`](https://riducms.com/reference/build/). ## Current boundaries {#boundaries} The main author workflows above are implemented, but related list/edit screens do not yet live-refresh after every mutation. - broader tablet acceptance and known dirty-state, leave-guard, and accessibility defects remain in progress; - array/block sorting and crop/focal editing work; extend keyboard, touch, and focus coverage when those interactions change or a defect exposes a gap; - route/bootstrap recovery exists, but plugin-isolated recovery and route-level plugin chunking do not; and - large relationship datasets are paginated and searched, but no virtualized picker is promised. For an evaluation-level view across the whole product, including planned features that are not callable today, see [Capability status](https://riducms.com/docs/status/). --- # TypeScript SDK Canonical URL: https://riducms.com/docs/typescript-sdk/ `@riducms/sdk` is a small Fetch client with ordinary `Promise` methods. Ridu’s generator binds it to your application so collection slugs, input shapes, filters, selection, population, and capability-specific methods are checked by TypeScript. ## Install and create a client {#install-and-create} Generated applications already include `generated/ridu.generated.ts`. Prefer that module in application code: it carries the config type produced from the same manifest as the server. When an external frontend or tool needs the framework-neutral SDK directly, install it with that project's package manager: Examples below use `~/generated` as a readable project alias. Configure that alias in your frontend, or replace it with the relative path to the CMS project's `generated/` directory. ```bash title="terminal" package-manager="bun" bun add @riducms/sdk ``` ```bash title="terminal" package-manager="npm" npm install @riducms/sdk ``` ```bash title="terminal" package-manager="pnpm" pnpm add @riducms/sdk ``` ```bash title="terminal" package-manager="yarn" yarn add @riducms/sdk ``` ```ts title="lib/ridu.ts" import { createClient } from '~/generated/ridu.generated'; export const ridu = createClient({ baseURL: 'https://cms.example.com' }); ``` If this code runs in a browser on another origin, configure the API before testing requests. The [CORS guide](https://riducms.com/docs/cors/) covers exact origins, credentialed cookies, custom headers, proxy trust, and preflight failures. Server-side SDK use does not need CORS. You can also import `createClient` from `@riducms/sdk`. A generated config augments the SDK’s `GeneratedRiduConfigRegistry`; when exactly one generated application is visible, inference selects it automatically. Tooling that loads no generated config—or several applications—should bind the config explicitly or import each application’s generated wrapper. This avoids silently choosing the wrong schema. ```ts title="tooling.ts" import { createClient } from '@riducms/sdk'; import type { RiduConfig } from '~/generated/ridu.generated'; const cms = createClient({ baseURL: process.env.RIDU_URL! }); ``` When `ridu dev` is running, a Go config change regenerates this module automatically. Commit the result. See [Generated contracts](https://riducms.com/docs/generated-contracts/) for one-shot generation and drift checks, and the complete [SDK reference](https://riducms.com/reference/sdk/) for every type and signature. ## Read content {#read-content} `list`, `find`, and `count` cover ordinary collection reads. `global` reads a singleton. Filters, selects, and populations are generated from the resource instead of accepting an untyped query bag. ```ts title="posts.ts" const page = await ridu.list('posts', { page: 1, limit: 24, where: { and: [{ status: { equals: 'published' } }, { title: { contains: 'ridu' } }] }, sort: ['-createdAt', 'title'], select: { title: true, status: true, author: true }, populate: { author: { depth: 1, select: { name: true } } } }); const post = await ridu.find('posts', page.docs[0].id, { select: { title: true, author: true } }); const { totalDocs } = await ridu.count('posts', { where: { status: { equals: 'published' } } }); const site = await ridu.global('site-settings'); ``` A group, array, or blocks container supports an `exists` filter. Nested group, array-row, and block filters use canonical dotted keys such as `"seo.description"`, `"sections.reviewer"`, and `"layout.quote.source"`. Generated where contracts do not model these paths as nested objects because the REST API decodes the same dotted path vocabulary used by the operation engine. Use either `depth` for uniform relationship expansion or `populate` for explicit paths, never both in one request. Locale-aware reads accept `locale`, including `"all"`, and `fallbackLocale: string | string[] | false`. The generated output changes to locale-keyed fields when `locale: "all"` is statically known. Locale-aware mutations accept one generated locale and reject `"all"`. ## Create and change content {#mutations} The core mutation family is `create`, `update`, and `delete`. Globals use `updateGlobal`. Optimistic concurrency is opt-in on revision-aware methods: pass the document revision and the SDK sends `If-Match`. Methods without a revision contract reject a revision-bearing options variable instead of silently ignoring it. ```ts title="mutations.ts" const post = await ridu.create('posts', { title: 'SDK guide', status: 'draft' }); const published = await ridu.update( 'posts', post.id, { status: 'published' }, { revision: post._revision } ); await ridu.copyLocale( 'posts', published.id, { from: 'en', to: 'fr' }, { revision: published._revision } ); await ridu.duplicate('posts', published.id); ``` Related task methods are grouped by capability: - `mutateJoin` mutates a writable inverse join. - `bulkUpdate`, `bulkPublish`, `bulkUnpublish`, `bulkDelete`, `bulkRestoreDeleted`, and `bulkDeletePermanent` operate on explicit document IDs. A request is limited to 100 unique IDs. - `restoreDeleted`, `deletePermanent`, and `emptyTrash` exist only for trash-enabled collections. - `copyGlobalLocale` copies localized global values. The SDK exposes three precise option families: `MutationLocaleOptions` for single-locale mutations without a revision fence, `MutationOptions` for localized revision-aware mutations, and `RevisionOptions` for revision-aware operations that do not consume a locale query. `copyLocale` and `copyGlobalLocale` take their locale scope from `from` and `to`; `updateUploadImage` and `schedulePublish` likewise use revision-only options. The type system removes collection slugs from capability-specific methods when the generated manifest says the capability is absent; the server remains the authorization authority. ## Drafts, versions, and publishing {#versions} For versioned collections, use `versions` and `version` to inspect snapshots, then `publish`, `publishChanges`, `unpublish`, or `restore`. `publishChanges` submits edited values and the status transition as one publish operation, so publish access and hooks cannot be bypassed by an ordinary update. `schedulePublish`, `scheduledPublishes`, and `cancelScheduledPublish` manage durable collection publication jobs. Versioned globals use `globalVersions`, `globalVersion`, `publishGlobal`, `publishGlobalChanges`, `unpublishGlobal`, and `restoreGlobal`; scheduled publishing is collection-only today. ```ts title="publishing.ts" const history = await ridu.versions('posts', post.id); const restored = await ridu.restore('posts', post.id, history[0].Revision, { draft: true, revision: post._revision }); const job = await ridu.schedulePublish('posts', restored.id, new Date('2027-01-02T09:00:00Z'), { revision: restored._revision }); ``` ## Uploads and media {#uploads} Upload-enabled collections add three creation paths and one metadata operation: ```ts title="media.ts" const asset = await ridu.upload('media', file, { data: { alt: 'Team gathered outside the studio' } }); const imported = await ridu.uploadFromURL('media', 'https://assets.example.com/photo.jpg', { data: { alt: 'Imported photo' } }); await ridu.updateUploadImage( 'media', asset.id, { focalX: 0.5, focalY: 0.35, cropX: 0, cropY: 0, cropWidth: 1200, cropHeight: 630 }, { revision: asset._revision } ); ``` `upload` sends multipart data and `uploadFromURL` asks the configured backend to fetch a URL. Stored object delivery is an access-checked REST `GET` rather than a document SDK method. File-size, MIME, image, remote-host, and storage limits come from server config, not the SDK. ## Authentication and account tasks {#authentication} `login`, `session`, `refreshSession`, `logout`, and `logoutAll` implement the ordinary browser session flow. The client defaults `credentials` to `"include"`, so the server’s `ridu_session` HttpOnly cookie is sent on same-origin or correctly configured cross-origin requests. Auth collections also enable `createAuthUser`. Configured recovery, verification, API-key, and login-attempt-lock features add `requestPasswordReset`, `resetPassword`, `requestVerification`, `verifyEmail`, `createAPIKey`, `apiKeys`, `revokeAPIKey`, and `forceUnlock`. Account operations include `changePassword`, `sessions`, and `revokeSession`. For a service client, supply an API key as a Bearer credential. For a raw session token, use the `Session` scheme (`JWT` remains accepted for compatibility). Creating an API key requires a cookie session, and its secret is returned only by `createAPIKey`; later listings expose metadata only. ```ts title="service-client.ts" const service = createClient({ baseURL: 'https://cms.example.com', headers: async () => ({ Authorization: `Bearer ${await loadAPIKey()}` }) }); ``` Preview reads use separate methods: `preview` and `previewGlobal` place the short-lived preview token in `Authorization: Bearer …` for that request. Use `createPreviewToken`, `createGlobalPreviewToken`, and `revokePreviewToken` to manage those credentials. For iframe updates, pair them with `connectLivePreview`; see [Live preview](https://riducms.com/guides/live-preview/). ## Access, locks, and preferences {#coordination} The admin-facing coordination APIs are public and useful in custom tools: - `collectionAccess` and `globalAccess` resolve operation and field capabilities for the proposed document context. `resolveFilteredSelection` converts an access-checked filter into at most 100 explicit IDs for safe bulk work. - `documentLock`, `acquireDocumentLock`, and `releaseDocumentLock` coordinate editors. Passing `takeover: true` does not bypass the server’s access rules. - `preference`, `setPreference`, `deletePreference`, and `resetPreferences` store actor-scoped UI state. Treat capability results as presentation guidance, not a replacement for handling authorization failure: access can depend on the actor, request, proposed data, or stored row. ## Plugin endpoints {#plugin-endpoints} Use `requestPlugin` for a compiled plugin's declared namespaced endpoint: ```ts const generated = await ridu.requestPlugin<{ result: string }>( 'seo', 'generate-title', { collection: 'pages', locale: 'en', document: { title: 'About Acme' } }, { signal } ); ``` The method sends `POST /api/plugins/{plugin}/{path}` through the same base URL, credentials, headers, middleware, cancellation, and `RiduError` handling as the typed content methods. It rejects invalid plugin keys and empty, whitespace, traversal, query, fragment, or wildcard path segments before dispatch. The result type is caller-supplied because each compiled plugin owns its endpoint contract; use that plugin's guide and API reference rather than treating the route as generic content CRUD. ## Raw custom endpoint requests {#custom-endpoints} Application custom endpoints can return JSON, text, empty responses, or streams. Use `request` to retain Fetch semantics instead of forcing an arbitrary route through a typed content envelope: ```ts const response = await ridu.request('/api/revalidate/storefront', { method: 'POST', body: JSON.stringify({ paths: ['/products'] }), headers: { 'Content-Type': 'application/json' } }); if (!response.ok) throw new Error(`revalidation failed: ${response.status}`); ``` The path must begin with one `/`, stay on the configured origin, and omit a fragment. The method returns the raw `Response` for every HTTP status, does not parse JSON, and does not supply a default content type. Client credentials, default/per-call headers, middleware, cancellation, and `keepalive` still apply. See [Custom endpoints](https://riducms.com/docs/custom-endpoints/) for the Go handler contract. ## Fetch, middleware, and cancellation {#fetch-and-errors} Pass a request-local `fetch` in SvelteKit or another server framework. `headers` may be static or an async function, and request-specific headers override client defaults. Middleware wraps a concrete `Request`, which makes tracing, retries, logging, and test interception possible without a separate transport adapter. ```ts title="server-client.ts" const cms = createClient({ baseURL: 'https://cms.example.com', fetch, credentials: 'include', headers: () => ({ 'X-App': 'storefront' }), middleware: [ async (request, next) => { const response = await next(request); console.debug(request.method, request.url, response.headers.get('X-Request-ID')); return response; } ] }); const controller = new AbortController(); const pending = cms.list('posts', { signal: controller.signal }); controller.abort(); await pending; ``` Every request option accepts `signal`; mutation requests also accept `keepalive`. Cancellation is standard Fetch cancellation and rejects with the runtime’s abort error, not `RiduError`. ## Structured errors {#errors} Successful calls return the useful value rather than the wire envelope. Non-success HTTP responses reject with `RiduError`, which preserves `code`, `status`, `message`, optional `requestId`, field `issues`, and `details`. ```ts title="errors.ts" import { RiduError } from '@riducms/sdk'; try { await ridu.update('posts', id, { title: '' }, { revision }); } catch (error) { if (error instanceof RiduError && error.code === 'validation') { for (const issue of error.issues) console.error(issue.path, issue.message); return; } if (error instanceof RiduError && error.code === 'conflict') { // Reload: another writer changed this revision. return; } throw error; } ``` If a proxy returns a non-Ridu error page, the SDK still produces a fallback `RiduError` from the HTTP status. It validates Ridu’s success envelopes, but does not runtime-validate every application document against the generated TypeScript type. Validation and authorization remain server-side. ## Current type boundaries {#boundaries} Generated `where`, `select`, and `populate` inputs are resource-specific, but a selected or populated read currently retains the collection’s complete output type rather than computing a projected return type. Sort terms are checked as strings rather than a generated union of sortable paths. The client does not cache, coalesce, or retry automatically; add policy in middleware only when the operation is safe to repeat. There is no required result-wrapper library and no Node-only transport. Use the [REST API guide](https://riducms.com/docs/rest-api/) for the underlying transport, the [protocol reference](https://riducms.com/reference/protocol/) for shared envelopes and error codes, and [Capability status](https://riducms.com/docs/status/) for wider product limits. --- # Ridu CLI Canonical URL: https://riducms.com/docs/cli/ `ridu` coordinates the Go application, generated contracts, selected database artifacts, and Svelte admin. Run project commands anywhere beneath the directory containing `ridu.toml`; discovery walks upward. When the CLI needs config, it executes the application-owned versioned project command—it never parses Go source as a substitute. ## Command map {#commands} | Command | Purpose | | --------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `ridu new` | Scaffold a generated application and write its initial contracts. | | `ridu doctor` | Diagnose Go, Bun, project discovery, frontend dependencies, and selected database prerequisites. | | `ridu dev` | Prepare the selected database and generation, then run/watch the Go API and Vite admin. | | `ridu generate` | Resolve executable config and atomically write the manifest, clients, OpenAPI, plugin registry, and configured plugin artifacts. | | `ridu check` | Verify generated and migration drift, Go format/vet/tests, and TypeScript/Svelte. | | `ridu build` | Regenerate, build the admin, and atomically emit one Go application binary. | | `ridu migrate` | Create immutable artifacts and run the migration commands supported by the selected adapter. | | `ridu plugin` | Scaffold, install, or remove compiled backend/static-admin plugin pairs. | | `ridu add` | Alias for `ridu plugin add`. | | `ridu agent` | Install or synchronize release-matched, offline coding-agent guidance. | | `ridu version` | Print the CLI release version. `--version` and `-v` are aliases. | | `ridu help` | Show the top-level command list plus project-protocol and schema-manifest versions. `--help` and `-h` are aliases. | Exact exported command contracts also appear in the [CLI reference](https://riducms.com/reference/cli/). ## Output and diagnostics {#output} Lifecycle messages use local `HH:MM:SS` timestamps. Routine timestamps are muted and use a `[ridu]` scope without repeating `INFO`; warnings and errors add an explicit level, and only error timestamps are bold. Stable command results—help, version, prompts, migration tables, generated paths, URLs, and machine-readable output—remain plain text. During `ridu dev`, Vite's duplicate startup banner is suppressed and its warning/error output retains Vite's own formatting. Go server output remains identifiable by a `[server]` badge. Foreground dependency installation retains the selected manager's native progress and summary output. Colour is detected and downsampled for the active terminal. Set `NO_COLOR` (including to an empty value) to disable Ridu-owned ANSI styling, or set `RIDU_ACCESSIBLE=1` to combine unstyled logs with the CLI's plain-text prompts. Child-process ANSI content is forwarded unchanged. ## Create a project {#new} Run `new` in a terminal to open the project wizard: ```bash title="terminal" ridu new ``` It collects the project directory, template, database, package manager, and coding-agent guidance, describes each choice, and asks for confirmation before writing. One prompt is active at a time; completed answers collapse into compact history and later prompts remain hidden. Set `RIDU_ACCESSIBLE=1` for stable plain-text prompts suitable for screen readers. After generation, run the exact directory, install, and `dev` commands printed under **Next**.
Automate or preselect the wizard
Every supplied choice skips its matching prompt. Specify every choice for a non-interactive script: ```bash title="terminal" ridu new \ --template starter \ --database postgres \ --package-manager npm \ --agent codex \ --module github.com/acme/my-cms \ --scope @acme \ my-cms ``` ```text title="ridu new --help" ridu new [--template starter|blank] [--database postgres|sqlite|mongodb] [--package-manager npm|bun|pnpm|yarn] [--agent codex|claude|cursor|all|none] [--no-agent] [--module path] [--scope @scope] [--release-version version] [directory] ```
`--module` defaults to `example.com/`, `--scope` to `@`, `--database` to `postgres`, and `--package-manager` to `npm` outside the wizard. Select `sqlite` explicitly for the embedded single-host adapter or `mongodb` for the bounded generated-project replica-set profile. MongoDB production support covers only the exact Linux x86-64, Community 8.2.9, authenticated verified-TLS three-member profile in its [adapter guide](https://riducms.com/docs/mongodb/). `--release-version` is a framework-development dependency override, not an application version. Use `--no-agent` or `--agent none` to omit agent guidance. Non-interactive runs default to `starter` and the Codex-compatible layout. `starter` includes the example posts collection, while `blank` keeps only the authentication collection and framework wiring. The command scaffolds, runs `go mod tidy`, and generates initial schema, client, OpenAPI, and admin plugin contracts. Unless omitted, it also installs the selected agent's root entrypoint and two complete local skills: `ridu-project` for ordinary application work and `payload-to-ridu` for assessment and migration. Their focused references are embedded in the CLI release, so agents can work without reaching into Ridu's private development repository or requiring network access. If dependency setup or initial generation fails, Ridu keeps the new directory and prints recovery commands; it does not discard your scaffold. Run `ridu doctor` when setup is uncertain. It accepts no flags or positional arguments. PostgreSQL projects need `DATABASE_URL` or Docker/OrbStack for the scaffolded service. SQLite projects report their configured path or the `.ridu/development.sqlite` default and do not require Docker. MongoDB projects need a replica-set `DATABASE_URL` or Docker/OrbStack for the scaffolded development replica set. ## Coding-agent guidance {#agent} Generated projects use the layout selected by `ridu new`: | Selection | Root entrypoint | Local skills | | ------------------- | --------------- | ------------------------------------------------ | | `codex` or `cursor` | `AGENTS.md` | `.agents/skills/{ridu-project,payload-to-ridu}/` | | `claude` | `CLAUDE.md` | `.claude/skills/{ridu-project,payload-to-ridu}/` | | `all` | Both | Both skill roots | | `none` | None | None | Add another layout to an existing project with `ridu agent install --agent `. The command preserves an existing `AGENTS.md` or `CLAUDE.md` and refuses to replace an untracked skill file. `.ridu-agent-docs.json` records only framework-managed skill files and their digests; commit it with the installed guidance. After upgrading the CLI, run `ridu agent sync`. Sync updates only files recorded in that manifest, writes each file atomically, and leaves root project instructions alone. If a managed reference was edited, sync stops before changing anything so you can move the project-specific note into `AGENTS.md`, `CLAUDE.md`, or `PROJECT.md` first. The same public documentation is available at [`/llms.txt`](https://riducms.com/llms.txt), [`/llms-full.txt`](https://riducms.com/llms-full.txt), and release-pinned `/v//llms-full.txt` URLs for tools that consume HTTP documentation feeds. ## Development lifecycle {#dev} ```bash title="terminal" ridu dev ``` In order, `dev` installs missing frontend dependencies with the package manager selected in `ridu.toml`, reads the selected database, builds one disposable Go candidate, resolves config by executing that exact binary, atomically writes generated contracts, applies only the non-destructive development schema plan, and reuses the candidate as the server. It starts Vite when an admin directory is configured, waits for both, then watches Go config. Each accepted edit prints its build, manifest, contract, database, and total timings. A generated Go contract change enters a bounded consistency loop only when the server imports that package, and each rebuilt executable resolves its own manifest before serving. A stable CLI-owned proxy keeps the public API address on the accepted process while a replacement starts on a private loopback address. A newer save normally skips a stale candidate. If MongoDB has already committed additive indexes for that candidate, Ridu first promotes the exact database-matching candidate and then immediately processes the queued newer revision; discarding it would leave the running manifest behind the physical plan. Every replacement must verify its own Store and pass development `/readyz` before the proxy promotes it. Plugin-registry changes signal a full admin reload. | Option | Default | Effect | | ------------------------ | --------------------------------------------------- | ---------------------------------------------------------------- | | `--database-url ` | `DATABASE_URL`, then the scaffold local URL | Choose development PostgreSQL or a MongoDB replica set. | | `--database-path ` | `RIDU_SQLITE_PATH`, then `.ridu/development.sqlite` | Choose the local SQLite file. | | `--address ` | `127.0.0.1:8080` | Bind the Go API. | | `--admin-port ` | `5173` | Bind the Vite admin. | | `--no-docker` | false | Do not start the selected PostgreSQL or MongoDB Compose service. | | `--no-install` | false | Do not install missing frontend dependencies. | | `--no-sync` | false | Skip the non-destructive development schema plan. | Development enables explicitly insecure local cookie/database settings and the Vite origin for the managed processes. Do not reproduce those settings as production defaults. If schema sync finds an ambiguous rename or destructive transition, stop and create a reviewed migration rather than expecting `dev` to guess intent. For MongoDB, sync creates only missing indexes. The separate serving Store verifies the exact resolved plan before cutover; incompatible physical drift rejects the candidate and leaves the last working process and data in place. See [MongoDB](https://riducms.com/docs/mongodb/). ## Generate and check contracts {#generated-contracts} `ridu generate` writes these configured artifacts atomically: - `generated/ridu.schema.json` — canonical manifest; - `generated/ridu.openapi.json` — concrete REST contract; - `generated/ridu.generated.go` — application Go models and handles; - `generated/ridu.generated.ts` — application-bound TypeScript config/client; - configured `generated..` destinations — including exact SDL from the compiled GraphQL plugin; - `admin/src/ridu.plugins.generated.ts` — validated static admin plugin imports; and - generated compiled-plugin registration derived from `ridu.plugins.json`. ```bash title="CI" ridu generate --check ridu check ``` `generate --check` resolves config and reports drift without writing. Plain `generate` writes changed files and accepts no other option. Generated paths are application-owned configuration in `ridu.toml`; disposable intermediates live in `.ridu/`. Read [Generated contracts](https://riducms.com/docs/generated-contracts/) before changing generated ownership. `ridu check` accepts no flags. It runs generation in check mode, requires migration artifact history to match the resolved manifest, checks `gofmt`, then runs `go vet ./...`, `go test ./...`, and the root Bun `check` script when an admin is configured. Missing frontend dependencies are an error; install them with `ridu dev` or `npm install` first. PostgreSQL, SQLite, and MongoDB projects all fail closed when committed migration history does not end at executable config. ## Build a release {#build} ```bash title="terminal" ridu build ridu build --output ./dist/cms-linux-amd64 ``` `build` regenerates contracts in write mode, installs missing frontend dependencies, runs the root Bun `build` script, then compiles the configured Go entry with a fingerprint of the exact ordered migration filenames and artifact digests. It builds to a temporary file and renames it into place only on success. The default target is `dist/` (`.exe` on Windows); `--output` accepts a project-relative or absolute file path. The result contains the admin assets when the application embeds its configured asset package. Official adapters compare the live ledger with that fingerprint at production readiness; a direct `go build` omits it and fails closed unless the application explicitly delegates readiness or enters the development-only startup path. Generation during `build` is not a drift check. Run `ridu check` in CI and review/commit generated changes before producing a release. MongoDB production use is supported only inside the adapter's documented generated-project, Linux, and replica-set profile. See [Production](https://riducms.com/docs/production/) for the full cutover. ## Migrations {#migrations} ```bash title="terminal" ridu migrate create --name add-post-summary ridu migrate plan ridu migrate verify ``` Those are preparation commands, not a MongoDB production cutover order. The exact MongoDB sequence is documented below and in the [MongoDB guide](https://riducms.com/docs/mongodb/#production). PostgreSQL and MongoDB expose the five forward-production commands. SQLite exposes those commands plus its reviewed local reversible lifecycle: | Subcommand | Database? | Behavior | | ---------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `create` | No | Compare resolved config with the latest artifact manifest, plan the transition, and write a new immutable artifact. PostgreSQL and MongoDB can confirm detected renames; SQLite and MongoDB data changes can name a compiled transform. Requires `--name `. | | `plan` | Yes | Read-only listing of artifacts, phases, steps, and committed progress. A missing SQLite file reports every artifact pending without creating it. `--json` emits machine-readable status. | | `status` | Yes | Read-only ledger/history and physical-state status. SQLite opens an existing file read-only without changing its journal mode. `--json` is available. | | `verify` | Adapter-dependent | Replay complete admitted history in an isolated PostgreSQL schema, temporary SQLite database, or random MongoDB shadow database and assert the final state. MongoDB needs a controlled credential able to create and drop that shadow database. | | `up` | Yes | Validate and apply pending history. PostgreSQL uses an advisory lock and resumable phases; MongoDB uses a fenced lease and durable step resumption; SQLite applies all pending artifacts atomically under one writer transaction. | | `down` | SQLite | Reverse the latest applied SQLite artifact after explicit destructive approval. | | `reset` | SQLite | Reverse every applied SQLite artifact atomically. | | `refresh` | SQLite | Reverse and reapply committed SQLite history atomically. | | `fresh` | SQLite | Drop non-internal objects and replay committed SQLite history atomically. | PostgreSQL and MongoDB database-backed subcommands take `--database-url ` or `DATABASE_URL` and accept `--allow-insecure-database` only as an explicit local plaintext or certificate-verification override. SQLite uses `--database-path ` or `RIDU_SQLITE_PATH`; its `verify` command replays in a temporary database and needs no deployment path. An explicit `--database-path` may be project-relative; `RIDU_SQLITE_PATH` must be an absolute file path or `file:` URI, matching the generated runtime. SQLite mutating migration commands reject `:memory:` because their successful state must survive the CLI process. `create` accepts `--name ` and adapter-specific review options: - PostgreSQL and MongoDB accept `--accept-renames` for unambiguous proposed renames. - SQLite accepts `--transform ` for a registered transaction-bound data transform and rejects `--accept-renames`; canonical JSON rewrites use the compiled transform instead. - MongoDB also accepts `--transform ` for a registered compiled transform bound to its exact artifact and runner. - All three accept `--allow-destructive` to record planner-confirmed destructive changes after review. It does not connect to or modify a database. MongoDB `create` always runs without a database URL. New planner-`2.0.0` artifacts record physical index steps, explicit rename intent, compiled transforms, reviewed resource retirement, and final assertions in immutable history. Authenticated planner-`1.0.0` history remains a supported immutable prefix that is validated and replayed before v2 rather than rewritten. `plan`, `status`, `verify`, and `up` use the production runner; `down`, `reset`, `refresh`, and `fresh` remain unsupported. Keep the running MongoDB application database-scoped. Use separate short-lived credentials for verification and backup/restore work in production. PostgreSQL `up` and `verify`, and MongoDB `up` and `verify`, share the applicable bounded runner controls: | Option | Adapter | Meaning | | ------------------------------------------ | -------- | ------------------------------------------------------------------------------------- | | `--advisory-lock-wait ` | Both | Maximum wait for PostgreSQL's advisory lock or MongoDB's fenced migration lease. | | `--lock-timeout ` | Postgres | PostgreSQL lock wait per phase. | | `--statement-timeout ` | Postgres | Transactional statement duration. | | `--batch-timeout ` | Postgres | One checkpoint batch duration. | | `--concurrent-index-timeout ` | Both | PostgreSQL concurrent-index duration or the complete MongoDB migration operation. | | `--idle-in-transaction-timeout ` | Postgres | Idle time inside a transaction phase. | | `--allow-unbounded` | Both | Explicitly admit zero runner waits/timeouts; MongoDB lease expiry remains bounded. | | `--allow-maintenance` | Both | Assert that every old process/writer/worker is stopped for a traffic-sensitive phase. | For PostgreSQL, only `up` accepts `--stop-after-phase ` and `--stop-after-step `; qualify a repeated ID as `/`. A successful boundary stop means progress was committed, not that history is current—run `status` before admitting application traffic. SQLite rejects these phased-runner options because its artifact history commits atomically. MongoDB also rejects explicit stop boundaries; an interrupted run resumes from its durable completed steps. For a MongoDB release with any new migration artifact—including a same-manifest data-only artifact—first drain all old processes and workers. Then run `DATABASE_URL="$MONGODB_OPERATIONAL_URL" ridu migrate verify`, capture the matched selected-database and upload snapshot, run `DATABASE_URL="$MONGODB_MIGRATION_URL" ridu migrate up` with the selected app/operator identity, run post-`up` `status` with that URL, and only then start the binary with `$MONGODB_APP_URL`. > [!IMPORTANT] > PostgreSQL and MongoDB have no generated `ridu migrate down`; use a reviewed forward correction or > restore the complete coordinated recovery point. SQLite artifacts carry explicit reversible steps > and expose `down`/`reset`/`refresh`/`fresh` only with destructive approval. Never edit an applied > artifact for any adapter. The flags above are safety admissions, not broad bypasses: `--allow-destructive` cannot override a semantic safeguard, and `--allow-maintenance` does not stop old writers for you. Read the selected adapter's [PostgreSQL migration workflow and recovery policy](https://riducms.com/docs/migrations/) or [SQLite migration and recovery contract](https://riducms.com/docs/sqlite/#migrations), or the bounded [MongoDB production profile](https://riducms.com/docs/mongodb/#migrations), then use [Troubleshooting](https://riducms.com/docs/troubleshooting/#migration-refused) when a plan fails closed. ## Plugins {#plugins} ```text title="ridu plugin --help" ridu plugin new --key --module --admin-package ridu plugin add --go-package [--go-version ] [--constructor New] [--admin-package ] [--admin-version ] [--no-install] ridu plugin remove [--no-install] ``` `plugin new` scaffolds paired Go and admin packages with the given stable key, module, and published admin package name. `plugin add` defaults Go/admin versions to `latest` and the exported zero-argument constructor to `New`; `ridu add` is its exact alias. It installs dependencies unless `--no-install`, updates registration, regenerates contracts, and rolls back the project mutation if compatibility or generation fails. `plugin remove` removes registration, then removes the unshared paired admin package from the root and admin manifests and tidies Go dependencies unless `--no-install`. That package remains installed when another plugin still references it. Separately installed field-type packages remain application-owned. The command regenerates and rolls back registration on contract failure. Removal never silently drops plugin-owned database state: create and review the resulting migration before applying any plugin down steps. See [Plugins](https://riducms.com/docs/plugins/). ## `ridu.toml` {#project-file} ```toml title="ridu.toml" version = 1 database = "postgres" # or "sqlite" or "mongodb"; credentials remain runtime-owned package_manager = "npm" # or "bun", "pnpm", or "yarn" entry = "./cmd/server" admin = "./admin" schema = "./generated/ridu.schema.json" client = "./generated/ridu.generated.ts" migrations = "./migrations" openapi = "./generated/ridu.openapi.json" # Set only after enabling the optional GraphQL plugin. # generated.graphql.schema = "./generated/ridu.graphql" assets = "./internal/adminassets/dist" plugins = "./ridu.plugins.json" plugin_go = "./content/ridu_plugins.generated.go" ``` Version 1 accepts these structural keys plus generic `generated..` destinations. `database`, `entry`, `schema`, `plugins`, and `plugin_go` are required; `database` must explicitly select `postgres`, `sqlite`, or `mongodb` because the CLI does not infer an adapter; `package_manager` selects npm, Bun, pnpm, or Yarn for frontend operations. Existing version-1 files that omit it retain Bun for compatibility, while new scaffolds always write the selection. `admin`, `client`, `migrations`, `openapi`, and `assets` may be empty when the project omits those outputs. Other paths are relative to the project root and may not escape it. The file is structural CLI configuration, not the CMS schema—application behavior remains in executable Go config. See [Configuration](https://riducms.com/docs/configuration/) and [Project structure](https://riducms.com/guides/project-structure/). --- # Testing Canonical URL: https://riducms.com/docs/testing/ Test the smallest boundary that can catch the failure you care about. Keep access rules, hooks, and validators in fast Go tests. Add a database-backed test for adapter behavior, a live server for HTTP behavior, and a browser for authoring behavior. ## Choose the smallest useful layer {#layers} | Layer | Use it for | | ------------------------ | ------------------------------------------------------------------------------ | | Go unit/config | Access rules, hooks, validators, helpers, and config resolution | | `plugintest` | Public plugin configuration, validation, Local API, and REST behavior | | Generated-contract check | Missing or stale manifest, Go, OpenAPI, TypeScript, and admin output | | Database integration | Queries, constraints, indexes, transactions, migrations, and recovery | | Live HTTP transport | URLs, headers, cookies, request bodies, response envelopes, and cancellation | | Browser | Authentication, fields, forms, server issues, persistence, and access-aware UI | Start low in the table and add a higher layer only when the boundary matters. ## Unit-test executable config {#config-tests} Access rules, hooks, task handlers, field helpers, and plugin validators are ordinary Go functions. Test their branches directly, then keep one resolution test that composes the application config: ```go title="content/config_test.go" package content import ( "testing" "github.com/riducms/ridu" ) func TestConfigResolves(t *testing.T) { resolved, err := ridu.Resolve(Config()) if err != nil { t.Fatal(err) } if len(resolved.Collections) == 0 { t.Fatal("expected at least one collection") } } ``` Assert stable public behavior such as issue codes and paths, access decisions, resolved fields, and operation results. Use table-driven tests for role and operation matrices. ## In-memory tests {#in-memory} Ridu does not publish an in-memory database adapter for applications. Unit-test pure policy and configuration without a store, then use a disposable instance of the same adapter you deploy for operation integration tests. This avoids passing tests against behavior your production database does not share. ## Use `plugintest` for public plugin conformance {#plugintest} Plugin authors can exercise the shared backend contract with `plugintest.Run`: ```go title="plugin_test.go" func TestConformance(t *testing.T) { plugintest.Run(t, plugintest.Fixture{ Plugin: plugin.New(), Fields: []field.Definition{ plugin.Field("value", field.Required()), }, ValidData: store.Values{"value": store.String("valid")}, InvalidData: store.Values{"value": store.String("")}, Compatibility: []plugintest.CompatibilityCase{ {RiduVersion: ridu.FrameworkVersion, Compatible: true}, }, }) } ``` This covers config resolution, manifest encoding, compatibility, validation, Local API, and REST behavior. A field with an admin component also needs frontend type checks and a browser test. See [Build a custom field](https://riducms.com/guides/custom-fields/). ## Check generated output {#generated-drift} Run these commands in CI after installing project dependencies: ```sh title="terminal" package-manager="npm" npm run ridu -- generate --check npm run ridu -- check ``` ```sh title="terminal" package-manager="bun" bun run ridu -- generate --check bun run ridu -- check ``` ```sh title="terminal" package-manager="pnpm" pnpm run ridu generate --check pnpm run ridu check ``` ```sh title="terminal" package-manager="yarn" yarn run ridu generate --check yarn run ridu check ``` `generate --check` reports missing or stale generated files without rewriting them. `ridu check` also checks migration history, Go formatting, `go vet`, Go tests, and the configured TypeScript and Svelte projects. Fix the source config and regenerate; do not hand-edit generated files. ## Test PostgreSQL behavior {#postgresql} Use a disposable database or uniquely named schema for integration tests that depend on PostgreSQL queries, constraints, indexes, locks, concurrency, task leasing, or recovery. Pass its URL through a test-only environment variable, clean it after the test, and never point a test suite at a shared development or production database. For schema changes, run `ridu migrate verify` to replay migration history in a shadow schema. See [PostgreSQL](https://riducms.com/docs/postgres/) and [Migrations](https://riducms.com/docs/migrations/). ## Test SQLite behavior {#sqlite} Create each SQLite test database under `t.TempDir()`. Test the same transaction, migration, index, and recovery paths your application uses. Do not place the file on a shared network filesystem or use a passing SQLite test to claim multi-host support. See [SQLite](https://riducms.com/docs/sqlite/). ## Test MongoDB behavior {#mongodb} Use a disposable database on the supported writable replica-set topology when a test depends on transactions, BSON encoding, indexes, migrations, or recovery. A standalone local server cannot exercise Ridu's transaction path. Run `ridu migrate verify` with a credential allowed to create and drop its temporary verification database. See [MongoDB](https://riducms.com/docs/mongodb/). ## Test a live transport {#transport} Handler tests are useful for a focused route. Keep at least one test that starts the application on a loopback port and calls it through the generated SDK. Cover login cookies, errors, cancellation, and the methods your frontend actually uses. Custom endpoint tests should also cover the wrong method, body limits, actor propagation, and calls through `PluginEndpointContext.Local`. ## Test authoring in a browser {#browser} Run browser tests against your generated admin. Prefer a few complete journeys over a large number of cosmetic assertions: 1. sign in; 2. create or edit a representative document; 3. confirm validation and access behavior; 4. reload and verify persisted values; and 5. exercise any custom admin field or plugin. Test the browsers your users rely on. Ridu's own Chromium coverage does not replace an application's browser matrix. ## Build readable test data {#fixtures} Use stable IDs, timestamps, sort order, array/block keys, and named accounts for distinct roles. Create one valid and one invalid value for each custom validator, and include explicit draft, published, deleted, or versioned states only when the workflow needs them. Give every test its own storage root, namespace, port, schema, or database and clean it afterward. ## Project commands {#commands} An ordinary project CI job usually needs: ```sh title="terminal" package-manager="npm" go test ./... npm run ridu -- generate --check npm run ridu -- migrate verify npm run ridu -- check npm run ridu -- build ``` The equivalent project-local commands work with Bun, pnpm, and Yarn. When one fails, identify the boundary first: configuration, generated output, operation behavior, database/migration behavior, HTTP encoding, or admin rendering. [Troubleshooting](https://riducms.com/docs/troubleshooting/) follows the same split. --- # Troubleshooting Canonical URL: https://riducms.com/docs/troubleshooting/ Start with the exact error and the narrowest failing command. ## `ridu` or a package cannot be found {#command-not-found} **Likely cause:** the CLI installation directory is not on `PATH`, the project has not installed its committed frontend dependencies, or its Go and `@riducms/*` versions do not match the CLI release. Confirm which binary the shell finds and print its version: ```sh command -v ridu ridu version ``` If the command is missing, install the released CLI and make sure Go's binary directory is on `PATH`: ```sh go install github.com/riducms/ridu/cmd/ridu@latest ``` Inside a generated project, run `ridu doctor` to compare the CLI, project, Go, Bun, and package requirements. Restore dependencies with the package manager and versions committed by the project; do not add absolute local `replace` directives or Vite aliases as a version workaround. ## `ridu new` refuses the project {#new-refuses-project} Check all three inputs: - the target path must not already exist; - the project name must use lowercase kebab-case; - `--module` must begin with a domain, such as `github.com/acme/content`; and - `--scope` must be a lowercase npm-safe scope such as `@acme`. If dependency installation or generation fails, the project is kept and the CLI prints the `cd`, `go mod tidy`, and `ridu generate` recovery commands. Run those commands after restoring registry or network access rather than deleting application work. See [CLI](https://riducms.com/docs/cli/) and the [generated project tour](https://riducms.com/guides/project-structure/). ## Config resolution or generation fails {#config-generation-fails} Ridu executes your project command; it does not parse Go source. Work through the failure in this order: 1. Run Go formatting and tests to find a compiler error or invalid callback signature. 2. Run `ridu generate` directly so the project-command or schema diagnostic is not hidden among dev server logs. 3. Check for duplicate collection, global, or field identifiers; invalid reserved paths; a relationship to a missing collection; an invalid locale fallback graph; or an unsupported unique/index shape. 4. Confirm every backend plugin and paired admin package supports the same Ridu and plugin API versions. Generation is atomic. A failed build, config validation, protocol handshake, encoding step, or final rename leaves the prior artifact set intact. Fix the source config and regenerate; do not patch `generated/` by hand. Read [Configuration](https://riducms.com/docs/configuration/), [Fields](https://riducms.com/docs/fields/), and [Plugins](https://riducms.com/docs/plugins/) for the owning contract. ## `ridu generate --check` reports drift {#generated-drift} The committed schema, OpenAPI, Go models, TypeScript client, and generated admin plugin imports no longer match executable config. Run: ```sh npm run ridu -- generate git diff -- generated admin/src/ridu.plugins.generated.ts ``` Review the complete set together and commit intended contract changes with the config change. If generation changes files on every run, stop: output is required to be deterministic. Check for a plugin transform that depends on map iteration, time, random values, machine-specific paths, or external I/O. ## `ridu dev` cannot start {#dev-cannot-start} Run `ridu doctor` first. It diagnoses the project, Go, Bun, database, and Docker/OrbStack prerequisites used by the development loop. Common branches are: - set `--database-url` or `DATABASE_URL` when PostgreSQL or MongoDB is managed outside the project; - set `--database-path` or `RIDU_SQLITE_PATH` when a SQLite project should not use its development default; - use `--no-docker` only when you have provided that external database; - use `--no-install` only after installing the committed frontend dependencies; and - use `--no-sync` when another tool manages development schema synchronization. Ridu reloads the admin only after a replacement server is healthy. If a Go edit restarts the server but the browser keeps an old schema, confirm generation completed and no invalid config prevented the healthy replacement. See the selected adapter's [PostgreSQL](https://riducms.com/docs/postgres/) or [SQLite](https://riducms.com/docs/sqlite/) guide, or [MongoDB](https://riducms.com/docs/mongodb/) guide. ## A migration is refused {#migration-refused} Use the migration command that answers the question you have: - `ridu migrate create` resolves config and writes a reviewable artifact without connecting to a database. - `ridu migrate verify` replays history in an isolated PostgreSQL schema or temporary SQLite or MongoDB database. - `ridu migrate status` compares committed artifacts with the target database. - `ridu migrate up` applies verified pending artifacts under adapter-owned coordination: a PostgreSQL advisory lock, one atomic SQLite writer transaction, or MongoDB's fenced expiring lease and durable step ledger. If creation finds a destructive change, review the machine-readable finding and pass `--allow-destructive` only when data loss is intentional and rehearsed. PostgreSQL and MongoDB can confirm an unambiguous detected rename to preserve semantic continuity. SQLite requires a registered compiled transform; `--accept-renames` alone is intentionally rejected because it cannot rewrite canonical JSON. MongoDB can bind a named compiled transform to its immutable artifact when explicit schema-driven rewriting is required. If status reports a digest mismatch, missing history, or changed applied artifact, restore the committed artifact that was actually applied. Migration files are immutable; do not edit applied PostgreSQL SQL, SQLite steps/transforms, or MongoDB plans/transforms. Authenticated MongoDB planner-`1.0.0` history remains a supported immutable prefix to v2; do not rewrite it. PostgreSQL and MongoDB recovery uses a forward corrective migration or a coordinated restore. SQLite's reviewed `down`, `reset`, `refresh`, and `fresh` commands require explicit destructive approval: `down`, `reset`, and `refresh` execute immutable reverse steps, while `fresh` drops non-internal objects and replays committed up history. PostgreSQL and MongoDB database-backed commands need a reachable URL, verified TLS and suitable privileges, and time for their bounded lock/lease and operation timeouts. Keep MongoDB's application credential scoped to its one database and use separate short-lived credentials for verification and backups. SQLite `create` is offline and writes only its artifact, while `verify` uses a temporary database and needs no deployment path. SQLite `plan` and `status` do not apply migrations, but they open the selected path through the ordinary writable SQLite store configuration. The database and parent directory must therefore be writable, and a missing path may be created during inspection. Mutating commands additionally need an available writer transaction. See [Production](https://riducms.com/docs/production/) before applying a plan to valuable data. Do not repair a MongoDB cutover by changing the order. Drain old processes, run command-scoped `verify` with the operational URL, capture the matched database/upload snapshot, run `up` with the selected app/operator URL, require post-`up` `status`, then start with the app URL. ## Login works in one client but not the browser {#browser-auth-fails} Check the browser boundary rather than weakening authentication: - the SDK defaults to Fetch credentials mode `include`; preserve it if you provide custom Fetch options; - configure allowed origins and hosts for the actual browser URL; - configure allowed request headers if your frontend sends custom headers; - use secure cookies behind HTTPS, and configure trusted proxies only for infrastructure you control; and - verify that the auth collection named by `Admin.User` exists and that the user is active. Use the [CORS guide](https://riducms.com/docs/cors/) to distinguish an unlisted origin, custom-header preflight, cookie SameSite restriction, and untrusted TLS proxy. If the admin-user collection is empty and its Create policy is omitted, the admin opens its one-time first-user setup screen. An explicit Create policy owns registration instead and disables that default. See [Authentication](https://riducms.com/docs/authentication/) and [REST API](https://riducms.com/docs/rest-api/). ## A request is denied or a field disappears {#access-denied} Ridu applies collection access, field access, and redaction to every operation surface. A local Go call is not privileged, and a hidden admin control is not authorization. Check these cases: - a nil actor means anonymous, never superuser; - a filtered access decision must match the target row atomically; - field read access may remove a value from the response even though the row itself is readable; - an update may be allowed at collection level but reject a protected field; and - create-field access defaults and update-field access are distinct contracts. Log the authenticated actor and operation kind, then test the access callback directly with an allowed, denied, and predicate-filtered case. Do not fetch broadly and filter rows in application memory. [Access control](https://riducms.com/docs/access-control/) explains the decision model. ## A query is rejected or a populated response is too large {#query-too-large} Confirm every filter operator matches the field type, every selected path exists, and every population path is a relationship. Then reduce `depth`, `limit`, selected fields, or nested population. Ridu validates query complexity and bounds relationship expansion before materializing a response. Those limits protect the server from cycles and unbounded graph reads; splitting a large graph into several explicit requests is preferable to raising limits blindly. The generated TypeScript client helps with path and response types, but the server remains the final validator. See [TypeScript SDK](https://riducms.com/docs/typescript-sdk/) and [REST API](https://riducms.com/docs/rest-api/). ## The SDK falls back to broad types {#sdk-broad-types} Import the generated project client, not only the framework-neutral `@riducms/sdk` package. Exact document, input, select, query, and population types come from the generated manifest. The SDK can infer a default config when exactly one generated Ridu config is registered in the TypeScript program. With zero or multiple generated configs, use the generated wrapper or provide the config type explicitly. This avoids silently choosing the wrong application in monorepos. With `ridu dev` running, save the schema change and wait for regeneration. Restart the TypeScript language service if the editor has cached the previous declarations. If the development loop is not running, use `ridu generate` once before restarting the language service. ## `/healthz` passes but `/readyz` fails {#readiness-fails} Liveness says the process is running; readiness says it can safely serve traffic with required dependencies. Check the selected database path or connection, migration/manifest state, and configured storage backends. MongoDB readiness additionally requires the executable manifest to be the exact complete ledger head and every required Ridu index to match. In production, Ridu requires stores and upload backends to provide readiness checks unless the application enables unverifiable readiness. Enable that option only after moving the omitted checks to an external system. Use `ridu migrate status` to inspect the ledger, durable progress, and managed database state; a ready process does not replace that deployment check. Keep load balancers on `/readyz` and process restarts on `/healthz`. [Production](https://riducms.com/docs/production/) covers the wider deployment checks. ## Upload cleanup or storage health fails {#upload-storage-fails} For S3-compatible storage, verify endpoint, region, bucket, access key, and secret key. Non-HTTPS endpoints are rejected unless `AllowInsecureEndpoint` is explicitly enabled for a trusted local environment. Signed URL lifetimes must remain within the backend's supported bounds. For cleanup and reconciliation, storage listings must provide a non-zero modification time. Keep database and object-store backups as one recovery point: restoring only metadata or only objects can create missing files or orphans. Do not trust client-supplied storage keys or checksums; upload metadata is server-owned. Read [Uploads](https://riducms.com/docs/uploads/) and [Storage](https://riducms.com/docs/storage/) before changing cleanup windows or deleting unmatched objects. ## A hook ran twice or caused recursion {#hook-side-effects} Hooks execute inside a defined operation lifecycle, and transactional work may be retried. Make external side effects idempotent and place them in the documented after-commit phase rather than a before hook. When a hook calls the local API, pass the hook context and deliberately choose whether the nested operation should run hooks; an unguarded write back to the same collection can recurse. Not every field or global hook phase exists. Use only the phases exposed by the public contract, and fail generation rather than assuming a Payload hook name has a Ridu equivalent. See [Hooks](https://riducms.com/docs/hooks/) and [Move from Payload](https://riducms.com/guides/from-payload/). ## Still stuck? {#still-stuck} Capture the Ridu revision, Go and Bun versions, operating system, command, full structured error, and the smallest config that reproduces it. For database issues, include the selected adapter, PostgreSQL version, SQLite path shape, or MongoDB version/topology/TLS mode, and migration status without secrets. Run `ridu doctor` and the narrow failing command before the full project check; their output makes a report much easier to act on. --- # Adapters Canonical URL: https://riducms.com/docs/adapters/ Adapters connect Ridu to infrastructure that the framework already knows how to use. A database adapter stores documents; an object-storage adapter stores upload bytes. An application normally selects one implementation for each required runtime port. Plugins are different: they add CMS or admin behavior such as rich text, GraphQL, fields, hooks, or views. Multiple plugins can coexist in `Config.Plugins`; adapters do not appear there. | Need | Use | Official implementation | | ---------------------------------------------------- | ------------------------- | ------------------------------------------------------------------------------------ | | Store content and framework state | `store.Store` adapter | [PostgreSQL](https://riducms.com/docs/postgres/), [SQLite](https://riducms.com/docs/sqlite/), or [MongoDB](https://riducms.com/docs/mongodb/) | | Store upload bytes locally | `storage.Backend` adapter | [Object storage](https://riducms.com/docs/storage/#local-storage) | | Store upload bytes in S3 or an S3-compatible service | `storage.Backend` adapter | [Object storage](https://riducms.com/docs/storage/#s3-storage) | | Add rich-text fields and their editor | Plugin | [Rich text](https://riducms.com/docs/rich-text/) | | Add a GraphQL transport | Plugin | [GraphQL](https://riducms.com/docs/graphql/) | Runtime adapters are created lazily with `ridu.WithStore` and `ridu.WithUploadStorage`. This keeps database URLs, cloud credentials, open clients, and network access out of schema generation and the canonical manifest. PostgreSQL is the general networked and multi-replica store. SQLite is official for a database file on one application host and small or local workloads; shared network filesystems and multi-replica SQLite deployments are outside its support promise. MongoDB is supported only for generated starter and blank projects on the authenticated TLS three-member replica-set, Linux x86-64 profile documented in its guide. The three adapters implement the same portable Store boundary; database selection does not create a private application API. --- # Plugins Canonical URL: https://riducms.com/docs/plugins/ Ridu plugins are trusted build dependencies. Their Go code is compiled into the server, optional Svelte/TypeScript code is bundled into the admin, and a descriptor connects both halves for generation, compatibility checks, and migrations. Plugins add behavior such as fields, hooks, transports, endpoints, or admin views. Database and object-storage packages are [adapters](https://riducms.com/docs/adapters/) instead: they supply one runtime service and do not belong in `Config.Plugins`. > [!WARNING] > Ridu never downloads plugin code at runtime and does not sandbox compiled dependencies. A plugin > and its SQL have every capability granted to the application process and database role. Review, > pin, test, and update them like any other server dependency. ## Install a plugin {#install} Install both halves together when a package provides an admin integration: ```sh title="terminal" npm run ridu -- plugin add color \ --go-package example.com/acme/ridu-color \ --go-version v1.2.0 \ --admin-package @acme/ridu-color-admin \ --admin-version '^1.2.0' ``` `ridu add` is the shorter alias. The command installs dependencies, updates `ridu.plugins.json`, registers the Go and admin packages, and regenerates application types. If field types come from a different npm package, install that package at the project root too. Failed setup or generation restores the changed files. Removal cleans up the paired admin package only when no remaining plugin uses it. Remove a separately installed field-type package yourself after confirming nothing else imports it. Use `--constructor` when the Go package exports a zero-argument constructor other than `New`. `--no-install` is for an already-resolved package; it does not weaken compatibility checks. Generated registration keeps application config small: ```go title="content/config.go" add={4} func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Plugins: installedPlugins(), Collections: []ridu.Collection{Users, Posts}, } } ``` Production never installs or discovers new code dynamically. A dependency change requires a new build of the Go binary and admin assets. ## What a plugin can contribute {#capabilities} The base `ridu.Plugin` interface contains only `Key() string`. Add the interfaces needed for each capability: | Capability | Public interface | Purpose | | ------------------------ | --------------------------- | --------------------------------------------------------------------------------------------------------------------- | | Deterministic metadata | `DescriptorProvider` | Versions, compatibility, generated field types, admin pairing, and exceptional adapter-scoped database contributions. | | Config transformation | `ConfigTransformer` | Add or transform authoring config before final validation. Plugins run in `Config.Plugins` order on defensive copies. | | Lifecycle hooks | `HookProvider` | Append collection or field hooks after application-authored hooks, preserving plugin order. | | Stored field validation | `FieldValidatorProvider` | Validate plugin field values with the resolved field, concrete runtime path, and candidate value. | | Namespaced HTTP endpoint | `EndpointProvider` | Add exact method/path handlers below `/api/plugins//`. | | Protocol transport | `TransportProvider` | Bind an established absolute transport such as `/api/graphql` once the manifest and application are ready. | | Admin extensions | descriptor `Admin` metadata | Statically register fields, routes, views, panels, navigation, document actions, shell components, and providers. | Executable functions, handlers, hooks, validators, credentials, and secrets never enter the public manifest. Only deterministic metadata needed by generation and tooling belongs in the descriptor. ## Describe compatibility and generated types {#descriptor} An advanced plugin returns a `ridu.PluginDescriptor`: ```go title="plugin.go" func (plugin) Descriptor() ridu.PluginDescriptor { return ridu.PluginDescriptor{ Version: "1.2.0", GoPackage: "example.com/acme/ridu-color", APIVersion: ridu.PluginAPIVersion, Ridu: ridu.RiduCompatibility{ Minimum: ridu.FrameworkVersion, }, FieldTypes: []ridu.PluginFieldType{{ Key: "color", TypeScriptPackage: "@acme/ridu-color-admin", TypeScriptOutput: "ColorValue", TypeScriptInput: "ColorInput", TypeScriptWhere: "ColorWhere", GoPackage: "example.com/acme/ridu-color", GoType: "Value", JSONSchema: colorJSONSchema, }}, } } ``` The descriptor's TypeScript exports and optional Go type keep generated models, create/update input, and query operands aligned. A JSON Schema adds the OpenAPI value schema. Omitting both Go type fields uses `encoding/json.RawMessage`; a TypeScript value mapping is still required. Schema resolution validates semantic versions, unique keys, capability/descriptor requirements, field mappings, route conflicts, migration continuity, and table prefixes before the application starts. ## Add endpoints {#endpoints} Plugin endpoints declare an exact HTTP method and a relative path. Ridu mounts them below `/api/plugins//`; a known path with the wrong method returns `405`. The handler receives the request and writer, client IP, authenticated actor and auth collection, local API, auth-attempt admission, and diagnostic reporting. Use `PluginEndpointContext.Local` for content operations so access, validation, hooks, transactions, and redaction still apply. Each endpoint may set `MaxBodyBytes`. Zero inherits the application handler bound; a negative value opts trusted streaming code out, so the endpoint must supply its own explicit work and byte limits. Authentication transports must call the provided admission function before amplifiable work. Use `TransportProvider` only for an established absolute protocol location. It binds once from the immutable manifest and application runtime; it should not rebuild schema state per request. The [GraphQL plugin](https://riducms.com/docs/graphql/) is the reference example. ## Pair the admin half {#admin-pairing} `AdminPluginMetadata` names the installed npm package and named export, declares `AdminPluginAPIVersion`, and carries a `PairingVersion`. It also lists authenticated admin routes and package-relative assets in deterministic order. Generation writes static imports. Before the admin is used, pairing resolution verifies the backend/admin key, API versions, pairing version, field declarations, route and asset lists, and route collisions. An admin route is mounted inside the authenticated shell, but route visibility is presentation—not authorization. Its API calls still need server access rules. Increment `PairingVersion` whenever separately published backend and admin versions cease to be interchangeable. Publish both packages together for such a change. ## Plugin data and database escape hatches {#migrations} Plugins should normally add stored records as ordinary collections and fields through `ConfigTransformer`. The selected adapter then plans their storage while Ridu keeps access, validation, hooks, transactions, REST, generated contracts, and admin behavior on the normal path. Only a feature that genuinely needs private dialect-specific schema should use `DatabaseContributions`. Each bundle names `PluginDatabaseAdapterPostgres` or `PluginDatabaseAdapterSQLite`; Ridu executes only the matching bundle and fails clearly when the active adapter is unsupported. SQL is never translated between adapters. Each adapter's migration history starts at version 1. Every entry has a stable lowercase kebab-case name and non-empty `UpSQL` and `DownSQL` arrays. Ridu copies the chosen direction into the application's immutable migration artifact with a checksum and validates it again before execution. Each SQL entry is one statement and cannot take control of the migration transaction or connection. SQLite rejects `ATTACH`, `DETACH`, and `PRAGMA` entries. Plugin tables must use `ridu_plugin__...`. This lets schema verification distinguish plugin objects from Ridu tables. The prefix does not sandbox SQL. Migration entries are immutable, including after removal and later reinstallation. Changing a version, name, or SQL direction is rejected. Declared private tables must exist after replay; SQLite also rejects changes to Ridu-managed schema and objects outside the plugin prefix. Plugin downgrade steps run newest-first and require destructive approval when an application artifact removes the plugin version. This reversible plugin history does not add automatic down migrations for application schema; follow [Migrations](https://riducms.com/docs/migrations/) for recovery and forward corrections. ## Remove a plugin {#remove} ```sh title="terminal" npm run ridu -- plugin remove color npm run ridu -- migrate create --name remove-color ``` Removal unregisters generated code, removes Go and configured frontend dependencies, and regenerates contracts. The CLI rolls those file changes back if the workflow fails. It never silently changes the database. Review the resulting plugin down steps, data loss, and table removal in the application migration. Back up and rehearse the removal before accepting a destructive artifact. If data must survive, export or migrate it while the plugin and its handlers are still installed. ## Scaffold and test your own plugin {#create-and-test} ```sh title="terminal" npm run ridu -- plugin new ./ridu-color \ --key color \ --module example.com/acme/ridu-color \ --admin-package @acme/ridu-color-admin ``` The scaffold includes a Go module, field helper, descriptor, validator, Svelte field, exported value type, and tests. Call `plugintest.Run` from an external-package Go test: ```go title="plugin_test.go" func TestPluginConformance(t *testing.T) { plugintest.Run(t, plugintest.Fixture{ Plugin: color.New(), Fields: []field.Definition{color.Field("accent")}, ValidData: store.Values{"accent": "#663399"}, InvalidData: store.Values{"accent": "not-a-color"}, Compatibility: []plugintest.CompatibilityCase{ {RiduVersion: ridu.FrameworkVersion, Compatible: true}, }, }) } ``` The suite checks deterministic resolution, manifest round-trip, exact field mappings, capability versioning, compatibility rows, in-memory storage, local API, REST, and validation. Also compile the generated Go/TypeScript/OpenAPI contracts, run admin checks and tests, and exercise both migration directions plus full replay against every adapter the plugin declares. ## Version compatibility {#versioning} | Version | Changes when | | ------------------------- | --------------------------------------------------------------------------- | | Plugin semantic `Version` | Every plugin publication. | | `PluginAPIVersion` | Ridu makes a breaking change to compiled Go capability interfaces. | | `AdminPluginAPIVersion` | Ridu makes a breaking change to TypeScript/admin extension contracts. | | Plugin `PairingVersion` | This plugin's backend and admin packages are no longer mutually compatible. | Keep compatibility test rows for every Ridu version you support, including rejected lower and upper boundaries. Silent behaviour changes under an existing API or pairing version are defects. Official examples include [PostgreSQL](https://riducms.com/docs/postgres/), [SQLite](https://riducms.com/docs/sqlite/), [Rich text](https://riducms.com/docs/rich-text/), [SEO](https://riducms.com/docs/seo/), [Form Builder](https://riducms.com/docs/form-builder/), [GraphQL](https://riducms.com/docs/graphql/), and [local/S3 object storage](https://riducms.com/docs/storage/). For a paired stored field, follow [Build a custom field](https://riducms.com/guides/custom-fields/). --- # MongoDB Canonical URL: https://riducms.com/docs/mongodb/ Choose MongoDB when you can run the supported replica-set topology below. Collections, access rules, REST, the generated SDK, and the admin work the same way as they do with Ridu's other database adapters; application code does not use MongoDB filters or driver types. Production support is limited to: - an ordinary Ridu-generated `starter` or `blank` project; - Linux x86-64; - MongoDB Community 8.2.9, with release evidence built from digest-pinned images; - SCRAM-SHA-256 authentication and TLS with CA and hostname verification; and - a writable three-member replica set. This does not include Atlas, Amazon DocumentDB, Azure Cosmos DB, a standalone `mongod`, another MongoDB version or topology, another operating system or architecture, arbitrary scale, network-partition/failover matrices, or point-in-time recovery. See [Releases and compatibility](https://riducms.com/docs/releases/#supported-matrix) before choosing this profile. ## Create a project {#new-project} ```bash title="terminal" package-manager="npm" npm create ridu@latest my-app ``` ```bash title="terminal" package-manager="bun" bun create ridu@latest my-app ``` ```bash title="terminal" package-manager="pnpm" pnpm create ridu@latest my-app ``` ```bash title="terminal" package-manager="yarn" yarn create ridu my-app ``` Choose **Starter** and **MongoDB** in the wizard, then run the exact install and `dev` commands it prints. Review the summary carefully: MongoDB is not the default database choice.
Preselect every scaffold choice
For a non-interactive npm setup, pass every choice as an argument: ```bash title="terminal" npm create ridu@latest -- \ --template starter \ --database mongodb \ --module github.com/acme/content \ --scope @acme \ --package-manager npm \ --agent codex \ content ```
Both generated templates include the same adapter wiring. The `dev` script starts the pinned local single-node replica set from `compose.yaml` and uses: ```text mongodb://127.0.0.1:27029/ridu?directConnection=true&replicaSet=ridu-rs0 ``` This convenient plaintext, unauthenticated service is for local development only. It is still a replica set because Ridu operations require MongoDB transactions; a standalone `mongod` is rejected. To use another development replica set without putting its URL in process arguments, supply a command-scoped environment value from your shell's secret binding: ```bash title="terminal" package-manager="npm" DATABASE_URL="$MONGODB_DEVELOPMENT_URL" npm run dev -- --no-docker ``` ```bash title="terminal" package-manager="bun" DATABASE_URL="$MONGODB_DEVELOPMENT_URL" bun run dev -- --no-docker ``` ```bash title="terminal" package-manager="pnpm" DATABASE_URL="$MONGODB_DEVELOPMENT_URL" pnpm run dev --no-docker ``` ```bash title="terminal" package-manager="yarn" DATABASE_URL="$MONGODB_DEVELOPMENT_URL" yarn run dev --no-docker ``` Configuration discovery, `generate`, `generate --check`, and `migrate create` through the project-local CLI remain offline. They do not open MongoDB or serialize its URL into config, generated contracts, or migration artifacts. ## Add MongoDB to an existing project {#existing-project} Use this path for a clean generated Ridu project before it has committed migration history or live data. Ridu has no generic PostgreSQL/SQLite-to-MongoDB data migration facility. Moving a live dataset is application-owned: export and transform every current document, localized value, version, auth/session record, relationship, task, preference, lock, and upload reference; preserve stable IDs; validate the destination; and rehearse backup, cutover, and rollback. ### 1. Select MongoDB in project metadata {#existing-project-config} Replace the existing adapter value. This example starts from PostgreSQL: ```toml title="ridu.toml" remove={2} add={3} version = 1 database = "postgres" database = "mongodb" entry = "./cmd/server" admin = "./admin" ``` The value must match the CLI's public adapter name. It controls development orchestration and migration routing; it does not contain a connection URL. ### 2. Use the generated adapter handshake {#existing-project-server} MongoDB development needs more than replacing one `Open` call. The internal candidate started by `ridu dev` must verify the resolved manifest's exact indexes before the stable proxy promotes it. Copy the following generated pattern into `cmd/server/main.go` (retaining the project's admin asset and handler options): ```go title="cmd/server/main.go" remove={10,26,34,38-42,77-78} add={3,11,15,19-22,27,35,43-62,79-80} import ( "context" "fmt" "log" "os" "github.com/acme/content/content" "github.com/acme/content/internal/adminassets" "github.com/riducms/ridu" "github.com/riducms/ridu/adapters/postgres" "github.com/riducms/ridu/adapters/mongodb" "github.com/riducms/ridu/store" ) const internalDevelopmentServerArgument = "--ridu-internal-development-server" func main() { applicationConfig := content.Config() internalDevelopmentServer := len(os.Args) == 2 && os.Args[1] == internalDevelopmentServerArgument if internalDevelopmentServer { os.Args = os.Args[:1] } var options []ridu.ExecuteOption if len(os.Args) == 1 { options = runtimeOptions(applicationConfig) options = runtimeOptions(applicationConfig, internalDevelopmentServer) } if err := ridu.Execute(applicationConfig, options...); err != nil { log.Fatal(err) } } func runtimeOptions(applicationConfig ridu.Config) []ridu.ExecuteOption { func runtimeOptions(applicationConfig ridu.Config, internalDevelopmentServer bool) []ridu.ExecuteOption { return []ridu.ExecuteOption{ ridu.WithStore(func(ctx context.Context) (store.Store, error) { return postgres.OpenWithConfig(ctx, postgres.PoolConfig{ DatabaseURL: os.Getenv("DATABASE_URL"), AllowInsecureTransport: envBool("RIDU_ALLOW_INSECURE_DATABASE"), MaxUploadLockConnections: envInt32("RIDU_POSTGRES_UPLOAD_LOCK_CONNECTIONS"), }) backend, err := mongodb.OpenWithConfig(ctx, mongodb.Config{ DatabaseURL: os.Getenv("DATABASE_URL"), AllowInsecureTransport: envBool("RIDU_ALLOW_INSECURE_DATABASE"), ApplicationName: "ridu-server", }) if err != nil { return nil, err } if internalDevelopmentServer { manifest, err := ridu.Resolve(applicationConfig) if err != nil { _ = backend.Close() return nil, fmt.Errorf("resolve MongoDB development manifest: %w", err) } if err := backend.VerifyIndexes(ctx, manifest); err != nil { _ = backend.Close() return nil, fmt.Errorf("verify MongoDB development indexes: %w", err) } } return backend, nil }), ridu.WithAddress(env("RIDU_ADDRESS", ":8080")), ridu.WithHandlerOptions(ridu.HandlerOptions{ AdminAssets: adminassets.FS(), AllowedOrigins: envList("RIDU_ALLOWED_ORIGINS"), AllowedHosts: envList("RIDU_ALLOWED_HOSTS"), TrustedProxyCIDRs: envList("RIDU_TRUSTED_PROXY_CIDRS"), ReadinessTimeout: envDuration("RIDU_READINESS_TIMEOUT"), StrictTransportSecurity: os.Getenv("RIDU_STRICT_TRANSPORT_SECURITY"), }), ridu.WithServerOptions(ridu.ServerOptions{ ShutdownTimeout: envDuration("RIDU_SHUTDOWN_TIMEOUT"), WorkerDrainTimeout: envDuration("RIDU_WORKER_DRAIN_TIMEOUT"), ReadinessDrainDelay: envDuration("RIDU_READINESS_DRAIN_DELAY"), AllowUnverifiableReadiness: envBool("RIDU_ALLOW_UNVERIFIABLE_READINESS"), SkipReadinessPreflight: envBool("RIDU_SKIP_READINESS_PREFLIGHT"), AllowUnverifiableReadiness: internalDevelopmentServer, SkipReadinessPreflight: internalDevelopmentServer, }), } } ``` The red PostgreSQL lines are context from the existing generated server. Remove them after adding the MongoDB lines; the finished file has one adapter import, one `runtimeOptions` call and declaration, one store factory, and one value for each readiness option. The readiness exceptions are **only** for the CLI's internal development candidate, after the explicit index check. Do not expose them as production environment fallbacks. Keep the template's `envBool` helper so invalid environment values fail clearly, and close the backend on every resolution/verification error as shown. ### 3. Add the local replica-set service {#existing-project-compose} Copy this service into `compose.yaml`: ```yaml title="compose.yaml" services: mongodb: image: mongo:8.2.9-noble@sha256:007773db61cb1aa44e526fb7175fc582902e67d4e6cc5f13106445767d46c818 command: ['mongod', '--replSet', 'ridu-rs0', '--bind_ip_all'] ports: - '127.0.0.1:27029:27017' healthcheck: test: - CMD-SHELL - >- mongosh --quiet --eval 'try { const h=db.hello(); if (h.setName === "ridu-rs0" && h.isWritablePrimary) { quit(0) }; if (!h.setName) { try { rs.initiate({_id:"ridu-rs0",members:[{_id:0,host:"mongodb:27017"}]}) } catch (_) {} } } catch (_) {}; quit(1)' interval: 2s timeout: 5s retries: 30 start_period: 5s ``` The health check initializes `ridu-rs0` and succeeds only when the node is its writable primary. Ridu requires sessions and transactions, so a standalone MongoDB server is not sufficient. The local URL is: ```text mongodb://127.0.0.1:27029/ridu?directConnection=true&replicaSet=ridu-rs0 ``` This single-node, unauthenticated, plaintext service is development-only and is not the three-member authenticated TLS production profile. ### 4. Start and verify development {#existing-project-verify} ```bash title="terminal" package-manager="npm" go mod tidy npm run dev ``` ```bash title="terminal" package-manager="bun" go mod tidy bun run dev ``` ```bash title="terminal" package-manager="pnpm" go mod tidy pnpm run dev ``` ```bash title="terminal" package-manager="yarn" go mod tidy yarn run dev ``` `ridu dev` starts the generated replica-set service, regenerates contracts, synchronizes safe additive changes, and starts the API and admin. Before deployment, create and verify the immutable migration history: ```bash title="terminal" package-manager="npm" export DATABASE_URL='mongodb://127.0.0.1:27029/ridu?directConnection=true&replicaSet=ridu-rs0' export RIDU_ALLOW_INSECURE_DATABASE=true npm run ridu -- migrate create --name initial npm run ridu -- migrate plan npm run ridu -- migrate verify npm run ridu -- migrate up npm run ridu -- migrate status ``` ```bash title="terminal" package-manager="bun" export DATABASE_URL='mongodb://127.0.0.1:27029/ridu?directConnection=true&replicaSet=ridu-rs0' export RIDU_ALLOW_INSECURE_DATABASE=true bun run ridu -- migrate create --name initial bun run ridu -- migrate plan bun run ridu -- migrate verify bun run ridu -- migrate up bun run ridu -- migrate status ``` ```bash title="terminal" package-manager="pnpm" export DATABASE_URL='mongodb://127.0.0.1:27029/ridu?directConnection=true&replicaSet=ridu-rs0' export RIDU_ALLOW_INSECURE_DATABASE=true pnpm run ridu migrate create --name initial pnpm run ridu migrate plan pnpm run ridu migrate verify pnpm run ridu migrate up pnpm run ridu migrate status ``` ```bash title="terminal" package-manager="yarn" export DATABASE_URL='mongodb://127.0.0.1:27029/ridu?directConnection=true&replicaSet=ridu-rs0' export RIDU_ALLOW_INSECURE_DATABASE=true yarn run ridu migrate create --name initial yarn run ridu migrate plan yarn run ridu migrate verify yarn run ridu migrate up yarn run ridu migrate status ``` For a separately managed development replica set, omit the Compose service and rerun the selected tab's `dev --no-docker` command with `DATABASE_URL="$MONGODB_DEVELOPMENT_URL"`. Keep TLS and authentication enabled unless the target is a disposable local development database. Before production, replace the local URL and insecure admission with the authenticated, CA- and hostname-verified three-member profile below and follow the full release cutover. ## Development schema changes {#development} During `ridu dev`, an additive manifest change creates only missing collections and indexes. A separate serving Store then non-mutatingly verifies the exact physical index plan and passes development readiness before the stable proxy promotes the candidate. A failed build, incompatible index, unhealthy candidate, or rejected rename leaves the last working process in place. Development synchronization never drops state or guesses how stored content should move. For a rename, compiled transform, index replacement, or reviewed retirement, create and apply an immutable production migration instead of repairing MongoDB by hand. `--no-sync` skips additive mutation, but it does not weaken verification: the candidate starts only when another owner has already prepared the selected database. ## Production connection and credentials {#production-connection} The production `DATABASE_URL` must select the application database, authenticate with SCRAM-SHA-256, name the replica set, and enable certificate and hostname verification. For example: ```text mongodb://ridu-app:@mongo-1.example.internal,mongo-2.example.internal,mongo-3.example.internal/content?authSource=content&authMechanism=SCRAM-SHA-256&replicaSet=ridu-rs0&tls=true&tlsCAFile=/run/secrets/mongodb-ca.pem ``` Keep the running application credential scoped to its database. Use separate, short-lived credentials for verification and backups: | Credential | Scope | | ------------ | ------------------------------------------------------------------------------------------------------------------------- | | Application | Database-scoped access to the Ridu database. Use it for the running app and, when sufficient, `plan`, `up`, and `status`. | | Verification | Permission to create and drop the temporary database used by `migrate verify`. | | Backup | The database-scoped permissions required by `mongodump` and `mongorestore`. | Supply each credential only to its command. Ridu redacts credentials and topology details from normal connection failures, but operators must still keep URLs out of shell history, process arguments, logs, generated files, and image layers. A mode-`0600` Database Tools configuration file is one way to keep backup credentials out of process arguments. `RIDU_ALLOW_INSECURE_DATABASE` and `--allow-insecure-database` are for local development only. They do not expand the production support profile. ## Immutable migration lifecycle {#migrations} Artifacts created by `ridu migrate create` use MongoDB planner contract `2.0.0` inside shared artifact-envelope format `1`. Authenticated planner-`1.0.0` artifacts remain a supported immutable prefix: the runner validates and replays that committed history before applying v2 artifacts rather than rewriting or rejecting it. Create and inspect the plan before the cutover: ```bash title="terminal" package-manager="npm" npm run ridu -- migrate create --name add-post-summary npm run ridu -- migrate plan --json ``` ```bash title="terminal" package-manager="bun" bun run ridu -- migrate create --name add-post-summary bun run ridu -- migrate plan --json ``` ```bash title="terminal" package-manager="pnpm" pnpm run ridu migrate create --name add-post-summary pnpm run ridu migrate plan --json ``` ```bash title="terminal" package-manager="yarn" yarn run ridu migrate create --name add-post-summary yarn run ridu migrate plan --json ``` Ridu binds each artifact to its manifest history and rejects altered or reordered migration files. `up` takes a fenced lease with a bounded wait, records durable step progress, and resumes the same immutable history after an interruption. It requires explicit maintenance admission only when the pending or incomplete history suffix contains a rename, transform, reference-index rebuild, or resource retirement. Run that work only after every old application process and worker is drained. `verify` creates a random isolated database, replays the complete history with the adapter's migration runner, checks the final ledger and index state, and drops that database. Because the temporary database starts empty, `verify` requires `--allow-maintenance` whenever any artifact in the complete history contains semantic work, including work already applied to the live database. `status` is non-mutating. `ridu build` embeds a fingerprint of the exact ordered migration filenames and artifact digests. Application readiness requires the live ledger to match that fingerprint, its head to match the executable manifest, and every required Ridu index to pass non-mutating verification. `ridu check` and `ridu build` remain offline and fail when committed history does not end at executable config. A direct `go build` has no fingerprint and fails closed in ordinary production startup. Deployment cutover additionally fails when the applied ledger or physical indexes do not exactly match the release history. MongoDB does not expose `down`, `reset`, `refresh`, or `fresh`. Correct forward with another reviewed artifact, or restore the complete matched recovery point. ## Deploy and recover {#production} For a code-only replacement with the same manifest digest and migration-history fingerprint, start the candidate, require `/readyz`, then drain the old process. For any new migration artifact—even an additive or same-manifest data-only one—use the coordinated sequence: 1. Rehearse the exact binary and history against a restored recovery point. 2. Drain every old application process and worker. 3. Run `migrate verify` through the project-local CLI with `DATABASE_URL="$MONGODB_OPERATIONAL_URL"` so the shadow-database authority exists only for that command. Append `--allow-maintenance` whenever the complete committed history contains semantic work. 4. After verification succeeds, capture one recovery point containing a database-scoped `mongodump` and the upload store. Use a separately scoped `$MONGODB_BACKUP_URL`. 5. Run `migrate up` through the project-local CLI with `DATABASE_URL="$MONGODB_MIGRATION_URL"`, using the selected database-scoped application or controlled operator identity. Append `--allow-maintenance` only when the pending or incomplete history suffix contains semantic work. 6. Run `migrate status` with the same migration identity and require exact complete history and Ridu-managed index state. 7. Start only the target release binary carrying the expected manifest and migration-history fingerprints with `$MONGODB_APP_URL`, then wait for `/readyz` before admitting traffic. Take the cutover recovery point only after draining writers and successfully completing the command-scoped verification, but before `up`. The recovery drill uses database-scoped `mongodump --archive --gzip --dumpDbUsersAndRoles`, restores that archive into an empty target with `mongorestore --archive --gzip --drop --restoreDbUsersAndRoles`, and restores upload storage from the same named point. The dump/restore must remain scoped to the selected application database; never restore over unrelated databases. Confirm the ledger and `status`, the restored scoped user, auth and sessions, content and versions, relationships, SDK/admin workflows, rich text, upload objects, tasks, and representative data before directing traffic. This is a logical dump/restore path, not point-in-time recovery. Define and rehearse your retention, encryption, off-site storage, recovery-point objective, and recovery-time objective. ## Test the deployment {#testing} Before production, rehearse migrations, startup, readiness, a primary election, graceful shutdown, and database/upload restoration on the topology you will deploy. Exercise authentication, content, versions, relationships, uploads, tasks, the SDK, and the admin after restoration. Use disposable databases for these tests; never point them at production. --- # PostgreSQL Canonical URL: https://riducms.com/docs/postgres/ PostgreSQL 17 is Ridu's official networked and multi-replica store. The adapter implements documents, globals, relationships, localization, auth, versions, tasks, locks, preferences, reference indexes, migrations, and readiness behind Ridu's public store contracts. ## Start a new PostgreSQL project {#new-project} PostgreSQL is the scaffold default: ```bash title="terminal" package-manager="npm" npm create ridu@latest my-app ``` ```bash title="terminal" package-manager="bun" bun create ridu@latest my-app ``` ```bash title="terminal" package-manager="pnpm" pnpm create ridu@latest my-app ``` ```bash title="terminal" package-manager="yarn" yarn create ridu my-app ``` Choose **Starter** and **PostgreSQL** in the wizard, then run the exact install and `dev` commands it prints. PostgreSQL is preselected, but the summary still makes the choice explicit before any files are written.
Preselect every scaffold choice
For a non-interactive npm setup, pass every choice as an argument: ```bash title="terminal" npm create ridu@latest -- \ --template starter \ --database postgres \ --module github.com/acme/content \ --scope @acme \ --package-manager npm \ --agent codex \ content ```
The generated `compose.yaml` exposes PostgreSQL 17 on `127.0.0.1:54329`, and the `dev` script starts it, waits for `pg_isready`, performs safe additive development synchronization, and runs the API/admin. To use a service you already operate, supply its secret only to the command and skip Compose: ```bash title="terminal" package-manager="npm" DATABASE_URL="$DEVELOPMENT_DATABASE_URL" npm run dev -- --no-docker ``` ```bash title="terminal" package-manager="bun" DATABASE_URL="$DEVELOPMENT_DATABASE_URL" bun run dev -- --no-docker ``` ```bash title="terminal" package-manager="pnpm" DATABASE_URL="$DEVELOPMENT_DATABASE_URL" pnpm run dev --no-docker ``` ```bash title="terminal" package-manager="yarn" DATABASE_URL="$DEVELOPMENT_DATABASE_URL" yarn run dev --no-docker ``` ## Add PostgreSQL to an existing project {#existing-project} Use this path for a clean Ridu project that does not yet have committed migrations or data. Ridu does not provide a generic live SQLite/MongoDB-to-PostgreSQL migration facility; moving an existing dataset between adapters is an application-owned export, transform, validation, and cutover. 1. Replace the current adapter in `ridu.toml`. This example starts from SQLite; if the project currently names MongoDB, replace that line instead: ```toml title="ridu.toml" remove={2} add={3} version = 1 database = "sqlite" database = "postgres" entry = "./cmd/server" admin = "./admin" ``` 2. Replace the old adapter import and store factory inside the existing `runtimeOptions` function. Keep the generated address, admin assets, handler options, and server options around it. Lazy opening keeps config resolution and generation offline: ```go title="cmd/server/main.go" remove={7,15} add={8,16-20} import ( "context" "os" "github.com/acme/content/internal/adminassets" "github.com/riducms/ridu" "github.com/riducms/ridu/adapters/sqlite" "github.com/riducms/ridu/adapters/postgres" "github.com/riducms/ridu/store" ) func runtimeOptions(applicationConfig ridu.Config) []ridu.ExecuteOption { return []ridu.ExecuteOption{ ridu.WithStore(func(ctx context.Context) (store.Store, error) { return sqlite.Open(ctx, sqliteDatabasePath()) return postgres.OpenWithConfig(ctx, postgres.PoolConfig{ DatabaseURL: os.Getenv("DATABASE_URL"), AllowInsecureTransport: envBool("RIDU_ALLOW_INSECURE_DATABASE"), MaxUploadLockConnections: envInt32("RIDU_POSTGRES_UPLOAD_LOCK_CONNECTIONS"), }) }), ridu.WithAddress(env("RIDU_ADDRESS", ":8080")), ridu.WithHandlerOptions(ridu.HandlerOptions{ AdminAssets: adminassets.FS(), AllowedOrigins: envList("RIDU_ALLOWED_ORIGINS"), }), } } ``` The duplicate return statements and adapter imports represent the before/after diff—the finished file contains only the PostgreSQL lines. The generated server template also supplies the `envBool` and `envInt32` parsers; copy them from a fresh `--database postgres` scaffold if the current entry does not already have them. 3. Either copy the generated PostgreSQL service from a disposable scaffold into `compose.yaml`, or point at an existing PostgreSQL 17 service. The generated local service uses database/user/password `ridu`, host port `54329`, and `sslmode=disable`; never carry that plaintext credential into production. 4. Start the development loop against the selected service: ```bash title="terminal" package-manager="npm" go mod tidy DATABASE_URL="$POSTGRES_URL" npm run dev -- --no-docker ``` ```bash title="terminal" package-manager="bun" go mod tidy DATABASE_URL="$POSTGRES_URL" bun run dev -- --no-docker ``` ```bash title="terminal" package-manager="pnpm" go mod tidy DATABASE_URL="$POSTGRES_URL" pnpm run dev --no-docker ``` ```bash title="terminal" package-manager="yarn" go mod tidy DATABASE_URL="$POSTGRES_URL" yarn run dev --no-docker ``` Use the generated Compose URL for `$POSTGRES_URL`, or an already managed development URL. Remove insecure admission when the service uses verified TLS. `ridu dev` resolves the Go config, regenerates contracts, synchronizes safe additive changes, and starts the API and admin. Before deploying, create and verify immutable migration artifacts using the [migration workflow](#migrations) below. ## Connect the generated server {#connect} Generated applications open the store lazily so schema generation never needs database access. The factory belongs inside `runtimeOptions`, between the surrounding address and handler settings, as shown in the [existing-project diff](#existing-project) above. Do not open a database from a package initializer or from `content.Config()`. Use encrypted transport outside an explicitly local environment: ```sh title="terminal" export DATABASE_URL='postgres://ridu:secret@db.example.com:5432/content?sslmode=verify-full' export RIDU_ADDRESS=':8080' ``` `postgres.Open` uses bounded defaults. Use `OpenWithConfig` when the application needs deliberate pool or session tuning: ```go title="cmd/server/main.go" return postgres.OpenWithConfig(ctx, postgres.PoolConfig{ DatabaseURL: os.Getenv("DATABASE_URL"), ApplicationName: "acme-content", MaxConnections: 30, MinConnections: 2, MaxUploadLockConnections: 4, ConnectTimeout: 10 * time.Second, StatementTimeout: 45 * time.Second, LockTimeout: 5 * time.Second, IdleInTransactionSessionTimeout: 30 * time.Second, }) ``` Size connections against the database service and the total replica count, not one process in isolation. ## Pool defaults and limits {#pool} Zero values select the following defaults: | Setting | Default | Purpose | | ------------------------ | ------------------------------: | --------------------------------------------------------------------------------------------------------------- | | Document connections | 20 maximum, 0 minimum | Bounds ordinary content and framework-state work per process. | | Upload-lock connections | 4 maximum | Separate advisory-lock pool so staged uploads cannot consume the document connection needed to commit metadata. | | Connection lifetime | 1 hour ± up to 5 minutes jitter | Rotates connections without synchronizing every replica. | | Idle connection lifetime | 30 minutes | Releases unused capacity. | | Pool health check | 1 minute | Checks idle connections. | | Connect timeout | 10 seconds | Bounds startup and new connections. | | Statement timeout | 60 seconds | Bounds server-side statements. | | Lock timeout | 10 seconds | Bounds PostgreSQL lock waits and upload-lock admission. | | Idle transaction timeout | 60 seconds | Prevents abandoned sessions from holding transaction state indefinitely. | A negative duration explicitly disables that individual timeout; connection counts cannot be negative, minimum cannot exceed maximum, and server timeout values must use whole milliseconds. An unbounded setting should be a measured exception, not a routine fix for blocked work. The upload-lock pool is additional to `MaxConnections`. Startup and readiness ping both pools. Loss or exhaustion of either makes the instance unready before the next upload discovers it. ## TLS is required by default {#tls} `OpenWithConfig` rejects plaintext and TLS-fallback URLs unless `AllowInsecureTransport` is true. Use `sslmode=require`, `verify-ca`, or preferably `verify-full` in production. Modes such as `prefer`, `allow`, and `disable` permit fallback and are rejected. `AllowInsecureTransport` exists for local Unix sockets and development databases protected outside PostgreSQL. Do not expose it as a silent production fallback. Protect credentials independently and use a least-privilege application role. ## Readiness checks {#readiness} The store exposes connectivity, manifest, and exact-history checks: | Check | Required state | | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Ping(ctx)` | Both document and upload-lock pools can reach PostgreSQL. | | `Ready(ctx, manifest)` | Ping succeeds, the immutable migration ledger exists, its latest complete digest exactly matches the executable manifest, and no phased migration work is incomplete. | | `ReadyWithMigrationHistory(ctx, manifest, hash)` | Ordinary readiness passes and the complete ordered ledger matches the filename/digest fingerprint embedded by `ridu build`. | `ridu.Execute` runs aggregate readiness before binding its listener and includes the same store check in `/readyz`. Production uses the exact-history form, so it also rejects a missing, altered, renamed, reordered, or additional artifact even when the final manifest happens to be unchanged. An older binary becomes unready after a migration, and a new binary is unready before it. Readiness does not inspect every physical table and index. Run `ridu migrate status` for complete ledger, phase/step, and physical-schema drift inspection. See [Production](https://riducms.com/docs/production/) for probe and drain behaviour. ## Transactions and access remain atomic {#transactions} Ridu's operation engine owns the lifecycle; PostgreSQL supplies its transactional implementation. Caller filters and filtered access predicates are compiled into the same SQL query for reads, updates, and deletes. A local Go call, REST request, task, admin action, or plugin transport cannot bypass that predicate by choosing another adapter entry point. Ordinary writes use a transaction. Read snapshots use repeatable-read, read-only transactions. Relationship admission and deletion coordinate row locks so a dangling target cannot commit; expected revisions produce stable conflicts without revealing access-filtered documents; hook or validation failure rolls persistence back; and joined mutations retain the outer transaction boundary. Retryable PostgreSQL serialization and deadlock outcomes become stable operation conflicts rather than raw driver errors. Application callers should re-read and deliberately retry the operation instead of replaying a stale mutation blindly. ## Schema ownership {#schema-ownership} Ridu owns the configured PostgreSQL schema, including its content tables, framework state, migration ledgers, indexes, and declared `ridu_plugin__...` tables. Unrelated tables in that schema are reported as drift. When another system shares the database, give Ridu a dedicated schema through the connection `search_path`: ```text postgres://ridu:secret@db.example.com/content?sslmode=verify-full&search_path=ridu_content ``` Do not grant a plugin ownership of a core or unrelated table merely to hide drift. Plugin table prefixes are validated as part of descriptor resolution. ## Development and production migrations {#migrations} `ridu dev` can apply additive, non-destructive development synchronization. It pauses when a possible rename needs explicit intent. Production uses committed immutable artifacts: ```sh title="terminal" package-manager="npm" npm run ridu -- migrate create --name rename-post-title npm run ridu -- migrate plan npm run ridu -- migrate verify npm run ridu -- migrate status npm run ridu -- migrate up ``` ```sh title="terminal" package-manager="bun" bun run ridu -- migrate create --name rename-post-title bun run ridu -- migrate plan bun run ridu -- migrate verify bun run ridu -- migrate status bun run ridu -- migrate up ``` ```sh title="terminal" package-manager="pnpm" pnpm run ridu migrate create --name rename-post-title pnpm run ridu migrate plan pnpm run ridu migrate verify pnpm run ridu migrate status pnpm run ridu migrate up ``` ```sh title="terminal" package-manager="yarn" yarn run ridu migrate create --name rename-post-title yarn run ridu migrate plan yarn run ridu migrate verify yarn run ridu migrate status yarn run ridu migrate up ``` Creation is offline. The database-backed commands use their own bounded pools, TLS policy, advisory-lock admission, and schema assertions. Read [Migrations](https://riducms.com/docs/migrations/) for exact command semantics, destructive and maintenance admission, resumable phases, and recovery. ## Test against PostgreSQL {#testing} Use a disposable PostgreSQL 17 database for application tests that cover access rules, localization, transactions, relationship locks, optimistic conflicts, tasks, uploads, migrations, or recovery. Give each test suite its own database or schema and clean it afterward. Never give a test role access to production. Run `ridu migrate verify` against a restored backup before deployment, then exercise the Local API, REST or SDK paths your application depends on. Review [Testing](https://riducms.com/docs/testing/), [Releases and compatibility](https://riducms.com/docs/releases/), and [Security](https://riducms.com/docs/security/) for the wider checks. --- # SQLite Canonical URL: https://riducms.com/docs/sqlite/ SQLite is Ridu's official embedded database adapter for local and small deployments. It implements the same content, relationship, auth, versions, uploads, preferences, document locks, and durable task contracts used by the operation engine. The pure-Go driver needs no CGO, database service, or JavaScript production runtime. ## Supported operating envelope {#operating-envelope} Use SQLite within this operating envelope: | Supported | Not supported | | ------------------------------------------------------------------ | ---------------------------------------------------------------- | | An ordinary database file on storage local to the application host | NFS, SMB, or another shared network filesystem | | One application host; same-host processes use SQLite file locking | Multiple application hosts or replicas sharing the file | | Small or local workloads that tolerate one writer | A horizontally scaled or independently operated database service | | SQLite-aware online backup or a stopped, quiesced, WAL-safe copy | Copying only the live main database file while WAL is active | SQLite file locking and busy-timeout handling coordinate ordinary same-host processes; they are not a distributed-database or high-availability contract. Choose [PostgreSQL](https://riducms.com/docs/postgres/) when the database must be remote, independently operated, shared across horizontally replicated Ridu deployments, or scaled beyond this envelope. Private in-memory databases are useful for tests and process-owned tools, not durable deployments. ## Create and run a SQLite project {#new-project} Select the adapter when scaffolding: ```bash title="terminal" package-manager="npm" npm create ridu@latest my-app ``` ```bash title="terminal" package-manager="bun" bun create ridu@latest my-app ``` ```bash title="terminal" package-manager="pnpm" pnpm create ridu@latest my-app ``` ```bash title="terminal" package-manager="yarn" yarn create ridu my-app ``` Choose **Starter** and **SQLite** in the wizard, then run the exact install and `dev` commands it prints. The summary confirms the embedded adapter before any files are written.
Preselect every scaffold choice
For a non-interactive npm setup, pass every choice as an argument: ```bash title="terminal" npm create ridu@latest -- \ --template starter \ --database sqlite \ --module github.com/acme/content \ --scope @acme \ --package-manager npm \ --agent codex \ content ```
The generated `ridu.toml` records `database = "sqlite"`, the server opens `RIDU_SQLITE_PATH`, and no PostgreSQL Compose service is generated. During development, `--database-path`, `RIDU_SQLITE_PATH`, or the project-local `.ridu/development.sqlite` default selects the file. An explicit `--database-path` may be project-relative; `RIDU_SQLITE_PATH` and the generated production server require an absolute path or `file:` URI: ```bash title="terminal" export RIDU_SQLITE_PATH='/var/lib/ridu/content.sqlite' export RIDU_ADDRESS=':8080' ``` Keep the database and its parent directory writable only by the application identity. Do not place the file on a shared volume as a substitute for PostgreSQL. ## Add SQLite to an existing project {#existing-project} Use this path for a clean project before it has committed migration history or production data. Ridu has no generic live PostgreSQL/MongoDB-to-SQLite migration facility. Moving an existing dataset is application-owned and must preserve IDs, references, localized values, versions, auth state, uploads, and a rehearsed cutover. 1. Replace the adapter in project metadata and remove any database service that is no longer used. This example starts from PostgreSQL; replace whichever adapter the project currently names: ```toml title="ridu.toml" remove={2} add={3} version = 1 database = "postgres" database = "sqlite" entry = "./cmd/server" admin = "./admin" ``` 2. Wire the server to the official adapter inside `runtimeOptions`. Keep the address and handler settings beside the store factory; the helper can remain lower in the same file: ```go title="cmd/server/main.go" remove={11,19-23} add={4,6,12,24,34-57} import ( "context" "log" "net/url" "os" "path/filepath" "strings" "github.com/acme/content/internal/adminassets" "github.com/riducms/ridu" "github.com/riducms/ridu/adapters/postgres" "github.com/riducms/ridu/adapters/sqlite" "github.com/riducms/ridu/store" ) func runtimeOptions(applicationConfig ridu.Config) []ridu.ExecuteOption { return []ridu.ExecuteOption{ ridu.WithStore(func(ctx context.Context) (store.Store, error) { return postgres.OpenWithConfig(ctx, postgres.PoolConfig{ DatabaseURL: os.Getenv("DATABASE_URL"), AllowInsecureTransport: envBool("RIDU_ALLOW_INSECURE_DATABASE"), MaxUploadLockConnections: envInt32("RIDU_POSTGRES_UPLOAD_LOCK_CONNECTIONS"), }) return sqlite.Open(ctx, sqliteDatabasePath()) }), ridu.WithAddress(env("RIDU_ADDRESS", ":8080")), ridu.WithHandlerOptions(ridu.HandlerOptions{ AdminAssets: adminassets.FS(), AllowedOrigins: envList("RIDU_ALLOWED_ORIGINS"), }), } } func sqliteDatabasePath() string { path := strings.TrimSpace(os.Getenv("RIDU_SQLITE_PATH")) switch { case path == "": log.Fatal("RIDU_SQLITE_PATH is required") case path == ":memory:": log.Fatal("RIDU_SQLITE_PATH must be a file because migrations and the server run in separate processes") case strings.HasPrefix(path, "file:"): parsed, err := url.Parse(path) if err != nil { log.Fatalf("RIDU_SQLITE_PATH must be a valid SQLite file URI: %v", err) } target := parsed.Path if target == "" { target, err = url.PathUnescape(parsed.Opaque) } if err != nil || !filepath.IsAbs(target) { log.Fatal("RIDU_SQLITE_PATH file URI must contain an absolute path") } case !filepath.IsAbs(path): log.Fatal("RIDU_SQLITE_PATH must be an absolute file path") } return path } ``` The duplicate adapter imports and return statements show the before/after change. Remove every red line; the finished file contains only the SQLite import and `sqlite.Open` call. A fresh generated SQLite project contains the canonical helper, including support for an absolute opaque `file:` URI. Prefer copying that generated helper verbatim if you use URI paths. 3. Start the development loop against the file: ```bash title="terminal" package-manager="npm" go mod tidy RIDU_SQLITE_PATH=/absolute/path/to/content.sqlite npm run dev ``` ```bash title="terminal" package-manager="bun" go mod tidy RIDU_SQLITE_PATH=/absolute/path/to/content.sqlite bun run dev ``` ```bash title="terminal" package-manager="pnpm" go mod tidy RIDU_SQLITE_PATH=/absolute/path/to/content.sqlite pnpm run dev ``` ```bash title="terminal" package-manager="yarn" go mod tidy RIDU_SQLITE_PATH=/absolute/path/to/content.sqlite yarn run dev ``` `ridu dev` regenerates contracts, synchronizes safe additive schema changes, and starts the API and admin. Omit `RIDU_SQLITE_PATH` to use its project-local `.ridu/development.sqlite` default. The generated production server requires an absolute `RIDU_SQLITE_PATH`, because migrations and the binary are separate processes and must agree on one durable file. Follow the immutable migration workflow below before deploying. ## Transactions and local concurrency {#transactions} File databases enable WAL, foreign keys, a bounded busy timeout, and `synchronous=FULL` by default. Read-only operations use snapshot transactions and can overlap the active writer in WAL mode. SQLite still has one writer: write-capable operation transactions reserve it up front, and contention fails when the configured timeout or caller deadline expires. Nested reads reuse the operation snapshot. A mutation attempted inside a read-only lifecycle fails before hooks or persistence rather than escaping into another transaction. ## Use immutable migrations {#migrations} Production does not mutate schema at startup. Create and verify adapter-owned artifacts offline, then apply them as a deployment step: ```bash title="terminal" package-manager="npm" npm run ridu -- migrate create --name initial npm run ridu -- migrate verify npm run ridu -- migrate plan --database-path /var/lib/ridu/content.sqlite npm run ridu -- migrate up --database-path /var/lib/ridu/content.sqlite npm run ridu -- migrate status --database-path /var/lib/ridu/content.sqlite ``` ```bash title="terminal" package-manager="bun" bun run ridu -- migrate create --name initial bun run ridu -- migrate verify bun run ridu -- migrate plan --database-path /var/lib/ridu/content.sqlite bun run ridu -- migrate up --database-path /var/lib/ridu/content.sqlite bun run ridu -- migrate status --database-path /var/lib/ridu/content.sqlite ``` ```bash title="terminal" package-manager="pnpm" pnpm run ridu migrate create --name initial pnpm run ridu migrate verify pnpm run ridu migrate plan --database-path /var/lib/ridu/content.sqlite pnpm run ridu migrate up --database-path /var/lib/ridu/content.sqlite pnpm run ridu migrate status --database-path /var/lib/ridu/content.sqlite ``` ```bash title="terminal" package-manager="yarn" yarn run ridu migrate create --name initial yarn run ridu migrate verify yarn run ridu migrate plan --database-path /var/lib/ridu/content.sqlite yarn run ridu migrate up --database-path /var/lib/ridu/content.sqlite yarn run ridu migrate status --database-path /var/lib/ridu/content.sqlite ``` SQLite also supports reviewed `down`, `reset`, `refresh`, and `fresh` workflows with `--allow-destructive`. Ridu rejects altered or reordered migration history; schema, data-transform, plugin, and ledger work commits or rolls back together. Mutating migration commands reject `:memory:` so a successful invocation always targets persistent state. `plan` and `status` inspect existing files read-only and report a missing file as all pending without creating it. Production readiness runs inside a stable SQLite read transaction. It requires the complete ordered ledger to match the migration filename/digest fingerprint embedded by `ridu build`, then verifies the head manifest and physical schema in that same snapshot. This rejects missing, altered, renamed, reordered, or rolled-back data-only artifacts even when the final schema is unchanged. SQLite stores canonical document values as JSON. A field rename or other stored-data rewrite must therefore use a compiled transaction-bound transform registered by the project and selected with `ridu migrate create --transform `. The PostgreSQL-only `--accept-renames` shortcut is not a substitute for that transform. Localized values remain locale maps inside that canonical JSON. SQLite compiles localized filters and sorting to JSON expressions and uses expression indexes or focused reference/uniqueness side tables where needed; it does not use PostgreSQL's typed per-locale column layout. ## Back up and test recovery {#backup} Use SQLite-aware online backup tooling. For a filesystem copy, stop all Ridu processes using the file and quiesce writers first. Copying only the main file while WAL is active can omit committed pages, and separate copies of the database and WAL do not form a complete recovery point. Restore into an isolated local path with the exact binary and immutable migration history. Run `ridu migrate status`, start the application through its normal readiness check, then exercise login, representative reads and writes, relationships, versions, tasks, and upload reconciliation. Do not rely on a backup until you have restored and tested it in isolation. For projects with uploads, restore the SQLite database and object backend to one matched recovery point. Database metadata without objects is incomplete, and objects without matching references can retain stale data. --- # Rich text Canonical URL: https://riducms.com/docs/rich-text/ The rich-text plugin pairs a Go field and validator with a Svelte 5 Lexical editor. It stores portable, versioned JSON rather than browser editor state. Choose the enabled features in Go config. ## Use it in a new project {#new-project} The `starter` template already installs and registers rich text. Open `content/posts.go`, use `richtext.Field("content")`, then run `ridu dev`. Do not add a second registration. If you chose the `blank` template, follow the existing-project installation below. ## Add it to an existing project {#existing-project} Add the Go and admin packages together: ```bash title="terminal" npm run ridu -- add richtext \ --go-package github.com/riducms/ridu/plugins/richtext \ --admin-package @riducms/plugin-richtext ``` Register the backend once and use `richtext.Field` like a built-in field: ```go title="content/config.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" "github.com/riducms/ridu/plugins/richtext" ) func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Plugins: []ridu.Plugin{richtext.New()}, Collections: []ridu.Collection{Posts}, } } var Posts = ridu.Collection{ Slug: "posts", Fields: []field.Definition{ field.Text("title", field.Required()), richtext.Field("content", field.Required()), }, } ``` Start the development loop and verify the editor locally: ```bash title="terminal" npm run dev ``` Create a document containing formatting and a link, reload it, and read the same value through the generated SDK. If uploads or relationships are enabled, verify those targets too. Before deployment, create and verify the immutable migration: ```bash title="terminal" npm run ridu -- migrate create --name add-rich-text npm run ridu -- migrate plan npm run ridu -- migrate verify npm run ridu -- check ``` Apply the reviewed artifact with `migrate up` during deployment, then require a clean `migrate status`. Supply the selected adapter's URL/path and production safety flags as described in its guide. ## Default authoring features {#defaults} `richtext.Field` enables the recommended set: - links with in-place editing and safe URL validation; - ordered, unordered, and check lists; - code blocks and horizontal rules; - access-aware upload cards with per-placement captions; - relationship cards; and - headings, quotes, alignment, indentation, line breaks, and inline bold, italic, underline, strike-through, subscript, superscript, and code as editor baseline nodes. Authors use a slash/insert menu, keyboard navigation, floating selection toolbar, and the admin's shared relationship/upload browser. Upload and relationship cards store only a stable collection slug and document ID; selecting a card can inspect, replace, or remove the placement without deleting the referenced document. ![The official Ridu rich-text field in a Post editor with portable Lexical content and the surrounding schema-driven form.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/ridu-admin-rich-text.png) _Saving persists the portable document value described below, not DOM or browser editor state._ An upload node can add a placement-specific caption without changing the asset's reusable `alt` field: ```json { "type": "upload", "version": 1, "relationTo": "media", "id": "asset_123", "caption": "A crop used only in this article" } ``` Reference pickers and hydrated cards respect target collection access. The server also validates the collection slug and ID when saving; an editor preview is never the authorization boundary. ## Choose a feature set {#features} `FieldWithConfig` accepts an allowlist. `Features: nil` inherits the defaults; any non-nil slice replaces them, including an empty slice: ```go richtext.FieldWithConfig("content", richtext.Config{ Features: []richtext.Feature{ richtext.FeatureLinks, richtext.FeatureLists, richtext.FeatureCode, richtext.FeatureHorizontalRule, richtext.FeatureUploads, richtext.FeatureRelationships, }, UploadCollections: []string{"media"}, RelationshipCollections: []string{"posts", "pages"}, }, field.Required()) ``` An empty upload/relationship collection list allows every compatible collection; a non-empty list restricts both admin choices and server validation. `FeatureBlocks` does not provide custom block registration or a complete authoring workflow. Custom blocks still need a versioned node schema, editor integration, and renderer. ## Portable document contract {#document} Every value has exactly one document version and one root: ```json { "version": 1, "root": { "type": "root", "children": [ { "type": "paragraph", "children": [{ "type": "text", "text": "Hello, Ridu", "format": 1 }] } ] } } ``` Ridu rejects an unsupported document version, disabled or unknown node, malformed child/reference, missing text/link data, a tree deeper than 64, or more than 10,000 nodes with path-aware validation issues. Changing `DocumentVersion` requires a content migration; the server never silently upgrades stored JSON during a read. Required, localized, read-only, and layout options work as they do for other fields. Test the exact combination of localization, versions, and live preview that your application uses. ## Render safe HTML in Go {#render-html} `RenderHTML` escapes text and renders paragraphs, headings, quotes, formatting, links, lists, check-list state, code, line breaks, alignment/indent metadata, and horizontal rules. It accepts only relative URLs or `http`, `https`, `mailto`, and `tel` links. Provide upload, relationship, and block renderers by node type. Inspect the collection and ID or `blockType`: ```go html, err := richtext.RenderHTML(value, map[string]func(store.Values) (string, error){ "upload": func(node store.Values) (string, error) { return renderUploadReference(ctx, node) }, "relationship": func(node store.Values) (string, error) { return renderRelationshipReference(ctx, node) }, "block": func(node store.Values) (string, error) { return renderApplicationBlock(ctx, node) }, }) if err != nil { return err } ``` Resolve referenced content through the local API so access and redaction still apply. Do not trust stored reference data as an HTML URL or concatenate unescaped application fields. ## Frontend rendering boundary {#frontend} Ridu supplies safe Go HTML rendering, not a generic read-only Svelte component. A frontend can render the JSON, call an endpoint that uses `RenderHTML`, or provide a custom renderer. Not included: tables, embeds, custom block authoring, Markdown shortcuts, HTML/Markdown import and export, plain-text rendering, custom-node migration hooks, Yjs collaboration, and a read-only Svelte renderer. See the [`richtext` Go reference](https://riducms.com/reference/richtext/), the [`@riducms/plugin-richtext` reference](https://riducms.com/reference/plugin-richtext/), [Uploads](https://riducms.com/docs/uploads/), and [Build a custom field](https://riducms.com/guides/custom-fields/). --- # SEO Canonical URL: https://riducms.com/docs/seo/ The SEO plugin adds metadata fields to selected collections and globals, with an overview, title and description guidance, an optional upload image, and a search-result preview. The fields use the resource's normal access, validation, localization, drafts, versions, hooks, REST routes, and generated types. ## Use it in a new project {#new-project} Generated projects include `@riducms/plugin-seo` in the root and admin workspaces. Add `seo.New` to your Go config, select the resources, and configure any generator callbacks. ## Add it to an existing project {#existing-project} Install the package in both the root and admin workspaces: ```bash title="terminal" package-manager="bun" bun add @riducms/plugin-seo bun add --cwd admin @riducms/plugin-seo go mod tidy ``` ```bash title="terminal" package-manager="npm" npm install @riducms/plugin-seo npm install --workspace admin @riducms/plugin-seo go mod tidy ``` ```bash title="terminal" package-manager="pnpm" pnpm add --workspace-root @riducms/plugin-seo pnpm --dir admin add @riducms/plugin-seo go mod tidy ``` ```bash title="terminal" package-manager="yarn" yarn add --ignore-workspace-root-check @riducms/plugin-seo yarn --cwd admin add @riducms/plugin-seo go mod tidy ``` Then add `seo.New` below. The plugin requires resource options, so configure it in Go rather than with a zero-argument `ridu plugin add` entry. ## Configure the paired plugin {#configure} Configure the compiled Go plugin and select the resources that receive metadata: ```go title="content/config.go" package content import ( "fmt" "github.com/riducms/ridu" "github.com/riducms/ridu/plugins/seo" "github.com/riducms/ridu/schema" ) func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Plugins: []ridu.Plugin{ seo.New(seo.Config{ Collections: []schema.CollectionSlug{"pages", "posts"}, Globals: []schema.CollectionSlug{"site-settings"}, UploadsCollection: "media", TabbedUI: true, GenerateTitle: func(ctx seo.GenerateContext) (string, error) { title, _ := ctx.Document["title"].(string) return title + " | Acme", nil }, GenerateURL: func(ctx seo.GenerateContext) (string, error) { if ctx.Collection == nil { return "https://example.com/", nil } slug, _ := ctx.Document["slug"].(string) return fmt.Sprintf("https://example.com/%s", slug), nil }, }), }, } } ``` ```sh title="terminal" npm install npm run dev ``` Open one configured collection or global, edit the SEO title, description, and image, save, and read the generated `meta` value through the SDK. Before deployment, create and verify the immutable migration: ```sh title="terminal" npm run ridu -- migrate create --name add-seo npm run ridu -- migrate plan npm run ridu -- migrate verify npm run ridu -- check ``` Apply the reviewed artifact with `migrate up` during deployment, then require a clean `migrate status`. Use the selected adapter's connection flags and safety admission for those commands. ## Default field shape {#default-fields} The plugin injects one `meta` group in this order: | Path | Field behavior | | ------------------ | --------------------------------------------------------------------------------- | | `meta.overview` | Presentation-only summary of title, description, and image checks. | | `meta.title` | Text with 50–60 character guidance and optional generation. | | `meta.description` | Textarea with 100–150 character guidance and optional generation. | | `meta.image` | Optional upload reference when `UploadsCollection` is configured. | | `meta.preview` | Presentation-only result preview using the current unsaved title and description. | The character ranges are authoring guidance, not validation. Add `field.MinLength` or `field.MaxLength` through a field override when the server must reject values outside a range. Injected metadata fields become localized when application content localization is enabled. The admin shows exact-language values, reports missing fallback values, and passes the selected locale to generation callbacks. `UploadsCollection` must name an upload-enabled collection. Authors can select an existing asset, inspect the selected upload, replace it, remove it, or ask the configured image generator for an asset ID. Upload access and normal document validation still apply. ## Place metadata in tabs {#tabs} Set `TabbedUI: true` to place metadata in a separate tab. Ridu preserves an existing leading tab group and appends an SEO tab. If fields are not already tabbed, it groups ordinary content under the resource label, preserves authored tabs, and adds SEO last. An auth collection's email field stays outside the tabs so authentication semantics do not change. Without `TabbedUI`, the `meta` group is appended to the selected resource's existing fields. ## Generate from the unsaved draft {#generation} Each callback receives a `GenerateContext` containing: - the current unsaved document snapshot; - the document ID, when editing an existing document; - the selected content locale; - a detached collection or global definition; and - the authenticated plugin endpoint context, including the access-controlled local API. `GenerateTitle`, `GenerateDescription`, and `GenerateImage` require create access for a new collection document, update access for an existing document, or update access for a global. `GenerateURL` requires create access for a new document and read access for an existing collection document or global. Every generation call requires an authenticated actor. Generated values are proposed form edits. The author can inspect or change them, and normal save or publish validation persists them. A generator never writes around the form or operation engine. The admin cancels superseded calls and discards a response when the draft, resource, ID, or locale has changed. While a URL request is pending or has failed, the preview clears the old URL instead of presenting it as current. > [!IMPORTANT] > Generator callbacks run on the server. Keep credentials and executable behavior there; never put > them in field or renderer configuration sent to the admin. ## Replace or directly place fields {#field-overrides} `Config.Fields` receives a copy of the ordered defaults and returns the complete contents of the injected `meta` group. Use it to add validation, change labels, insert fields, or remove a default: ```go Fields: func(defaults []field.Definition) ([]field.Definition, error) { return []field.Definition{ defaults[0], seo.MetaTitle(true, field.Required(), field.MaxLength(70)), seo.MetaDescription(true, field.MaxLength(180)), defaults[3], defaults[4], }, nil }, ``` The callback must return at least one field. Its output is resolved and validated like application config, so duplicate names, incompatible options, invalid renderer metadata, and bad upload targets fail before startup. `Overview`, `MetaTitle`, `MetaDescription`, `MetaImage`, and `Preview` are also public constructors for direct placement. Their `WithConfig` variants map overview and preview components to custom paths or customize image presentation. Direct title, description, and image constructors are localized by default; use injected fields or an ordinary field plus the lower-level admin-component contract when an application has no localization configuration. `Collections` and `Globals` select automatic injection. Direct fields can live on another configured resource: the authenticated generation endpoint resolves that resource and applies its ordinary access rules even when it is not in an injection selector. ## Endpoint and failure behavior {#endpoints} The plugin declares four `POST` endpoints under `/api/plugins/seo/`: | Endpoint | Result | | ---------------------- | ------------------------------------------------- | | `generate-title` | `{ "result": "..." }` from `GenerateTitle`. | | `generate-description` | `{ "result": "..." }` from `GenerateDescription`. | | `generate-image` | An upload document ID from `GenerateImage`. | | `generate-url` | A preview URL from `GenerateURL`. | All four routes remain present when a callback is omitted and return an empty result. Requests are limited to 1 MiB, reject unknown or trailing JSON, require exactly one collection or global, and return the normal structured Ridu error envelope. Use the SDK's `requestPlugin` method rather than building a URL manually; it retains base URL, credentials, headers, middleware, cancellation, and `RiduError` behavior. | Authoring state | Result | | -------------------------------------- | -------------------------------------------------------------------------- | | Callback is not configured | Auto-generation is not offered; the endpoint returns an empty result. | | Actor lacks resource access | The endpoint returns `access_denied`; existing field values remain intact. | | Callback fails | The admin reports a retryable generation error and does not change value. | | Draft changes during generation | The old request is cancelled or its response is discarded. | | Referenced image is unreadable/deleted | The field reports the unavailable reference without inventing metadata. | ## Scope and boundaries {#boundaries} The plugin owns search metadata authoring. It does not inject canonical links, robots directives, Open Graph variants, Twitter cards, JSON-LD, redirects, sitemaps, or frontend `` rendering. Read the stored metadata in your application frontend and render the exact tags your delivery surface needs. See the [`seo` Go reference](https://riducms.com/reference/seo/), [`@riducms/plugin-seo` reference](https://riducms.com/reference/plugin-seo/), [Plugin system](https://riducms.com/docs/plugins/), [Localization](https://riducms.com/docs/localization/), [Uploads](https://riducms.com/docs/uploads/), and [TypeScript SDK](https://riducms.com/docs/typescript-sdk/). --- # Form Builder Canonical URL: https://riducms.com/docs/form-builder/ The Form Builder plugin lets editors assemble reusable forms from blocks in the Ridu admin. Frontends read those definitions, render them in their own design system, and submit values to a generated `form-submissions` collection. Forms and submissions use normal collection access, validation, hooks, REST routes, generated types, and SDK methods. ## Use it in a new project {#new-project} Generated projects include `@riducms/plugin-form-builder` in the root and admin workspaces. Add `formbuilder.New` to your Go config, choose the admin-user collection and any email, upload, redirect, or payment options, then follow the configuration below. ## Add it to an existing project {#existing-project} Install the package in both workspaces: ```bash title="terminal" package-manager="bun" bun add @riducms/plugin-form-builder bun add --cwd admin @riducms/plugin-form-builder go mod tidy ``` ```bash title="terminal" package-manager="npm" npm install @riducms/plugin-form-builder npm install --workspace admin @riducms/plugin-form-builder go mod tidy ``` ```bash title="terminal" package-manager="pnpm" pnpm add --workspace-root @riducms/plugin-form-builder pnpm --dir admin add @riducms/plugin-form-builder go mod tidy ``` ```bash title="terminal" package-manager="yarn" yarn add --ignore-workspace-root-check @riducms/plugin-form-builder yarn --cwd admin add @riducms/plugin-form-builder go mod tidy ``` Add `formbuilder.New` below. Review the default public submission access before migrating; do not expose form creation or submission reads accidentally. ## Configure the paired plugin {#configure} Configure the Go plugin: ```go title="content/config.go" package content import ( "context" "github.com/riducms/ridu" "github.com/riducms/ridu/field" "github.com/riducms/ridu/plugins/formbuilder" "github.com/riducms/ridu/schema" ) func Config() ridu.Config { return ridu.Config{ Name: "Acme Forms", Plugins: []ridu.Plugin{ formbuilder.New(formbuilder.Config{ EnabledFields: []formbuilder.FieldType{ formbuilder.FieldText, formbuilder.FieldEmail, formbuilder.FieldSelect, formbuilder.FieldTextarea, formbuilder.FieldUpload, }, UploadCollections: []schema.CollectionSlug{"media"}, RedirectRelationships: []schema.CollectionSlug{"pages"}, DefaultToEmail: "forms@example.com", SendEmail: func(ctx context.Context, email formbuilder.Email) error { return mailer.Send(ctx, email) }, }), }, } } ``` ```sh title="terminal" npm install npm run dev ``` Create a form in the admin, read it through the generated SDK, and submit one valid and one invalid payload from the application. Before deployment, create and verify the immutable migration: ```sh title="terminal" npm run ridu -- migrate create --name add-form-builder npm run ridu -- migrate plan npm run ridu -- migrate verify npm run ridu -- check ``` Apply the reviewed artifact with `migrate up` during deployment, then require a clean `migrate status`. Use the selected adapter's URL/path and safety flags for those commands. Confirm the stored submission and any configured after-commit email or task behavior. ## Collections and access {#collections} The plugin creates two collections by default: | Collection | Purpose | Default access | | ------------------ | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `forms` | Reusable field definitions, button text, confirmation behavior, and notification templates. | Public read; configured admin-user create, update, and delete. `emails` is visible only to that configured admin-user collection. | | `form-submissions` | The selected form, scalar values, optional upload references, and optional payment result. | Public create; configured admin-user read and delete; update denied. | `FormsSlug` and `SubmissionsSlug` rename these collections. `Forms` and `Submissions` receive copies of the defaults and must return complete replacements. Overrides can replace the default access rules, while the plugin keeps the required collection identities and lifecycle validation hooks. Form deletion is restricted while submissions reference it. Submitted uploads use restrict-on-delete references so a retained submission cannot silently lose its files. ## Editor field blocks {#fields} The default field set matches Payload's default Form Builder selection: - checkbox, country, email, message, number, select, state, text, and textarea. Set `EnabledFields` to opt into an exact ordered selection. Date, radio, upload, and payment are available but are not default-enabled. Upload requires at least one upload-enabled collection in `UploadCollections`. Payment requires at least one `PaymentProcessors` choice and a compiled `HandlePayment` callback. A form may contain at most one payment block. Every input block carries a stable `name`, optional label, required flag, and width. Choice fields carry their exact allowed options. Upload fields choose one enabled target plus optional MIME, maximum-size, and multiple-file constraints. Payment fields carry a base price, processor, and ordered conditional arithmetic. `Fields` receives copies of the default `field.Block` definitions and replaces the complete ordered set. It may add custom block types; provide rendering and client validation for those blocks. Ridu still enforces field identity and required presence. Malformed fields, duplicate names, invalid targets, bad widths, duplicate choice values, and payment references to unknown fields fail before or during the form write with field-addressable validation issues. ## Render and submit from an application {#render-submit} Import the helpers from `@riducms/plugin-form-builder`, render the discriminated `FormField` union with your own components, then use the generated SDK collection method: ```ts title="src/lib/submit-form.ts" import { buildSubmissionInput, confirmationFor, validateFormValues, type FormDefinition, type FormValues } from '@riducms/plugin-form-builder'; import { client } from './ridu'; export async function submitForm(form: FormDefinition, values: FormValues) { const issues = validateFormValues(form, values); if (issues.length) return { issues }; const submission = await client.create('form-submissions', buildSubmissionInput(form, values)); return { submission, confirmation: confirmationFor(form) }; } ``` Client validation is only immediate author feedback. The server reloads the selected form inside the submission transaction and rejects missing required fields, unknown or duplicate names, invalid email/date/number/checkbox values, unavailable choice values, and invalid upload references with a `422 validation` error and exact issue paths. Submitted field names are data, never trusted schema instructions. ## Confirmations and redirects {#confirmation} Editors choose either a localized confirmation message or a redirect. Redirects may use a custom URL or a polymorphic relationship limited by `RedirectRelationships`. The TypeScript `confirmationFor` helper normalizes the saved definition after a successful create; your frontend handles navigation. ## Templated email after commit {#email} Each form may define multiple messages with To, CC, BCC, From, Reply-To, subject, and trusted application-authored HTML. Anonymous form reads cannot see this `emails` field. Templates support: | Placeholder | Output | | ---------------------- | ---------------------------------------- | | `{{fieldName}}` | One submitted scalar value. | | `{{*}}` | Every submitted scalar as text. | | `{{*:table}}` | Every submitted scalar in an HTML table. | | `{{formSubmissionID}}` | The committed submission ID. | Submission-derived HTML is escaped, addresses are parsed before delivery, and subjects containing line breaks are rejected. `DefaultToEmail` supplies a recipient when a row omits one. `BeforeEmail` may transform or filter the batch; `SendEmail` connects your email provider. Keep provider credentials in server-side Go code. Email work runs only after the submission commits. Failures call `ReportError` or structured logging and do not turn a durable successful submission into an HTTP failure. Use a durable task inside `SendEmail` when delivery needs persistent retries. ## Upload and payment lifecycle {#uploads-payments} An upload row stores references separately from scalar `submissionData`. A field targeting one collection uses document IDs such as `['media_1']`; a polymorphic upload block uses `{ relationTo, id }` references. Before commit, the server verifies that each target collection is enabled, each document exists and is readable to the submitter, its detected MIME type matches the form allowlist, its size is within the configured maximum, and a singular field does not receive multiple files. Missing or redacted MIME/size metadata fails closed. Upload bytes themselves must first pass through Ridu's upload endpoint, so the target upload collection's create access must admit the public actor or authenticated user who is completing the form. For payment, configure display choices and one trusted callback: ```go title="content/config.go" PaymentProcessors: []field.Choice{{Value: "stripe", Label: "Card"}}, HandlePayment: func(ctx formbuilder.PaymentContext) (store.Value, error) { charge, err := payments.Charge(ctx.Context.Context, ctx.Total) if err != nil { return store.Value{}, err } return store.Object(store.Values{"chargeID": store.String(charge.ID)}), nil }, ``` `GetPaymentTotal` applies matching conditions in authored order. Static or field-derived operands may add, subtract, multiply, or divide. Negative or non-finite totals and division by zero are rejected. An optional payment block does not invoke the callback when omitted. When present, the callback runs before commit; an error rolls back the submission, while its returned JSON is stored in the read-only `payment` field. External provider side effects cannot be rolled back with the database transaction: make the callback idempotent, prefer an authorization or payment-intent step keyed to the request, and capture irrevocably only after durable application state exists. The matching TypeScript helper is for display only—the Go calculation and provider callback are authoritative. ## What your application provides {#boundaries} Provide the public form UI, any rich-message rendering, and the email or payment integrations. Use Ridu's `{ relationTo, id }` shape when converting polymorphic references from another system. See the exact exported contracts in the [`formbuilder` Go reference](https://riducms.com/reference/formbuilder/) and [`@riducms/plugin-form-builder` reference](https://riducms.com/reference/plugin-form-builder/). --- # GraphQL Canonical URL: https://riducms.com/docs/graphql/ GraphQL is an optional compiled transport. REST-only applications do not import it and therefore do not link the parser, executable schema, handler, or GraphQL runtime into their binary. The plugin derives one immutable executable schema from the canonical Ridu manifest at startup. Resolvers enter the same local operation engine as REST and the SDK; GraphQL selection does not bypass access, validation, hooks, transactions, localization, population, or redaction. ## Use it in a new project {#new-project} Create an ordinary `starter` or `blank` project, then add the `graphqlplugin.New()` registration below. GraphQL is Go-only and has no admin package to install: applications that do not import it do not link its parser or execution runtime into the binary. ## Add it to an existing project {#existing-project} Import `github.com/riducms/ridu/plugins/graphql` from the published Ridu module already used by the project, add it to `Config.Plugins`, and run `go mod tidy`. Do not add an npm package or generated admin import; this plugin owns a transport, not an authoring control. ## Enable the endpoint {#enable} ```go title="content/config.go" package content import ( "github.com/riducms/ridu" graphqlplugin "github.com/riducms/ridu/plugins/graphql" ) func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Plugins: []ridu.Plugin{ graphqlplugin.New(), }, Collections: []ridu.Collection{Users, Posts}, } } ``` The default route is `POST /api/graphql`. An invalid GraphQL name, generated type/root collision, unknown resource override, or malformed extension stops startup instead of hiding part of the schema. Ridu does not serve a browser playground. Start the complete development loop: ```bash title="terminal" go mod tidy npm run dev ``` `ridu dev` regenerates the committed SDL and other contracts before starting the API and admin. Enabling only the transport does not add stored fields or adapter tables, so it does not need a database migration. If the same change also modifies resources, prepare the selected adapter's reviewed migration before deployment. Run `npm run ridu -- check` before committing so generated SDL drift is caught. With the server running, send an authenticated bounded query to `POST /api/graphql`. Also confirm that an unauthorized query receives the same denial and field redaction as REST. ## Query collections {#query-collections} Root names come from resolved singular/plural labels. A `posts` collection normally produces `Post`, `Posts`, and `countPosts` queries: ```graphql query RecentPosts { Posts( where: { featured: { equals: true }, score: { greater_than: 5 } } sort: ["-score"] page: 1 limit: 20 ) { docs { id title category { id name } } totalDocs totalPages hasNextPage } } ``` Typed filter inputs compile into Ridu's finite [query vocabulary](https://riducms.com/docs/querying/). Nested group, array, and block filter paths use flattened double underscores such as `seo__description` and `links__label`. Selected relationship/upload fields become bounded operation-engine population and reapply target access and redaction. Groups and arrays have typed nested output/input objects. Select/radio choices use GraphQL enums. Blocks return typed output unions selected with inline fragments; mutation input uses JSON because GraphQL has no input union. Polymorphic references use `{ relationTo, value }`. ## Create and mutate {#mutations} Collections add generated create, update, delete, and duplicate fields when mutations are enabled: ```graphql mutation CreatePost($category: ID!) { createPost(data: { title: "Hello", category: $category }) { id title category { id name } } } ``` Optimistic mutations accept `expectedRevision` when the resource is versioned. Duplicate runs the ordinary create lifecycle. Upload-enabled collections deliberately omit GraphQL create: JSON cannot carry the byte source or server-owned metadata. Use multipart/remote [upload APIs](https://riducms.com/docs/uploads/) for new files; upload document reads and metadata remain available in GraphQL. ## Globals, drafts, versions, and trash {#editorial} Globals expose read/update and matching version/draft operations. Versioned collections add single/list version queries and restore; draft-enabled resources add publish/unpublish. Trash adds `trash: true` reads, restore-deleted, and permanent-delete mutations. `draft: true` includes or writes a draft; `draft: false` selects published behavior. These operations use the same revision checks, access rules, hooks, retention, reference cleanup, and scheduled-state semantics as other transports. Scheduling, document locks, previews, bulk operations, and raw file transfer remain REST/SDK-focused surfaces rather than inferred GraphQL fields. ## Localized content {#localization} Configured locales become a deterministic `RiduLocale` enum: ```graphql query LocalizedPost($id: ID!) { english: Post(id: $id, locale: EN) { title } french: Post(id: $id, locale: FR, fallbackLocale: [EN]) { title } exactArabic: Post(id: $id, locale: AR, disableFallback: true) { title } } ``` The selected locale reaches filters, relationships, access, hooks, and versions. GraphQL does not overload scalar fields with the local/REST `all` locale-keyed shape; request one locale per field alias when a query needs several translations. ## Authentication and preferences {#authentication} Auth collections generate login, current-user/session, refresh, logout, initialized-state, unlock, recovery, and verification fields according to configuration. The result contains an opaque token, expiry, exact auth collection, and redacted user. Browser applications should prefer the REST/SDK HTTP-only cookie. A non-browser GraphQL client can authenticate with: ```text Authorization: Session Authorization: Bearer ridu__ ``` Session and API-key identity includes its auth collection, so colliding document IDs across auth collections remain distinct. Admin-identity GraphQL clients also get preference read/set/delete/ reset fields with the same exact ownership contract. ## Configure resources {#resources} Rename or suppress a generated GraphQL surface without changing the manifest slug, REST path, or SDK type: ```go graphqlplugin.New(graphqlplugin.Options{ Resources: map[string]graphqlplugin.ResourceOptions{ "posts": { SingularName: "Article", PluralName: "Articles", DisableMutations: true, }, }, }) ``` Disabling a GraphQL query/mutation removes only that transport field. It is not an access rule for REST, the local API, SDK, admin, or plugin endpoints. ## Add trusted root fields {#extensions} Compiled extension queries/mutations receive the authenticated actor, exact auth collection, local API, and public application facade—never a store adapter: ```go graphqlplugin.New(graphqlplugin.Options{ Queries: []graphqlplugin.ExtensionField{ { Name: "postTotal", Type: graphql.NewNonNull(graphql.Int), Cost: 5, Resolve: func(input graphqlplugin.ExtensionContext) (any, error) { page, err := input.Local.List(input.Context, "posts", ridu.ListOptions{ Page: 1, Limit: 1, Actor: input.Actor, ActorCollection: input.ActorCollection, }) return page.Total, err }, }, }, }) ``` Using the supplied API keeps application authorization and lifecycle behavior intact. Extension code is trusted compiled code; `Cost` protects query budgeting, not sandboxing. ## Generate deterministic SDL {#sdl} Configure a project-owned destination after enabling the plugin: ```toml title="ridu.toml" generated.graphql.schema = "./generated/ridu.graphql" ``` The development loop now writes the exact compiled schema without enabling network introspection: ```bash npm run dev ``` Use `npm run ridu -- generate --check` in CI to verify that the committed SDL matches executable config. Use `npm run ridu -- generate` only when you need a one-shot write without starting the development server. Resource renames, disabled surfaces, and custom root fields come from the same executable plugin instance used at runtime. They are never duplicated into the serializable manifest. Ridu validates the project-relative path through the generic `generated..` mapping and installs the SDL atomically beside the other contracts. `graphqlplugin.GenerateSDL` remains available when application-owned Go tooling needs the bytes directly. Before removing the GraphQL plugin, remove its generated mapping and delete the now-unowned SDL file. Ridu never deletes paths that disappear from `ridu.toml`. ## Resource safeguards {#limits} Secure zero-value defaults are: | Limit | Default | | ----------------- | -------: | | HTTP body | 1 MiB | | Encoded variables | 256 KiB | | Executable depth | 12 | | Aliases | 100 | | Total complexity | 1,000 | | Per-list limit | 100 | | Introspection | disabled | Fragments are expanded for list/cost analysis, nested join limits are charged, and cycles fail closed. Hard syntax/token/fragment ceilings remain even if application options are raised. Keep introspection disabled on untrusted production endpoints unless your operational policy needs it. ```go graphqlplugin.New(graphqlplugin.Options{ AllowIntrospection: true, MaxComplexity: 2_000, MaxDepth: 16, }) ``` GraphQL validation failures use the normal response shape. Operation errors expose stable Ridu `code`, `status`, and validation `issues` extensions; unexpected internal failures do not expose a message or stack. See the [`graphql` plugin reference](https://riducms.com/reference/graphql/), [REST API](https://riducms.com/docs/rest-api/), and [TypeScript SDK](https://riducms.com/docs/typescript-sdk/). Use [Capability status](https://riducms.com/docs/status/) to track the remaining conformance boundary. --- # Object storage Canonical URL: https://riducms.com/docs/storage/ Upload documents live in the selected database; their bytes live in a `storage.Backend`. Configure the backend once for the application. Ridu coordinates writes with document transactions and checks references again before cleanup. ## Set a stable application namespace {#namespace} Every application with an upload collection must declare `Config.StorageNamespace`: ```go title="content/config.go" func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", StorageNamespace: "acme-production", Collections: []ridu.Collection{Media}, } } ``` The namespace is an object prefix, not a display label. Keep it unchanged when `Config.Name` or an upload collection slug changes, and never reuse it for another application that shares the backend. It must contain 3–64 lowercase letters, digits, underscores, or hyphens. New objects use a slug-independent `ridu//objects//...` layout, so renaming a collection does not move bytes. Create the backend lazily through `WithUploadStorage` so manifest resolution and generation never touch the filesystem or network. ## Implement a backend {#backend-contract} ```go type Backend interface { Put(context.Context, string, io.Reader, int64, string) error Open(context.Context, string) (io.ReadCloser, Object, error) Delete(context.Context, string) error List(context.Context, ListRequest) (ListPage, error) } type Object struct { Key string Size int64 ContentType string ModifiedAt time.Time } type ListRequest struct { Prefix string Cursor string Limit int } type ListPage struct { Objects []Object NextCursor string } ``` The small interface has strict semantics: | Operation | Required behaviour | | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Put` | Honour context cancellation and the declared byte count. Replacing an existing key is atomic; a partial object must never appear as committed. | | `Open` | Return a streaming body plus authoritative metadata, or `storage.ErrNotFound` for absence. The caller closes the body. | | `Delete` | Deleting a missing key succeeds as a no-op so retries are safe. | | `List` | Return one bounded page in unique key order under the requested prefix. Every object has an authoritative non-zero `ModifiedAt`; `NextCursor` advances until the final page. | `ModifiedAt` is a safety input, not optional decoration. Reconciliation uses it to enforce the grace period and fails closed if an adapter cannot prove object age. Ridu still validates namespaced keys, application namespace, committed references, and fresh object-lock state immediately before a destructive call. Production backends should also implement: ```go type HealthBackend interface { Ping(context.Context) error } ``` `Ping` must be bounded, repeatable, and safe without reading or mutating an application object. `ridu.Execute` includes it in startup preflight and `/readyz`. The optional `storage.URLSigner` provides short-lived direct downloads, but private framework delivery remains access checked. ## Local filesystem {#local-storage} The local backend suits development and a single node with a durable mounted volume: ```go title="cmd/server/storage.go" func openUploadStorage(context.Context) (storage.Backend, error) { return localstorage.New("/var/lib/acme/uploads") } ``` Register it with the server: ```go ridu.WithUploadStorage(openUploadStorage) ``` Writes use a temporary file, sync it, atomically rename it into place, and sync the directory. Object paths reject absolute paths and traversal. The readiness probe verifies the root is a directory, performs a durable private probe write, removes it, and syncs cleanup. A local volume must be durable across replacement and mounted at the same path before readiness. It is not shared automatically across replicas: use a shared object service for a multi-node deployment rather than putting independent local disks behind one application. ## S3-compatible storage {#s3-storage} The dependency-free S3 backend implements SigV4 PUT, GET, DELETE, complete paginated listing, bucket health, and signed GET URLs: ```go title="cmd/server/storage.go" func openUploadStorage(context.Context) (storage.Backend, error) { return s3storage.New(s3storage.Config{ Endpoint: os.Getenv("S3_ENDPOINT"), Region: os.Getenv("S3_REGION"), Bucket: os.Getenv("S3_BUCKET"), AccessKey: os.Getenv("S3_ACCESS_KEY"), SecretKey: os.Getenv("S3_SECRET_KEY"), MaxSpoolBytes: 256 << 20, // 256 × 2²⁰ = 268,435,456 bytes (256 MiB) SpoolDirectory: "/var/tmp/ridu-spool", }) } ``` Endpoint, region, bucket, access key, and secret key are required. Supply a custom `http.Client` to set deployment-specific transport and timeout policy; the default client timeout is 30 seconds. S3 signing needs the payload hash before upload. A seekable input is hashed and rewound. A non-seekable input is copied to a private temporary file, bounded by `MaxSpoolBytes`; zero selects 256 MiB. Size mismatch, cancellation, or signing failure removes the spool file. Plan local scratch space for concurrent non-seekable uploads. > [!IMPORTANT] > S3 endpoints must use HTTPS. `AllowInsecureEndpoint` permits HTTP only for a trusted local emulator > such as MinIO. It sends storage credentials over plaintext and is not production configuration. `SignedURL` accepts a lifetime from one second through seven days. Signed possession is a temporary capability, not collection authorization; issue it only after the application has made the relevant access decision. Ordinary Ridu delivery remains private and `no-store` because collection read rules may depend on the actor or row even when an upload collection is not marked private. The current backend does not implement multipart, resumable, or direct browser upload. Large files still pass through Ridu's bounded upload operation and, for non-seekable S3 bodies, the spool. ## Reconciliation and deletion {#reconciliation} Database metadata and objects cannot share one atomic commit. Ridu narrows that boundary with staged writes, rollback, cross-process object locks, last-reference checks, and reconciliation. `App.ReconcileUploads` reports candidates from an ACL-independent snapshot of current, trashed, and versioned references. The grace period must be at least five minutes. After review, `App.CleanupUploads` re-checks candidates in bounded batches under fresh snapshots and object locks before deletion. A candidate that gained a reference is retained. Keep the grace period longer than the slowest admitted upload or import and quiesce imports during a destructive cleanup pass. Failed after-commit cleanup retains bytes as reconciliation candidates; it does not roll back a durable document deletion. See [Uploads](https://riducms.com/docs/uploads/) for collection metadata, image variants, remote ingestion, private delivery, and the 65-key per-document object bound. ## Build a safe custom adapter {#custom-adapter} Before using another provider, test these behaviours directly: - exact declared-size enforcement, cancellation, short reads, extra bytes, and partial-write cleanup; - atomic same-key replacement and idempotent missing-key deletion; - path and key traversal rejection; - `Open` metadata, body close behaviour, and `storage.ErrNotFound` mapping; - prefix-restricted, fully paginated `List` results with non-zero modification times; - bounded repeatable `Ping`, plus credential and dependency failure; - concurrent `Put`, `Open`, `Delete`, reconciliation, and retry races; and - no logging of credentials, private keys, signed URLs, or sensitive provider responses. Custom storage used with `ridu.Execute` needs `HealthBackend` unless you configure external dependency checks and opt into unverifiable readiness. Prefer implementing `HealthBackend` so Ridu can report dependency failures. ## Back up both halves {#backup} Back up the selected database's metadata, versions, and reference indexes together with the object namespace. Restore both to the same recovery point and test document reads, private delivery, representative checksums, and reconciliation. A database-only restore can reference missing bytes; an object-only restore can retain stale data. Read [Production](https://riducms.com/docs/production/) for deployment and restore drills and [Security](https://riducms.com/docs/security/) for trust and capability boundaries. --- # Production Canonical URL: https://riducms.com/docs/production/ Ridu deploys as one Go binary containing the API, operation engine, workers, generated schema, and static admin. PostgreSQL and MongoDB remain external durable dependencies; SQLite runs in the process against a local file. An optional object backend remains separate. Bun and Node are build-time tools, not production servers. > [!IMPORTANT] > SQLite supports one application host, a local filesystem, and small or local > workloads. Same-host processes can coordinate through SQLite's file locks, but horizontally > replicated Ridu deployments are not promised. The replica, rolling-deployment, and PostgreSQL > recovery guidance below does not widen that envelope. See [SQLite](https://riducms.com/docs/sqlite/) for its WAL-safe > deployment and recovery contract. > [!IMPORTANT] > MongoDB production support is limited to generated starter and blank projects on Linux x86-64, > Community 8.2.9, SCRAM-SHA-256, CA and hostname verified TLS, and a writable > three-member replica set. It does not cover Atlas, DocumentDB, Cosmos DB, standalone servers, > other versions/topologies/platforms, arbitrary scale, network-partition matrices, or PITR. See > [MongoDB](https://riducms.com/docs/mongodb/) for the exact boundary. ## Deployment checklist {#checklist} 1. Pin one coordinated Ridu release across the CLI, Go module, npm packages, and official plugins. 2. Run `ridu check` and application tests against committed generated contracts. 3. Create and review any schema migration; rehearse `ridu migrate verify` with the exact release in staging. MongoDB's final cutover verification runs command-scoped after the production drain. 4. Restore a recent selected-database and object-storage backup into staging and rehearse the plan at representative scale. 5. Build the production binary and immutable deployment image. 6. Follow the [abuse-prevention checklist](https://riducms.com/docs/preventing-abuse/) for access rules, authentication limits, hosts, origins, proxies, request bounds, uploads, and edge rate limiting. 7. For any release with a changed migration-history fingerprint—including a manifest change or a same-manifest data-only artifact—drain old PostgreSQL or MongoDB replicas and workers, or quiesce every same-host process using the SQLite file; follow the adapter's exact migration and recovery-point order below. 8. Start the new binary and wait for `/readyz` before sending traffic. 9. Exercise login, access-filtered reads, writes, drafts, uploads, tasks, and representative admin flows. 10. Keep monitoring and the complete prior recovery point through the rollback window. ## Build one runtime artifact {#build} ```sh title="terminal" npm run ridu -- check npm run ridu -- migrate verify npm run ridu -- build ``` `ridu build` resolves config, updates generated contracts, compiles the Svelte admin, embeds its assets and the exact ordered migration filename/digest fingerprint, and writes the Go binary to `dist/`. Build with the Go and Bun versions listed in [Releases and compatibility](https://riducms.com/docs/releases/) and committed locks. The runtime image needs the binary, certificates, and application environment; it does not need source, `node_modules`, Bun, or Node. A direct `go build` omits the fingerprint and therefore fails closed in ordinary production startup with an official database adapter. Run a PostgreSQL- or MongoDB-selected project with the exact migration history used during verification: ```sh title="terminal" DATABASE_URL="$DATABASE_URL" \ RIDU_ADDRESS=':8080' \ ./dist/content ``` A SQLite-selected project instead supplies an absolute local `RIDU_SQLITE_PATH`, keeps every process using that file on the same host, and does not horizontally replicate the deployment. Ridu never mutates the production schema at startup. The process performs readiness preflight before binding the listener and fails if the store, storage, complete applied migration history, executable manifest, or required maintenance contract cannot be verified. PostgreSQL, SQLite, and MongoDB all compare the live ordered ledger with the fingerprint embedded by `ridu build`. ## Configure the generated boundary {#environment} Generated projects expose the deployment-owned topology as environment: | Environment | Production use | | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `DATABASE_URL` | PostgreSQL URL using `sslmode=require`, `verify-ca`, or preferably `verify-full`; or a MongoDB URL selecting one database, SCRAM-SHA-256, replica set, and verified TLS. Plaintext and TLS fallback are rejected. | | `RIDU_SQLITE_PATH` | Absolute local SQLite file path or `file:` URI. Do not use a shared network filesystem or mount the file on multiple hosts. | | `RIDU_ADDRESS` | Listener address, default `:8080`. Put TLS at the platform edge unless the application deliberately supplies it elsewhere. | | `RIDU_POSTGRES_UPLOAD_LOCK_CONNECTIONS` | Additional bounded pool for cross-process object locks; default 4. Count it alongside document connections across all replicas. | | `RIDU_ALLOWED_HOSTS` | Comma-separated public hosts, optionally with ports. Set it because an empty list accepts any syntactically valid host for development compatibility. | | `RIDU_ALLOWED_ORIGINS` | Exact browser origins allowed to make [cross-origin requests](https://riducms.com/docs/cors/). Same-origin embedded admin traffic needs no entry. | | `RIDU_TRUSTED_PROXY_CIDRS` | Immediate proxy networks allowed to supply forwarded address and scheme. Leave empty when directly exposed. | | `RIDU_STRICT_TRANSPORT_SECURITY` | HSTS header value. Set only when HTTPS is permanent for the complete declared scope. | | `RIDU_READINESS_TIMEOUT` | Bound for combined database, object-storage, and custom readiness checks. | | `RIDU_READINESS_DRAIN_DELAY` | Time between becoming unready and beginning request shutdown. Unset or zero uses two seconds; a negative duration disables this propagation delay without disabling graceful shutdown. | | `RIDU_SHUTDOWN_TIMEOUT` | Bound for HTTP shutdown and runtime-resource cleanup. | | `RIDU_WORKER_DRAIN_TIMEOUT` | Bound for cooperative task and maintenance-worker drain. | Disable the readiness-propagation delay on platforms that atomically remove the old deployment from routing before sending its termination signal. For Kubernetes or a self-managed load balancer, choose it from measured endpoint/routing propagation and include it in the platform termination grace period; two seconds is a default, not a universal safe value. On Railway, where traffic cutover precedes termination, set `RIDU_READINESS_DRAIN_DELAY=-1s` and use the platform's separate drain window for in-flight work. `RIDU_ALLOW_INSECURE_DATABASE` is for an explicitly local database. `RIDU_ALLOW_UNVERIFIABLE_READINESS` is for a custom adapter only after equivalent external checks and auth maintenance exist. Neither is a remedy for a failing production dependency. Secrets belong in the platform secret store, not generated files or image layers. Rotate database, storage, signing, and external-provider credentials through an application-owned procedure that keeps readiness and rollback viable. For MongoDB, keep the running application on a database-scoped credential and use that or a selected database operator for `plan`, `status`, and `up`. Use separately scoped, short-lived credentials for verification and backups. Never make the application a cluster administrator to simplify operations. ## Harden HTTP and proxies {#http} The generated environment covers common topology. `HandlerOptions` and `ServerOptions` expose finer bounds: ```go title="cmd/server/main.go" ridu.WithHandlerOptions(ridu.HandlerOptions{ AdminAssets: adminassets.FS(), SecureCookies: true, AllowedHosts: []string{"cms.example.com"}, AllowedOrigins: []string{"https://app.example.com"}, AllowedRequestHeaders: []string{"X-Acme-Tenant"}, TrustedProxyCIDRs: []string{"10.0.0.0/8"}, MaxBodyBytes: 8 << 20, // 8 × 2²⁰ = 8,388,608 bytes (8 MiB) RequestTimeout: 20 * time.Second, ReadinessTimeout: 5 * time.Second, ContentSecurityPolicy: "default-src 'self'; object-src 'none'", Observe: observeRequest, Audit: recordAuditEvent, RequestError: reportTrustedError, JobError: reportWorkerError, }) ridu.WithServerOptions(ridu.ServerOptions{ ReadHeaderTimeout: 5 * time.Second, ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second, IdleTimeout: 60 * time.Second, ShutdownTimeout: 15 * time.Second, WorkerDrainTimeout: 15 * time.Second, ReadinessDrainDelay: 5 * time.Second, }) ``` The framework supplies conservative defaults; customize them from measured traffic. A negative request timeout is an explicit streaming opt-out and must be paired with endpoint-owned bounds. TLS termination must replace untrusted forwarding headers before traffic reaches a configured trusted proxy network. Keep CIDRs to immediate controlled hops. Secure cookies are enabled by the production executor unless `RIDU_SECURE_COOKIES=false`; never disable them behind a public HTTPS origin. Configure CORS only for intentional browser clients and list custom request headers explicitly. The default admin CSP is conservative and preview-compatible. Override it narrowly; disabling CSP because a plugin needs broad execution hides a supply-chain problem rather than fixing one. Use [Prevent abuse](https://riducms.com/docs/preventing-abuse/) for the public-traffic checklist and [Security](https://riducms.com/docs/security/) for the full trust boundary and request-work ceilings. ## Apply migrations as a deployment step {#migrations} Use the exact target binary and committed artifacts for planning and rehearsal: ```sh title="terminal" npm run ridu -- migrate plan --json npm run ridu -- migrate verify ``` Shadow replay checks migration history, not production data volume or lock timing. Rehearse against a recent restored backup, set migration timeouts below the deployment deadline, and stop old writers for every maintenance-classified artifact. PostgreSQL and MongoDB permit rolling overlap only for binaries embedding both the same manifest digest and the same migration-history fingerprint. For a MongoDB release with any new artifact—even an additive or same-manifest data-only one—the production cutover order is exact: drain old replicas and workers; run `verify` with its command-scoped operational URL; capture the matched database/upload snapshot; run `up` with the selected database-scoped application or operator URL; run `status` after `up`; then start the new binary with the application URL. SQLite does not promise horizontally replicated rollout overlap; quiesce every same-host process using the file for the migration cutover. Rollback mechanics are a separate concern from deployment overlap. PostgreSQL and MongoDB have no generated down migration, while SQLite exposes only the explicit reversible steps stored in its artifacts. A down migration can revert state, but it does not make incompatible application versions safe to run together; Ridu uses forward repair or complete recovery-point restoration instead. [Migrations](https://riducms.com/docs/migrations/) documents create/plan/status/verify/up, resumable boundaries, destructive and maintenance admission, stable safety codes, and immutable artifact validation. ## Liveness, readiness, and drain {#health} | Signal | Meaning | Use | | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | | `/healthz` | The process is alive. | Restart policy. It does not confirm a matching schema or reachable dependency. | | `/readyz` | The process is not draining and its migration ledger/manifest, document store, upload backend, and custom checks pass within the readiness timeout; MongoDB also verifies the exact Ridu-managed indexes. | Load-balancer traffic admission. | | `ridu migrate status` | Immutable ledger, phase/step completion, and managed database schema agree with committed history. | Explicit operator deployment/drift report; readiness does not replace it. | On `SIGTERM` or interrupt, Ridu marks the instance draining so readiness fails, waits the configured drain delay, performs bounded HTTP shutdown, cancels request contexts, drains cooperative workers, and closes runtime resources within a separate bound. If a task ignores context past the worker bound, its lease remains fenced and recovers after expiry. Set the platform termination grace period longer than readiness delay + longest admitted request + worker drain + resource-close budgets. Remove traffic on readiness before the platform sends a hard kill. ## Observe the application {#observability} Ridu keeps telemetry vendor-neutral: - `RequestObservation` reports request ID, method/path, status, response bytes, duration, and stable error code. - `AuditEvent` reports security-relevant actions with request ID, resolved client IP, action, collection/document target, and actor collection/document identity. - `RequestError` receives trusted internal causes and recovered-panic detail while the HTTP response remains redacted. - `JobError` receives worker and scheduled-operation infrastructure failures; handler retry state is also queryable through [durable tasks](https://riducms.com/docs/tasks/). - custom `ReadinessChecks` add required application or plugin dependencies without coupling Ridu to a metrics vendor. The diagnostic callback is trusted and must enforce its own redaction and access policy. Audit callbacks are structured observations, not a tamper-aware durable audit log. At minimum, alert on readiness failures, login throttle/recovery anomalies, migration and physical drift, exhausted database pools, repeated task retries or terminal failures, upload reconciliation deltas, elevated conflicts, and sustained latency or error-rate changes. Track RSS and connection use per replica; the [performance baseline](https://riducms.com/docs/performance/) is not capacity planning for your schema. ## Back up and test restoration {#backup} Back up the selected database and object storage as one recovery point. Retain the binary, configuration, generated manifest, and immutable migration history needed to interpret it. Database metadata without objects is incomplete; objects without matching references can retain stale data. Regularly restore into an empty isolated environment and verify: - migration ledger, `ridu migrate status`, and zero physical drift; - collection, global, version, task, and auth-state counts; - login, session rotation, access-filtered reads, update conflicts, and private upload delivery; - representative object hashes and image variants; - task claiming, scheduled publishing, and cleanup/reconciliation; and - measured recovery-point and recovery-time objectives. For PostgreSQL, logical dumps complement rather than replace managed point-in-time recovery. For SQLite, use an online backup or stop all processes using the file and quiesce WAL writers before a filesystem copy; never accept a copy of only the live main file. Restore the selected database and object storage to the same named point before accepting the drill. For MongoDB, drain writers, complete command-scoped `verify`, then create a database-scoped compressed archive with `mongodump --archive --gzip --dumpDbUsersAndRoles` before running `up`; pair it with the upload-storage backup from the same point. Restore into an empty target with `mongorestore --archive --gzip --drop --restoreDbUsersAndRoles`, restore uploads from the same named point, and confirm that unrelated databases were untouched. This is a logical dump/restore workflow, not point-in-time recovery. ## Stage, cut over, and roll back {#cutover} For a PostgreSQL or MongoDB code release with the same manifest and migration-history fingerprints, canary beside the previous binary and compare errors, p50/p95 latency, RSS, database connections, response checksums, tasks, private uploads, drafts, and conflicts. Shift traffic only after the replacement stays ready. For a MongoDB release with any new migration artifact: 1. Rehearse the exact sequence in staging, then drain every old process and worker in production. 2. Run `DATABASE_URL="$MONGODB_OPERATIONAL_URL" ridu migrate verify`. Append `--allow-maintenance` whenever the complete committed history contains semantic work, because clean-shadow verification replays every artifact. 3. After verification, capture the matched database/upload snapshot with a separately scoped backup identity. 4. Run `DATABASE_URL="$MONGODB_MIGRATION_URL" ridu migrate up`, where the selected URL is the database-scoped application or controlled operator identity. Append `--allow-maintenance` only when the pending or incomplete history suffix contains semantic work. 5. Run `DATABASE_URL="$MONGODB_MIGRATION_URL" ridu migrate status` and require exact complete history and managed indexes. 6. Start only the target release binary carrying the expected manifest and migration-history fingerprints with `$MONGODB_APP_URL`, wait for readiness, and run acceptance checks. 7. Prefer a forward corrective migration. Restore only when the entire database/object pair and compatible binary can return to the same point. For PostgreSQL, use its documented drain, recovery-point, `up`, and post-apply `status` contract; SQLite requires every same-host process to be quiesced. Retry an immutable artifact after fixing an operational blocker rather than editing it. Use expand–migrate–verify–contract across separate reviewed releases for large transformations, while keeping each migration-history boundary on the documented coordinated cutover. A dual-manifest admission contract would be an optional deployment enhancement for teams with a strict zero-downtime requirement, not a prerequisite for safe production use. Review [Releases and compatibility](https://riducms.com/docs/releases/) for supported platforms and upgrade policy, [PostgreSQL](https://riducms.com/docs/postgres/) for pools and transactions, [SQLite](https://riducms.com/docs/sqlite/) for the embedded operating envelope, [MongoDB](https://riducms.com/docs/mongodb/) for its bounded replica-set profile, and [Object storage](https://riducms.com/docs/storage/) for backend and reconciliation requirements. --- # Migrations Canonical URL: https://riducms.com/docs/migrations/ Ridu derives PostgreSQL and MongoDB migrations from executable Go config, but it never treats a schema diff as permission to change a database. The CLI writes an immutable artifact for review, verifies complete history in an isolated shadow target, and applies it only through an explicit command. > [!NOTE] > This page covers the shared forward workflow and the PostgreSQL and MongoDB production runners. > SQLite uses its own immutable planner and explicit reversible lifecycle; see > [SQLite migrations](https://riducms.com/docs/sqlite/#migrations). > [!IMPORTANT] > Ridu does not run production migrations when the server starts and does not generate an automatic > down contract for PostgreSQL or MongoDB. Rehearse on restored data and prefer a forward > corrective migration after deployment. During the MongoDB cutover, capture the matched > selected-database/upload recovery point after the drained production `verify` and before `up`. ## The ordinary workflow {#workflow} Change application config, then create and inspect one artifact: ```sh title="terminal" npm run ridu -- migrate create --name add-post-summary npm run ridu -- migrate plan npm run ridu -- migrate verify ``` Commit the `*.ridu.json` file with the config and generated-contract changes. Deploy the exact binary and artifact history that passed verification. This preparation example is not the MongoDB production cutover order; follow the exact sequence under [Deployment and recovery](#deployment-recovery). | Command | Database connection | What it does | What it never does | | -------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | `create` | No | Resolves current config, compares it with the latest artifact manifest, detects renames, binds a compiled transform when selected, plans phases, and writes one immutable artifact. | It does not inspect or change the database. | | `plan` | Yes | Compares local history with the database and shows each artifact, phase, step, and committed checkpoint. Add `--json` for automation. | It does not apply a step. | | `status` | Yes | Reports applied and pending artifacts and checks the exact ledger and adapter-managed physical state. | It does not repair drift or apply history. | | `verify` | Yes | Creates a random temporary PostgreSQL schema or MongoDB database, replays complete admitted history, checks final assertions/readiness, then drops that exact target. | It does not test production data volume, lock timing, or content-specific collisions. It cannot stop at a phase or step. | | `up` | Yes | Validates history and the ledger, takes the adapter's bounded migration lock/lease, and applies pending work with durable resumption where supported. | It does not invent a rollback or bypass a safety finding. | Every command except `create` requires a non-empty artifact history whose newest manifest digest matches executable config. This prevents a database from being reported as current while config and migrations describe different applications. Supply PostgreSQL or MongoDB through `DATABASE_URL` or `--database-url`. ## What is in an artifact {#artifact} An artifact records the information needed to identify and re-run the transition: - the full before and after manifests and their SHA-256 digests; - the artifact, planner, and runner contract versions; - stable phase and step IDs, execution modes, physical-state lineage, and a final assertion; - confirmed collection and field rename intent; and - machine-readable safety findings with notice, warning, or destructive severity. PostgreSQL artifacts can use atomic transaction phases, checkpointed batch phases, and narrowly typed non-transactional concurrent-index phases. New MongoDB planner contract `2.0.0` artifacts emit only their typed physical index, confirmed rename, compiled-transform, retirement, and assertion steps; it does not embed arbitrary driver commands. Authenticated planner-`1.0.0` history remains a supported immutable prefix to v2 and is validated and replayed rather than rewritten. Arbitrary non-transactional SQL is not admitted. Formatting-only JSON changes do not alter the canonical artifact digest, but renaming, reordering, removing, editing, or inserting applied history is detected by the database ledger. Never edit an applied artifact. If a deployment needs correction, restore the committed history and create a new forward migration. ## Renames preserve identity {#renames} When a slug or field path changes, `create` proposes only unambiguous one-to-one candidates: ```text Detected field rename "posts".title -> "posts".headline. Preserve its existing data as a rename? [Y/n] ``` Confirm interactively or use `--accept-renames` only after reviewing every proposed match. Ridu can then preserve physical tables, columns, indexes, constraints, nested stored values, versions, auth state, task references, polymorphic relationships, and declared plugin reference keys as the specific transition requires. Ambiguous mappings are rejected rather than guessed. Collection slug swaps and chains must be split into separate artifacts with a temporary slug so a value cannot be rewritten twice. Application task input and arbitrary JSON remain opaque; the generic runner never searches them heuristically. ## Destructive and maintenance admission {#admission} Safety flags have the following scope: | Admission | Accepted by | Meaning | | --------------------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `--allow-destructive` | `create` | Record a planner-confirmed destructive finding in the artifact after review. It does **not** connect to or change a database. | | `--allow-maintenance` | `verify`, `up` | Admit a traffic-sensitive phase after every old application process, writer, and worker has been stopped. Keep them stopped through retries until `status` is complete. | | `--allow-insecure-database` | database-backed commands | Permit plaintext or bypass certificate verification only for a local PostgreSQL or MongoDB environment. `create` is offline and rejects the flag. | | `--allow-unbounded` | `up`, `verify` | Permit an applicable zero runner wait/timeout. Ordinary production defaults remain bounded; MongoDB lease expiry is always bounded. | Deleting ordinary resources can require both destructive approval at creation and maintenance approval at execution because the runner also purges sessions, credentials, versions, tasks, preferences, locks, and reference-index state. Removing an upload collection also requires moving or deleting its external objects yourself; the database artifact cannot do that work, so the planner fails closed even with `--allow-destructive`. ## Common safety codes {#safety-codes} Stable codes are intended for CI policy and runbook search, not for bypass scripts. | Code | What it protects | Safe response | | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | `RIDU_MIGRATION_PLAN_MISMATCH` | The artifact no longer exactly matches the plan regenerated from its embedded manifests and rename intent. | Restore or recreate the reviewed artifact; do not trust or apply the changed file. | | `RIDU_REFERENCE_SHAPE_DECREASE_UNSAFE` | Stored current values or version snapshots could retain dormant references after a field/target/cardinality decrease. | Keep the shape, remove the entire owning root with typed retirement, or design an application-owned data-cleanup contract first. | | `RIDU_REFERENCE_RENAME_MAPPING_AMBIGUOUS` | A source or destination field is mapped more than once. | Split the change into unambiguous artifacts. | | `RIDU_COLLECTION_SLUG_REWRITE_OVERLAP_UNSAFE` | A collection rename chain or swap could rewrite a value twice. | Use a unique temporary slug across separate reviewed artifacts. | | `RIDU_UPLOAD_COLLECTION_REMOVAL_UNSAFE` | A database migration cannot manage external objects. | Transfer/delete through upload operations, reconcile, and verify matched backups; retain the collection until a typed retirement path exists. | | `RIDU_AUTH_DISABLE_STATE_UNSAFE` and related `*_DISABLE_STATE_UNSAFE` codes | Disabling auth, API keys, recovery, verification, versions, drafts, locks, or trash could leave dormant state that reactivates later. | Keep the capability enabled or introduce the narrower cleanup contract the finding requires. | | `RIDU_RETIRE_DEPENDENT_VERSION_HISTORY` | Resource retirement must also delete dependent owner history to prevent references from returning on restore. | Treat the version-history loss as destructive and include it in backup, review, and acceptance. | The error is useful information. `--allow-destructive` does not silence semantic safeguards. ## Applying and resuming {#apply-resume} Shared artifact-envelope format `1` remains the committed history contract. PostgreSQL writes phase and step progress separately: an interrupted transaction leaves neither its data nor step rows, a batch resumes after its last committed keyset checkpoint, and a concurrent index resumes from catalog state or removes an invalid interrupted build before retrying the reviewed definition. New MongoDB planner contract `2.0.0` artifacts use that same immutable format-`1` envelope. The runner authenticates and replays a committed planner-`1.0.0` prefix before v2 artifacts, takes a fenced, expiring lease, records completed steps durably, recognizes already-completed physical work, and resumes the same artifact after an interrupted process. It never treats process exit or lease expiry alone as completion. Production defaults bound PostgreSQL advisory-lock, statement, batch, concurrent-index, and idle transaction work, plus MongoDB lease waits and complete migration operations. PostgreSQL `up` can stop after a committed boundary with `--stop-after-phase` or `--stop-after-step`; qualify a repeated ID as `/`. MongoDB rejects explicit stop boundaries and instead resumes from durable progress after interruption. `verify` always replays to completion. Use `plan --json` and `status --json` to feed deployment automation. Do not infer success merely from process exit after a requested stop boundary: `status` must show the complete target history before application readiness can pass. ## Deployment and recovery {#deployment-recovery} Only binaries with the same manifest digest and migration-history fingerprint may overlap. Rehearse on a restored recovery point before production. For a MongoDB release with any new artifact, including an additive or same-manifest data-only artifact, use this exact production sequence: 1. Drain every old application replica and worker. 2. Run `DATABASE_URL="$MONGODB_OPERATIONAL_URL" ridu migrate verify` so shadow-database authority is scoped to that command. Append `--allow-maintenance` whenever the complete committed history contains semantic work, because clean-shadow verification replays every artifact. 3. After verification succeeds, capture the matched selected-database and upload recovery point with a separate least-privilege credential such as `$MONGODB_BACKUP_URL`. 4. Run `DATABASE_URL="$MONGODB_MIGRATION_URL" ridu migrate up` with the selected database-scoped application or controlled operator identity. Append `--allow-maintenance` only when the pending or incomplete history suffix contains semantic work. 5. Run `DATABASE_URL="$MONGODB_MIGRATION_URL" ridu migrate status` and require complete history and exact Ridu-managed indexes. 6. Start only the target release binary carrying the expected manifest and migration-history fingerprints using `$MONGODB_APP_URL`, then wait for `/readyz`. Semantic work includes persisted content renames, compiled transforms, reference-index rebuilds, and typed resource retirement. MongoDB `verify` requires maintenance admission whenever any of that work appears in the complete committed history; `up` requires it only when the pending or incomplete suffix contains that work. The flag is an assertion that old writers are stopped, not a lock that stops them for you. See [PostgreSQL](https://riducms.com/docs/postgres/) or [MongoDB](https://riducms.com/docs/mongodb/) for connection and adapter-specific recovery configuration, [Production](https://riducms.com/docs/production/) for the wider cutover checklist, [Security](https://riducms.com/docs/security/) for trust boundaries, and [Troubleshooting](https://riducms.com/docs/troubleshooting/#migration-refused) for failure-first diagnosis. --- # Performance and footprint Canonical URL: https://riducms.com/docs/performance/ One Go process serves Ridu's API and embedded admin; Node and package managers are not production services. The benchmark below measures that process for one editorial application. Use the method at the end of this page to measure your own schema and workload. > [!NOTE] > These are local benchmark results, not a service-level objective. ## Headline baseline {#headline} The 15 August 2026 reference run compared Ridu with Payload 3.87.0 on the same Apple M2 Max and shared local PostgreSQL 16.12 server. The values are medians of three trials with alternating server order. | Runtime state | Ridu RSS | Payload RSS | Ridu reduction | | ------------------------------- | --------: | ----------: | -------------: | | Idle, PostgreSQL connected | 26.86 MiB | 182.27 MiB | 85.3% | | After first admin HTML response | 26.86 MiB | 220.17 MiB | 87.8% | | After 250 additional documents | 32.56 MiB | 290.66 MiB | 88.8% | | Highest median workload peak | 36.95 MiB | 493.17 MiB | 92.5% | Idle RSS ranged from 26.00–26.89 MiB for Ridu and 181.69–183.17 MiB for Payload across the three trials. PostgreSQL memory is excluded because both applications used the same server. RSS includes the complete application process tree and was sampled asynchronously while the load ran. Do not use the 27 MiB idle result as a production sizing estimate without testing your application. ## What the run exercised {#method} Each fresh trial seeded equivalent editorial applications and 250 additional published posts, then ran: - 3,000 selected-field list reads and 3,000 selected-field point reads at concurrency 16; - 300 authenticated draft creates, updates, and deletes at concurrency 8; and - 300 admin HTML requests at concurrency 8. Schema migration, deterministic seeding, warmup, and settling were outside the timed windows. Every timed request had to return its expected `200` or `201`; the reference run completed 43,200 timed requests without an unexpected status. The environment was macOS 26.2 with 32 GiB RAM, Go 1.25.7, Bun 1.3.14, Node 24.13.0, and fresh databases on PostgreSQL 16.12. These historical tool versions describe the run; consult the repository's current compatibility policy before reproducing it. ## REST results {#rest-results} Latencies are p50 / p95 / p99 in milliseconds. Measure a restored application before using these numbers for capacity planning. | Operation | Concurrency | Ridu req/s | Payload req/s | Ridu latency | Payload latency | | ----------------------- | ----------: | ---------: | ------------: | ------------------ | --------------------- | | List 10 published posts | 16 | 9,988 | 1,322 | 1.48 / 2.37 / 4.55 | 11.73 / 16.07 / 19.51 | | Find one published post | 16 | 19,732 | 2,196 | 0.78 / 1.25 / 1.65 | 6.32 / 10.34 / 32.49 | | Create draft | 8 | 3,748 | 377 | 2.01 / 2.91 / 3.29 | 20.30 / 28.10 / 31.03 | | Update draft | 8 | 3,738 | 288 | 2.06 / 2.69 / 3.29 | 27.08 / 35.41 / 40.72 | | Delete draft | 8 | 4,885 | 327 | 1.61 / 2.09 / 2.53 | 24.01 / 29.99 / 37.88 | Reads selected equivalent application fields and disabled Payload population with `depth=0`. The wire formats were not identical: Ridu's selected-list response was larger in this run, 2,796 bytes versus 1,348 bytes. Writes used administrator accounts and exercised draft versions and deletion through trash-enabled Posts collections. A focused Payload run at mutation concurrency 16 exceeded a ten-second update deadline after its creates completed. Ridu completed the same focused stages. An observation of Payload sessions idle in transaction was consistent with pool starvation, but did not prove the cause, so the completed headline write comparison uses concurrency 8 for both systems. ## Admin response and artifact size {#admin-and-artifact} | Measurement | Ridu | Payload | | ------------------------------ | -----------: | -----------: | | Cold admin HTML response | 1.14 ms | 391.66 ms | | Warm admin HTML throughput | 54,472 req/s | 260 req/s | | Warm admin HTML p95 | 0.23 ms | 43.28 ms | | HTML response size | 454 bytes | 50,267 bytes | | Production deployment artifact | 17.32 MiB | 76.39 MiB | This measures the server response, not the author's experience in a browser. Ridu returns a small static SPA entry and serves assets embedded in its binary; Payload server-renders the initial React document. The test did not time JavaScript and CSS downloads, parsing, route chunks, rich-text startup, or interaction readiness. The Ridu artifact was one stripped binary with admin assets embedded. Payload's value was its Next standalone directory with `.next/static` copied in. That traced directory also retained modules for the sample application's SQLite fallback, so the artifact-size comparison is less controlled than the RSS result. ## What this baseline does not cover {#limitations} The benchmark does not cover: - the dataset is modest and all traffic is loopback-only; - byte-for-byte identical applications; - relationship-heavy, access-filter-heavy, localized, upload and image-processing, job, and 10,000-plus-document workloads were not tested; - admin browser download, parse, route, rich-text, and interaction timing were not measured; - three local trials are not a hardware matrix or statistical confidence study; and - CPU profiles and Go allocation profiles were not captured. ## Measure your application {#measure-your-application} The harness and exact rerun instructions live in `tests/performance/` in the Ridu repository. Use them to reproduce the reference before changing the sample application, then add a workload representative of your own collections, access filters, relationships, and uploads. For deployment sizing, record at least idle and peak RSS, request latency percentiles, database connection use, response sizes, build artifact size, browser interaction timings, and behaviour under your expected concurrency. Run more than one trial on the target operating system and test a realistic restored dataset rather than extrapolating from this page. See [Production](https://riducms.com/docs/production/) for operational readiness, [PostgreSQL](https://riducms.com/docs/postgres/) and [SQLite](https://riducms.com/docs/sqlite/) for the official stores, and [Coming from PocketBase](https://riducms.com/guides/from-pocketbase/) or [Move from Payload](https://riducms.com/guides/from-payload/) for product-level trade-offs. --- # Prevent abuse Canonical URL: https://riducms.com/docs/preventing-abuse/ Use this page before exposing a Ridu application to public traffic. Ridu bounds the work one request can ask the framework to perform, but it cannot decide who should write your content or how much traffic one customer is allowed to send. Configure both the application and its public edge. ## Before you go public {#checklist} 1. Add explicit collection and field access rules. In particular, do not leave public create, update, delete, upload, or administrative operations open. 2. Keep account lockout enabled and configure HTTP authentication throttling for the traffic you expect. 3. Set the public host, exact browser origins, trusted proxy networks, request size, and request deadline. 4. If GraphQL is enabled, keep introspection off and choose limits from representative queries. 5. Give every upload collection a narrow MIME allow-list, useful size limit, and appropriate access rules. 6. Put tenant-, actor-, route-, and IP-aware rate limiting at the load balancer, gateway, or CDN. 7. Monitor Ridu's stable rejection codes so a limit protects the service without silently breaking legitimate clients. The following sections provide a usable starting point for each item. ## Restrict writes first {#access} Access rules are the most important abuse control. A hidden admin action or a TypeScript type does not protect the corresponding API route. Collection and field rules run on REST, GraphQL, the generated SDK, and local operations. For a typical editorial collection, public users may read published content while authenticated authors create content and can only update or delete documents they own. Implement that policy in Go before adding a public frontend. The [Access control guide](https://riducms.com/docs/access-control/) includes the complete `signedIn` and ownership-filter examples; filtered update and delete decisions remain part of the database operation rather than becoming a post-query check. Review special operations too. Draft publication, trash, version restore, document unlock, upload delivery, auth user creation, API keys, plugin endpoints, and custom endpoints each need the smallest access surface the application requires. ## Limit login and recovery attempts {#authentication} An auth collection has two complementary defenses: - `MaxLoginAttempts` locks one account after consecutive credential failures. It defaults to `5`. - `HandlerOptions.AuthRateLimit` limits HTTP login, recovery, and verification attempts by client and identity. It defaults to `10` attempts per minute and is stored through the selected official adapter, so restarting or changing replicas does not clear it. Keep the account lockout explicit when defining users: ```go title="content/users.go" package content import ( "time" "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) var Users = ridu.Collection{ Slug: "users", Auth: true, AuthConfig: ridu.AuthConfig{ MaxLoginAttempts: 5, LockDuration: 15 * time.Minute, Password: ridu.PasswordPolicy{ MinLength: 12, MaxBytes: 72, }, }, Fields: []field.Definition{ field.Email("email", field.Required(), field.Unique()), }, } ``` Ridu returns the same credential error for an unknown account, wrong password, and locked account. Do not replace that response with application code that reveals whether an email address exists. If users can register themselves, enable email verification and apply bot protection at the public registration boundary. See [Authentication](https://riducms.com/docs/authentication/#password-policy) for recovery, verification, password validation, and administrative unlocks. ## Bound the HTTP server {#http-boundary} Generated projects already contain the following `HandlerOptions` block in `cmd/server/main.go`. Add the highlighted request and authentication limits alongside its existing host, origin, proxy, readiness, and HSTS settings: ```go title="cmd/server/main.go" add={6-9} ridu.WithHandlerOptions(ridu.HandlerOptions{ AdminAssets: adminassets.FS(), AllowedOrigins: envList("RIDU_ALLOWED_ORIGINS"), AllowedHosts: envList("RIDU_ALLOWED_HOSTS"), TrustedProxyCIDRs: envList("RIDU_TRUSTED_PROXY_CIDRS"), MaxBodyBytes: 1 << 20, // 1 × 2²⁰ = 1,048,576 bytes (1 MiB) AuthRateLimit: 5, AuthRateWindow: 5 * time.Minute, RequestTimeout: 20 * time.Second, ReadinessTimeout: envDuration("RIDU_READINESS_TIMEOUT"), StrictTransportSecurity: os.Getenv("RIDU_STRICT_TRANSPORT_SECURITY"), }) ``` This is a starting point, not a universal production value. Confirm that normal imports, rich-text documents, hooks, and custom endpoints finish within the chosen body and time limits. A custom or plugin endpoint can declare a smaller `MaxBodyBytes`; a negative endpoint value opts that trusted handler out of the shared body limit and therefore needs its own bound. Set the deployment environment as narrowly as possible: ```sh title=".env" RIDU_ALLOWED_HOSTS=cms.example.com RIDU_ALLOWED_ORIGINS=https://app.example.com RIDU_TRUSTED_PROXY_CIDRS=10.20.0.0/24 RIDU_STRICT_TRANSPORT_SECURITY=max-age=31536000 ``` Leave `RIDU_ALLOWED_ORIGINS` empty when every browser client is same-origin. Only list the origins where trusted browser code runs. Configure `RIDU_TRUSTED_PROXY_CIDRS` with the immediate proxy networks you operate, not every possible client address. Otherwise an attacker can influence the scheme or client IP Ridu uses for origin checks and throttling. The production executor enables secure cookies. If your application constructs `app.Handler` directly, set `SecureCookies: true` yourself whenever the public URL uses HTTPS. ## Keep browser requests same-origin {#csrf-and-cors} Ridu's session cookie is HTTP-only and `SameSite=Lax`. For state-changing requests, Ridu also checks the `Origin` header and rejects cross-site browser requests without an allowed origin. When an `Origin` header is absent, a mutating request identified by `Sec-Fetch-Site: cross-site` is rejected as well. This protection depends on an accurate public scheme and host. If TLS terminates before the Go process, trust only that proxy and make sure it replaces untrusted forwarded headers. Test a denied origin before launch: ```sh title="terminal" curl -i -X POST 'https://cms.example.com/api/collections/posts' \ -H 'Content-Type: application/json' \ -H 'Origin: https://untrusted.example' \ --data '{"title":"Should not be accepted"}' ``` The response should be `403` with `origin_denied`. Then exercise the same route from each intended browser origin. CORS only permits the browser to send a request; authentication and access rules still decide whether it succeeds. The [CORS guide](https://riducms.com/docs/cors/) covers credentialed SDK requests, custom headers, preflights, and proxy diagnosis. ## Keep queries finite {#query-limits} REST list requests default to 10 documents and reject a `limit` above 100. Relationship population has a hard maximum depth of 5 and a response may materialize at most 4,096 related documents. Filters, selected fields, sort fields, JSON nesting, body size, and validation output are also bounded. Clients should request the smallest page and explicit population paths they actually use. GraphQL is absent unless the application imports and registers the GraphQL plugin. If you do not need it, remove `graphqlplugin.New()` and its import. If you do need it, start below the framework defaults and raise a limit only after measuring a legitimate operation: ```go title="content/config.go" add={12-19} package content import ( "github.com/riducms/ridu" graphqlplugin "github.com/riducms/ridu/plugins/graphql" ) func Config() ridu.Config { return ridu.Config{ Name: "Acme Editorial", Plugins: []ridu.Plugin{ graphqlplugin.New(graphqlplugin.Options{ MaxBodyBytes: 512 << 10, // 512 × 2¹⁰ = 524,288 bytes (512 KiB) MaxVariableBytes: 128 << 10, // 128 × 2¹⁰ = 131,072 bytes (128 KiB) MaxDepth: 8, MaxAliases: 30, MaxComplexity: 500, MaxListLimit: 50, }), }, Collections: []ridu.Collection{Users, Posts}, } } ``` Introspection remains disabled unless `AllowIntrospection` is explicitly set. Relationship and upload selections cost more than scalar reads, and custom root fields must declare a realistic `Cost`. Read [GraphQL safeguards](https://riducms.com/docs/graphql/#limits) before changing these values. ## Treat uploads as untrusted {#uploads} Do not make an upload collection writable merely because its files are intended to become public. Restrict who can create and replace media, then specify the file types and size the application actually needs: ```go title="content/media.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) func authenticatedOnly(ctx ridu.AccessContext) (ridu.AccessDecision, error) { if ctx.Actor == nil { return ridu.Deny(), nil } return ridu.Allow(), nil } var Media = ridu.Collection{ Slug: "media", Upload: true, UploadConfig: ridu.UploadConfig{ MaxFileSize: 10 << 20, // 10 × 2²⁰ = 10,485,760 bytes (10 MiB) MimeTypes: []string{"image/jpeg", "image/png"}, Private: true, }, Access: ridu.CollectionAccess{ Create: authenticatedOnly, Read: authenticatedOnly, Update: authenticatedOnly, Delete: authenticatedOnly, }, Fields: []field.Definition{ field.Text("alt", field.Required()), }, } ``` Ridu enforces the collection's byte limit, detects MIME type from the file contents, bounds image dimensions and generated-image work, normalizes names and paths, and sends active content as a download with restrictive response headers. Remote imports also reject private network targets, unsafe redirects, and oversized responses. The zero-value upload size is 10 MiB, while an empty MIME list accepts images and generic binary content. Prefer an explicit allow-list for an internet-facing collection rather than relying on that general-purpose default. Those controls do not scan for malware or moderate what an image depicts. If the application accepts files from untrusted public users, use a trusted pre-ingestion or quarantine service before publishing them. Ridu does not currently provide built-in malware quarantine. See [Uploads and media](https://riducms.com/docs/uploads/#limits) for the complete boundary. ## Rate-limit public traffic at the edge {#edge-rate-limits} Ridu's distributed limiter protects authentication operations; it is not a general API quota. Apply rate limits before traffic reaches the Go process, especially for: - login, recovery, verification, and public registration routes; - collection writes, bulk actions, uploads, remote imports, and custom endpoints; - GraphQL and expensive read routes that populate relationships; - any route billed to a tenant or integrated with a paid external service. Prefer an authenticated actor or tenant key when one exists, with a client-IP fallback for anonymous traffic. Add separate burst and sustained limits instead of one very low global limit, and count all application replicas together. If the edge forwards client addresses, configure the exact immediate proxy CIDRs in Ridu and strip client-supplied forwarding headers there. Do not rely on an IP limit as authorization, and do not return a successful cached response for a write. A rejected request should use `429 Too Many Requests` and a useful retry interval. ## Monitor rejections {#monitoring} Set `HandlerOptions.Observe` to export request duration, status, response size, and Ridu's stable error code. Alert on sustained changes rather than individual bad requests: | Error code | Usually means | | ------------------------------------------ | ------------------------------------------------------------------------- | | `rate_limited` | Ridu rejected an authentication or bounded-work admission | | `origin_denied` | A browser origin or cross-site mutation did not pass policy | | `host_denied` | The request used a host outside `AllowedHosts` | | `body_too_large` | A REST JSON or multipart request exceeded its byte limit | | `body_too_complex` | JSON exceeded its structural budget | | `bad_query` | A list, filter, selection, or population exceeded query rules | | `request_too_large`, `variables_too_large` | A GraphQL body or encoded variables exceeded the plugin limit | | `graphql_*_exceeded` | A GraphQL query exceeded its depth, alias, fragment, or complexity budget | | `request_timeout` | Work outlived the configured handler deadline | | `access_denied` | Authentication or an application access rule rejected the action | Never record credentials, cookies, reset tokens, API keys, complete request bodies, or private upload URLs in an abuse log. Use the request ID to correlate the public response, observation, audit event, and trusted internal error report. ## Troubleshooting {#troubleshooting} | Symptom | What to check | | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | Every browser write returns `origin_denied` | Compare the exact scheme, host, and port; then check whether the TLS proxy is inside `TrustedProxyCIDRs`. | | Real users receive `rate_limited` too quickly | Distinguish HTTP auth throttling from per-account lockout, inspect the resolved client IP, and tune from measured traffic. | | Changing the email still produces `429` | Auth throttling includes a client-wide bucket so attackers cannot bypass it by rotating identities. | | A legitimate document returns `body_too_large` | Measure its encoded request, then raise only the relevant shared or endpoint limit; do not disable every body limit. | | A valid upload reports the wrong allowed type | Ridu uses detected bytes, not the browser filename or claimed `Content-Type`; add only the detected MIME type if the application genuinely accepts it. | | GraphQL rejects a normal application query | Remove unused selections, lower list sizes, avoid repeated aliases, and then adjust the measured complexity budget if necessary. | Continue with [Production](https://riducms.com/docs/production/), [Security model](https://riducms.com/docs/security/), [Authentication](https://riducms.com/docs/authentication/), [Access control](https://riducms.com/docs/access-control/), and [Uploads and media](https://riducms.com/docs/uploads/). --- # Security model Canonical URL: https://riducms.com/docs/security/ Ridu's central security rule is simple: authoring UI state is never authority. REST, GraphQL, the generated SDK, the admin, local operations, hooks, and durable tasks converge on server-owned schema, access, validation, transaction, and redaction contracts. The table below separates Ridu's controls from the security work owned by your application and infrastructure. ## Trust boundaries {#trust-boundaries} Ridu protects content and version history, credentials and sessions, private uploads, migration identity, task data, preview capabilities, and generated application contracts. 1. An untrusted browser or API client reaches the Go HTTP server through deployment-owned TLS and optional trusted proxies. 2. The server authenticates, authorizes, validates, runs hooks, and applies field redaction before one official store transaction observes or mutates content. 3. The selected database and object storage are separate durable systems. Staged-object rollback, locks, last-reference scans, reconciliation, and matched backups bridge the fact that they cannot share one atomic commit. 4. The Svelte admin and static admin plugins execute in the browser. They improve authoring but cannot grant server access. 5. Go config, hooks, validators, task handlers, and backend plugins execute inside the trusted server process. Installing one is equivalent to installing application code; Ridu does not sandbox it. Operators, application authors, and compiled plugins can control the process and its credentials. Treat authors, clients, compromised browser state, uploaded bytes, remote URLs, headers, filters, GraphQL documents, generated-client input, and stored application content as untrusted. ## Framework and deployment responsibilities {#responsibilities} | Surface | Ridu enforces | You must provide | | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | REST and GraphQL | Body/query/token/member/depth bounds, stable errors, panic redaction, atomic access predicates, field redaction, optimistic conflicts, and bounded population/complexity. | Independent edge and abuse limits for public high-volume APIs, plus monitoring of rejection and error rates. | | Sessions and credentials | Bounded bcrypt admission, generic auth failures, distributed login/recovery/verification throttles, rotation/revocation, HTTP-only secure/SameSite cookies, CSRF and origin checks. | Signing-secret protection, HTTPS, allowed origins, and application-specific password and identity policy. | | Hosts and proxies | Explicit allowed hosts/origins, trusted-proxy CIDRs, CORS, CSP, security headers, and optional HSTS. | Only the public hosts you serve and immediate proxy networks; forwarding-header stripping; HSTS only behind permanent HTTPS. | | Uploads | Size and MIME admission, name and path normalization, namespace ownership, image work bounds, SSRF-safe remote fetches, private delivery checks, object locks, rollback, and reconciliation. | Malware scanning/quarantine where required, a production storage backend, and matched database/object backups. | | PostgreSQL | TLS required by default, bounded pools and waits, atomic predicates, row/advisory locks, immutable migration ledger, destructive/maintenance preflight, and manifest-aware readiness. | Least-privilege roles, verified TLS where possible, managed backup/PITR, restored-data rehearsals, and physical-drift checks with `ridu migrate status`. | | SQLite | Pure-Go local-file store, WAL and foreign-key enforcement, bounded waits, atomic predicates, immutable migration ledger, reversible lifecycle atomicity, and manifest/physical readiness. | One host, a local filesystem, small/local workloads, WAL-safe backup/recovery drills, and no shared network filesystem or horizontally replicated topology. | | MongoDB | Verified TLS by default, writable replica-set admission, bounded pools/lease waits, exact immutable ledger/index readiness, atomic predicates, credential redaction, and crash-safe resume. | The supported version, topology, and platform; SCRAM-SHA-256; CA and hostname verification; least-privilege operational credentials; and matched drills. | | Durable tasks | Compiled handler registry, strict typed input, leases, heartbeat fencing, retry/backoff, concurrency keys, cancellation, retention bounds, and graceful drain. | Idempotent external effects and monitoring of retries and terminal failures. | | Admin and plugins | Embedded CSP-compatible admin, exact manifest/plugin pairing, server-owned permission checks, and origin/source/channel-bound preview messaging. | Dependency review; treat frontend and compiled plugins as shipped trusted code; never expose dev servers publicly. | | Supply chain | Version compatibility checks and generated-contract drift detection. | Pin and review dependencies; protect the repository, registry, secrets, and deployment identity. | ## Configure the HTTP boundary {#http-boundary} Generated applications expose the relevant policy through `HandlerOptions`: ```go title="cmd/server/main.go" ridu.WithHandlerOptions(ridu.HandlerOptions{ AdminAssets: adminassets.FS(), SecureCookies: true, AllowedOrigins: []string{"https://admin.example.com"}, AllowedHosts: []string{"cms.example.com"}, TrustedProxyCIDRs: []string{"10.0.0.0/8"}, MaxBodyBytes: 8 << 20, // 8 × 2²⁰ = 8,388,608 bytes (8 MiB) RequestTimeout: 20 * time.Second, StrictTransportSecurity: "max-age=31536000; includeSubDomains", }) ``` List trusted proxies narrowly. Forwarding headers are accepted only from configured networks; an over-broad CIDR lets an untrusted hop influence scheme or client-address decisions. Enable HSTS only when HTTPS is permanent for its complete declared scope. The browser SDK includes credentials by default. Keep origins exact, cookies secure in production, and custom request headers explicitly allowed. Follow [CORS](https://riducms.com/docs/cors/) for same-origin rules, generated-project configuration, preflights, and proxy diagnosis; see [Authentication](https://riducms.com/docs/authentication/) for session and account flows. ## Authorization is server work {#authorization} Admin visibility, disabled buttons, generated TypeScript types, object keys, and signed URLs are not authorization. Collection and field rules run inside the operation engine, and filtered decisions remain part of the atomic store query for reads, updates, and deletes. An authenticated principal is the pair `{auth collection, document ID}`. Do not assume document IDs are globally unique across auth collections. REST, GraphQL, local calls, hooks, preview, locks, uploads, scheduled work, and audit events preserve both values. A nil actor is anonymous, not an administrator. Private upload delivery checks collection access before returning bytes. Treat an object key or signed URL as a capability and avoid logging it casually, but never use possession as the content access policy. ## Bounded work {#bounded-work} Ridu rejects expensive or ambiguous work before it becomes an unbounded database or serialization problem. Important framework ceilings include: | Bound | Current ceiling | Why it exists | | ------------------------------------------------------------- | --------------: | -------------------------------------------------------------------------------------------- | | Relationship and upload occurrences in one document mutation | 512 | Bounds recursively nested reference maps and store admission across effective locales. | | Validation issues returned for one operation | 128 | Keeps adversarial invalid input from creating an unbounded response. | | Recursive population depth | 5 | Prevents unrestricted graph traversal. | | Materialized related-document nodes in one populated response | 4,096 | Charges complete subtrees so dense cycles cannot grow exponentially below the depth ceiling. | | Durable task input or output | 1 MiB each | Keeps database-backed work records bounded; large data belongs in object storage. | Application schemas and edge infrastructure may impose tighter limits. Public deployments still need tenant-, user-, route-, and abuse-aware rate policy: Ridu's distributed auth-operation throttling is not a universal API quota. ## Migrations, readiness, and recovery {#operations} Production startup never mutates schema. Apply only committed [migration artifacts](https://riducms.com/docs/migrations/) with the release's exact binary. For any artifact requiring `--allow-maintenance`, stop all old processes and workers and keep them stopped through completion and retries. For MongoDB, keep the running application credential scoped to one application database and use that or a selected database operator for `plan`, `status`, and `up`. Use separate least-privilege, short-lived credentials for verification and backups. Keep every URL out of generated files, image layers, logs, shell history, and process arguments; never grant cluster-wide administration to the long-running application merely to simplify operations. `/healthz` reports whether the process is alive. `/readyz` aggregates bounded checks for the migration ledger/manifest, database, and upload dependency; MongoDB readiness also verifies the exact Ridu-managed index plan. `ridu migrate status` remains the explicit operator report for immutable history, durable step progress, and managed database state; readiness does not replace it. Remove an instance from traffic before graceful drain. Back up the selected database and object storage as one recovery point. Restoring only the database can leave missing objects; restoring only objects can expose stale or orphaned bytes. Test every backup with an isolated restore. MongoDB's supported cutover order is drain, command-scoped verification with the operational URL, a matched database/upload snapshot, `up` with the selected application/operator URL, post-`up` `status`, then application start with the app URL. This workflow covers a database-scoped logical dump/restore plus uploads, not point-in-time recovery or an unsupported managed provider. ## Residual risks and non-features {#residual-risks} These boundaries require an application or infrastructure design: - Auth operations are throttled, but general distributed API quotas are not built in. - Audit callbacks are structured but are not a framework-owned tamper-aware durable audit log. - After-commit callbacks can enqueue tasks, but no atomic database outbox closes the narrow crash window between the content commit and callback dispatch. - Preview capabilities are process-local; multi-replica preview currently needs process affinity. - Malware quarantine, resumable/direct uploads, and sandboxing of untrusted plugins are not provided. - Prometheus and OpenTelemetry adapters are application-owned; Ridu exposes observations and readiness without requiring a vendor SDK. Use reconciliation or an application-owned transactional outbox when an external effect cannot tolerate the after-commit window. Treat every plugin as reviewed application code, even when its configuration comes from a manifest. Start with [Prevent abuse](https://riducms.com/docs/preventing-abuse/) before exposing the application publicly. See [Access control](https://riducms.com/docs/access-control/), [Uploads](https://riducms.com/docs/uploads/), [Durable tasks](https://riducms.com/docs/tasks/), [Production](https://riducms.com/docs/production/), and [Releases and compatibility](https://riducms.com/docs/releases/) for the contracts around this model. --- # Releases and compatibility Canonical URL: https://riducms.com/docs/releases/ Ridu uses one version across its Go module, project-local CLI, npm packages, and official plugins. Keep them on the same release line. Mixing versions can fail during generation, plugin registration, or startup. ## Supported matrix {#supported-matrix} | Surface | Supported environment | | --------------- | ----------------------------------------------------------------------------------------------------- | | Go | Go 1.25 or newer | | Initializer | Node.js 20 or newer | | Source checkout | Bun 1.4.0 | | PostgreSQL | PostgreSQL 17.x | | SQLite | The bundled driver, using a local file on one application host | | MongoDB | Community 8.2.9, SCRAM-SHA-256, verified TLS, and a writable three-member replica set on Linux x86-64 | | Browser tests | Chromium | PostgreSQL-compatible services must provide the PostgreSQL behavior Ridu depends on, including transaction semantics, migration locks, concurrent indexes, and TLS. Test a managed service before using it in production. MongoDB support does not extend to Atlas, DocumentDB, Cosmos DB, standalone servers, other versions or topologies, or other operating systems and architectures. Follow the supported setup in [MongoDB](https://riducms.com/docs/mongodb/). ## Versioning rules {#versioning} Before `v1.0.0`, a release may change a public contract. Upgrade one project at a time and read its release notes before updating. Only the latest pre-1 release is supported. From `v1.0.0`, breaking changes to public Go, CLI, REST, SDK, and extension contracts require a major version. Additions use a minor version and compatible fixes use a patch version. ## Contracts fail mismatches early {#contract-versions} Ridu checks related versions during generation and startup: | Contract | What happens when versions do not match | | ------------------- | ---------------------------------------------------------------------------- | | Schema manifest | Readers reject an unsupported manifest version. | | Project command | The CLI stops before reading config from an incompatible application. | | Migration artifacts | The adapter rejects unsupported or altered migration history. | | Backend plugins | Registration fails outside the plugin's supported Ridu range. | | Admin plugins | Generation fails when the browser package does not match its backend plugin. | | REST and SDK | Stable envelopes and error codes allow compatible additive responses. | Fix the package versions and regenerate. Do not copy generated files from another project or bypass plugin checks. ## What counts as public {#public-surface} Compatibility covers documented exported Go packages, CLI commands, REST and protocol contracts, published TypeScript packages, generated application contracts, and documented plugin interfaces. Go `internal/` packages, `.ridu/` intermediates, unexported symbols, and generated implementation details are not customization surfaces. Change the executable config and regenerate instead of editing generated output. ## Upgrade a project {#upgrade} Read the release notes, then upgrade the project as one unit: 1. Update `@riducms/cli` to the target version. 2. Update the Go module, framework npm packages, and official plugins to the same release line. 3. Run `ridu generate` and review the generated changes. 4. Create and review a [migration](https://riducms.com/docs/migrations/) when the model changed. 5. Run `ridu check`, `ridu migrate verify`, and the application's tests. 6. Rehearse the deployment on a recent restored backup. Set the version once so the CLI and Go module cannot drift: ```bash title="terminal" package-manager="npm" TARGET_VERSION="X.Y.Z" npm install --save-dev --save-exact "@riducms/cli@$TARGET_VERSION" go get "github.com/riducms/ridu@v$TARGET_VERSION" npm run ridu -- generate ``` ```bash title="terminal" package-manager="bun" TARGET_VERSION="X.Y.Z" bun add --dev --exact "@riducms/cli@$TARGET_VERSION" go get "github.com/riducms/ridu@v$TARGET_VERSION" bun run ridu -- generate ``` ```bash title="terminal" package-manager="pnpm" TARGET_VERSION="X.Y.Z" pnpm add --save-dev --save-exact --workspace-root "@riducms/cli@$TARGET_VERSION" go get "github.com/riducms/ridu@v$TARGET_VERSION" pnpm run ridu generate ``` ```bash title="terminal" package-manager="yarn" TARGET_VERSION="X.Y.Z" yarn add --dev --exact --ignore-workspace-root-check "@riducms/cli@$TARGET_VERSION" go get "github.com/riducms/ridu@v$TARGET_VERSION" yarn run ridu generate ``` Never edit an applied migration. Add a forward migration to correct it. ## Verify an installation {#framework-gate} Check that the project resolves one Ridu version across its tools: ```bash title="terminal" ridu version go list -m github.com/riducms/ridu ``` Then run `ridu doctor` to find a mismatched CLI, Go module, package, project file, or generated contract. ## Before production {#application-gate} Before sending traffic to an upgraded application: - run `ridu migrate verify` against restored data; - restore the database and upload storage together and test representative media; - confirm database transport, credentials, topology, and timeouts; - monitor `/healthz`, `/readyz`, request errors, tasks, latency, and storage health; - exercise authentication, writes, access-controlled reads, uploads, drafts, and rollback on a canary; and - record who approves the traffic switch and who can roll it back. See [Production](https://riducms.com/docs/production/), [Security](https://riducms.com/docs/security/), [Migrations](https://riducms.com/docs/migrations/), and [Troubleshooting](https://riducms.com/docs/troubleshooting/) for the complete operational paths. --- # Move from Payload Canonical URL: https://riducms.com/guides/from-payload/ Payload and Ridu share executable configuration, collections, globals, access rules, hooks, drafts, uploads, generated types, plugins, and an admin. Ridu defines the config and server runtime in Go, generates a Fetch client for TypeScript, and serves the admin from the same binary. Treat a migration as a model translation and a data migration—not a line-by-line conversion of Payload configuration or a copy of Payload's database tables. ## Give an agent the migration contract {#agent-guidance} New projects can include the `payload-to-ridu` coding-agent skill. Ask the agent to inventory the Payload application, keep a source-to-target ledger, and migrate one complete feature at a time. It must stop for decisions about missing semantics, credentials, production writes, or lossy conversion. For an existing project, install it with `ridu agent install --agent codex|claude|cursor|all`. After a CLI upgrade, run `ridu agent sync`; it will not overwrite a managed file with local edits. ## Decide whether the shape fits {#fit} Start with the workflows people rely on, not only the field list. | Evaluate | Ridu equivalent | Migration question | | ---------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------- | | Collections and globals | `ridu.Collection` and `ridu.Global` | Do slugs, IDs, timestamps, and singleton semantics remain stable? | | Fields | Constructors in `field`, plus plugin fields | Which values need conversion rather than a direct JSON mapping? | | Access callbacks | allow, deny, or filtered `Where` decisions | Can every rule be expressed without depending on a Node-only service? | | Hooks | typed Go collection, field, and global hooks | Which side effects must move, and which should become durable tasks? | | Drafts and versions | versioned resources with optional drafts | Which revision becomes the imported document? Is old history required elsewhere? | | Upload collections | upload documents plus a storage backend | How will bytes, checksums, metadata, and derived sizes be copied and verified? | | Admin components | statically registered Svelte plugins | Which custom React views or fields need a Svelte replacement? | | Local API and Payload client | local Go API and generated `@riducms/sdk` client | Which callers move in-process and which remain HTTP clients? | The normalized importer accepts collection records only. Payload globals, non-default locale values, credentials, upload bytes, and complete revision timelines require custom migration code or an archival decision. Review the [capability status](https://riducms.com/docs/status/) before committing to a cutover. In particular, custom rich-text blocks, UI localization, resumable uploads, and some long-tail query operators have narrower contracts than their Payload counterparts. ## Translate the configuration {#configuration} The closest conceptual mappings are: | Payload | Ridu | | --------------------------------- | ------------------------------------------------------------------------ | | `buildConfig({...})` | `func Config() ridu.Config` | | `CollectionConfig` | `ridu.Collection` | | `GlobalConfig` | `ridu.Global` | | field object | `field.*` constructor plus typed options | | access callback | `ridu.AccessRule` returning allow, deny, or a query predicate | | lifecycle callback | a function in `ridu.CollectionHooks` or `ridu.GlobalHooks` | | server plugin | a compiled Go `ridu.Plugin` | | admin component/import map | a Svelte/TypeScript plugin registration | | `@payloadcms/plugin-seo` | paired `plugins/seo` and `@riducms/plugin-seo` packages | | `@payloadcms/plugin-form-builder` | paired `plugins/formbuilder` and `@riducms/plugin-form-builder` packages | | `payload.find(...)` | `app.Local().List(...)` or a generated typed handle | | generated Payload client/types | `generated/ridu.generated.ts`, built on `@riducms/sdk` | For example, a versioned post collection becomes: ```go title="content/posts.go" package content import ( "github.com/riducms/ridu" "github.com/riducms/ridu/field" "github.com/riducms/ridu/plugins/richtext" ) var Posts = ridu.Collection{ Slug: "posts", Versions: true, VersionConfig: ridu.VersionConfig{ Drafts: true, }, Admin: ridu.CollectionAdmin{ UseAsTitle: "title", DefaultColumns: []string{"title", "author", "updatedAt"}, }, Fields: []field.Definition{ field.Text("title", field.Required()), field.Text("slug", field.Required(), field.Unique(), field.Index()), field.Relationship("author", field.To("users"), field.Required()), richtext.Field("content"), }, Access: ridu.CollectionAccess{ Read: postReadAccess, }, } ``` Start `ridu dev` early so config resolution, generation, and the local schema stay together. `ridu check` catches invalid field paths, relationships, plugin pairing, and manifest problems before any data is moved. The [configuration](https://riducms.com/docs/configuration/), [fields](https://riducms.com/docs/fields/), [access control](https://riducms.com/docs/access-control/), and [hooks](https://riducms.com/docs/hooks/) guides cover the corresponding contracts in depth. Payload `endpoints` map to `ridu.Endpoint` values on the root config, a collection, or a global. Move the handler to compiled Go, read complete `/:param` segments from `EndpointContext.RouteParams`, and use `EndpointContext.Local` for access-controlled content operations. Ridu route parameters cover complete `/:param` segments, not Payload's broader `path-to-regexp` wildcard, optional, or partial-segment grammar. Encoded slash and backslash values do not match, and declarations sharing one path shape across methods must use the same parameter names. Collection URLs also change from Payload’s `/api//…` to Ridu’s `/api/collections//…`; global endpoints use `/api/globals//…`. Like Payload, custom endpoints are anonymous unless the handler requires an actor. See [Custom endpoints](https://riducms.com/docs/custom-endpoints/) for the complete route and security contract. [SEO](https://riducms.com/docs/seo/) provides localized metadata fields and server-side generators. [Form Builder](https://riducms.com/docs/form-builder/) provides reusable forms and submissions; your application supplies the public renderer, email transport, and payment callbacks. ## Produce a normalized export {#normalized-export} Import from a `migration/payload.Export` instead of reading Payload's database tables directly, which can vary by version and adapter. ```go import payloadmigration "github.com/riducms/ridu/migration/payload" source := payloadmigration.Export{ Collections: []payloadmigration.Collection{ { Slug: "posts", Documents: []payloadmigration.Record{ { ID: "post_01", Data: json.RawMessage(`{"title":"Hello","author":"user_01"}`), Status: store.StatusPublished, CreatedAt: createdAt, UpdatedAt: updatedAt, }, }, }, }, } ``` Write a small extractor inside the Payload project so it can use that project's exact generated types and Payload APIs. Normalize these shapes: - preserve document IDs and UTC creation/update timestamps; - convert relationship objects to stable target IDs; - carry polymorphic relationships as both target collection and ID where the Ridu field requires them; - preserve array and block row identity as non-empty, unique `_key` strings; - emit Ridu rich-text documents with `version: 1`, and convert or reject nodes outside the enabled feature set; - emit a valid draft or published status; - distinguish an absent optional value from a meaningful zero, `false`, or empty string; - keep upload metadata and the corresponding object-copy manifest together. Do not export Payload password hashes, sessions, API keys, or reset tokens as content. Provision Ridu credentials independently and use a password-reset or invitation process for users. ## Assess before writing {#assessment} `payload.Assess` compares the export with Ridu's resolved manifest. It reports unknown collections, missing document IDs, version selection against a non-versioned target, and a selected revision that does not exist. Issues are sorted so repeated runs are easy to diff. ```go manifest, err := ridu.Resolve(content.Config()) if err != nil { return err } assessment := payloadmigration.Assess(manifest, source) log.Printf( "collections=%d documents=%d versions=%d", assessment.Collections, assessment.Documents, assessment.Versions, ) if len(assessment.Issues) > 0 { return fmt.Errorf("migration assessment failed: %v", assessment.Issues) } ``` Assessment is read-only. Run it against a production-shaped export before allocating a maintenance window. It is a structural check, not a complete data preflight: decoding, required fields, relationships, row keys, rich-text nodes, upload keys, and hook behavior are validated only when records enter the operation engine. A project migration should add its own read-only checks for those shapes before cutover. ## Import through the operation engine {#import} The normalized importer calls the local API's migration operation. Stable IDs, status, and timestamps are preserved, while access rules, normalization, validation, hooks, transactions, relationship checks, and version logic still run. ```go result, err := payloadmigration.Import( ctx, app.Local(), source, migrationActor, ) if err != nil { return err } log.Printf("imported=%d", result.Imported) log.Printf("Payload post_01 became %s", result.IDs["posts"]["post_01"]) ``` Use a dedicated actor with the permissions required for the import. A `nil` actor is not an administrative bypass: collections whose access rules require a user will reject it. Import referenced collections before their dependants. Because IDs are preserved, most references need no remapping, but validation still rejects a relationship to a document that is not present. Resolve dependency cycles in the extractor or with a custom staging pass. ## Stage upload bytes before their documents {#uploads} An upload row is not a complete file migration. Ridu opens the original and configured variants while admitting an imported upload document, so the target objects must already exist. For each asset: 1. transform the document metadata into the target upload collection shape; 2. copy the original object and named variants into an isolated target prefix; 3. compare every staged size and checksum with the source manifest; 4. import the upload document through the operation engine; 5. exercise public and private delivery paths; and 6. remove failed-run orphans only after the configured reconciliation grace period. Do not manufacture storage keys by string concatenation. Follow the target backend's namespace and the [upload contract](https://riducms.com/docs/uploads/). ## Rehearse the migration {#rehearsal} Run the complete process more than once against a fresh target restored from production-shaped backups. Record at least: - document counts by collection and status; - IDs and timestamps that failed to match; - relationship and upload referential integrity; - checksums for stored objects; - selected rich-text documents rendered in the frontend; - representative localized, draft, versioned, and access-filtered reads; - hook side effects and tasks created during import; - total duration and the final-delta duration. Make the migration command fail on the first rejected document and print its collection and ID. The importer returns completed mappings up to that point, but it is not a resumable whole-export transaction or a mapping UI. The safest retry target is a fresh database and object prefix. ## Cut over and roll back {#cutover} 1. Take and verify database and object-store backups. 2. Put Payload into read-only mode for the final delta window. 3. Run the final normalized export, assessment, upload-object staging, document import, and verification. 4. Run `ridu migrate verify` and the Ridu readiness checks. 5. Switch application reads to the generated Ridu client behind a reversible flag. 6. Canary a small cohort, watching structured operation errors, audit events, and storage health. 7. Keep the Payload database and objects untouched until the rollback window closes. Rollback means switching traffic back to the still-intact Payload deployment. Do not plan a reverse data conversion during an incident. The [production](https://riducms.com/docs/production/), [migrations](https://riducms.com/docs/migrations/), and [security](https://riducms.com/docs/security/) guides cover the surrounding operational controls. ## Common migration failures {#failures} | Symptom | Likely cause | What to do | | ------------------------------------------ | --------------------------------------------------------------- | --------------------------------------------------------------------- | | `collection ... is not present` | The export slug has no Ridu collection | Add the model or exclude and archive that source collection. | | `selected revision ... is missing` | The extractor named a revision it did not export | Correct selection in the source export; do not silently fall back. | | Relationship validation fails | Targets were omitted, renamed, or imported later | Preserve IDs and import dependencies first. | | `missing_row_key` or `duplicate_row_key` | Payload row identity was discarded | Map row IDs to stable `_key` values before import. | | Rich text is rejected | The document version or enabled-node set differs | Convert to the Ridu document contract and report lossy nodes. | | Upload metadata imports but delivery fails | The corresponding object was not copied or namespaced correctly | Verify backend keys, object checksums, and collection storage config. | | Access is denied | The migration actor cannot perform the create | Use a dedicated, least-privileged actor and test its rules. | For the exact importer types and functions, see the [`migration/payload` API reference](https://riducms.com/reference/migration-payload/). --- # Coming from PocketBase Canonical URL: https://riducms.com/guides/from-pocketbase/ PocketBase packages SQLite, realtime subscriptions, file and user management, an admin dashboard, and APIs in one executable. Ridu packages its Go API and Svelte admin in one binary, with PostgreSQL, SQLite, and MongoDB within its [bounded production profile](https://riducms.com/docs/mongodb/). Ridu is a code-configured CMS framework inspired by Payload's authoring model, not a PocketBase compatibility layer or database GUI. ## The important differences {#differences} | Concern | PocketBase | Ridu | | ---------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | Primary data store | Embedded SQLite | PostgreSQL 17, embedded SQLite, or MongoDB within its bounded profile through official store adapters | | Content model | Collections managed through APIs, dashboard, or Go | Executable Go config | | Server customization | Extend a PocketBase Go application | Access, hooks, fields, and backend plugins are compiled Go | | Browser client | General JavaScript SDK | Generated project types over a framework-neutral Fetch SDK | | Admin | Embedded dashboard | Schema-driven Svelte 5 admin | | Production JS runtime | None | None; built admin assets are embedded in the Go binary | | Realtime | Built-in realtime subscriptions | Not a general supported transport | | Schema migrations | PocketBase collection migrations | Reviewable migration files generated from config | | Draft/version workflow | Not the central model | Implemented collection versions, drafts, scheduling, and restore | | PocketBase data import | Not applicable | No supported PocketBase importer | Ridu generates a schema snapshot, OpenAPI, Go models and handles, TypeScript types, and the admin plugin registry from Go config. Frontends get project-specific types for selected and populated fields. Read [Core concepts](https://riducms.com/docs/core-concepts/) for that pipeline and [Go for TypeScript developers](https://riducms.com/docs/go-for-typescript/) if code-configured content models are new to you. ## When PocketBase remains the clearer fit {#choose-pocketbase} PocketBase is the more direct choice when your requirements depend on capabilities Ridu does not provide: - the schema should be managed dynamically through PocketBase's dashboard or collection APIs; - general realtime subscriptions are a core application transport; - you want PocketBase's established SQLite and realtime operating model; or - you need to preserve PocketBase collections, migrations, hooks, or client behaviour without a rewrite. Ridu's SQLite adapter is supported only for a local filesystem database on one application host and small or local workloads. Same-host processes can coordinate through SQLite's file locks, but Ridu does not promise a shared network filesystem or horizontally replicated deployment. [Live preview](https://riducms.com/guides/live-preview/) documents Ridu's narrower realtime surface rather than promising PocketBase-style subscriptions. ## When Ridu is worth evaluating {#evaluate-ridu} Ridu may fit the direction of your project when: - PostgreSQL is already an operational requirement, Ridu's single-host SQLite envelope fits, or the exact [bounded MongoDB profile](https://riducms.com/docs/mongodb/) matches your deployment; - the content schema should be reviewed as code and drive migrations and generated contracts; - filtered access rules and lifecycle hooks must apply equally to local Go calls, REST, jobs, and the admin; - editors need draft versions, scheduling, restore, rich text, uploads, and schema-driven forms; - application frontends benefit from exact generated TypeScript query and response types; and - you want one small production process without a JavaScript server. Check the actual surface in [PostgreSQL](https://riducms.com/docs/postgres/), [SQLite](https://riducms.com/docs/sqlite/), [MongoDB](https://riducms.com/docs/mongodb/), [Drafts and versions](https://riducms.com/docs/drafts-and-versions/), [Uploads](https://riducms.com/docs/uploads/), and [TypeScript SDK](https://riducms.com/docs/typescript-sdk/). ## Translate the project, not just the schema {#translate-project} A PocketBase application often concentrates important behaviour in collection rules, application hooks, file conventions, realtime listeners, and client-side query strings. Inventory each of those before reproducing the collections in Ridu. | Inventory item | Ridu destination | | ----------------------------- | ----------------------------------------------------------------------------------- | | Collection fields and indexes | `ridu.Collection` plus typed `field.*` definitions | | API rules | collection and field [access rules](https://riducms.com/docs/access-control/) | | Go event hooks | [hook phases](https://riducms.com/docs/hooks/) | | Files and file metadata | upload collections plus a [storage backend](https://riducms.com/docs/storage/) | | Browser API calls | generated [TypeScript SDK](https://riducms.com/docs/typescript-sdk/) package | | Realtime listeners | redesign; no general Ridu equivalent is supported | | SQLite-specific queries | redesign for Ridu's query vocabulary; do not depend on PocketBase's internal tables | Do not translate dashboard visibility into authorization. Ridu's admin reads the same manifest as other clients, but hiding a field or action in the UI is never permission. Access decisions remain part of the atomic store operation. ## Migration approach {#migration-reality} Ridu has no PocketBase importer or command that reads a PocketBase database and preserves its internal migration history. A migration therefore needs custom export and import code: 1. Freeze and back up the PocketBase database and uploaded objects. 2. Export stable document IDs, timestamps, relationship IDs, auth identities, file metadata, and application state into a format you can inspect. 3. Model and resolve the target Ridu config, then review the selected adapter's migration before writing content. 4. Import through Ridu's local API so validation, access policy, hooks, and transactions run. Decide which hooks should be disabled or made idempotent for the import. 5. Copy objects into the configured storage backend and reconcile them with imported metadata. 6. Compare counts, representative documents, access behaviour, hashes, and auth flows against a restored rehearsal before any cutover. Authentication needs special treatment: do not assume PocketBase password material, sessions, or tokens can be copied into Ridu. Plan an identity mapping and session reset unless a tested application-specific bridge proves otherwise. ## Evaluate without committing to a migration {#evaluate-without-migrating} Start with a small parallel model—users, one editorial collection, and media—then exercise its author experience and API. Measure your workload and compare it with the [performance baseline](https://riducms.com/docs/performance/). Use [Troubleshooting](https://riducms.com/docs/troubleshooting/) if installation or local prerequisites get in the way, and review [Production](https://riducms.com/docs/production/) before interpreting a successful local demo as a deployment recommendation. --- # Build a custom field Canonical URL: https://riducms.com/guides/custom-fields/ A reusable Ridu field combines: - a Go plugin defines schema config, the stored value, server validation, and generated type metadata; - an npm package exports the TypeScript value types and a Svelte field renderer; and - a shared plugin key and pairing version keep the server and admin compatible. This guide builds a `color` field that stores a `#RRGGBB` string, validates it on the server, exports exact generated types, and renders it in the admin. This is the full path for adding a new value contract. If a built-in field already has the storage, validation, access, and generated types you need, keep those semantics and replace only its Svelte editor with `field.AdminComponent`. See [Custom components](https://riducms.com/docs/fields/#custom-components) for the smaller configuration, registration example, and the exact comparison with Payload's field-component slots. ## 1. Scaffold the paired plugin {#scaffold} ```sh title="terminal" npm run ridu -- plugin new ./ridu-color \ --key color \ --module example.com/acme/ridu-color \ --admin-package @acme/ridu-color-admin ``` The command creates Go and Svelte packages with a descriptor, field helper, validator, value export, and tests. Replace the starter value with the color implementation below. Change the generated Ridu compatibility range only after testing the new range. ## 2. Define the Go value and field helper {#go-field} The helper writes field config into the schema manifest. Export a distinct Go value type so generated application models do not fall back to `json.RawMessage`. ```go title="plugin.go" package color import ( "encoding/json" "github.com/riducms/ridu" "github.com/riducms/ridu/field" ) const Key = "color" type Value string type Config struct { Palette []Value `json:"palette,omitempty"` } type plugin struct{} func New() ridu.Plugin { return plugin{} } func (plugin) Key() string { return Key } func Field(name string, config Config, options ...field.PluginOption) field.Definition { encoded, err := json.Marshal(config) if err != nil { panic(err) } return field.Plugin(name, Key, encoded, options...) } ``` `field.PluginOption` accepts common capabilities such as `field.Label`, `field.Required`, `field.Description`, `field.ReadOnly`, `field.Columns`, `field.Tab`, `field.ShowWhen`, and `field.Localized`. It does not accept `field.Unique` or a generic default because a plugin must define its own storage and indexing semantics before those could be safe. If plugin config contains collection slugs, declare their exact JSON property names with `field.CollectionReferenceKeys(...)`. Ridu can then update references during a schema rename and reject a change that would leave current values or version snapshots pointing at a removed target. > [!WARNING] > Plugin config is public schema metadata delivered to tooling and the admin. Do not put secrets, > credentials, executable access rules, or request-specific data in it. ## 3. Declare generated types and the admin pair {#descriptor} `PluginDescriptor.FieldTypes` maps the field to generated Go, TypeScript, and OpenAPI types. The admin metadata names the renderer export. ```go title="descriptor.go" package color import "github.com/riducms/ridu" const AdminPluginPairingVersion = 1 func (plugin) Descriptor() ridu.PluginDescriptor { admin := ridu.AdminPluginMetadata{ Package: "@acme/ridu-color-admin", Export: "colorAdminPlugin", APIVersion: ridu.AdminPluginAPIVersion, PairingVersion: AdminPluginPairingVersion, } return ridu.PluginDescriptor{ Version: "1.0.0", GoPackage: "example.com/acme/ridu-color", APIVersion: ridu.PluginAPIVersion, Ridu: ridu.RiduCompatibility{ Minimum: ridu.FrameworkVersion, }, Admin: &admin, FieldTypes: []ridu.PluginFieldType{{ Key: Key, TypeScriptPackage: "@acme/ridu-color-admin", TypeScriptOutput: "Color", TypeScriptInput: "ColorInput", GoPackage: "example.com/acme/ridu-color", GoType: "Value", JSONSchema: []byte( `{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$"}`, ), }}, } } ``` Replace the example compatibility values with the range you test. `TypeScriptWhere` is optional; without it, the generated client uses `ScalarWhere`. Supply a named where export only when the field supports a different query shape. Omitting both `GoPackage` and `GoType` produces `json.RawMessage`. Omitting descriptor field mappings makes TypeScript output `unknown`. Provide both mappings for a reusable field. ## 4. Enforce the value on the server {#validation} The Go validator checks local API, REST, SDK, admin, task, and plugin-transport writes: ```go title="validation.go" package color import ( "regexp" "github.com/riducms/ridu" "github.com/riducms/ridu/schema" ) var hexadecimal = regexp.MustCompile(`^#[0-9A-Fa-f]{6}$`) func (plugin) FieldValidators() map[string]ridu.PluginFieldValidator { return map[string]ridu.PluginFieldValidator{Key: validateColor} } func validateColor(ctx ridu.PluginFieldValidationContext) []schema.Issue { value, ok := ctx.Value.StringValue() if ok && hexadecimal.MatchString(value) { return nil } return []schema.Issue{{ Code: "invalid_color", Path: ctx.RuntimePath, Message: "color must use the #RRGGBB format", }} } ``` Use a stable machine-readable code and `RuntimePath`. Unlike the schema-level `Field.Path`, the runtime path identifies the concrete occurrence inside arrays and blocks, so the admin can attach an issue to the correct repeated row. Required/missing validation is still handled by `field.Required`; the plugin validator owns the value's shape and semantics. ## 5. Export the TypeScript contract {#typescript-contract} The names must exactly match `TypeScriptOutput` and `TypeScriptInput` in the Go descriptor: ```ts title="admin/src/value.ts" export type Color = `#${string}`; export type ColorInput = Color; ``` This template-literal type improves completion but cannot express “exactly six hexadecimal digits.” The JSON Schema supplies that pattern to OpenAPI and the Go validator enforces it at runtime. Keep all three aligned; none substitutes for the other two. ## 6. Render through the form controller {#svelte-field} The Svelte component receives the resolved `SchemaField` and a `FieldForm`. Read and write the field through the form; do not submit documents or call REST from the component. ```svelte title="admin/src/color-field.svelte"
form.set(field.path, event.currentTarget.value)} /> {#each issues as issue (issue.code)}

{issue.message}

{/each}
``` `form.register` returns the unregister function, which the Svelte effect uses for cleanup. Respect `field.admin.readOnly`, keep the input ID/label association, display server issues, and treat `field.plugin?.config` as untrusted `unknown` until the admin package narrows it. Register that renderer and export the paired admin descriptor: ```ts title="admin/src/index.ts" import { ADMIN_PLUGIN_API_VERSION, defineAdminPlugin, defineFieldPlugin } from '@riducms/plugin'; import ColorField from './color-field.svelte'; export type { Color, ColorInput } from './value'; export const colorFieldPlugin = defineFieldPlugin({ type: 'plugin', key: 'color', component: ColorField, canRender: (field) => field.plugin?.key === 'color' }); export const colorAdminPlugin = defineAdminPlugin({ apiVersion: ADMIN_PLUGIN_API_VERSION, key: 'color', pairingVersion: 1, fields: [colorFieldPlugin] }); ``` The key, API version, pairing version, field registrations, routes, and assets must match the backend declaration. Increment the pairing version when separately published Go and admin packages stop being interchangeable. ## 7. Test the paired contract {#testing} Put the conformance test in the external `color_test` package. It checks resolution, generated mapping, local API, REST, and validation: ```go title="plugin_test.go" package color_test import ( "testing" color "example.com/acme/ridu-color" "github.com/riducms/ridu/field" "github.com/riducms/ridu/plugintest" "github.com/riducms/ridu/store" ) func TestConformance(t *testing.T) { plugintest.Run(t, plugintest.Fixture{ Plugin: color.New(), Fields: []field.Definition{ color.Field("accent", color.Config{}, field.Required()), }, ValidData: store.Values{"accent": store.String("#663399")}, InvalidData: store.Values{"accent": store.String("purple")}, Compatibility: []plugintest.CompatibilityCase{ {RiduVersion: ridu.FrameworkVersion, Compatible: true}, }, }) } ``` Keep the scaffolded admin test, run `svelte-check`, and compile generated output that imports `Color`, `ColorInput`, and the application client. If the plugin adds database changes, test both migration directions and full replay against every declared adapter. See [Testing](https://riducms.com/docs/testing/) and the broader [Plugin system](https://riducms.com/docs/plugins/). ## 8. Install and use it {#install} After publishing both packages, install the pair into an application: ```sh title="terminal" npm run ridu -- plugin add color \ --go-package example.com/acme/ridu-color \ --go-version v1.0.0 \ --admin-package @acme/ridu-color-admin \ --admin-version '^1.0.0' ``` The CLI records the dependencies, emits compiled Go registration and a static admin import, and regenerates contracts. Use the helper like a built-in field: Keep `Plugins: installedPlugins()` in `content.Config()` so the generated registration is loaded. ```go title="content/brands.go" var Brands = ridu.Collection{ Slug: "brands", Fields: []field.Definition{ color.Field( "accent", color.Config{Palette: []color.Value{"#663399", "#FFFFFF"}}, field.Required(), ), }, } ``` With `ridu dev` running, save the config and use the field in the admin. Then inspect the generated manifest, OpenAPI, Go, and TypeScript diffs. Before deployment, create and review the required database migration, verify its history, and run `ridu check`. ## Failure modes {#failure-modes} | Symptom | Likely boundary and fix | | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | Unknown plugin field during resolution | Register `color.New()` in compiled config and keep the helper key identical. | | Generated TypeScript is `unknown` | Add the descriptor `FieldTypes` mapping, run `plugintest.Run`, and save while `ridu dev` is running. | | Generated Go uses `json.RawMessage` | Supply both `GoPackage` and exported `GoType`, or accept the fallback. | | Admin says no renderer handles `plugin:color` | Install/export the admin pair, check its key, and let `ridu dev` rebuild the static registry. | | Admin pairing/API mismatch | Publish compatible halves, align `PairingVersion`, and keep `AdminPluginAPIVersion` current. | | Bun/Vite cannot resolve the generated import | Install the descriptor's exact npm package/export; do not edit the generated registry. | | Nested validation appears on the wrong row | Return `schema.Issue.Path: ctx.RuntimePath`, not only the schema-level path. | | Browser accepts a value REST later rejects | Align the input control, exported input type, JSON Schema, and authoritative Go validator. | | A field-config secret appears in `/api/schema` | Remove it immediately; manifest config is public deterministic metadata. | | A renamed plugin key looks removed and added | Restore the key or plan a data and plugin migration. | Custom field data uses generic JSONB persistence. A plugin that needs indexes, custom tables, or different query semantics must declare and test those capabilities. --- # Add live preview Canonical URL: https://riducms.com/guides/live-preview/ Ridu live preview has two complementary paths: - a short-lived server capability lets the frontend fetch the saved, access-checked draft without receiving the author's admin cookie; - a browser channel sends the current unsaved form values from the admin to an iframe or popup. Browser messages make editing feel immediate, but they do not grant API access and must not be persisted directly. ## Before you configure it {#requirements} Live preview is available for versioned collections and globals with drafts enabled. The document must already exist: the admin does not open a live-preview panel for an unsaved create form. ```go Versions: true, VersionConfig: ridu.VersionConfig{ Drafts: true, }, ``` Your preview frontend can run in any framework. It only needs a server-side Fetch-compatible client for capability reads and, if you want unsaved updates, a browser that can use `postMessage`. ## Configure the URL and viewports {#configure} Set `Admin.LivePreview` on the collection or global. A URL can be an absolute HTTP(S) URL or an absolute path resolved against the admin origin. ```go title="content/posts.go" Admin: ridu.CollectionAdmin{ LivePreview: ridu.LivePreviewConfig{ URL: "https://www.example.com/preview/{collection}/{id}?slug={field:slug}", Breakpoints: []ridu.PreviewBreakpoint{ {Name: "mobile", Label: "Mobile", Width: 390, Height: 844}, {Name: "tablet", Label: "Tablet", Width: 820, Height: 1180}, {Name: "desktop", Label: "Desktop", Width: 1440, Height: 900}, }, }, }, ``` The URL template accepts: | Placeholder | Value | | ----------------------- | ------------------------------------------------- | | `{id}` | Current document ID | | `{collection}` | Collection or global slug used by the admin route | | `{field:path.to.value}` | Current scalar form value at a stored field path | Values are URL-encoded. Non-scalar or missing field values become an empty string. `ridu check` rejects unknown stored paths, unsupported placeholders, malformed braces, non-HTTP absolute URLs, duplicate breakpoint names, and non-positive dimensions. Breakpoint names are unique lowercase kebab-case; an omitted label is humanized from the name. When the panel opens, the admin adds two reserved query parameters: - `__ridu_preview` identifies the browser message channel; - `__ridu_preview_token` carries the short-lived read capability. Preserve both parameters through application redirects. ![A focused Ridu Article editor beside its connected responsive live-preview panel, showing the current title in the separate preview application.](https://raw.githubusercontent.com/riducms/ridu/main/docs/assets/ridu-admin-live-preview.png) _The panel reads the saved draft with a scoped capability and receives unsaved form updates through a validated browser channel._ ## Read the saved draft on the server {#server-read} Use the generated client from your application frontend. It sends the preview token as a bearer credential to the dedicated read-only route; it does not forward the admin session. ```ts title="src/routes/preview/posts/[id]/+page.server.ts" import { createClient } from '@riducms/sdk'; import type { RiduConfig } from '~/generated/ridu.generated'; const ridu = createClient({ baseURL: 'https://cms.example.com', credentials: 'omit' }); export async function load({ params, url, setHeaders }) { const token = url.searchParams.get('__ridu_preview_token'); if (!token) throw new Response('Missing preview capability', { status: 401 }); setHeaders({ 'cache-control': 'private, no-store', 'x-robots-tag': 'noindex, nofollow' }); return { post: await ridu.preview('posts', params.id, token) }; } ``` For a global, call `ridu.previewGlobal('site-settings', token)`. The corresponding authenticated minting methods are `createPreviewToken` and `createGlobalPreviewToken`; custom admin tools should normally let the built-in panel own minting and cleanup. Every preview read checks the current actor, access predicates, field redaction, computed values, hooks, and document identity. Deleting or recreating the actor or target invalidates the grant instead of transferring it to a reused ID. ## Receive unsaved form updates {#browser-updates} Install the receiver in the preview page's browser code. Pass the expected admin origin and resource identity. ```ts title="src/lib/live-preview.ts" import { connectLivePreview } from '@riducms/sdk'; import type { Posts } from '~/generated/ridu.generated'; export function connectPostPreview(id: string, onPost: (post: Posts) => void) { const connection = connectLivePreview({ adminOrigin: 'https://cms.example.com', target: { resource: 'collection', slug: 'posts', id }, onUpdate({ data }) { onPost(data); } }); return () => connection.disconnect(); } ``` `connectLivePreview` reads the channel from the current URL and rejects messages whose origin, source window, channel, resource kind, slug, ID, sequence, or data shape does not match. It announces readiness on connection and again after `pageshow`, focus, or network return. Call `ready()` after an application-side route or renderer reset; call `disconnect()` when the preview component unmounts. For globals, use a target such as: ```ts { resource: 'global', slug: 'site-settings', id: 'site-settings' } ``` The message data is the admin's current form state. It may contain values that have not passed server validation or hooks, so render it defensively and never persist it directly. ## Cross-origin setup {#cross-origin} If the frontend and CMS use different origins: 1. if the browser itself exchanges the capability, add the frontend origin to `RIDU_ALLOWED_ORIGINS` (or `HandlerOptions.AllowedOrigins`); 2. pass the exact CMS origin—not `*`—to `connectLivePreview`; 3. serve both applications over HTTPS; 4. allow the preview page to be embedded by the CMS origin in its CSP `frame-ancestors` policy; 5. keep the preview route out of shared caches and search indexes. CORS controls cross-origin browser fetches; it does not apply to a server-side capability exchange. The browser receiver separately validates `postMessage` origin and window identity, so configuring [CORS](https://riducms.com/docs/cors/) does not configure the message channel. ## Capability lifecycle and limits {#capabilities} A preview token is opaque, read-only, and valid for five minutes. It is bound to one authenticated actor collection, actor instance, resource kind, slug, and exact document. It cannot authenticate ordinary REST calls or preview a different target. Ridu bounds the in-memory registry to 64 active tokens per actor and 4,096 per application process. Minting beyond either limit returns `rate_limited`. Expired grants are discarded, and the built-in admin revokes a superseded token and its current token when the panel exits. If a custom tool mints tokens, call `revokePreviewToken(token)` when its session ends; revocation is idempotent for a token that is already absent. ## Keep tokens out of logs and caches {#security} The token appears in the preview URL so the server-rendered frontend can exchange it. Treat it as a short-lived bearer secret: - redact `__ridu_preview_token` from CDN, proxy, application, analytics, and error-reporting logs; - do not persist it in browser storage or forward it to another service; - set a restrictive `Referrer-Policy` on the preview page; - avoid third-party scripts and assets that can observe the full page URL; - return `Cache-Control: private, no-store` from the frontend as well as relying on Ridu's no-store API response; - revoke tokens created by custom tools as soon as the preview closes. ## Troubleshoot the connection {#troubleshooting} | Symptom | Check | | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- | | The Live Preview button is absent | The document must already exist, `Admin.LivePreview.URL` must resolve, and versions plus drafts must be enabled. | | `bad_operation` while minting | Live preview or drafts are not configured for that resource. | | `invalid_preview_token` | The token is missing, expired, revoked, scoped to another target, on another replica, or its actor/target identity changed. | | `rate_limited` while opening panels | Close stale custom preview sessions and verify custom tools revoke their tokens. | | The saved draft loads but typing does not update | Preserve `__ridu_preview`, run `connectLivePreview` in the browser, and verify the exact CMS origin and target identity. | | The iframe is blocked | Update the frontend CSP `frame-ancestors` rule for the CMS origin. | | The request is rejected cross-origin | Add the frontend origin to Ridu's allowed origins; do not use an origin with a path. | | Preview works on one replica only | Configure affinity for mint and read requests. | See the [TypeScript SDK](https://riducms.com/docs/typescript-sdk/) for all preview methods, the [drafts and versions guide](https://riducms.com/docs/drafts-and-versions/) for the underlying document states, and the [`@riducms/sdk` reference](https://riducms.com/reference/sdk/) for the receiver contract. --- # API Reference: ridu Canonical URL: https://riducms.com/reference/ridu/ Package: github.com/riducms/ridu The ergonomic application facade for config, startup, and access decisions. ## New Canonical URL: https://riducms.com/reference/ridu/new/ Kind: function Create an application from config and a document store. ```go func New(applicationConfig Config, backend store.Store) (*App, error) ``` When compiled by ridu build, the application carries the exact ordered migration-history fingerprint used by official adapter readiness. Application-owned servers remain responsible for running readiness before admitting traffic. ```go app, err := ridu.New(content.Config(), backend) if err != nil { log.Fatal(err) } post, err := app.Local().Find(ctx, "posts", postID, nil) ``` ## Resolve Canonical URL: https://riducms.com/reference/ridu/resolve/ Kind: function Resolve executable config into a deterministic schema manifest. ```go func Resolve(applicationConfig Config) (schema.Manifest, error) ``` Resolution runs plugin transforms without opening a database. ```go manifest, err := ridu.Resolve(content.Config()) if err != nil { log.Fatal(err) } fmt.Println(manifest.Snapshot().Version) ``` ## Execute Canonical URL: https://riducms.com/reference/ridu/execute/ Kind: function Run the API, admin, jobs, and shutdown lifecycle. ```go func Execute(applicationConfig Config, options ...ExecuteOption) error ``` With project-command arguments, Execute resolves config and runs the versioned CLI protocol without applying runtime options or opening adapters. With no arguments, it starts the framework-owned HTTP server and requires WithStore. Server startup opens the document store, opens optional upload storage, constructs the application, verifies readiness, binds the listener, and only then starts background workers. SIGINT or SIGTERM marks readiness as draining, shuts down HTTP work, drains workers, and closes lifecycle-owned adapters. Execute blocks until the command or server lifecycle finishes. Return its error from main or log it as a fatal startup/runtime failure. ```go err := ridu.Execute( content.Config(), ridu.WithStore(func(ctx context.Context) (store.Store, error) { return postgres.Open(ctx, os.Getenv("DATABASE_URL")) }), ridu.WithAddress(":8080"), ) if err != nil { log.Fatal(err) } ``` ## Allow Canonical URL: https://riducms.com/reference/ridu/allow/ Kind: function Allow an access-controlled operation. ```go func Allow() AccessDecision ``` ## Deny Canonical URL: https://riducms.com/reference/ridu/deny/ Kind: function Deny an access-controlled operation. ```go func Deny() AccessDecision ``` ## Where Canonical URL: https://riducms.com/reference/ridu/where/ Kind: function Constrain access to documents matching a query expression. ```go func Where(expression query.Expression) AccessDecision ``` Use filtered decisions only for operations with an atomic document predicate. Creates, globals, and admin entry accept Allow or Deny. ## Operation Canonical URL: https://riducms.com/reference/ridu/operation/ Kind: type The lifecycle operation currently being authorized or handled. ```go type Operation = core.Operation ``` ```go if ctx.Operation == ridu.OperationCreate || ctx.Operation == ridu.OperationUpdate { ctx.Data["lastEditedBy"] = store.String(ctx.Actor.ID) } ``` ## AccessDecision Canonical URL: https://riducms.com/reference/ridu/access-decision/ Kind: type An allow, deny, or atomic document-filter decision. ```go type AccessDecision = core.AccessDecision ``` AccessDecision is immutable. Construct it with Allow, Deny, or Where; filtered predicates remain attached to the same atomic store query as the operation. ## AccessRule Canonical URL: https://riducms.com/reference/ridu/access-rule/ Kind: type Authorize one operation with actor and transaction context. ```go type AccessRule = core.AccessRule ``` ```go var authenticated ridu.AccessRule = func( ctx ridu.AccessContext, ) (ridu.AccessDecision, error) { if ctx.Actor == nil { return ridu.Deny(), nil } return ridu.Allow(), nil } ``` ## AccessContext Canonical URL: https://riducms.com/reference/ridu/access-context/ Kind: type Actor, target, locale, data, and nested API supplied to an access rule. ```go type AccessContext = core.AccessContext ``` Use the root alias in application configuration. ```go func ownerOnly(ctx ridu.AccessContext) (ridu.AccessDecision, error) { if ctx.Actor == nil { return ridu.Deny(), nil } author, err := query.NewPath("author") if err != nil { return ridu.Deny(), err } return ridu.Where( query.Equal(author, query.String(ctx.Actor.ID)), ), nil } ``` ## CollectionAccess Canonical URL: https://riducms.com/reference/ridu/collection-access/ Kind: type Access rules for collection admin, create, read, update, delete, and unlock operations. ```go type CollectionAccess = core.CollectionAccess ``` ```go var Posts = ridu.Collection{ Access: ridu.CollectionAccess{ Create: authenticated, Read: publishedOrOwner, Update: ownerOrEditor, Delete: administratorsOnly, }, } ``` ## GlobalAccess Canonical URL: https://riducms.com/reference/ridu/global-access/ Kind: type Allow-or-deny rules for global reads, versions, and updates. ```go type GlobalAccess = core.GlobalAccess ``` ## FieldAccess Canonical URL: https://riducms.com/reference/ridu/field-access/ Kind: type Independent create, read, and update rules for one authored field. ```go type FieldAccess = core.FieldAccess ``` ## FieldAccessRule Canonical URL: https://riducms.com/reference/ridu/field-access-rule/ Kind: type Authorize or redact one authored field value. ```go type FieldAccessRule = core.FieldAccessRule ``` ```go func editorsOnly(ctx ridu.FieldAccessContext) (bool, error) { return actorHasRole(ctx.Actor, "editor"), nil } ``` ## FieldAccessContext Canonical URL: https://riducms.com/reference/ridu/field-access-context/ Kind: type Operation, actor, path, value, siblings, and locale supplied to a field rule. ```go type FieldAccessContext = core.FieldAccessContext ``` ## Config Canonical URL: https://riducms.com/reference/ridu/config/ Kind: type The complete author-owned application definition. ```go type Config = core.Config ``` Resolve applies compiled plugin transforms to a defensive copy of the executable Go config before validation and manifest generation. ## Collection Canonical URL: https://riducms.com/reference/ridu/collection/ Kind: type A repeatable model with fields, access, hooks, and capabilities. ```go type Collection = core.Collection ``` ```go var Posts = ridu.Collection{ Slug: "posts", Fields: []field.Definition{ field.Text("title", field.Required()), }, } ``` ## Global Canonical URL: https://riducms.com/reference/ridu/global/ Kind: type A singleton model exposed through the same operation engine. ```go type Global = core.Global ``` ## HookContext Canonical URL: https://riducms.com/reference/ridu/hook-context/ Kind: type The request, document, actor, locale, and transaction state available to a hook. ```go type HookContext = core.HookContext ``` Most applications import the ridu.HookContext alias from the root package. AfterCommit and AfterError run outside the original transaction. This is the application-facing alias of core.HookContext. Import it from github.com/riducms/ridu in ordinary application code. ```go func normalizeTitle(ctx ridu.HookContext) error { title, ok := ctx.Data["title"].StringValue() if !ok { return nil } ctx.Data["title"] = store.String(strings.TrimSpace(title)) return nil } ``` ## Hook Canonical URL: https://riducms.com/reference/ridu/hook/ Kind: type A deterministic lifecycle callback. ```go type Hook = core.Hook ``` ```go var auditTitle ridu.Hook = func(ctx ridu.HookContext) error { if ctx.Document == nil { return nil } log.Printf("%s changed %s", ctx.Operation, ctx.Document.ID) return nil } ``` ## CollectionHooks Canonical URL: https://riducms.com/reference/ridu/collection-hooks/ Kind: type Ordered lifecycle callbacks for one collection. ```go type CollectionHooks = core.CollectionHooks ``` Each hook slice runs in order. In FieldHooks, BeforeRead and AfterError remain resource-level phases, and map order across paths is not significant. Each hook slice runs in order. In FieldHooks, BeforeRead and AfterError are not field-level phases, and map order across field paths is not significant. ```go var Posts = ridu.Collection{ Hooks: ridu.CollectionHooks{ BeforeValidate: []ridu.Hook{normalizeSlug}, AfterChange: []ridu.Hook{recordAuditEntry}, AfterCommit: []ridu.Hook{enqueueSearchIndex}, }, } ``` ## AfterCommitDispatcher Canonical URL: https://riducms.com/reference/ridu/after-commit-dispatcher/ Kind: type Deliver a hook effect after its document transaction commits. ```go type AfterCommitDispatcher = core.AfterCommitDispatcher ``` ```go type InlineDispatcher struct{} func (InlineDispatcher) Dispatch( ctx context.Context, effect ridu.AfterCommitEffect, ) error { return effect.Run(ctx) } ``` ## AfterCommitEffect Canonical URL: https://riducms.com/reference/ridu/after-commit-effect/ Kind: type Identity and executable work for one committed lifecycle effect. ```go type AfterCommitEffect = core.AfterCommitEffect ``` ## LocalizationConfig Canonical URL: https://riducms.com/reference/ridu/localization-config/ Kind: type Content locales, fallback behavior, and optional request-scoped admin availability. ```go type LocalizationConfig = core.LocalizationConfig ``` Leave Locales empty to disable content localization. When localization is enabled, DefaultLocale must name one configured locale and every fallback must also be configured. FallbackLocales are checked in order after the requested locale unless DisableFallback is true. AvailableLocales only narrows the locale picker for the current admin request; it cannot add locales, change API validation, or grant access, and executable callbacks are never serialized into the schema manifest. Assign this value to Config.Localization. Because the root package aliases the canonical core contract, an AvailableLocales callback names its input as core.LocaleAvailabilityContext. ```go application := ridu.Config{ Name: "Editorial", Localization: ridu.LocalizationConfig{ Locales: []ridu.Locale{ {Code: "en", Label: "English"}, { Code: "fr", Label: "Français", FallbackLocales: []schema.LocaleCode{"en"}, }, }, DefaultLocale: "en", }, } ``` ## Locale Canonical URL: https://riducms.com/reference/ridu/locale/ Kind: type One content locale and its ordered fallback chain. ```go type Locale = core.Locale ``` Code is the stable wire and storage identity; changing it is a data migration. Label and RTL affect authoring presentation. Fallback chains must be acyclic and may name only configured locales. ## CollectionAdmin Canonical URL: https://riducms.com/reference/ridu/collection-admin/ Kind: type Serializable collection presentation and editorial organization. ```go type CollectionAdmin = core.CollectionAdmin ``` Presentation never grants access. FolderField and ParentField configure hierarchy metadata; LivePreview is an implemented authoring preview surface. ## LivePreviewConfig Canonical URL: https://riducms.com/reference/ridu/live-preview-config/ Kind: type A frontend URL template and named authoring viewports. ```go type LivePreviewConfig = core.LivePreviewConfig ``` URL may contain {id}, {collection}, and {field:path.to.value} placeholders. Preview tokens are short-lived, read-only, and scoped to one resource. ## AuthConfig Canonical URL: https://riducms.com/reference/ridu/auth-config/ Kind: type Policy for an auth-enabled collection. ```go type AuthConfig = core.AuthConfig ``` Local password auth is built in. Recovery/email flows require trusted Send callbacks. External strategies are compiled Go integrations, not dynamically loaded providers. Private hashes and tokens never enter content fields or hooks. ## UploadConfig Canonical URL: https://riducms.com/reference/ridu/upload-config/ Kind: type Validation, privacy, and image-variant policy for an upload collection. ```go type UploadConfig = core.UploadConfig ``` Upload collections also require Config.Storage, a stable StorageNamespace, and a store implementing UploadObjectLocker. Image variants are generated only for supported images. ## VersionConfig Canonical URL: https://riducms.com/reference/ridu/version-config/ Kind: type Drafts, snapshot retention, and autosave policy. ```go type VersionConfig = core.VersionConfig ``` Versions must be enabled on the collection/global. MaxPerDocument zero resolves to 100. AutosaveInterval zero currently resolves to 30 seconds, and a configured interval must be at least one second; it drives admin update calls rather than a server-side mutation timer. Optimistic revision checks are available through MutationOptions. ## Computed Canonical URL: https://riducms.com/reference/ridu/computed/ Kind: type Resolve a virtual output field after an operation produces a document. ```go type Computed = core.Computed ``` Computed values are not stored. They are resolved through explicit OutputFields selection and redacted by field read access like authored output. ## HandlerOptions Canonical URL: https://riducms.com/reference/ridu/handler-options/ Kind: type HTTP security, size bounds, observers, and trusted-proxy policy. ```go type HandlerOptions = core.HandlerOptions ``` Pass this value to App.Handler when embedding Ridu, or install it with WithHandlerOptions when Execute owns the server. The zero value is development-friendly. Before production, set SecureCookies and AllowedHosts, add AllowedOrigins only for cross-origin browser clients, and trust only proxy ranges you operate. Body, request, readiness, worker, and maintenance bounds resolve independently when left at zero. ```go options := ridu.HandlerOptions{ SecureCookies: true, AllowedHosts: []string{"cms.example.com"}, AllowedOrigins: []string{"https://app.example.com"}, RequestTimeout: 15 * time.Second, } ``` ## WithStore Canonical URL: https://riducms.com/reference/ridu/with-store/ Kind: function Provide the singular document-store adapter through the Execute lifecycle. ```go func WithStore(factory StoreFactory) ExecuteOption ``` WithStore is required only for the no-argument server branch of Execute. Project commands such as generate and check resolve config without applying this option, so they do not need DATABASE_URL or a reachable database. The factory receives the server lifecycle context. Return an unopened error rather than terminating the process inside the factory; Execute wraps it as open document store and returns it to main. The returned store must implement the base store.Store contract and every optional capability enabled by the application. Production startup also requires store.ReadinessStore unless ServerOptions.AllowUnverifiableReadiness delegates readiness checking to an external system. Execute owns the returned adapter. On startup failure or shutdown it calls Close() or Close() error when implemented, bounded by ServerOptions.ShutdownTimeout. Optional upload storage closes first, then the document store. ```go err := ridu.Execute( content.Config(), ridu.WithStore(func(ctx context.Context) (store.Store, error) { return postgres.Open(ctx, os.Getenv("DATABASE_URL")) }), ridu.WithAddress(":8080"), ) if err != nil { log.Fatal(err) } ``` ## WithProjectMigrations Canonical URL: https://riducms.com/reference/ridu/with-project-migrations/ Kind: function Register the selected adapter’s compiled migration driver for project commands. ```go func WithProjectMigrations(driver migration.ProjectDriver) ExecuteOption ``` The driver is used only by project migration commands whose artifacts contain compiled data callbacks. It is not used by schema generation or the ordinary HTTP runtime. ```go ridu.WithProjectMigrations(sqlite.ProjectMigrations(transforms...)) ``` ## WithAddress Canonical URL: https://riducms.com/reference/ridu/with-address/ Kind: function Configure the HTTP listen address independently from the store adapter. ```go func WithAddress(address string) ExecuteOption ``` The default is :8080, which listens on every interface. Use a loopback address when Ridu must be reachable only through a local reverse proxy or during development. This controls only the listener. Public host validation belongs to HandlerOptions.AllowedHosts. ```go ridu.WithAddress("127.0.0.1:8080") ``` ## WithUploadStorage Canonical URL: https://riducms.com/reference/ridu/with-upload-storage/ Kind: function Provide object storage through the Execute lifecycle. ```go func WithUploadStorage(factory StorageFactory) ExecuteOption ``` The factory runs only in the server branch. It supplies Config.Storage before application construction, keeping credentials and network setup out of the resolved schema manifest. Upload-enabled config still needs a stable Config.StorageNamespace and a document store with the upload capability contracts. Closable object storage shuts down before the document store. ```go ridu.WithUploadStorage(func(context.Context) (storage.Backend, error) { return s3.New(s3.Config{ Region: os.Getenv("S3_REGION"), Bucket: os.Getenv("S3_BUCKET"), }) }) ``` ## WithHandlerOptions Canonical URL: https://riducms.com/reference/ridu/with-handler-options/ Kind: function Configure the generated HTTP handler used by Execute. ```go func WithHandlerOptions(options HandlerOptions) ExecuteOption ``` Generated projects use this option to attach the compiled admin assets and environment-derived HTTP policy. Passing it replaces the complete HandlerOptions value; combine settings in one value rather than scattering repeated WithHandlerOptions calls. ```go ridu.WithHandlerOptions(ridu.HandlerOptions{ AdminAssets: adminassets.FS(), AllowedHosts: []string{"cms.example.com"}, SecureCookies: true, }) ``` ## WithServerOptions Canonical URL: https://riducms.com/reference/ridu/with-server-options/ Kind: function Configure production socket and graceful-drain bounds. ```go func WithServerOptions(options ServerOptions) ExecuteOption ``` Zero values select bounded production defaults. Repeating WithServerOptions replaces the complete value, so configure related bounds together. ```go ridu.WithServerOptions(ridu.ServerOptions{ ShutdownTimeout: 20 * time.Second, WorkerDrainTimeout: 30 * time.Second, ReadinessDrainDelay: 5 * time.Second, }) ``` ## NewTask Canonical URL: https://riducms.com/reference/ridu/new-task/ Kind: function Define a compiled typed durable task. ```go func NewTask[Input, Output any](slug string, handler TaskHandler[Input, Output], options ...TaskOption) TypedTask[Input, Output] ``` Add the returned definition to Config.Tasks. Input and output use strict JSON contracts, are capped by MaxTaskPayloadBytes, and never select executable code from serialized data. The backing store must implement store.TaskStore. ```go var RebuildSearch = ridu.NewTask( "rebuild-search", func( ctx ridu.TaskContext, input RebuildInput, ) (RebuildOutput, error) { // compiled application work return RebuildOutput{}, nil }, ridu.TaskQueue("maintenance"), ridu.TaskRetries( 3, time.Second, time.Minute, ridu.TaskBackoffExponential, ), ) ``` ## TypedTask Canonical URL: https://riducms.com/reference/ridu/typed-task/ Kind: type A registered typed handle for durable admission, status, and cancellation. ```go type TypedTask[Input, Output any] = core.TypedTask[Input, Output] ``` Only NewTask constructs a valid definition. Add it to Config.Tasks before using its runtime methods. The handle slug/type contract must match the definition registered in the running application. HasOutput distinguishes a valid zero/null output from incomplete work. ## TaskQueue Canonical URL: https://riducms.com/reference/ridu/task-queue/ Kind: function Select the queue used by a typed task. ```go func TaskQueue(queue string) TaskOption ``` ## TaskRetries Canonical URL: https://riducms.com/reference/ridu/task-retries/ Kind: function Persist retry count, delay, maximum delay, and backoff policy. ```go func TaskRetries(maxAttempts int, delay, maxDelay time.Duration, backoff TaskBackoff) TaskOption ``` Persisted policy prevents deployments from silently changing already-admitted work. ## TaskTimeout Canonical URL: https://riducms.com/reference/ridu/task-timeout/ Kind: function Bound one handler attempt. ```go func TaskTimeout(timeout time.Duration) TaskOption ``` ## TaskRetention Canonical URL: https://riducms.com/reference/ridu/task-retention/ Kind: function Keep terminal task status/output for a bounded duration. ```go func TaskRetention(retention time.Duration) TaskOption ``` ## TaskAdmissionReconciler Canonical URL: https://riducms.com/reference/ridu/task-admission-reconciler/ Kind: function Repair durable domain records that missed task admission. ```go func TaskAdmissionReconciler(reconcile TaskReconciler) TaskOption ``` The runtime invokes this bounded, idempotent callback before each selected claim cycle, including startup. ## RetryTask Canonical URL: https://riducms.com/reference/ridu/retry-task/ Kind: function Return a retryable handler failure using configured backoff. ```go func RetryTask(code string, cause error) error ``` ## RetryTaskAfter Canonical URL: https://riducms.com/reference/ridu/retry-task-after/ Kind: function Return a retryable handler failure with an explicit delay. ```go func RetryTaskAfter(code string, cause error, delay time.Duration) error ``` ## AbortTask Canonical URL: https://riducms.com/reference/ridu/abort-task/ Kind: function Return a terminal handler failure. ```go func AbortTask(code string, cause error) error ``` Use stable non-secret codes. Local runtime, store, and codec boundary failures use structured TaskError values. Handler panics and handler/output failures are classified into durable retry or dead-letter state instead. ## App Canonical URL: https://riducms.com/reference/ridu/app/ Kind: type A resolved application bound to its document and optional service stores. ```go type App = core.App ``` App owns initialized runtime services; its fields are intentionally private. Construct it with New, or let Execute own the ordinary production lifecycle. ## AdminConfig Canonical URL: https://riducms.com/reference/ridu/admin-config/ Kind: type Select the auth collection trusted to enter the framework admin. ```go type AdminConfig = core.AdminConfig ``` This setting selects the admin identity source; collection access still provides the authorization decision. ```go AdminConfig{User: "users"} ``` ## AdminLocalizationConfig Canonical URL: https://riducms.com/reference/ridu/admin-localization-config/ Kind: type Configure admin interface languages and editor timezone choices. ```go type AdminLocalizationConfig = core.AdminLocalizationConfig ``` ## AdminLanguage Canonical URL: https://riducms.com/reference/ridu/admin-language/ Kind: type One statically bundled admin interface language. ```go type AdminLanguage = core.AdminLanguage ``` ## AdminTimeZone Canonical URL: https://riducms.com/reference/ridu/admin-time-zone/ Kind: type One timezone offered to editors. ```go type AdminTimeZone = core.AdminTimeZone ``` ## CollectionLabels Canonical URL: https://riducms.com/reference/ridu/collection-labels/ Kind: type Singular and plural author-facing collection labels. ```go type CollectionLabels = core.CollectionLabels ``` ## CollectionIndex Canonical URL: https://riducms.com/reference/ridu/collection-index/ Kind: type One ordered compound index; Unique enforces tuple uniqueness. ```go type CollectionIndex = core.CollectionIndex ``` Compound paths traverse non-repeated groups. Unique indexes permit multiple rows containing null. ```go CollectionIndex{Fields: []string{"tenant", "slug"}, Unique: true} ``` ## GlobalAdmin Canonical URL: https://riducms.com/reference/ridu/global-admin/ Kind: type Serializable singleton presentation metadata. ```go type GlobalAdmin = core.GlobalAdmin ``` ## DocumentLockConfig Canonical URL: https://riducms.com/reference/ridu/document-lock-config/ Kind: type Expiration policy for coordinated authoring locks. ```go type DocumentLockConfig = core.DocumentLockConfig ``` ## PasswordPolicy Canonical URL: https://riducms.com/reference/ridu/password-policy/ Kind: type Length, byte, bcrypt, and common-password policy for local credentials. ```go type PasswordPolicy = core.PasswordPolicy ``` Ridu deliberately uses length-based defaults rather than mandatory character classes. The custom validator runs only in trusted Go code and is never serialized. ## PasswordResetConfig Canonical URL: https://riducms.com/reference/ridu/password-reset-config/ Kind: type Token lifetime and trusted notification callback for password recovery. ```go type PasswordResetConfig = core.PasswordResetConfig ``` ## VerifyEmailConfig Canonical URL: https://riducms.com/reference/ridu/verify-email-config/ Kind: type Token lifetime and trusted notification callback for email verification. ```go type VerifyEmailConfig = core.VerifyEmailConfig ``` ## AuthAccess Canonical URL: https://riducms.com/reference/ridu/auth-access/ Kind: type Rules for login, sessions, recovery, API keys, and external authentication. ```go type AuthAccess = core.AuthAccess ``` A nil rule allows its operation. These rules complement collection CRUD access; they do not replace it. ## AuthContext Canonical URL: https://riducms.com/reference/ridu/auth-context/ Kind: type Exact actor, operation, request, and LocalAPI state for an auth rule or hook. ```go type AuthContext = core.AuthContext ``` Passwords, bearer tokens, reset tokens, and API keys are intentionally never included. ## AuthHooks Canonical URL: https://riducms.com/reference/ridu/auth-hooks/ Kind: type Compiled authentication lifecycle observers. ```go type AuthHooks = core.AuthHooks ``` Before hooks can reject an operation. If an after-login or after-refresh hook fails, Ridu revokes the newly issued credential before returning the error. ## AuthStrategy Canonical URL: https://riducms.com/reference/ridu/auth-strategy/ Kind: type One compiled external request-authentication strategy. ```go type AuthStrategy = core.AuthStrategy ``` Strategies run in declaration order after built-in session and API-key authentication. Return Authenticated false when the request does not belong to the strategy. Strategies run in order and return not-applicable, authenticated, or rejected. They do not dynamically install identity providers. ## AuthIdentity Canonical URL: https://riducms.com/reference/ridu/auth-identity/ Kind: type An exact auth collection plus actor document. ```go type AuthIdentity = core.AuthIdentity ``` Prefer identity-aware methods when an application has more than one auth collection. Actor-only compatibility methods reject ambiguous identities rather than guessing. PreviewEpoch is opaque framework lifecycle state; ordinary callers leave it zero. ## AuthSession Canonical URL: https://riducms.com/reference/ridu/auth-session/ Kind: type A new bearer session, safe ID, typed user, and expiry. ```go type AuthSession = core.AuthSession ``` Token is a bearer secret. Store it only in a secure HTTP-only cookie or equivalent secret store; protocol/session-list representations never expose it. ## AuthSessionInfo Canonical URL: https://riducms.com/reference/ridu/auth-session-info/ Kind: type Safe session/device metadata without the bearer secret. ```go type AuthSessionInfo = core.AuthSessionInfo ``` ## APIKey Canonical URL: https://riducms.com/reference/ridu/api-key/ Kind: type A newly minted API key including its one-time secret. ```go type APIKey = core.APIKey ``` Key is a bearer secret. Persist it in the caller’s secret store because Ridu cannot display it again. ## APIKeyInfo Canonical URL: https://riducms.com/reference/ridu/api-key-info/ Kind: type Safe metadata for listing an existing API key. ```go type APIKeyInfo = core.APIKeyInfo ``` ## LoginOptions Canonical URL: https://riducms.com/reference/ridu/login-options/ Kind: type Client IP and user-agent metadata recorded with a session. ```go type LoginOptions = core.LoginOptions ``` Transports should derive IPAddress only after applying their trusted-proxy policy. These values are session metadata, not authentication factors. ## ImageSize Canonical URL: https://riducms.com/reference/ridu/image-size/ Kind: type One named derived image variant and fit policy. ```go type ImageSize = core.ImageSize ``` ## UploadInput Canonical URL: https://riducms.com/reference/ridu/upload-input/ Kind: type Streamed file bytes, application metadata, identity, and locale. ```go type UploadInput = core.UploadInput ``` Bytes, metadata, access, validation, hooks, storage, and document persistence run through one upload operation. The caller retains ownership of Reader. ## ReconcileResult Canonical URL: https://riducms.com/reference/ridu/reconcile-result/ Kind: type Scanned, candidate, and deleted counts from upload reconciliation. ```go type ReconcileResult = core.ReconcileResult ``` ## FindOptions Canonical URL: https://riducms.com/reference/ridu/find-options/ Kind: type Projection, population, actor, draft, trash, and locale controls for one read. ```go type FindOptions = core.FindOptions ``` The root package re-exports this type as ridu.FindOptions. A nil OutputFields resolves every output field; a non-nil empty slice resolves none. ## ListOptions Canonical URL: https://riducms.com/reference/ridu/list-options/ Kind: type Filter, page, sort, projection, population, actor, draft, trash, and locale list controls. ```go type ListOptions = core.ListOptions ``` The root package re-exports this type as ridu.ListOptions. TrashOnly is valid only for trash-enabled collections. ## DistinctOptions Canonical URL: https://riducms.com/reference/ridu/distinct-options/ Kind: type Field, filter, page, actor, draft, trash, and locale controls for a unique-value read. ```go type DistinctOptions = core.DistinctOptions ``` The root package re-exports this type as ridu.DistinctOptions. The initial contract intentionally excludes nested fields, arrays, and general aggregations. ## ListWindowOptions Canonical URL: https://riducms.com/reference/ridu/list-window-options/ Kind: type Bounded unique-index range, projection, actor, and locale controls. ```go type ListWindowOptions = core.ListWindowOptions ``` The root package re-exports this type as ridu.ListWindowOptions. The store transaction must implement the optional store.WindowTransaction capability. ## MutationOptions Canonical URL: https://riducms.com/reference/ridu/mutation-options/ Kind: type Actor, revision, draft, response, and locale controls for one write. ```go type MutationOptions = core.MutationOptions ``` The root package re-exports this type as ridu.MutationOptions. Updates preserve status so publish and unpublish hooks cannot be bypassed. Populate affects only the response, never validation or stored values. ## LocaleOptions Canonical URL: https://riducms.com/reference/ridu/locale-options/ Kind: type Locale selection for concise single-document calls. ```go type LocaleOptions = core.LocaleOptions ``` The root package re-exports this type as ridu.LocaleOptions. When a variadic method receives more than one value, the last one is used. ## CapabilityOptions Canonical URL: https://riducms.com/reference/ridu/capability-options/ Kind: type Proposed data, actor, trash, and locale input for side-effect-free access evaluation. ```go type CapabilityOptions = core.CapabilityOptions ``` Data models proposed create/update values. Capabilities runs no hooks, validation, or mutation and returns booleans only—not access predicates. ## AccessCapabilities Canonical URL: https://riducms.com/reference/ridu/access-capabilities/ Kind: type Evaluated operation and field permission booleans. ```go type AccessCapabilities = core.AccessCapabilities ``` Suitable for authoring UI hints. The actual operation always re-runs authorization transactionally; capabilities are never authority. ## ImportOptions Canonical URL: https://riducms.com/reference/ridu/import-options/ Kind: type Trusted migration identity, status, and source timestamps. ```go type ImportOptions = core.ImportOptions ``` LocalAPI.Import still runs access, field validation, hooks, transaction, reference, upload, and version logic. Use only for trusted migrations. ## OperationError Canonical URL: https://riducms.com/reference/ridu/operation-error/ Kind: type The stable code, HTTP status, message, validation issues, cause, and commit-state error returned across operation boundaries. ```go type OperationError = core.OperationError ``` When CommitAttempted is true, retain and reconcile external resources instead of eagerly rolling them back. OperationError implements Error and Unwrap. ## ServerOptions Canonical URL: https://riducms.com/reference/ridu/server-options/ Kind: type Socket timeouts, graceful drain, and readiness admission. ```go type ServerOptions = core.ServerOptions ``` Zero values use conservative defaults. Negative socket timeouts disable that individual bound; non-positive shutdown and worker-drain timeouts still use bounded defaults. WithServerOptions installs one complete value into Execute. Socket timeouts accept negative values to disable an individual bound; shutdown and worker-drain timeouts remain bounded at 15 seconds when non-positive. AllowUnverifiableReadiness and SkipReadinessPreflight are explicit escape hatches, not general production defaults. Official adapters implement the readiness contracts required by normal startup. ```go options := ridu.ServerOptions{ ReadHeaderTimeout: 10 * time.Second, ShutdownTimeout: 20 * time.Second, WorkerDrainTimeout: 30 * time.Second, ReadinessDrainDelay: 5 * time.Second, } ``` ## StoreFactory Canonical URL: https://riducms.com/reference/ridu/store-factory/ Kind: type A lazy, lifecycle-owned document-store constructor. ```go type StoreFactory = core.StoreFactory ``` Project commands resolve configuration without calling this factory. Execute closes the returned store during shutdown. Use a closure to read runtime configuration and adapt a concrete constructor such as postgres.Open to the store.Store return type. Go function types do not widen concrete return values automatically. Do not open the database in package initialization or content.Config. Keeping the connection inside this factory is what lets schema discovery and generation run without database access. ```go func openStore(ctx context.Context) (store.Store, error) { return postgres.Open(ctx, os.Getenv("DATABASE_URL")) } err := ridu.Execute(content.Config(), ridu.WithStore(openStore)) ``` ## StorageFactory Canonical URL: https://riducms.com/reference/ridu/storage-factory/ Kind: type A lazy, lifecycle-owned object-storage constructor. ```go type StorageFactory = core.StorageFactory ``` This is runtime infrastructure, not a plugin. Execute closes closable storage before the document store. Use this runtime factory with WithUploadStorage. It keeps storage credentials out of the serializable config and schema manifest. Execute closes a backend implementing Close() or Close() error before it closes the document store. ```go func openStorage(context.Context) (storage.Backend, error) { return s3.New(s3.Config{ Region: os.Getenv("S3_REGION"), Bucket: os.Getenv("S3_BUCKET"), }) } ``` ## ReadinessCheck Canonical URL: https://riducms.com/reference/ridu/readiness-check/ Kind: type A bounded repeatable custom readiness dependency check. ```go type ReadinessCheck = core.ReadinessCheck ``` Checks must be read-only, repeatable, and honor context cancellation. Add them through HandlerOptions.ReadinessChecks. ## AuditEvent Canonical URL: https://riducms.com/reference/ridu/audit-event/ Kind: type Security-relevant application event metadata. ```go type AuditEvent = core.AuditEvent ``` ## RequestObservation Canonical URL: https://riducms.com/reference/ridu/request-observation/ Kind: type Completed request timing, route, response size, error code, and status metadata. ```go type RequestObservation = core.RequestObservation ``` ## RequestErrorEvent Canonical URL: https://riducms.com/reference/ridu/request-error-event/ Kind: type Trusted internal diagnostic detail hidden from public HTTP responses. ```go type RequestErrorEvent = core.RequestErrorEvent ``` This value is for trusted diagnostics and may contain dependency detail. Never forward Error or Stack to an untrusted client. ## Plugin Canonical URL: https://riducms.com/reference/ridu/plugin/ Kind: type The minimum stable-key contract for trusted compiled backend extensions. ```go type Plugin = core.Plugin ``` Focused capability interfaces add transforms, descriptors, hooks, validators, endpoints, or transports without one universal option bag. Plugins are trusted compiled Go code; production never installs code dynamically. ## PluginDescriptor Canonical URL: https://riducms.com/reference/ridu/plugin-descriptor/ Kind: type Versioned public generation, migration, and admin metadata. ```go type PluginDescriptor = core.PluginDescriptor ``` Deterministic public metadata copied into the manifest. Executable code, handlers, validators, secrets, and environment-specific configuration never belong here. ## DescriptorProvider Canonical URL: https://riducms.com/reference/ridu/descriptor-provider/ Kind: type A plugin providing versioned public metadata. ```go type DescriptorProvider = core.DescriptorProvider ``` Required for plugins exposing advanced admin, endpoint, transport, hook, generated-field, or migration capabilities. Key-only plugins remain valid for simple config transforms or validators without build metadata. ## GenerationProvider Canonical URL: https://riducms.com/reference/ridu/generation-provider/ Kind: type A plugin contributing deterministic files from executable configuration. ```go type GenerationProvider = core.GenerationProvider ``` Runs only when a generated.. destination requests the provider. Execution stays inside the compiled project command without stores, storage, listeners, or network introspection; the portable CLI owns destinations, atomic installation, and drift checks. ## PluginGenerationContext Canonical URL: https://riducms.com/reference/ridu/plugin-generation-context/ Kind: type Immutable manifest input for compiled plugin generation. ```go type PluginGenerationContext = core.PluginGenerationContext ``` ## PluginGeneratedArtifact Canonical URL: https://riducms.com/reference/ridu/plugin-generated-artifact/ Kind: type A deterministic plugin-scoped generated file. ```go type PluginGeneratedArtifact = core.PluginGeneratedArtifact ``` Name is lowercase kebab-case beneath the provider key. Content must be non-empty and is defensively copied before crossing the project protocol. ## ConfigTransformer Canonical URL: https://riducms.com/reference/ridu/config-transformer/ Kind: type A plugin transforming defensive config copies before final resolution. ```go type ConfigTransformer = core.ConfigTransformer ``` Runs in Config.Plugins declaration order. Prefer focused capabilities for hooks and fields when a general config transform is unnecessary. ## HookProvider Canonical URL: https://riducms.com/reference/ridu/hook-provider/ Kind: type A plugin contributing ordered collection or field hooks. ```go type HookProvider = core.HookProvider ``` Contributions run in plugin order after application-authored hooks. FieldPath is an optional canonical path. ## FieldValidatorProvider Canonical URL: https://riducms.com/reference/ridu/field-validator-provider/ Kind: type A plugin validating its custom field values. ```go type FieldValidatorProvider = core.FieldValidatorProvider ``` RuntimePath contains concrete array/block indexes. Validators return schema.Issue values and must be deterministic and side-effect-free. ## EndpointProvider Canonical URL: https://riducms.com/reference/ridu/endpoint-provider/ Kind: type A plugin contributing namespaced REST endpoints. ```go type EndpointProvider = core.EndpointProvider ``` Routes live below /api/plugins//. Handlers receive exact actor identity, LocalAPI, trusted client IP, auth-admission, and diagnostic reporting helpers. Body limits inherit the application bound unless explicitly overridden. ## TransportProvider Canonical URL: https://riducms.com/reference/ridu/transport-provider/ Kind: type A plugin binding an application-level protocol transport. ```go type TransportProvider = core.TransportProvider ``` For absolute protocol paths such as /api/graphql, not ordinary plugin endpoints. Binding receives the immutable manifest, LocalAPI, and fully initialized App; do not rebuild schemas per request. ## TaskContext Canonical URL: https://riducms.com/reference/ridu/task-context/ Kind: type Cancellation, task identity, attempt number, and application access for one handler. ```go type TaskContext = core.TaskContext ``` Tasks do not receive a privileged content path. ## TaskEnqueueOptions Canonical URL: https://riducms.com/reference/ridu/task-enqueue-options/ Kind: type Run time, queue, concurrency key, target, and requester for admission. ```go type TaskEnqueueOptions = core.TaskEnqueueOptions ``` ## TaskReceipt Canonical URL: https://riducms.com/reference/ridu/task-receipt/ Kind: type A typed stable handle returned by durable admission. ```go type TaskReceipt[Output any] = core.TaskReceipt[Output] ``` ## TaskResult Canonical URL: https://riducms.com/reference/ridu/task-result/ Kind: type Typed task status, attempts, failure, timestamps, and optional output. ```go type TaskResult[Output any] = core.TaskResult[Output] ``` ## TaskError Canonical URL: https://riducms.com/reference/ridu/task-error/ Kind: type A stable typed durable-task failure. ```go type TaskError = core.TaskError ``` TaskError implements Error and Unwrap for local runtime, store, and codec failures. Handler failures use RetryTask, RetryTaskAfter, or AbortTask; their bounded messages are persisted on durable task state instead. ## AccessDecisionKind Canonical URL: https://riducms.com/reference/ridu/access-decision-kind/ Kind: type Allow, deny, or filtered-decision discriminant. ```go type AccessDecisionKind = core.AccessDecisionKind ``` ## AdminPluginMetadata Canonical URL: https://riducms.com/reference/ridu/admin-plugin-metadata/ Kind: type Static package/export pairing for a plugin admin half. ```go type AdminPluginMetadata = core.AdminPluginMetadata ``` Package and Export are statically imported at admin build time. Increment PairingVersion when backend and admin halves cease to be compatible. ## AuthAccessRule Canonical URL: https://riducms.com/reference/ridu/auth-access-rule/ Kind: type Allow or deny one non-CRUD authentication operation. ```go type AuthAccessRule = core.AuthAccessRule ``` ## AuthHook Canonical URL: https://riducms.com/reference/ridu/auth-hook/ Kind: type Observe or reject one authentication lifecycle phase. ```go type AuthHook = core.AuthHook ``` ## AuthOperation Canonical URL: https://riducms.com/reference/ridu/auth-operation/ Kind: type Login, logout, refresh, recovery, verification, API-key, or external-auth operation. ```go type AuthOperation = core.AuthOperation ``` ## AuthStrategyContext Canonical URL: https://riducms.com/reference/ridu/auth-strategy-context/ Kind: type Normalized headers and target collection for an external strategy. ```go type AuthStrategyContext = core.AuthStrategyContext ``` ## AuthStrategyResult Canonical URL: https://riducms.com/reference/ridu/auth-strategy-result/ Kind: type Whether an external strategy recognized and authenticated a request. ```go type AuthStrategyResult = core.AuthStrategyResult ``` An authenticated result must supply UserID. A false result means “not applicable,” allowing the next strategy to run. ## ComputedContext Canonical URL: https://riducms.com/reference/ridu/computed-context/ Kind: type Trusted document, actor, locale, operation, and LocalAPI inputs for a virtual resolver. ```go type ComputedContext = core.ComputedContext ``` ## ExecuteOption Canonical URL: https://riducms.com/reference/ridu/execute-option/ Kind: type One opaque runtime option accepted by Execute. ```go type ExecuteOption = core.ExecuteOption ``` Applications cannot implement this type because its input is private. Use WithStore, WithProjectMigrations, WithUploadStorage, WithAddress, WithHandlerOptions, and WithServerOptions; later duplicate options replace earlier values. ExecuteOption is intentionally opaque: application code chooses from Ridu’s public With… constructors rather than mutating the internal server state or defining custom lifecycle options. Options are applied in argument order when Execute starts the no-argument server branch. If the same constructor is supplied more than once, the later value replaces the earlier value for that setting. When the executable is serving a project command, Execute resolves config and returns before applying these options. Store and storage factories therefore remain untouched during schema discovery, generate, and check. ```go options := []ridu.ExecuteOption{ ridu.WithStore(openStore), ridu.WithProjectMigrations(projectMigrations), ridu.WithAddress(":8080"), ridu.WithHandlerOptions(ridu.HandlerOptions{ AdminAssets: adminassets.FS(), }), } if err := ridu.Execute(content.Config(), options...); err != nil { log.Fatal(err) } ``` ## LocalAPI Canonical URL: https://riducms.com/reference/ridu/local-api/ Kind: type In-process content operations over the shared operation engine. ```go type LocalAPI = core.LocalAPI ``` HookContext.Local reuses the active transaction during pre-commit phases. AfterCommit and AfterError run outside it, so nested calls start a new transaction. Application services normally access this API through app.Local(). ```go post, err := app.Local().Create(ctx, "posts", store.Values{ "title": store.String("Hello, Ridu"), }, actor) if err != nil { return err } ``` ## OperationCapabilities Canonical URL: https://riducms.com/reference/ridu/operation-capabilities/ Kind: type Evaluated boolean permissions for resource operations. ```go type OperationCapabilities = core.OperationCapabilities ``` The summary deliberately excludes executable rules and filtered-access predicates. Treat it as UI capability data, never as authorization. ## FieldCapabilities Canonical URL: https://riducms.com/reference/ridu/field-capabilities/ Kind: type Evaluated read/create/update booleans for one field path. ```go type FieldCapabilities = core.FieldCapabilities ``` ## JoinMutationResult Canonical URL: https://riducms.com/reference/ridu/join-mutation-result/ Kind: type Refreshed source document plus applied inverse-relation delta counts. ```go type JoinMutationResult = core.JoinMutationResult ``` ## PasswordResetNotification Canonical URL: https://riducms.com/reference/ridu/password-reset-notification/ Kind: type Trusted password-reset delivery payload including the raw one-time token. ```go type PasswordResetNotification = core.PasswordResetNotification ``` Token is shown once and must never be logged. Build and deliver the application-owned reset link inside the trusted callback. ## VerifyEmailNotification Canonical URL: https://riducms.com/reference/ridu/verify-email-notification/ Kind: type Trusted email-verification delivery payload including the raw one-time token. ```go type VerifyEmailNotification = core.VerifyEmailNotification ``` Token is shown once and must never be logged. Build and deliver the application-owned verification link inside the trusted callback. ## PreviewBreakpoint Canonical URL: https://riducms.com/reference/ridu/preview-breakpoint/ Kind: type One named live-preview viewport. ```go type PreviewBreakpoint = core.PreviewBreakpoint ``` ## RiduCompatibility Canonical URL: https://riducms.com/reference/ridu/ridu-compatibility/ Kind: type Half-open framework version range supported by a plugin. ```go type RiduCompatibility = core.RiduCompatibility ``` Minimum is inclusive. Empty MaximumExclusive leaves the upper bound open. Test published ranges with plugintest. ## PluginFieldType Canonical URL: https://riducms.com/reference/ridu/plugin-field-type/ Kind: type Generated Go, TypeScript, where, and OpenAPI mapping for a plugin field. ```go type PluginFieldType = core.PluginFieldType ``` Go type mapping is optional and falls back to json.RawMessage. TypeScript names are emitted as type-only imports. JSONSchema must be deterministic. ## PluginDatabaseAdapter Canonical URL: https://riducms.com/reference/ridu/plugin-database-adapter/ Kind: type PostgreSQL or SQLite identity for exceptional private plugin schema. ```go type PluginDatabaseAdapter = core.PluginDatabaseAdapter ``` PluginDatabaseAdapterPostgres selects PostgreSQL SQL; PluginDatabaseAdapterSQLite selects SQLite SQL. ## PluginDatabaseContribution Canonical URL: https://riducms.com/reference/ridu/plugin-database-contribution/ Kind: type One explicitly adapter-scoped private plugin migration bundle. ```go type PluginDatabaseContribution = core.PluginDatabaseContribution ``` Use ordinary ConfigTransformer collections for normal plugin records. Ridu never translates contribution SQL between adapters. ## PluginMigration Canonical URL: https://riducms.com/reference/ridu/plugin-migration/ Kind: type One immutable contiguous reversible plugin database transition. ```go type PluginMigration = core.PluginMigration ``` Versions start at 1 without gaps. Ridu copies the SQL into migration artifacts and rejects changed history before execution. ## PluginHookContribution Canonical URL: https://riducms.com/reference/ridu/plugin-hook-contribution/ Kind: type Ordered collection or field hooks contributed by a plugin. ```go type PluginHookContribution = core.PluginHookContribution ``` ## PluginFieldValidationContext Canonical URL: https://riducms.com/reference/ridu/plugin-field-validation-context/ Kind: type Resolved field, concrete runtime path, and candidate value for validation. ```go type PluginFieldValidationContext = core.PluginFieldValidationContext ``` ## PluginFieldValidator Canonical URL: https://riducms.com/reference/ridu/plugin-field-validator/ Kind: type Return path-aware issues for one plugin-owned value. ```go type PluginFieldValidator = core.PluginFieldValidator ``` ## Endpoint Canonical URL: https://riducms.com/reference/ridu/endpoint/ Kind: type One application-authored method and path handler mounted at root, collection, or global scope. ```go type Endpoint = core.Endpoint ``` Root endpoints mount below /api. Collection and global endpoints mount below their resource route and run before a matching built-in route for the same method. Custom endpoints are anonymous by default. Handler must enforce endpoint-specific authorization. ## EndpointContext Canonical URL: https://riducms.com/reference/ridu/endpoint-context/ Kind: type Raw HTTP, route parameters, actor identity, and LocalAPI supplied to a custom endpoint. ```go type EndpointContext = core.EndpointContext ``` ## EndpointHandler Canonical URL: https://riducms.com/reference/ridu/endpoint-handler/ Kind: type Trusted compiled custom endpoint handler. ```go type EndpointHandler = core.EndpointHandler ``` ## PluginEndpoint Canonical URL: https://riducms.com/reference/ridu/plugin-endpoint/ Kind: type One exact method-specific namespaced REST endpoint. ```go type PluginEndpoint = core.PluginEndpoint ``` ## PluginEndpointContext Canonical URL: https://riducms.com/reference/ridu/plugin-endpoint-context/ Kind: type HTTP, exact actor identity, LocalAPI, rate-admission, and diagnostic helpers. ```go type PluginEndpointContext = core.PluginEndpointContext ``` ## PluginEndpointHandler Canonical URL: https://riducms.com/reference/ridu/plugin-endpoint-handler/ Kind: type Trusted compiled namespaced endpoint handler. ```go type PluginEndpointHandler = core.PluginEndpointHandler ``` ## PluginTransport Canonical URL: https://riducms.com/reference/ridu/plugin-transport/ Kind: type One absolute application-level protocol route. ```go type PluginTransport = core.PluginTransport ``` Unlike PluginEndpoint, a transport is not placed below a plugin namespace. Use it for established protocol locations, not ordinary plugin REST endpoints. ## PluginTransportContext Canonical URL: https://riducms.com/reference/ridu/plugin-transport-context/ Kind: type Immutable manifest and initialized public APIs supplied during protocol binding. ```go type PluginTransportContext = core.PluginTransportContext ``` ## TaskBackoff Canonical URL: https://riducms.com/reference/ridu/task-backoff/ Kind: type Fixed, linear, or exponential durable retry schedule. ```go type TaskBackoff = core.TaskBackoff ``` ## TaskDefinition Canonical URL: https://riducms.com/reference/ridu/task-definition/ Kind: type Non-generic compiled task boundary stored in Config.Tasks. ```go type TaskDefinition = core.TaskDefinition ``` Only values returned by NewTask can implement this sealed interface, so serialized input can never select or supply executable code. ## TaskErrorCode Canonical URL: https://riducms.com/reference/ridu/task-error-code/ Kind: type Stable framework task failure category. ```go type TaskErrorCode = core.TaskErrorCode ``` ## TaskOption Canonical URL: https://riducms.com/reference/ridu/task-option/ Kind: type One typed task policy option. ```go type TaskOption = core.TaskOption ``` Application code cannot inspect or implement TaskOption because taskConfig is private. Use TaskQueue, TaskRetries, TaskTimeout, TaskRetention, and TaskAdmissionReconciler to construct values. ## TaskReconciler Canonical URL: https://riducms.com/reference/ridu/task-reconciler/ Kind: type Bounded recovery scan for a durable task admission gap. ```go type TaskReconciler = core.TaskReconciler ``` Reconcilers run before every selected task claim cycle, including startup, and must be bounded, idempotent, and safe across concurrent instances. ## TaskRunSummary Canonical URL: https://riducms.com/reference/ridu/task-run-summary/ Kind: type Claimed, succeeded, failed, and released counts for a worker cycle. ```go type TaskRunSummary = core.TaskRunSummary ``` Handler failures are persisted as retry or dead-letter state and do not become infrastructure errors. ## FrameworkVersion Canonical URL: https://riducms.com/reference/ridu/framework-version/ Kind: constant The semantic Ridu framework version used by project and CLI compatibility checks. ```go const FrameworkVersion = core.FrameworkVersion ``` ## PluginAPIVersion Canonical URL: https://riducms.com/reference/ridu/plugin-api-version/ Kind: constant The compiled backend plugin API version required by PluginDescriptor. ```go const PluginAPIVersion = core.PluginAPIVersion ``` ## AdminPluginAPIVersion Canonical URL: https://riducms.com/reference/ridu/admin-plugin-api-version/ Kind: constant The statically bundled admin-plugin API version required by AdminPluginMetadata. ```go const AdminPluginAPIVersion = core.AdminPluginAPIVersion ``` ## PluginDatabaseAdapterPostgres Canonical URL: https://riducms.com/reference/ridu/plugin-database-adapter-postgres/ Kind: constant Select PostgreSQL-specific private plugin schema. ```go const PluginDatabaseAdapterPostgres = core.PluginDatabaseAdapterPostgres ``` ## PluginDatabaseAdapterSQLite Canonical URL: https://riducms.com/reference/ridu/plugin-database-adapter-sqlite/ Kind: constant Select SQLite-specific private plugin schema. ```go const PluginDatabaseAdapterSQLite = core.PluginDatabaseAdapterSQLite ``` ## MaxTaskPayloadBytes Canonical URL: https://riducms.com/reference/ridu/max-task-payload-bytes/ Kind: constant The maximum encoded JSON size accepted for durable task input or output. ```go const MaxTaskPayloadBytes = core.MaxTaskPayloadBytes ``` ## TaskHandler Canonical URL: https://riducms.com/reference/ridu/task-handler/ Kind: type A compiled typed durable task function. ```go type TaskHandler[Input, Output any] = core.TaskHandler[Input, Output] ``` Handlers must honor cancellation and make external side effects idempotent because a process crash or lease expiry can cause another attempt. ## TaskState Canonical URL: https://riducms.com/reference/ridu/task-state/ Kind: type Queued, running, succeeded, failed, or canceled durable state. ```go type TaskState = store.TaskState ``` ## AccessAllow Canonical URL: https://riducms.com/reference/ridu/access-allow/ Kind: constant Public constant AccessAllow from github.com/riducms/ridu. ```go const AccessAllow = core.AccessAllow ``` ## AccessDeny Canonical URL: https://riducms.com/reference/ridu/access-deny/ Kind: constant Public constant AccessDeny from github.com/riducms/ridu. ```go const AccessDeny = core.AccessDeny ``` ## AccessWhere Canonical URL: https://riducms.com/reference/ridu/access-where/ Kind: constant Public constant AccessWhere from github.com/riducms/ridu. ```go const AccessWhere = core.AccessWhere ``` ## AuthOperationAPIKey Canonical URL: https://riducms.com/reference/ridu/auth-operation-api-key/ Kind: constant Public constant AuthOperationAPIKey from github.com/riducms/ridu. ```go const AuthOperationAPIKey = core.AuthOperationAPIKey ``` ## AuthOperationEmailVerification Canonical URL: https://riducms.com/reference/ridu/auth-operation-email-verification/ Kind: constant Public constant AuthOperationEmailVerification from github.com/riducms/ridu. ```go const AuthOperationEmailVerification = core.AuthOperationEmailVerification ``` ## AuthOperationExternalStrategy Canonical URL: https://riducms.com/reference/ridu/auth-operation-external-strategy/ Kind: constant Public constant AuthOperationExternalStrategy from github.com/riducms/ridu. ```go const AuthOperationExternalStrategy = core.AuthOperationExternalStrategy ``` ## AuthOperationLogin Canonical URL: https://riducms.com/reference/ridu/auth-operation-login/ Kind: constant Public constant AuthOperationLogin from github.com/riducms/ridu. ```go const AuthOperationLogin = core.AuthOperationLogin ``` ## AuthOperationLogout Canonical URL: https://riducms.com/reference/ridu/auth-operation-logout/ Kind: constant Public constant AuthOperationLogout from github.com/riducms/ridu. ```go const AuthOperationLogout = core.AuthOperationLogout ``` ## AuthOperationPasswordReset Canonical URL: https://riducms.com/reference/ridu/auth-operation-password-reset/ Kind: constant Public constant AuthOperationPasswordReset from github.com/riducms/ridu. ```go const AuthOperationPasswordReset = core.AuthOperationPasswordReset ``` ## AuthOperationRefresh Canonical URL: https://riducms.com/reference/ridu/auth-operation-refresh/ Kind: constant Public constant AuthOperationRefresh from github.com/riducms/ridu. ```go const AuthOperationRefresh = core.AuthOperationRefresh ``` ## OperationAdmin Canonical URL: https://riducms.com/reference/ridu/operation-admin/ Kind: constant Public constant OperationAdmin from github.com/riducms/ridu. ```go const OperationAdmin = core.OperationAdmin ``` ## OperationCreate Canonical URL: https://riducms.com/reference/ridu/operation-create/ Kind: constant Public constant OperationCreate from github.com/riducms/ridu. ```go const OperationCreate = core.OperationCreate ``` ## OperationDelete Canonical URL: https://riducms.com/reference/ridu/operation-delete/ Kind: constant Public constant OperationDelete from github.com/riducms/ridu. ```go const OperationDelete = core.OperationDelete ``` ## OperationDeletePermanent Canonical URL: https://riducms.com/reference/ridu/operation-delete-permanent/ Kind: constant Public constant OperationDeletePermanent from github.com/riducms/ridu. ```go const OperationDeletePermanent = core.OperationDeletePermanent ``` ## OperationDuplicate Canonical URL: https://riducms.com/reference/ridu/operation-duplicate/ Kind: constant Public constant OperationDuplicate from github.com/riducms/ridu. ```go const OperationDuplicate = core.OperationDuplicate ``` ## OperationPublish Canonical URL: https://riducms.com/reference/ridu/operation-publish/ Kind: constant Public constant OperationPublish from github.com/riducms/ridu. ```go const OperationPublish = core.OperationPublish ``` ## OperationRead Canonical URL: https://riducms.com/reference/ridu/operation-read/ Kind: constant Public constant OperationRead from github.com/riducms/ridu. ```go const OperationRead = core.OperationRead ``` ## OperationReadVersions Canonical URL: https://riducms.com/reference/ridu/operation-read-versions/ Kind: constant Public constant OperationReadVersions from github.com/riducms/ridu. ```go const OperationReadVersions = core.OperationReadVersions ``` ## OperationRestoreDeleted Canonical URL: https://riducms.com/reference/ridu/operation-restore-deleted/ Kind: constant Public constant OperationRestoreDeleted from github.com/riducms/ridu. ```go const OperationRestoreDeleted = core.OperationRestoreDeleted ``` ## OperationUnpublish Canonical URL: https://riducms.com/reference/ridu/operation-unpublish/ Kind: constant Public constant OperationUnpublish from github.com/riducms/ridu. ```go const OperationUnpublish = core.OperationUnpublish ``` ## OperationUpdate Canonical URL: https://riducms.com/reference/ridu/operation-update/ Kind: constant Public constant OperationUpdate from github.com/riducms/ridu. ```go const OperationUpdate = core.OperationUpdate ``` ## TaskBackoffExponential Canonical URL: https://riducms.com/reference/ridu/task-backoff-exponential/ Kind: constant Public constant TaskBackoffExponential from github.com/riducms/ridu. ```go const TaskBackoffExponential = core.TaskBackoffExponential ``` ## TaskBackoffFixed Canonical URL: https://riducms.com/reference/ridu/task-backoff-fixed/ Kind: constant Public constant TaskBackoffFixed from github.com/riducms/ridu. ```go const TaskBackoffFixed = core.TaskBackoffFixed ``` ## TaskBackoffLinear Canonical URL: https://riducms.com/reference/ridu/task-backoff-linear/ Kind: constant Public constant TaskBackoffLinear from github.com/riducms/ridu. ```go const TaskBackoffLinear = core.TaskBackoffLinear ``` ## TaskErrorInvalidInput Canonical URL: https://riducms.com/reference/ridu/task-error-invalid-input/ Kind: constant Public constant TaskErrorInvalidInput from github.com/riducms/ridu. ```go const TaskErrorInvalidInput = core.TaskErrorInvalidInput ``` ## TaskErrorInvalidOutput Canonical URL: https://riducms.com/reference/ridu/task-error-invalid-output/ Kind: constant Public constant TaskErrorInvalidOutput from github.com/riducms/ridu. ```go const TaskErrorInvalidOutput = core.TaskErrorInvalidOutput ``` ## TaskErrorLeaseLost Canonical URL: https://riducms.com/reference/ridu/task-error-lease-lost/ Kind: constant Public constant TaskErrorLeaseLost from github.com/riducms/ridu. ```go const TaskErrorLeaseLost = core.TaskErrorLeaseLost ``` ## TaskErrorNotFound Canonical URL: https://riducms.com/reference/ridu/task-error-not-found/ Kind: constant Public constant TaskErrorNotFound from github.com/riducms/ridu. ```go const TaskErrorNotFound = core.TaskErrorNotFound ``` ## TaskErrorNotRegistered Canonical URL: https://riducms.com/reference/ridu/task-error-not-registered/ Kind: constant Public constant TaskErrorNotRegistered from github.com/riducms/ridu. ```go const TaskErrorNotRegistered = core.TaskErrorNotRegistered ``` ## TaskErrorStoreFailed Canonical URL: https://riducms.com/reference/ridu/task-error-store-failed/ Kind: constant Public constant TaskErrorStoreFailed from github.com/riducms/ridu. ```go const TaskErrorStoreFailed = core.TaskErrorStoreFailed ``` ## TaskErrorUnavailable Canonical URL: https://riducms.com/reference/ridu/task-error-unavailable/ Kind: constant Public constant TaskErrorUnavailable from github.com/riducms/ridu. ```go const TaskErrorUnavailable = core.TaskErrorUnavailable ``` ## TaskStateCanceled Canonical URL: https://riducms.com/reference/ridu/task-state-canceled/ Kind: constant Public constant TaskStateCanceled from github.com/riducms/ridu. ```go const TaskStateCanceled = store.TaskStateCanceled ``` ## TaskStateFailed Canonical URL: https://riducms.com/reference/ridu/task-state-failed/ Kind: constant Public constant TaskStateFailed from github.com/riducms/ridu. ```go const TaskStateFailed = store.TaskStateFailed ``` ## TaskStateQueued Canonical URL: https://riducms.com/reference/ridu/task-state-queued/ Kind: constant Public constant TaskStateQueued from github.com/riducms/ridu. ```go const TaskStateQueued = store.TaskStateQueued ``` ## TaskStateRunning Canonical URL: https://riducms.com/reference/ridu/task-state-running/ Kind: constant Public constant TaskStateRunning from github.com/riducms/ridu. ```go const TaskStateRunning = store.TaskStateRunning ``` ## TaskStateSucceeded Canonical URL: https://riducms.com/reference/ridu/task-state-succeeded/ Kind: constant Public constant TaskStateSucceeded from github.com/riducms/ridu. ```go const TaskStateSucceeded = store.TaskStateSucceeded ``` --- # API Reference: core Canonical URL: https://riducms.com/reference/core/ Package: github.com/riducms/ridu/core Application contracts and the operation runtime behind the root facade. ## FrameworkVersion Canonical URL: https://riducms.com/reference/core/framework-version/ Kind: constant The semantic Ridu framework version used by the CLI and project-command compatibility handshake. ```go const FrameworkVersion = "0.1.1" ``` Release builds replace the development value. Generated projects and the CLI must use matching framework versions; do not use this as a schema-manifest or REST protocol version. ## PluginAPIVersion Canonical URL: https://riducms.com/reference/core/plugin-api-version/ Kind: constant The compiled backend plugin contract version supported by this Ridu release. ```go const PluginAPIVersion = schema.CurrentPluginAPIVersion ``` PluginDescriptor.APIVersion must equal this value. The current value is 1. ## AdminPluginAPIVersion Canonical URL: https://riducms.com/reference/core/admin-plugin-api-version/ Kind: constant The statically bundled admin-plugin contract version supported by this Ridu release. ```go const AdminPluginAPIVersion = schema.CurrentAdminPluginAPIVersion ``` AdminPluginMetadata.APIVersion must equal this value. The current value is 1. ## MaxTaskPayloadBytes Canonical URL: https://riducms.com/reference/core/max-task-payload-bytes/ Kind: constant The maximum encoded JSON size accepted for durable task input or output. ```go const MaxTaskPayloadBytes = store.MaxTaskPayloadBytes ``` The current limit is 1 MiB. Larger files belong in object storage, referenced by a compact task payload. ## App Canonical URL: https://riducms.com/reference/core/app/ Kind: type A resolved application bound to operation services. ```go type App struct { manifest schema.Manifest local *LocalAPI auth store.AuthStore authMaintenance store.AuthMaintenanceStore authByID map[schema.StableID]schema.Collection authBySlug map[string]schema.Collection authOrder []schema.Collection authConfigBySlug map[string]AuthConfig authCreatePolicySet map[string]bool dummyPasswordHashes map[string][]byte passwordWork *passwordWorkLimiter bySlug map[string]schema.Collection globalsBySlug map[string]schema.Global uploads uploads.Manager tasks store.TaskStore taskRegistry map[string]taskRuntime health store.HealthStore readiness store.ReadinessStore migrationReadiness store.MigrationReadinessStore migrationHistoryDigest string storageHealth storage.HealthBackend readinessAdmission chan struct{} uploadCleanupAdmission chan struct{} uploadCleanupTimeout time.Duration draining atomic.Bool preferences store.PreferenceStore documentLocks store.DocumentLockStore documentStore store.Store previewTokens *previewTokenRegistry adminUserCollection schema.StableID pluginEndpoints []runtimePluginEndpoint customEndpoints []runtimeEndpoint pluginTransports []runtimePluginTransport availableLocales LocaleAvailability } ``` App owns initialized runtime services; its fields are intentionally private. Construct it with New, or let Execute own the ordinary production lifecycle. ## LocalAPI Canonical URL: https://riducms.com/reference/core/local-api/ Kind: type In-process content operations that share the REST authorization and lifecycle pipeline. ```go type LocalAPI struct { engine *operationengine.Engine } ``` HookContext.Local reuses the active transaction during pre-commit phases. AfterCommit and AfterError run outside it, so nested calls start a new transaction. Application services normally access this API through app.Local(). ```go post, err := app.Local().Create(ctx, "posts", store.Values{ "title": store.String("Hello, Ridu"), }, actor) if err != nil { return err } ``` ## LocaleOptions Canonical URL: https://riducms.com/reference/core/locale-options/ Kind: type Locale selection for one single-document Local API operation. ```go type LocaleOptions struct { Locale schema.LocaleCode FallbackLocales []schema.LocaleCode DisableFallback bool AllLocales bool } ``` The root package re-exports this type as ridu.LocaleOptions. When a variadic method receives more than one value, the last one is used. ## FindOptions Canonical URL: https://riducms.com/reference/core/find-options/ Kind: type Projection, population, authorization, draft, trash, and locale controls for one read. ```go type FindOptions struct { // Select is nil for all authored fields. A non-nil empty slice returns only // document metadata. Select []query.Path Populate []query.Population // OutputFields limits computed and inverse-join resolution independently // from Select. Nil resolves all; a non-nil empty slice resolves none. OutputFields []query.Path // Draft explicitly includes draft documents when true or restricts reads to // published documents when false. Nil preserves the Local API default. Draft *bool Actor *store.Document ActorCollection schema.CollectionSlug TrashOnly bool Locale schema.LocaleCode FallbackLocales []schema.LocaleCode DisableFallback bool AllLocales bool } ``` The root package re-exports this type as ridu.FindOptions. A nil OutputFields resolves every output field; a non-nil empty slice resolves none. ## ListOptions Canonical URL: https://riducms.com/reference/core/list-options/ Kind: type Filtering, pagination, projection, population, authorization, and locale controls for a list read. ```go type ListOptions struct { // Where filters documents before pagination and remains atomic with access predicates. Where query.Expression // Page is the one-based result page. Zero selects the first page. Page int // Limit is the maximum documents returned per page. Limit int // Sort orders results by authored field paths. Sort []query.Sort // Select restricts returned document fields. Select []query.Path // Populate expands configured relationship paths. Populate []query.Population // OutputFields limits computed and inverse-join resolution without // projecting away stored fields. Nil resolves all output fields; a non-nil // empty slice resolves none. OutputFields []query.Path // Draft explicitly includes draft documents when true or restricts reads to // published documents when false. Nil preserves the Local API default. Draft *bool // Actor is the authenticated document used by access rules. Actor *store.Document // ActorCollection identifies the exact auth collection that owns Actor. ActorCollection schema.CollectionSlug // TrashOnly returns deleted documents and is valid only for trash-enabled collections. TrashOnly bool // Locale selects one configured content locale. Empty uses the application default. Locale schema.LocaleCode // FallbackLocales replaces the locale's configured fallback chain when non-nil. FallbackLocales []schema.LocaleCode // DisableFallback requires an exact value in Locale. DisableFallback bool // AllLocales returns locale-keyed values for localized fields. AllLocales bool } ``` The root package re-exports this type as ridu.ListOptions. TrashOnly is valid only for trash-enabled collections. ## DistinctOptions Canonical URL: https://riducms.com/reference/core/distinct-options/ Kind: type Field, filtering, pagination, authorization, draft, trash, and locale controls for one unique-value read. ```go type DistinctOptions struct { // Field names the authored scalar, singular relationship, singular upload, // or document ID whose unique values should be returned. Field query.Path // Where remains atomic with the collection read-access predicate. Where query.Expression // Page is one-based. Zero selects the first page. Page int // Limit follows ordinary Ridu list bounds and defaults. Limit int Actor *store.Document // ActorCollection identifies the exact auth collection that owns Actor. ActorCollection schema.CollectionSlug // Draft follows List semantics for versioned collections. Draft *bool // TrashOnly returns values from deleted documents and requires trash support. TrashOnly bool Locale schema.LocaleCode FallbackLocales []schema.LocaleCode DisableFallback bool } ``` The root package re-exports this type as ridu.DistinctOptions. The initial contract intentionally excludes nested fields, arrays, and general aggregations. ## ListWindowOptions Canonical URL: https://riducms.com/reference/core/list-window-options/ Kind: type A count-free bounded unique-index range for background work. ```go type ListWindowOptions struct { Index query.Path LowerBound string UpperBound string Limit int Select []query.Path Actor *store.Document ActorCollection schema.CollectionSlug Locale schema.LocaleCode FallbackLocales []schema.LocaleCode DisableFallback bool AllLocales bool } ``` The root package re-exports this type as ridu.ListWindowOptions. The store transaction must implement the optional store.WindowTransaction capability. ## MutationOptions Canonical URL: https://riducms.com/reference/core/mutation-options/ Kind: type Authorization, optimistic concurrency, response population, create status, and locale controls for one write. ```go type MutationOptions struct { // ID supplies a caller-owned document ID for create operations when // Config.AllowIDOnCreate is enabled. Other mutations ignore it. ID string Actor *store.Document ActorCollection schema.CollectionSlug ExpectedRevision int Populate []query.Population // OutputFields limits computed and inverse-join resolution in the returned // document. Nil resolves all; a non-nil empty slice resolves none. OutputFields []query.Path // Draft selects draft (true) or published (false) status for versioned // creates. Updates preserve status so publish and unpublish hooks cannot be bypassed. Draft *bool Locale schema.LocaleCode FallbackLocales []schema.LocaleCode DisableFallback bool AllLocales bool } ``` The root package re-exports this type as ridu.MutationOptions. Updates preserve status so publish and unpublish hooks cannot be bypassed. Populate affects only the response, never validation or stored values. ## CapabilityOptions Canonical URL: https://riducms.com/reference/core/capability-options/ Kind: type Side-effect-free access evaluation input. ```go type CapabilityOptions struct { Data store.Values Actor *store.Document ActorCollection schema.CollectionSlug TrashOnly bool Locale schema.LocaleCode FallbackLocales []schema.LocaleCode DisableFallback bool AllLocales bool } ``` Data models proposed create/update values. Capabilities runs no hooks, validation, or mutation and returns booleans only—not access predicates. ## AccessCapabilities Canonical URL: https://riducms.com/reference/core/access-capabilities/ Kind: type Evaluated operation and per-field permission booleans. ```go type AccessCapabilities struct { Operations OperationCapabilities Fields map[string]FieldCapabilities } ``` Suitable for authoring UI hints. The actual operation always re-runs authorization transactionally; capabilities are never authority. ## ImportOptions Canonical URL: https://riducms.com/reference/core/import-options/ Kind: type Migration-owned source identity, status, and timestamps. ```go type ImportOptions struct { // ID preserves the source document identity. ID string // Status preserves the source draft or published status. Status store.Status // CreatedAt preserves the source creation timestamp. CreatedAt time.Time // UpdatedAt preserves the source modification timestamp. UpdatedAt time.Time } ``` LocalAPI.Import still runs access, field validation, hooks, transaction, reference, upload, and version logic. Use only for trusted migrations. ## LocalAPI.Create Canonical URL: https://riducms.com/reference/core/local-api-create/ Kind: method Create and validate a document through the shared operation engine. ```go func (local *LocalAPI) Create(ctx context.Context, collection string, values store.Values, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ```go post, err := app.Local().Create( ctx, "posts", store.Values{"title": store.String("Hello, Ridu")}, actor, ) ``` ## LocalAPI.CreateWithOptions Canonical URL: https://riducms.com/reference/core/local-api-create-with-options/ Kind: method Create a document with draft, locale, population, and authorization options. ```go func (local *LocalAPI) CreateWithOptions(ctx context.Context, collection string, values store.Values, options MutationOptions) (store.Document, error) ``` ## LocalAPI.Duplicate Canonical URL: https://riducms.com/reference/core/local-api-duplicate/ Kind: method Create a document from an access-checked source and apply overrides. ```go func (local *LocalAPI) Duplicate(ctx context.Context, collection, id string, overrides store.Values, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` The source must pass read access. The copy then runs create access, duplicate hooks, validation, persistence, and version logic. ```go copy, err := app.Local().Duplicate(ctx, "posts", sourceID, store.Values{ "title": store.String("Copy of the original"), }, actor) ``` ## LocalAPI.DuplicateWithOptions Canonical URL: https://riducms.com/reference/core/local-api-duplicate-with-options/ Kind: method Duplicate a document with write and response options. ```go func (local *LocalAPI) DuplicateWithOptions(ctx context.Context, collection, id string, overrides store.Values, options MutationOptions) (store.Document, error) ``` ## LocalAPI.Find Canonical URL: https://riducms.com/reference/core/local-api-find/ Kind: method Read one authorized document. ```go func (local *LocalAPI) Find(ctx context.Context, collection, id string, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ```go post, err := app.Local().Find(ctx, "posts", postID, actor) ``` ## LocalAPI.FindWithOptions Canonical URL: https://riducms.com/reference/core/local-api-find-with-options/ Kind: method Read one document with projection, population, draft, trash, and locale controls. ```go func (local *LocalAPI) FindWithOptions(ctx context.Context, collection, id string, options FindOptions) (store.Document, error) ``` ```go post, err := app.Local().FindWithOptions( ctx, "posts", postID, ridu.FindOptions{ Actor: actor, Populate: []query.Population{{Path: authorPath, Depth: 1}}, }, ) ``` ## LocalAPI.List Canonical URL: https://riducms.com/reference/core/local-api-list/ Kind: method List authorized documents with filtering, pagination, projection, sorting, and population. ```go func (local *LocalAPI) List(ctx context.Context, collection string, options ListOptions) (store.Page, error) ``` ```go page, err := app.Local().List(ctx, "posts", ridu.ListOptions{ Where: query.Equal(statusPath, query.String("published")), Page: 1, Limit: 20, Actor: actor, }) ``` ## LocalAPI.Distinct Canonical URL: https://riducms.com/reference/core/local-api-distinct/ Kind: method Return paginated unique values for one direct field after access checks. ```go func (local *LocalAPI) Distinct(ctx context.Context, collection string, options DistinctOptions) (store.DistinctPage, error) ``` Collection access and Where remain atomic in the adapter query; field read access is checked before values are selected. ## LocalAPI.ListWindow Canonical URL: https://riducms.com/reference/core/local-api-list-window/ Kind: method Read one count-free bounded unique-index range for reconciliation work. ```go func (local *LocalAPI) ListWindow(ctx context.Context, collection string, options ListWindowOptions) (store.Window, error) ``` Requires collection read access to resolve to Allow and the adapter transaction to implement store.WindowTransaction. ## LocalAPI.Update Canonical URL: https://riducms.com/reference/core/local-api-update/ Kind: method Apply partial values to one authorized document. ```go func (local *LocalAPI) Update(ctx context.Context, collection, id string, values store.Values, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ## LocalAPI.UpdateWithOptions Canonical URL: https://riducms.com/reference/core/local-api-update-with-options/ Kind: method Update one document with optimistic concurrency and response controls. ```go func (local *LocalAPI) UpdateWithOptions(ctx context.Context, collection, id string, values store.Values, options MutationOptions) (store.Document, error) ``` ```go post, err := app.Local().UpdateWithOptions( ctx, "posts", postID, changes, ridu.MutationOptions{ Actor: actor, ExpectedRevision: currentRevision, }, ) ``` ## LocalAPI.Delete Canonical URL: https://riducms.com/reference/core/local-api-delete/ Kind: method Delete an authorized document, moving it to trash when the collection enables trash. ```go func (local *LocalAPI) Delete(ctx context.Context, collection, id string, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ## LocalAPI.DeleteWithOptions Canonical URL: https://riducms.com/reference/core/local-api-delete-with-options/ Kind: method Delete a document with optimistic concurrency and response controls. ```go func (local *LocalAPI) DeleteWithOptions(ctx context.Context, collection, id string, options MutationOptions) (store.Document, error) ``` ## LocalAPI.RestoreDeleted Canonical URL: https://riducms.com/reference/core/local-api-restore-deleted/ Kind: method Move an authorized trashed document back into ordinary collection reads. ```go func (local *LocalAPI) RestoreDeleted(ctx context.Context, collection, id string, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ```go restored, err := app.Local().RestoreDeleted(ctx, "posts", postID, actor) ``` ## LocalAPI.DeletePermanent Canonical URL: https://riducms.com/reference/core/local-api-delete-permanent/ Kind: method Irreversibly remove an authorized document that is already in trash. ```go func (local *LocalAPI) DeletePermanent(ctx context.Context, collection, id string, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` This operation is irreversible and only accepts documents already in trash. ## LocalAPI.Publish Canonical URL: https://riducms.com/reference/core/local-api-publish/ Kind: method Publish one authorized versioned document. ```go func (local *LocalAPI) Publish(ctx context.Context, collection, id string, expectedRevision int, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ```go published, err := app.Local().Publish( ctx, "posts", postID, currentRevision, actor, ) ``` ## LocalAPI.PublishWithOptions Canonical URL: https://riducms.com/reference/core/local-api-publish-with-options/ Kind: method Publish a versioned document with optimistic concurrency and response controls. ```go func (local *LocalAPI) PublishWithOptions(ctx context.Context, collection, id string, options MutationOptions) (store.Document, error) ``` ## LocalAPI.PublishChanges Canonical URL: https://riducms.com/reference/core/local-api-publish-changes/ Kind: method Atomically apply field changes and publish the resulting versioned document through the publish lifecycle. ```go func (local *LocalAPI) PublishChanges(ctx context.Context, collection, id string, values store.Values, expectedRevision int, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ## LocalAPI.PublishChangesWithOptions Canonical URL: https://riducms.com/reference/core/local-api-publish-changes-with-options/ Kind: method Atomically apply field changes and publish with exact identity, concurrency, locale, and response controls. ```go func (local *LocalAPI) PublishChangesWithOptions(ctx context.Context, collection, id string, values store.Values, options MutationOptions) (store.Document, error) ``` ## LocalAPI.Unpublish Canonical URL: https://riducms.com/reference/core/local-api-unpublish/ Kind: method Move one authorized versioned document back to draft. ```go func (local *LocalAPI) Unpublish(ctx context.Context, collection, id string, expectedRevision int, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ## LocalAPI.UnpublishWithOptions Canonical URL: https://riducms.com/reference/core/local-api-unpublish-with-options/ Kind: method Unpublish a versioned document with optimistic concurrency and response controls. ```go func (local *LocalAPI) UnpublishWithOptions(ctx context.Context, collection, id string, options MutationOptions) (store.Document, error) ``` ## LocalAPI.Versions Canonical URL: https://riducms.com/reference/core/local-api-versions/ Kind: method Return authorized retained revisions for one versioned document. ```go func (local *LocalAPI) Versions(ctx context.Context, collection, id string, actor *store.Document, localeOptions ...LocaleOptions) ([]store.Version, error) ``` ```go history, err := app.Local().Versions(ctx, "posts", postID, actor) ``` ## LocalAPI.Version Canonical URL: https://riducms.com/reference/core/local-api-version/ Kind: method Return one authorized retained revision. ```go func (local *LocalAPI) Version(ctx context.Context, collection, id string, revision int, actor *store.Document, localeOptions ...LocaleOptions) (store.Version, error) ``` ## LocalAPI.Restore Canonical URL: https://riducms.com/reference/core/local-api-restore/ Kind: method Restore a retained revision as the current published document. ```go func (local *LocalAPI) Restore(ctx context.Context, collection, id string, revision, expectedRevision int, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ```go restored, err := app.Local().Restore( ctx, "posts", postID, revisionToRestore, currentRevision, actor, ) ``` ## LocalAPI.RestoreAsDraft Canonical URL: https://riducms.com/reference/core/local-api-restore-as-draft/ Kind: method Restore a retained revision while explicitly keeping the current document unpublished. ```go func (local *LocalAPI) RestoreAsDraft(ctx context.Context, collection, id string, revision, expectedRevision int, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ## LocalAPI.RestoreVersionWithOptions Canonical URL: https://riducms.com/reference/core/local-api-restore-version-with-options/ Kind: method Restore a retained revision with explicit draft, concurrency, locale, and response controls. ```go func (local *LocalAPI) RestoreVersionWithOptions(ctx context.Context, collection, id string, revision int, draft bool, options MutationOptions) (store.Document, error) ``` ## LocalAPI.Import Canonical URL: https://riducms.com/reference/core/local-api-import/ Kind: method Create a document with trusted source identity and timestamps. ```go func (local *LocalAPI) Import(ctx context.Context, collection string, values store.Values, options ImportOptions, actor *store.Document) (store.Document, error) ``` Intended for migration tooling. It still runs ordinary access, validation, hooks, transaction, upload-reference, and version logic. ## LocalAPI.Capabilities Canonical URL: https://riducms.com/reference/core/local-api-capabilities/ Kind: method Evaluate collection, document, and field access without side effects. ```go func (local *LocalAPI) Capabilities(ctx context.Context, collection, id string, options CapabilityOptions) (AccessCapabilities, error) ``` No hooks, validation, or mutation run. Results are presentation hints only; every later operation re-authorizes transactionally. ## LocalAPI.UpdateRevision Canonical URL: https://riducms.com/reference/core/local-api-update-revision/ Kind: method Update with an optimistic current-revision fence. ```go func (local *LocalAPI) UpdateRevision(ctx context.Context, collection, id string, values store.Values, expectedRevision int, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` Equivalent to UpdateWithOptions with ExpectedRevision set. A stale revision returns a conflict. ## LocalAPI.MutateJoin Canonical URL: https://riducms.com/reference/core/local-api-mutate-join/ Kind: method Atomically add and remove inverse-relation target IDs. ```go func (local *LocalAPI) MutateJoin(ctx context.Context, collection, id, field string, additions, removals []string, actor *store.Document, localeOptions ...LocaleOptions) (JoinMutationResult, error) ``` Applies deltas without requiring the caller to load the complete relationship set. MutateJoinWithOptions adds revision, locale, and response controls. ## LocalAPI.CopyLocale Canonical URL: https://riducms.com/reference/core/local-api-copy-locale/ Kind: method Copy every localized field from one locale to another. ```go func (local *LocalAPI) CopyLocale(ctx context.Context, collection, id string, source, target schema.LocaleCode, expectedRevision int, actor *store.Document) (store.Document, error) ``` Runs as one ordinary authorized update with optimistic concurrency. CopyLocaleWithOptions supports exact actor identity and response controls. ## LocalAPI.RestoreDeletedWithOptions Canonical URL: https://riducms.com/reference/core/local-api-restore-deleted-with-options/ Kind: method Restore a trashed document with exact actor and response controls. ```go func (local *LocalAPI) RestoreDeletedWithOptions(ctx context.Context, collection, id string, options MutationOptions) (store.Document, error) ``` ## LocalAPI.DeletePermanentWithOptions Canonical URL: https://riducms.com/reference/core/local-api-delete-permanent-with-options/ Kind: method Permanently delete a trashed document with exact actor controls. ```go func (local *LocalAPI) DeletePermanentWithOptions(ctx context.Context, collection, id string, options MutationOptions) (store.Document, error) ``` Reconciles current incoming references, removes framework-owned state, and coordinates upload-object deletion. Retained external owners may restrict the operation. ## LocalAPI.MutateJoinWithOptions Canonical URL: https://riducms.com/reference/core/local-api-mutate-join-with-options/ Kind: method Atomically add and remove inverse-relation IDs with complete mutation controls. ```go func (local *LocalAPI) MutateJoinWithOptions(ctx context.Context, collection, id, field string, additions, removals []string, options MutationOptions) (JoinMutationResult, error) ``` ## LocalAPI.CopyLocaleWithOptions Canonical URL: https://riducms.com/reference/core/local-api-copy-locale-with-options/ Kind: method Copy localized fields with exact identity, concurrency, and response controls. ```go func (local *LocalAPI) CopyLocaleWithOptions(ctx context.Context, collection, id string, source, target schema.LocaleCode, options MutationOptions) (store.Document, error) ``` ## LocalAPI.VersionsWithOptions Canonical URL: https://riducms.com/reference/core/local-api-versions-with-options/ Kind: method List retained document revisions with exact identity, locale, and response controls. ```go func (local *LocalAPI) VersionsWithOptions(ctx context.Context, collection, id string, options FindOptions) ([]store.Version, error) ``` ## LocalAPI.VersionWithOptions Canonical URL: https://riducms.com/reference/core/local-api-version-with-options/ Kind: method Read one retained document revision with exact identity and locale controls. ```go func (local *LocalAPI) VersionWithOptions(ctx context.Context, collection, id string, revision int, options FindOptions) (store.Version, error) ``` ## LocalAPI.BulkUpdate Canonical URL: https://riducms.com/reference/core/local-api-bulk-update/ Kind: method Apply one partial update atomically to an explicit bounded ID set. ```go func (local *LocalAPI) BulkUpdate(ctx context.Context, collection string, ids []string, values store.Values, actor *store.Document, localeOptions ...LocaleOptions) ([]store.Document, error) ``` Every ID is selected and authorized in one transaction; partial success is never returned. ## LocalAPI.BulkPublish Canonical URL: https://riducms.com/reference/core/local-api-bulk-publish/ Kind: method Publish an explicit bounded set of versioned documents atomically. ```go func (local *LocalAPI) BulkPublish(ctx context.Context, collection string, ids []string, actor *store.Document, localeOptions ...LocaleOptions) ([]store.Document, error) ``` ## LocalAPI.BulkUnpublish Canonical URL: https://riducms.com/reference/core/local-api-bulk-unpublish/ Kind: method Unpublish an explicit bounded set of versioned documents atomically. ```go func (local *LocalAPI) BulkUnpublish(ctx context.Context, collection string, ids []string, actor *store.Document, localeOptions ...LocaleOptions) ([]store.Document, error) ``` ## LocalAPI.BulkDelete Canonical URL: https://riducms.com/reference/core/local-api-bulk-delete/ Kind: method Delete or trash an explicit bounded set of documents atomically. ```go func (local *LocalAPI) BulkDelete(ctx context.Context, collection string, ids []string, actor *store.Document, localeOptions ...LocaleOptions) ([]store.Document, error) ``` ## LocalAPI.BulkRestoreDeleted Canonical URL: https://riducms.com/reference/core/local-api-bulk-restore-deleted/ Kind: method Restore an explicit bounded set of trashed documents atomically. ```go func (local *LocalAPI) BulkRestoreDeleted(ctx context.Context, collection string, ids []string, actor *store.Document, localeOptions ...LocaleOptions) ([]store.Document, error) ``` ## LocalAPI.BulkDeletePermanent Canonical URL: https://riducms.com/reference/core/local-api-bulk-delete-permanent/ Kind: method Permanently delete an explicit bounded set of trashed documents atomically. ```go func (local *LocalAPI) BulkDeletePermanent(ctx context.Context, collection string, ids []string, actor *store.Document, localeOptions ...LocaleOptions) ([]store.Document, error) ``` ## LocalAPI.EmptyTrash Canonical URL: https://riducms.com/reference/core/local-api-empty-trash/ Kind: method Permanently delete the current authorized trash selection for one collection. ```go func (local *LocalAPI) EmptyTrash(ctx context.Context, collection string, actor *store.Document, localeOptions ...LocaleOptions) ([]store.Document, error) ``` The operation is bounded and atomic; it fails rather than silently truncating an oversized selection. ## LocalAPI.Global Canonical URL: https://riducms.com/reference/core/local-api-global/ Kind: method Read one authorized singleton. ```go func (local *LocalAPI) Global(ctx context.Context, slug string, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` GlobalWithOptions adds projection, population, draft, exact identity, and locale controls. ## LocalAPI.UpdateGlobal Canonical URL: https://riducms.com/reference/core/local-api-update-global/ Kind: method Create or update one singleton. ```go func (local *LocalAPI) UpdateGlobal(ctx context.Context, slug string, values store.Values, expectedRevision int, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` The first singleton update cannot be authorized by a filtered Where decision because no persisted row exists; it requires Allow. UpdateGlobalWithOptions provides complete controls. ## LocalAPI.GlobalWithOptions Canonical URL: https://riducms.com/reference/core/local-api-global-with-options/ Kind: method Read one authorized singleton with projection, population, draft, identity, and locale controls. ```go func (local *LocalAPI) GlobalWithOptions(ctx context.Context, slug string, options FindOptions) (store.Document, error) ``` ## LocalAPI.UpdateGlobalWithOptions Canonical URL: https://riducms.com/reference/core/local-api-update-global-with-options/ Kind: method Create or update a singleton with complete mutation and response controls. ```go func (local *LocalAPI) UpdateGlobalWithOptions(ctx context.Context, slug string, values store.Values, options MutationOptions) (store.Document, error) ``` ## LocalAPI.PublishGlobal Canonical URL: https://riducms.com/reference/core/local-api-publish-global/ Kind: method Publish one authorized versioned singleton. ```go func (local *LocalAPI) PublishGlobal(ctx context.Context, slug string, expectedRevision int, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ## LocalAPI.PublishGlobalWithOptions Canonical URL: https://riducms.com/reference/core/local-api-publish-global-with-options/ Kind: method Publish a singleton with complete mutation and response controls. ```go func (local *LocalAPI) PublishGlobalWithOptions(ctx context.Context, slug string, options MutationOptions) (store.Document, error) ``` ## LocalAPI.PublishGlobalChanges Canonical URL: https://riducms.com/reference/core/local-api-publish-global-changes/ Kind: method Atomically apply singleton field changes and publish through the global publish lifecycle. ```go func (local *LocalAPI) PublishGlobalChanges(ctx context.Context, slug string, values store.Values, expectedRevision int, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ## LocalAPI.PublishGlobalChangesWithOptions Canonical URL: https://riducms.com/reference/core/local-api-publish-global-changes-with-options/ Kind: method Atomically apply singleton field changes and publish with complete mutation and response controls. ```go func (local *LocalAPI) PublishGlobalChangesWithOptions(ctx context.Context, slug string, values store.Values, options MutationOptions) (store.Document, error) ``` ## LocalAPI.UnpublishGlobal Canonical URL: https://riducms.com/reference/core/local-api-unpublish-global/ Kind: method Move one authorized versioned singleton back to draft. ```go func (local *LocalAPI) UnpublishGlobal(ctx context.Context, slug string, expectedRevision int, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ## LocalAPI.UnpublishGlobalWithOptions Canonical URL: https://riducms.com/reference/core/local-api-unpublish-global-with-options/ Kind: method Unpublish a singleton with complete mutation and response controls. ```go func (local *LocalAPI) UnpublishGlobalWithOptions(ctx context.Context, slug string, options MutationOptions) (store.Document, error) ``` ## LocalAPI.CopyGlobalLocale Canonical URL: https://riducms.com/reference/core/local-api-copy-global-locale/ Kind: method Copy every localized singleton field from one locale to another. ```go func (local *LocalAPI) CopyGlobalLocale(ctx context.Context, slug string, source, target schema.LocaleCode, expectedRevision int, actor *store.Document) (store.Document, error) ``` ## LocalAPI.CopyGlobalLocaleWithOptions Canonical URL: https://riducms.com/reference/core/local-api-copy-global-locale-with-options/ Kind: method Copy localized singleton fields with exact identity, concurrency, and response controls. ```go func (local *LocalAPI) CopyGlobalLocaleWithOptions(ctx context.Context, slug string, source, target schema.LocaleCode, options MutationOptions) (store.Document, error) ``` ## LocalAPI.GlobalVersionsWithOptions Canonical URL: https://riducms.com/reference/core/local-api-global-versions-with-options/ Kind: method List retained singleton revisions with exact identity and locale controls. ```go func (local *LocalAPI) GlobalVersionsWithOptions(ctx context.Context, slug string, options FindOptions) ([]store.Version, error) ``` ## LocalAPI.GlobalVersion Canonical URL: https://riducms.com/reference/core/local-api-global-version/ Kind: method Read one access-filtered retained singleton revision. ```go func (local *LocalAPI) GlobalVersion(ctx context.Context, slug string, revision int, actor *store.Document, localeOptions ...LocaleOptions) (store.Version, error) ``` ## LocalAPI.GlobalVersionWithOptions Canonical URL: https://riducms.com/reference/core/local-api-global-version-with-options/ Kind: method Read one retained singleton revision with exact identity and locale controls. ```go func (local *LocalAPI) GlobalVersionWithOptions(ctx context.Context, slug string, revision int, options FindOptions) (store.Version, error) ``` ## LocalAPI.RestoreGlobal Canonical URL: https://riducms.com/reference/core/local-api-restore-global/ Kind: method Restore a retained singleton revision as the current published value. ```go func (local *LocalAPI) RestoreGlobal(ctx context.Context, slug string, revision, expectedRevision int, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ## LocalAPI.RestoreGlobalAsDraft Canonical URL: https://riducms.com/reference/core/local-api-restore-global-as-draft/ Kind: method Restore a retained singleton revision while keeping it unpublished. ```go func (local *LocalAPI) RestoreGlobalAsDraft(ctx context.Context, slug string, revision, expectedRevision int, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ## LocalAPI.RestoreGlobalVersionWithOptions Canonical URL: https://riducms.com/reference/core/local-api-restore-global-version-with-options/ Kind: method Restore a retained singleton revision with explicit draft, identity, concurrency, and response controls. ```go func (local *LocalAPI) RestoreGlobalVersionWithOptions(ctx context.Context, slug string, revision int, draft bool, options MutationOptions) (store.Document, error) ``` ## LocalAPI.GlobalVersions Canonical URL: https://riducms.com/reference/core/local-api-global-versions/ Kind: method List access-filtered retained singleton revisions. ```go func (local *LocalAPI) GlobalVersions(ctx context.Context, slug string, actor *store.Document, localeOptions ...LocaleOptions) ([]store.Version, error) ``` GlobalVersion reads one revision. Both have WithOptions forms and apply access to stored snapshots, not merely the current singleton. ## App.Manifest Canonical URL: https://riducms.com/reference/core/app-manifest/ Kind: method Return the immutable resolved schema. ```go func (application *App) Manifest() schema.Manifest ``` ## App.Local Canonical URL: https://riducms.com/reference/core/app-local/ Kind: method Return the in-process content API. ```go func (application *App) Local() *LocalAPI ``` ## App.Handler Canonical URL: https://riducms.com/reference/core/app-handler/ Kind: method Build the REST API, admin, plugin routes, health, and readiness handler. ```go func (application *App) Handler(options HandlerOptions) http.Handler ``` Use this when embedding Ridu in an existing Go server. ridu.Execute owns the ordinary production server lifecycle. ## AuthIdentity Canonical URL: https://riducms.com/reference/core/auth-identity/ Kind: type An exact authenticated collection and actor document. ```go type AuthIdentity struct { Collection schema.CollectionSlug Actor store.Document // PreviewEpoch is an opaque lifecycle snapshot captured before transport // authentication. Zero lets direct Go callers snapshot at mint entry. PreviewEpoch uint64 } ``` Prefer identity-aware methods when an application has more than one auth collection. Actor-only compatibility methods reject ambiguous identities rather than guessing. PreviewEpoch is opaque framework lifecycle state; ordinary callers leave it zero. ## AuthSession Canonical URL: https://riducms.com/reference/core/auth-session/ Kind: type A newly authenticated session and its one-time raw token. ```go type AuthSession struct { // ID is the non-secret identifier used to manage this session. ID string // Token is the opaque credential accepted by session-aware transports. Token string // Collection is the auth-enabled collection that owns the identity. Collection schema.CollectionSlug // User is the current document from Collection. User store.Document // ExpiresAt is the absolute UTC expiry time. ExpiresAt time.Time } ``` Token is a bearer secret. Store it only in a secure HTTP-only cookie or equivalent secret store; protocol/session-list representations never expose it. ## LoginOptions Canonical URL: https://riducms.com/reference/core/login-options/ Kind: type Request metadata and cookie-independent controls for local login. ```go type LoginOptions struct { // IPAddress is the direct or trusted-forwarded client address. IPAddress string // UserAgent is the untrusted client user-agent string. UserAgent string } ``` Transports should derive IPAddress only after applying their trusted-proxy policy. These values are session metadata, not authentication factors. ## App.AuthInitialized Canonical URL: https://riducms.com/reference/core/app-auth-initialized/ Kind: method Report whether an auth collection has any active account. ```go func (application *App) AuthInitialized(ctx context.Context, collection string) (initialized bool, err error) ``` Used for the one-time first-user bootstrap flow. It is not a general user-count API. ## App.AuthBootstrapAvailable Canonical URL: https://riducms.com/reference/core/app-auth-bootstrap-available/ Kind: method Report whether one-time anonymous setup is available for the configured admin collection. ```go func (application *App) AuthBootstrapAvailable(ctx context.Context, collection string) (bool, error) ``` Returns false for secondary auth collections, explicit Create policies, and initialized admin collections. The atomic create transaction remains authoritative if callers race. ## App.CreateAuthUser Canonical URL: https://riducms.com/reference/core/app-create-auth-user/ Kind: method Create a content document and private credential atomically. ```go func (application *App) CreateAuthUser(ctx context.Context, collection string, values store.Values, password string, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` Runs create access, field access, validation, hooks, transaction logic, password policy, and credential creation. The password never enters values or hooks. ## App.Login Canonical URL: https://riducms.com/reference/core/app-login/ Kind: method Authenticate one collection identity with a password. ```go func (application *App) Login(ctx context.Context, collection, email, password string) (AuthSession, error) ``` Use LoginWithOptions to persist safe device metadata. Lockout, email verification, timing defenses, and optional hash upgrades are enforced. ## App.Session Canonical URL: https://riducms.com/reference/core/app-session/ Kind: method Resolve one raw session token and current user. ```go func (application *App) Session(ctx context.Context, token string) (AuthSession, error) ``` ## App.RotateSession Canonical URL: https://riducms.com/reference/core/app-rotate-session/ Kind: method Atomically replace a valid bearer session. ```go func (application *App) RotateSession(ctx context.Context, token string) (AuthSession, error) ``` ## App.Sessions Canonical URL: https://riducms.com/reference/core/app-sessions/ Kind: method List safe active-session metadata for the bearer user. ```go func (application *App) Sessions(ctx context.Context, token string) ([]AuthSessionInfo, error) ``` ## App.RevokeSession Canonical URL: https://riducms.com/reference/core/app-revoke-session/ Kind: method Revoke one session belonging to the bearer user. ```go func (application *App) RevokeSession(ctx context.Context, token, sessionID string) error ``` ## App.Logout Canonical URL: https://riducms.com/reference/core/app-logout/ Kind: method Delete the presented session. ```go func (application *App) Logout(ctx context.Context, token string) error ``` ## App.LogoutAll Canonical URL: https://riducms.com/reference/core/app-logout-all/ Kind: method Revoke every session for the presented identity. ```go func (application *App) LogoutAll(ctx context.Context, token string) error ``` ## App.ChangePassword Canonical URL: https://riducms.com/reference/core/app-change-password/ Kind: method Verify the current password, replace it, and revoke all sessions and API keys. ```go func (application *App) ChangePassword(ctx context.Context, sessionToken, currentPassword, nextPassword string) error ``` ## App.RequestPasswordReset Canonical URL: https://riducms.com/reference/core/app-request-password-reset/ Kind: method Issue and send a single-use reset token when configured. ```go func (application *App) RequestPasswordReset(ctx context.Context, collection, identity string) error ``` Returns a non-enumerating success shape whether or not the identity exists. Raw tokens are delivered only to the trusted Config callback. ## App.ResetPassword Canonical URL: https://riducms.com/reference/core/app-reset-password/ Kind: method Consume a single-use reset token and revoke credentials. ```go func (application *App) ResetPassword(ctx context.Context, collection, token, password string) error ``` ## App.RequestVerification Canonical URL: https://riducms.com/reference/core/app-request-verification/ Kind: method Issue and send a new email-verification token. ```go func (application *App) RequestVerification(ctx context.Context, collection, identity string) error ``` ## App.VerifyEmail Canonical URL: https://riducms.com/reference/core/app-verify-email/ Kind: method Consume a single-use email-verification token. ```go func (application *App) VerifyEmail(ctx context.Context, collection, token string) error ``` ## App.CreateAPIKey Canonical URL: https://riducms.com/reference/core/app-create-api-key/ Kind: method Mint a revocable API bearer secret for a current session. ```go func (application *App) CreateAPIKey(ctx context.Context, sessionToken, name string, expiresAt time.Time) (APIKey, error) ``` Requires AuthConfig.APIKeys. The raw Key is returned once; lists expose APIKeyInfo only. ## App.AuthenticateAPIKeyIdentity Canonical URL: https://riducms.com/reference/core/app-authenticate-api-key-identity/ Kind: method Resolve an API key to its exact auth identity. ```go func (application *App) AuthenticateAPIKeyIdentity(ctx context.Context, raw string) (AuthIdentity, error) ``` ## App.AuthenticateExternalIdentity Canonical URL: https://riducms.com/reference/core/app-authenticate-external-identity/ Kind: method Run compiled external strategies in declaration order. ```go func (application *App) AuthenticateExternalIdentity(ctx context.Context, headers map[string][]string) (AuthIdentity, error) ``` Strategies must return NotApplicable to continue; malformed or rejected credentials fail closed. ## UploadInput Canonical URL: https://riducms.com/reference/core/upload-input/ Kind: type File bytes and application-owned metadata for one upload. ```go type UploadInput struct { // Filename is the original client-supplied file name. Filename string // Reader provides the uploaded bytes. Reader io.Reader // Data contains application-owned upload document fields. Data store.Values // Actor is the authenticated document used by access rules. Actor *store.Document // ActorCollection identifies the exact auth collection that owns Actor. ActorCollection schema.CollectionSlug // Locale selects the content locale for application-owned upload metadata. Locale LocaleOptions } ``` Bytes, metadata, access, validation, hooks, storage, and document persistence run through one upload operation. The caller retains ownership of Reader. ## RemoteUploadInput Canonical URL: https://riducms.com/reference/core/remote-upload-input/ Kind: type A public HTTP(S) asset and upload metadata. ```go type RemoteUploadInput struct { URL string Data store.Values Actor *store.Document ActorCollection schema.CollectionSlug Locale LocaleOptions } ``` Remote fetches are SSRF-hardened, bounded, and pass through the same MIME, storage, access, validation, and hook pipeline as streamed uploads. ## App.Upload Canonical URL: https://riducms.com/reference/core/app-upload/ Kind: method Validate, store, and create an upload document atomically. ```go func (application *App) Upload(ctx context.Context, collection string, input UploadInput) (store.Document, error) ``` Staged objects are rolled back if the document transaction fails. Storage keys are namespaced and opaque. ## App.UploadFromURL Canonical URL: https://riducms.com/reference/core/app-upload-from-url/ Kind: method Safely fetch and store a public HTTP(S) asset. ```go func (application *App) UploadFromURL(ctx context.Context, collection string, input RemoteUploadInput) (store.Document, error) ``` ## App.OpenUploadWithOptions Canonical URL: https://riducms.com/reference/core/app-open-upload-with-options/ Kind: method Authorize a document-backed object read. ```go func (application *App) OpenUploadWithOptions(ctx context.Context, collection, key string, options FindOptions) (io.ReadCloser, storage.Object, error) ``` Private delivery remains mediated by Ridu unless an explicit storage.URLSigner flow is used. Close the returned reader. ## App.UpdateUploadImage Canonical URL: https://riducms.com/reference/core/app-update-upload-image/ Kind: method Regenerate configured variants around a focal point or crop. ```go func (application *App) UpdateUploadImage(ctx context.Context, collection, id string, input UpdateUploadImageInput) (store.Document, error) ``` Coordinates object locks, optimistic revision, ordinary update access, and rollback. ## App.ReconcileUploads Canonical URL: https://riducms.com/reference/core/app-reconcile-uploads/ Kind: method Report old unreferenced application-owned objects without deleting them. ```go func (application *App) ReconcileUploads(ctx context.Context, olderThan time.Duration) (ReconcileResult, error) ``` Reconciliation uses an ACL-independent store snapshot and a minimum five-minute safety window. Call CleanupUploads explicitly to delete the reported candidates. ## App.SchedulePublish Canonical URL: https://riducms.com/reference/core/app-schedule-publish/ Kind: method Queue a revision-fenced future publish. ```go func (application *App) SchedulePublish(ctx context.Context, collection, documentID string, runAt time.Time, expectedRevision int, identity *AuthIdentity) (store.ScheduledPublish, error) ``` ## App.ScheduledPublishes Canonical URL: https://riducms.com/reference/core/app-scheduled-publishes/ Kind: method List scheduled publishes for one authorized document. ```go func (application *App) ScheduledPublishes(ctx context.Context, collection, documentID string, identity *AuthIdentity) ([]store.ScheduledPublish, error) ``` ## App.CancelScheduledPublish Canonical URL: https://riducms.com/reference/core/app-cancel-scheduled-publish/ Kind: method Dismiss one scheduled publish for an authorized document. ```go func (application *App) CancelScheduledPublish(ctx context.Context, collection, documentID, jobID string, identity *AuthIdentity) error ``` ## App.RunScheduledPublishes Canonical URL: https://riducms.com/reference/core/app-run-scheduled-publishes/ Kind: method Claim and run a bounded publish batch. ```go func (application *App) RunScheduledPublishes(ctx context.Context, limit int, actor *store.Document) (int, error) ``` Execute normally runs this worker. Direct use is for explicit job runners and tests. Each publish rechecks revision and access. ## DocumentLockState Canonical URL: https://riducms.com/reference/core/document-lock-state/ Kind: type Safe current lock metadata and actor capabilities. ```go type DocumentLockState struct { Lock *store.DocumentLock Owned bool Acquired bool CanTakeOver bool } ``` Lock state coordinates editors but does not replace collection access or optimistic revision checks. ## App.DocumentLock Canonical URL: https://riducms.com/reference/core/app-document-lock/ Kind: method Read one document lock after read authorization. ```go func (application *App) DocumentLock(ctx context.Context, collection, documentID string, identity *AuthIdentity) (DocumentLockState, error) ``` ## App.AcquireDocumentLock Canonical URL: https://riducms.com/reference/core/app-acquire-document-lock/ Kind: method Acquire, refresh, or explicitly take over an authoring lock. ```go func (application *App) AcquireDocumentLock(ctx context.Context, collection, documentID string, takeover bool, identity *AuthIdentity) (DocumentLockState, error) ``` Takeover uses CollectionAccess.Unlock, falling back to Update when omitted. Locks coordinate editors; they do not replace optimistic revision checks or authorization. ## PreviewToken Canonical URL: https://riducms.com/reference/core/preview-token/ Kind: type One short-lived read-only resource capability. ```go type PreviewToken struct { Token string Resource string Slug string DocumentID string ExpiresAt time.Time } ``` The token is read-only and scoped to one exact resource. Treat Token as a bearer secret and pass it only to the intended preview frontend. ## App.CreateCollectionPreviewToken Canonical URL: https://riducms.com/reference/core/app-create-collection-preview-token/ Kind: method Mint a token after read authorization. ```go func (application *App) CreateCollectionPreviewToken(ctx context.Context, collection, documentID string, identity *AuthIdentity) (PreviewToken, error) ``` ## App.FindCollectionPreview Canonical URL: https://riducms.com/reference/core/app-find-collection-preview/ Kind: method Read the exact token-scoped draft without a session. ```go func (application *App) FindCollectionPreview(ctx context.Context, token, collection, documentID string) (store.Document, error) ``` The token must match resource type, slug, and ID and is revoked/fenced by permanent deletion. Global equivalents are also available. ## App.Preference Canonical URL: https://riducms.com/reference/core/app-preference/ Kind: method Read one opaque user-owned preference. ```go func (application *App) Preference(ctx context.Context, identity *AuthIdentity, key string) (json.RawMessage, error) ``` ## App.SetPreference Canonical URL: https://riducms.com/reference/core/app-set-preference/ Kind: method Validate and persist a bounded preference value. ```go func (application *App) SetPreference(ctx context.Context, identity *AuthIdentity, key string, value json.RawMessage) (json.RawMessage, error) ``` Exact identities disambiguate multiple auth collections. Preferences are independent from content documents and never schema fields. ## App.DeletePreference Canonical URL: https://riducms.com/reference/core/app-delete-preference/ Kind: method Delete one preference owned by an exact authenticated identity. ```go func (application *App) DeletePreference(ctx context.Context, identity *AuthIdentity, key string) error ``` ## App.ResetPreferences Canonical URL: https://riducms.com/reference/core/app-reset-preferences/ Kind: method Delete every preference owned by an exact authenticated identity. ```go func (application *App) ResetPreferences(ctx context.Context, identity *AuthIdentity) error ``` ## App.APIKeys Canonical URL: https://riducms.com/reference/core/app-api-keys/ Kind: method List safe active API-key metadata for the current session identity. ```go func (application *App) APIKeys(ctx context.Context, sessionToken string) ([]APIKeyInfo, error) ``` ## App.RevokeAPIKey Canonical URL: https://riducms.com/reference/core/app-revoke-api-key/ Kind: method Revoke one API key belonging to the current session identity. ```go func (application *App) RevokeAPIKey(ctx context.Context, sessionToken, id string) error ``` ## App.AuthenticateAPIKey Canonical URL: https://riducms.com/reference/core/app-authenticate-api-key/ Kind: method Resolve a bearer API key to its current user without creating a browser session. ```go func (application *App) AuthenticateAPIKey(ctx context.Context, raw string) (store.Document, error) ``` ## App.PruneExpiredAuth Canonical URL: https://riducms.com/reference/core/app-prune-expired-auth/ Kind: method Remove one bounded batch of expired sessions and API keys. ```go func (application *App) PruneExpiredAuth(ctx context.Context, limit int) (store.AuthPruneResult, error) ``` Execute workers call this automatically when the configured store supports authentication maintenance. ## App.ReleaseDocumentLock Canonical URL: https://riducms.com/reference/core/app-release-document-lock/ Kind: method Release only the exact authenticated identity’s document lease. ```go func (application *App) ReleaseDocumentLock(ctx context.Context, collection, documentID string, identity *AuthIdentity) error ``` ## App.CreateGlobalPreviewToken Canonical URL: https://riducms.com/reference/core/app-create-global-preview-token/ Kind: method Mint a short-lived preview token for one draft global. ```go func (application *App) CreateGlobalPreviewToken(ctx context.Context, slug string, identity *AuthIdentity) (PreviewToken, error) ``` ## App.FindGlobalPreview Canonical URL: https://riducms.com/reference/core/app-find-global-preview/ Kind: method Read the exact token-scoped draft global without a session. ```go func (application *App) FindGlobalPreview(ctx context.Context, token, slug string) (store.Document, error) ``` ## App.RevokePreviewToken Canonical URL: https://riducms.com/reference/core/app-revoke-preview-token/ Kind: method Revoke a preview capability owned by the exact authenticated identity. ```go func (application *App) RevokePreviewToken(ctx context.Context, raw string, identity *AuthIdentity) error ``` Missing and expired tokens are treated as already revoked. ## App.RunTasks Canonical URL: https://riducms.com/reference/core/app-run-tasks/ Kind: method Claim and execute one bounded durable-task batch. ```go func (application *App) RunTasks(ctx context.Context, limit int) (TaskRunSummary, error) ``` Concurrent callers are safe. Store leases are authoritative and handlers remain at-least-once. ## App.CreateAuthUserWithOptions Canonical URL: https://riducms.com/reference/core/app-create-auth-user-with-options/ Kind: method Create an auth document and credential with exact identity and response-selection controls. ```go func (application *App) CreateAuthUserWithOptions(ctx context.Context, collection string, values store.Values, password string, options MutationOptions) (store.Document, error) ``` ## App.CreateAuthUserForTransport Canonical URL: https://riducms.com/reference/core/app-create-auth-user-for-transport/ Kind: method Apply the safe anonymous first-user default used by framework transports. ```go func (application *App) CreateAuthUserForTransport(ctx context.Context, collection string, values store.Values, password string, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` This transport form permits one anonymous bootstrap only for the configured admin-user collection when no Create rule is authored. ## App.CreateAuthUserForTransportWithOptions Canonical URL: https://riducms.com/reference/core/app-create-auth-user-for-transport-with-options/ Kind: method Use the transport bootstrap policy with exact mutation options. ```go func (application *App) CreateAuthUserForTransportWithOptions(ctx context.Context, collection string, values store.Values, password string, options MutationOptions) (store.Document, error) ``` ## App.SetPassword Canonical URL: https://riducms.com/reference/core/app-set-password/ Kind: method Validate and replace a local password, then revoke existing sessions and API keys. ```go func (application *App) SetPassword(ctx context.Context, collection, userID, password string) error ``` ## App.LoginWithOptions Canonical URL: https://riducms.com/reference/core/app-login-with-options/ Kind: method Authenticate and record safe client metadata on the resulting session. ```go func (application *App) LoginWithOptions(ctx context.Context, collection, email, password string, options LoginOptions) (AuthSession, error) ``` Credential failures intentionally share one public response. ## App.AuthenticateExternal Canonical URL: https://riducms.com/reference/core/app-authenticate-external/ Kind: method Run configured request strategies and return the recognized actor. ```go func (application *App) AuthenticateExternal(ctx context.Context, headers map[string][]string) (store.Document, error) ``` Use AuthenticateExternalIdentity when the exact auth collection is required. ## App.ForceUnlock Canonical URL: https://riducms.com/reference/core/app-force-unlock/ Kind: method Clear an account lock for an exact authenticated identity. ```go func (application *App) ForceUnlock(ctx context.Context, collection, id string, identity *AuthIdentity) error ``` ## App.UnlockAuthUser Canonical URL: https://riducms.com/reference/core/app-unlock-auth-user/ Kind: method Find an account by configured identity and clear its login lock. ```go func (application *App) UnlockAuthUser(ctx context.Context, collection, identity string, actorIdentity *AuthIdentity) error ``` Missing users remain indistinguishable from denied access. ## App.Duplicate Canonical URL: https://riducms.com/reference/core/app-duplicate/ Kind: method Duplicate an authorized document and independently copy upload objects. ```go func (application *App) Duplicate(ctx context.Context, collection, id string, overrides store.Values, actor *store.Document, localeOptions ...LocaleOptions) (store.Document, error) ``` ## App.DuplicateForIdentity Canonical URL: https://riducms.com/reference/core/app-duplicate-for-identity/ Kind: method Duplicate for one exact authenticated collection identity. ```go func (application *App) DuplicateForIdentity(ctx context.Context, collection, id string, overrides store.Values, identity *AuthIdentity, localeOptions ...LocaleOptions) (store.Document, error) ``` ## App.DuplicateWithOptions Canonical URL: https://riducms.com/reference/core/app-duplicate-with-options/ Kind: method Duplicate with exact actor identity and response selection. ```go func (application *App) DuplicateWithOptions(ctx context.Context, collection, id string, overrides store.Values, options MutationOptions) (store.Document, error) ``` ## App.UploadForIdentity Canonical URL: https://riducms.com/reference/core/app-upload-for-identity/ Kind: method Store a file for one exact authenticated collection identity. ```go func (application *App) UploadForIdentity(ctx context.Context, collection string, input UploadInput, identity *AuthIdentity) (store.Document, error) ``` ## App.UploadFromURLForIdentity Canonical URL: https://riducms.com/reference/core/app-upload-from-url-for-identity/ Kind: method Fetch and store a remote file for one exact authenticated identity. ```go func (application *App) UploadFromURLForIdentity(ctx context.Context, collection string, input RemoteUploadInput, identity *AuthIdentity) (store.Document, error) ``` Identity is rechecked before networking begins. ## App.UpdateUploadImageForIdentity Canonical URL: https://riducms.com/reference/core/app-update-upload-image-for-identity/ Kind: method Regenerate image variants for one exact authenticated identity. ```go func (application *App) UpdateUploadImageForIdentity(ctx context.Context, collection, id string, input UpdateUploadImageInput, identity *AuthIdentity) (store.Document, error) ``` ## App.OpenUpload Canonical URL: https://riducms.com/reference/core/app-open-upload/ Kind: method Open an object after proving it belongs to an access-visible upload document. ```go func (application *App) OpenUpload(ctx context.Context, collection, key string, actor *store.Document) (io.ReadCloser, storage.Object, error) ``` ## App.OpenUploadForIdentity Canonical URL: https://riducms.com/reference/core/app-open-upload-for-identity/ Kind: method Open an upload through one exact authenticated collection identity. ```go func (application *App) OpenUploadForIdentity(ctx context.Context, collection, key string, identity *AuthIdentity) (io.ReadCloser, storage.Object, error) ``` ## App.CleanupUploads Canonical URL: https://riducms.com/reference/core/app-cleanup-uploads/ Kind: method Delete orphan candidates reported by upload reconciliation. ```go func (application *App) CleanupUploads(ctx context.Context, olderThan time.Duration) (ReconcileResult, error) ``` Use a grace period of at least five minutes so in-flight storage preparation is not mistaken for an orphan before its document transaction commits. ## Input Canonical URL: https://riducms.com/reference/core/input/ Kind: type A presence-aware value used by nullable generated Go mutation fields. ```go type Input[T any] struct { value T null bool } ``` A nil *Input omits the field, Set emits a concrete JSON value, and Null emits explicit JSON null. This preserves outbound partial-update semantics that an ordinary *T cannot represent. Input intentionally implements marshaling only. Generated mutation structs are typed local-API arguments, not general-purpose JSON decode DTOs. ## Set Canonical URL: https://riducms.com/reference/core/set/ Kind: function Construct a present generated mutation field with a concrete value. ```go func Set[T any](value T) *Input[T] ``` ## Null Canonical URL: https://riducms.com/reference/core/null/ Kind: function Construct a present generated mutation field whose JSON value is null. ```go func Null[T any]() *Input[T] ``` ## NonNullInput Canonical URL: https://riducms.com/reference/core/non-null-input/ Kind: type A write-only generated mutation value that refuses to encode JSON null. ```go type NonNullInput[T any] struct { value T } ``` Generated non-null slice, map, fallback json.RawMessage, and plugin-owned named mutation fields use this wrapper because the manifest does not fully describe their JSON nullability. A required field uses a NonNullInput value constructed by NonNull. A defaulted or update field uses *NonNullInput: nil omits the key and SetNonNull supplies a present value. NonNullInput intentionally implements marshaling only. Nil slices, nil maps, nil interfaces, and null json.RawMessage values fail encoding instead of weakening the schema contract. ## NonNull Canonical URL: https://riducms.com/reference/core/non-null/ Kind: function Construct a required generated mutation value that must not encode as JSON null. ```go func NonNull[T any](value T) NonNullInput[T] ``` ## SetNonNull Canonical URL: https://riducms.com/reference/core/set-non-null/ Kind: function Construct a present omittable generated mutation value that must not encode as JSON null. ```go func SetNonNull[T any](value T) *NonNullInput[T] ``` ## NewTypedCollection Canonical URL: https://riducms.com/reference/core/new-typed-collection/ Kind: function Create a generated-model handle for one collection slug. ```go func NewTypedCollection[Document, Create, Update any](slug string) TypedCollection[Document, Create, Update] ``` Generated application contracts use this core API; ordinary hand-written code may prefer LocalAPI with store.Values. Construction stores the supplied slug without validation; ridu.Resolve validates it when resolving the schema. ## TypedCollection Canonical URL: https://riducms.com/reference/core/typed-collection/ Kind: type An unbound typed collection descriptor. ```go type TypedCollection[Document, Create, Update any] struct { slug string } ``` ## BoundTypedCollection Canonical URL: https://riducms.com/reference/core/bound-typed-collection/ Kind: type Typed Create, Import, Find, List, Update, UpdateRevision, and Delete methods. ```go type BoundTypedCollection[Document, Create, Update any] struct { definition TypedCollection[Document, Create, Update] local *LocalAPI } ``` Inputs and outputs cross the same operation engine as untyped LocalAPI. JSON conversion reports incompatible field types; unknown stored fields are ignored and absent model fields keep their Go zero values. The wrapper does not create a second runtime. ## TypedPage Canonical URL: https://riducms.com/reference/core/typed-page/ Kind: type A typed list result with the ordinary page metadata. ```go type TypedPage[Document any] struct { Documents []Document Page int Limit int Total int } ``` Document is the generated collection model supplied to NewTypedCollection. Pagination metadata follows LocalAPI.List. ## TypedListOptions Canonical URL: https://riducms.com/reference/core/typed-list-options/ Kind: type List controls whose result shape remains compatible with one generated Go document model. ```go type TypedListOptions struct { Where query.Expression Page int Limit int Sort []query.Sort Select []query.Path OutputFields []query.Path Draft *bool Actor *store.Document ActorCollection schema.CollectionSlug TrashOnly bool Locale schema.LocaleCode FallbackLocales []schema.LocaleCode DisableFallback bool } ``` Population and all-locale reads change field value shapes dynamically, so they remain available through LocalAPI rather than this statically decoded wrapper. ## NewTypedGlobal Canonical URL: https://riducms.com/reference/core/new-typed-global/ Kind: function Create a generated-model handle for one global slug. ```go func NewTypedGlobal[Document, Update any](slug string) TypedGlobal[Document, Update] ``` ## BoundTypedGlobal Canonical URL: https://riducms.com/reference/core/bound-typed-global/ Kind: type Typed Find, Update, Publish, Unpublish, Restore, and RestoreAsDraft methods. ```go type BoundTypedGlobal[Document, Update any] struct { definition TypedGlobal[Document, Update] local *LocalAPI } ``` Generated wrappers keep singleton methods discoverable without changing LocalAPI semantics or authorization. ## Operation Canonical URL: https://riducms.com/reference/core/operation/ Kind: type The operation being authorized and dispatched. ```go type Operation string ``` ## AccessDecision Canonical URL: https://riducms.com/reference/core/access-decision/ Kind: type An allow, deny, or filtered authorization result. ```go type AccessDecision struct { kind AccessDecisionKind expression query.Expression } ``` AccessDecision is immutable. Construct it with Allow, Deny, or Where; filtered predicates remain attached to the same atomic store query as the operation. ## CollectionAccess Canonical URL: https://riducms.com/reference/core/collection-access/ Kind: type Access rules for collection reads and mutations. ```go type CollectionAccess struct { // Admin controls whether an authenticated user from this auth collection may // enter the framework admin. It accepts only Allow or Deny and defaults to // Allow when omitted. Admin AccessRule // Create controls document creation. Create AccessRule // Read controls individual and list reads and may return a Where decision. Read AccessRule // ReadVersions controls version-history reads and may return a Where // decision. When omitted, Read is used. ReadVersions AccessRule // Update controls document updates and may return a Where decision. Update AccessRule // Publish controls publishing and atomic published-document edits. When // omitted, Update is used so existing policies remain coherent. Publish AccessRule // Unpublish controls moving a published document back to draft. When // omitted, Update is used. Unpublish AccessRule // Delete controls document deletion and may return a Where decision. Delete AccessRule // Unlock controls takeover of another editor's active document lock. When // omitted, Update is used so existing collection policies remain coherent. Unlock AccessRule } ``` ```go var Posts = ridu.Collection{ Access: ridu.CollectionAccess{ Create: authenticated, Read: publishedOrOwner, Update: ownerOrEditor, Delete: administratorsOnly, }, } ``` ## GlobalAccess Canonical URL: https://riducms.com/reference/core/global-access/ Kind: type Access rules for reading, updating, publishing, and unpublishing a global. ```go type GlobalAccess struct { // Read controls global reads and may return a Where decision. Read AccessRule // ReadVersions controls version-history reads and may return a Where decision. // When omitted, Read is used. ReadVersions AccessRule // Update controls global updates and may return a Where decision for an // existing singleton. Update AccessRule // Publish controls publishing and atomic published-global edits. When // omitted, Update is used. Publish AccessRule // Unpublish controls moving a published global back to draft. When omitted, // Update is used. Unpublish AccessRule } ``` ## AccessRule Canonical URL: https://riducms.com/reference/core/access-rule/ Kind: type Return an authorization decision for one operation. ```go type AccessRule func(AccessContext) (AccessDecision, error) ``` ```go var authenticated ridu.AccessRule = func( ctx ridu.AccessContext, ) (ridu.AccessDecision, error) { if ctx.Actor == nil { return ridu.Deny(), nil } return ridu.Allow(), nil } ``` ## AccessContext Canonical URL: https://riducms.com/reference/core/access-context/ Kind: type Identity, operation, locale, and request data for an access rule. ```go type AccessContext struct { // Context is the request-scoped cancellation and deadline context. Context context.Context // Operation is the collection operation being evaluated. Operation Operation // CollectionID is the stable identity of the target collection. CollectionID schema.StableID // GlobalID is the stable identity of the target global, when applicable. GlobalID schema.StableID // ID is the requested document ID. It is empty for creates and list reads. ID string // Actor is the authenticated document, or nil for an anonymous request. Actor *store.Document // ActorCollection identifies the exact auth collection that owns Actor. ActorCollection schema.CollectionSlug // Data is a detached snapshot of incoming create or update values. Data store.Values // Local exposes nested operations through the same transaction and access // pipeline. Rules must avoid recursively invoking themselves without a guard. Local *LocalAPI Locale schema.LocaleCode AllLocales bool } ``` ```go func ownerOnly(ctx ridu.AccessContext) (ridu.AccessDecision, error) { if ctx.Actor == nil { return ridu.Deny(), nil } author, err := query.NewPath("author") if err != nil { return ridu.Deny(), err } return ridu.Where( query.Equal(author, query.String(ctx.Actor.ID)), ), nil } ``` ## FieldAccess Canonical URL: https://riducms.com/reference/core/field-access/ Kind: type Independent authorization rules for one authored field path. ```go type FieldAccess struct { // Create controls whether the field may be supplied during creation. Create FieldAccessRule // Read controls whether the field is visible in returned documents. Read FieldAccessRule // Update controls whether the field may be changed. Update FieldAccessRule } ``` ## FieldAccessRule Canonical URL: https://riducms.com/reference/core/field-access-rule/ Kind: type Authorize one field operation; false rejects writes or redacts reads. ```go type FieldAccessRule func(FieldAccessContext) (bool, error) ``` ```go func editorsOnly(ctx ridu.FieldAccessContext) (bool, error) { return actorHasRole(ctx.Actor, "editor"), nil } ``` ## FieldAccessContext Canonical URL: https://riducms.com/reference/core/field-access-context/ Kind: type The concrete field occurrence and transaction state supplied to a field rule. ```go type FieldAccessContext struct { // Context is the request-scoped cancellation and deadline context. Context context.Context // Operation is the create, read, update, or delete being evaluated. Operation Operation // CollectionID is the stable identity of the containing collection. CollectionID schema.StableID // GlobalID is the stable identity of the containing global, when applicable. GlobalID schema.StableID // ID is the current document ID. It is empty during creation. ID string // Path is the authored path of the field being evaluated. Path string // RuntimePath identifies the concrete value occurrence, including array or // block indexes. It equals Path for non-repeating fields. RuntimePath string // Actor is the authenticated document, or nil for an anonymous request. Actor *store.Document // ActorCollection identifies the exact auth collection that owns Actor. ActorCollection schema.CollectionSlug // Data contains incoming values for a write operation. Data store.Values // Value is the submitted value for a write or stored value for a read. Value store.Value // SiblingData contains the nearest containing object's values. Mutating this // detached snapshot does not mutate the operation input. SiblingData store.Values // Document is the existing or result document when available. Document *store.Document // Original is the persisted document before an update when available. Original *store.Document // Local exposes nested operations through the same transaction and access // pipeline. Rules must avoid recursively invoking themselves without a guard. Local *LocalAPI // Locale is the selected content locale. It is empty only when localization is disabled. Locale schema.LocaleCode // AllLocales reports that locale-keyed values were requested. AllLocales bool } ``` ## CollectionHooks Canonical URL: https://riducms.com/reference/core/collection-hooks/ Kind: type Ordered lifecycle hooks for a collection. ```go type CollectionHooks struct { // BeforeDuplicate runs after the source is access-checked and copied but before validation. BeforeDuplicate []Hook // BeforeValidate runs before field validation. BeforeValidate []Hook // BeforeChange runs after validation for create, duplicate, update, publish, and unpublish. BeforeChange []Hook // BeforeOperation runs after validation but before persistence. BeforeOperation []Hook // BeforeRead runs before one or many documents are read. BeforeRead []Hook // BeforeDelete runs after the original document is loaded but before deletion. BeforeDelete []Hook // AfterChange runs inside the transaction after a changed document is persisted. AfterChange []Hook // AfterRead runs after computed values resolve and before field redaction. AfterRead []Hook // AfterDelete runs inside the transaction after deletion or trashing. AfterDelete []Hook // AfterOperation runs inside the transaction after persistence. AfterOperation []Hook // AfterError runs when an operation associated with this resource fails. AfterError []Hook // AfterCommit runs only after the transaction commits successfully. AfterCommit []Hook } ``` Each hook slice runs in order. In FieldHooks, BeforeRead and AfterError remain resource-level phases, and map order across paths is not significant. ```go var Posts = ridu.Collection{ Hooks: ridu.CollectionHooks{ BeforeValidate: []ridu.Hook{trimTitle}, BeforeChange: []ridu.Hook{recordEditor}, AfterCommit: []ridu.Hook{reindexPost}, }, } ``` ## Hook Canonical URL: https://riducms.com/reference/core/hook/ Kind: type A collection lifecycle callback. ```go type Hook func(HookContext) error ``` ```go func trimTitle(ctx ridu.HookContext) error { title, ok := ctx.Data["title"].StringValue() if ok { ctx.Data["title"] = store.String(strings.TrimSpace(title)) } return nil } ``` ## HookContext Canonical URL: https://riducms.com/reference/core/hook-context/ Kind: type Transactional operation state passed to lifecycle hooks. ```go type HookContext struct { // Context is the request-scoped cancellation and deadline context. Context context.Context // Operation is the lifecycle operation currently running. Operation Operation // CollectionID is the stable identity of the target collection. CollectionID schema.StableID // GlobalID is the stable identity of the target global, when applicable. GlobalID schema.StableID // Actor is the authenticated document, or nil for an anonymous operation. Actor *store.Document // ActorCollection identifies the exact auth collection that owns Actor. ActorCollection schema.CollectionSlug // Data contains mutable incoming values before persistence. Data store.Values // Document is the current operation result when available. Document *store.Document // Original is the persisted document before an update or delete. Original *store.Document // Local exposes nested operations through the same operation engine. Local *LocalAPI // FieldPath is set when a hook is registered for a specific field. FieldPath string // Error is set only for after-error hooks and preserves the original failure. Error error Locale schema.LocaleCode AllLocales bool } ``` Most applications import the ridu.HookContext alias from the root package. AfterCommit and AfterError run outside the original transaction. ```go func writeAuditEntry(ctx ridu.HookContext) error { if ctx.Document == nil { return nil } _, err := ctx.Local.Create(ctx.Context, "audit-log", store.Values{ "document": store.String(ctx.Document.ID), }, ctx.Actor) return err } ``` ## RootHooks Canonical URL: https://riducms.com/reference/core/root-hooks/ Kind: type Application-wide failure hooks for errors raised before a resource resolves. ```go type RootHooks struct { AfterError []Hook } ``` ## AfterCommitDispatcher Canonical URL: https://riducms.com/reference/core/after-commit-dispatcher/ Kind: interface Deliver committed lifecycle effects immediately or through an application boundary. ```go type AfterCommitDispatcher interface { Dispatch(context.Context, AfterCommitEffect) error } ``` ## AfterCommitEffect Canonical URL: https://riducms.com/reference/core/after-commit-effect/ Kind: type Identity and executable work for one committed hook. ```go type AfterCommitEffect struct { // Operation identifies the committed operation. Operation Operation // CollectionID identifies the affected collection. CollectionID schema.StableID // GlobalID identifies the affected global, when applicable. GlobalID schema.StableID // DocumentID identifies the affected document. DocumentID string // Run performs the post-commit side effect. Run func(context.Context) error } ``` ## Plugin Canonical URL: https://riducms.com/reference/core/plugin/ Kind: interface The minimum compiled backend plugin contract. ```go type Plugin interface { Key() string } ``` Focused capability interfaces add transforms, descriptors, hooks, validators, endpoints, or transports without one universal option bag. Plugins are trusted compiled Go code; production never installs code dynamically. ## DescriptorProvider Canonical URL: https://riducms.com/reference/core/descriptor-provider/ Kind: interface Opt into versioned generation, migration, and compatibility tooling. ```go type DescriptorProvider interface { Plugin Descriptor() PluginDescriptor } ``` Required for plugins exposing advanced admin, endpoint, transport, hook, generated-field, or migration capabilities. Key-only plugins remain valid for simple config transforms or validators without build metadata. ## PluginDescriptor Canonical URL: https://riducms.com/reference/core/plugin-descriptor/ Kind: type Versioned plugin metadata and capabilities. ```go type PluginDescriptor struct { // Version is the plugin's complete semantic release without a leading v. Version string // GoPackage is the canonical import path that provides the plugin. GoPackage string // APIVersion must equal PluginAPIVersion for this Ridu release. APIVersion uint32 // Ridu limits the framework releases allowed to compile this plugin. Ridu RiduCompatibility // Admin describes the optional statically bundled admin half. Admin *AdminPluginMetadata // FieldTypes maps every reusable plugin field to generated public types. FieldTypes []PluginFieldType // DatabaseContributions contains exceptional, adapter-specific private // database state. Ordinary plugin data should be added as collections or // fields through ConfigTransformer instead. DatabaseContributions []PluginDatabaseContribution } ``` Deterministic public metadata copied into the manifest. Executable code, handlers, validators, secrets, and environment-specific configuration never belong here. ## RiduCompatibility Canonical URL: https://riducms.com/reference/core/ridu-compatibility/ Kind: type A half-open supported framework semantic-version interval. ```go type RiduCompatibility struct { // Minimum is the oldest supported Ridu semantic version, inclusive. Minimum string // MaximumExclusive is the optional first unsupported Ridu version. MaximumExclusive string } ``` Minimum is inclusive. Empty MaximumExclusive leaves the upper bound open. Test published ranges with plugintest. ## AdminPluginMetadata Canonical URL: https://riducms.com/reference/core/admin-plugin-metadata/ Kind: type Static pairing metadata for a plugin admin package. ```go type AdminPluginMetadata struct { // Package is an installed bare JavaScript package specifier. Package string // Export is the named AdminPlugin export in Package. Export string // APIVersion must equal AdminPluginAPIVersion. APIVersion uint32 // PairingVersion changes when backend and admin halves cease to match. PairingVersion uint32 // Routes lists authenticated admin route paths in exact registration order. Routes []string // Assets lists package-relative static assets in exact registration order. Assets []string } ``` Package and Export are statically imported at admin build time. Increment PairingVersion when backend and admin halves cease to be compatible. ## PluginFieldType Canonical URL: https://riducms.com/reference/core/plugin-field-type/ Kind: type Exact generated Go, TypeScript, where, and OpenAPI types for a plugin field. ```go type PluginFieldType struct { // Key matches the PluginField key stored in the schema manifest. Key string // TypeScriptPackage exports the named output, input, and where types. TypeScriptPackage string // TypeScriptOutput is the stored document value type export. TypeScriptOutput string // TypeScriptInput is the create and update value type export. TypeScriptInput string // TypeScriptWhere is the optional query operand type export. TypeScriptWhere string // GoPackage and GoType optionally name the generated Go model type. GoPackage string // GoType is an exported type in GoPackage; both Go fields are optional together. GoType string // JSONSchema is the deterministic OpenAPI 3.1 schema for one field value. JSONSchema []byte } ``` Go type mapping is optional and falls back to json.RawMessage. TypeScript names are emitted as type-only imports. JSONSchema must be deterministic. ## PluginDatabaseAdapter Canonical URL: https://riducms.com/reference/core/plugin-database-adapter/ Kind: type A closed adapter identity for exceptional private plugin schema. ```go type PluginDatabaseAdapter = schema.PluginDatabaseAdapter ``` PluginDatabaseAdapterPostgres selects PostgreSQL SQL; PluginDatabaseAdapterSQLite selects SQLite SQL. ## PluginDatabaseContribution Canonical URL: https://riducms.com/reference/core/plugin-database-contribution/ Kind: type One explicitly adapter-scoped private migration bundle. ```go type PluginDatabaseContribution struct { Adapter PluginDatabaseAdapter Migrations []PluginMigration Tables []string } ``` Use ordinary ConfigTransformer collections for normal plugin records. Ridu never translates contribution SQL between adapters. ## PluginMigration Canonical URL: https://riducms.com/reference/core/plugin-migration/ Kind: type One immutable contiguous reversible adapter-specific transition. ```go type PluginMigration struct { // Version starts at 1 and increments without gaps. Version uint32 // Name is a stable lowercase kebab-case review label. Name string // UpSQL executes in order when entering Version. UpSQL []string // DownSQL executes in order when leaving Version. DownSQL []string } ``` Versions start at 1 without gaps. Ridu copies the SQL into migration artifacts and rejects changed history before execution. ## GenerationProvider Canonical URL: https://riducms.com/reference/core/generation-provider/ Kind: interface Contribute deterministic files that require executable plugin configuration. ```go type GenerationProvider interface { Plugin GeneratedArtifacts(PluginGenerationContext) ([]PluginGeneratedArtifact, error) } ``` Runs only when a generated.. destination requests the provider. Execution stays inside the compiled project command without stores, storage, listeners, or network introspection; the portable CLI owns destinations, atomic installation, and drift checks. ## PluginGenerationContext Canonical URL: https://riducms.com/reference/core/plugin-generation-context/ Kind: type Immutable schema state supplied to plugin generation. ```go type PluginGenerationContext struct { Manifest schema.Manifest } ``` ## PluginGeneratedArtifact Canonical URL: https://riducms.com/reference/core/plugin-generated-artifact/ Kind: type One deterministic plugin-scoped generated file. ```go type PluginGeneratedArtifact struct { Name string Content []byte } ``` Name is lowercase kebab-case beneath the provider key. Content must be non-empty and is defensively copied before crossing the project protocol. ## ConfigTransformer Canonical URL: https://riducms.com/reference/core/config-transformer/ Kind: interface Transform a defensive copy of authored config before final validation. ```go type ConfigTransformer interface { Plugin TransformConfig(Config) (Config, error) } ``` Runs in Config.Plugins declaration order. Prefer focused capabilities for hooks and fields when a general config transform is unnecessary. ## HookProvider Canonical URL: https://riducms.com/reference/core/hook-provider/ Kind: interface Append compiled collection or field hooks. ```go type HookProvider interface { Plugin Hooks() []PluginHookContribution } ``` Contributions run in plugin order after application-authored hooks. FieldPath is an optional canonical path. ## FieldValidatorProvider Canonical URL: https://riducms.com/reference/core/field-validator-provider/ Kind: interface Provide path-aware runtime validators for plugin field keys. ```go type FieldValidatorProvider interface { Plugin FieldValidators() map[string]PluginFieldValidator } ``` RuntimePath contains concrete array/block indexes. Validators return schema.Issue values and must be deterministic and side-effect-free. ## EndpointProvider Canonical URL: https://riducms.com/reference/core/endpoint-provider/ Kind: interface Contribute exact REST endpoints below a namespaced plugin prefix. ```go type EndpointProvider interface { Plugin Endpoints() []PluginEndpoint } ``` Routes live below /api/plugins//. Handlers receive exact actor identity, LocalAPI, trusted client IP, auth-admission, and diagnostic reporting helpers. Body limits inherit the application bound unless explicitly overridden. ## TransportProvider Canonical URL: https://riducms.com/reference/core/transport-provider/ Kind: interface Bind an established application-level protocol once at startup. ```go type TransportProvider interface { Plugin BindTransports(PluginTransportContext) ([]PluginTransport, error) } ``` For absolute protocol paths such as /api/graphql, not ordinary plugin endpoints. Binding receives the immutable manifest, LocalAPI, and fully initialized App; do not rebuild schemas per request. ## AdminConfig Canonical URL: https://riducms.com/reference/core/admin-config/ Kind: type Application-level configuration for the framework-owned admin. ```go type AdminConfig struct { // User is the slug of the auth-enabled collection whose sessions may access // the admin. It is required when the application has any auth collection. User schema.CollectionSlug // Localization configures the language and timezone choices for the // framework-owned interface. It is independent from content localization. Localization AdminLocalizationConfig } ``` This setting selects the admin identity source; collection access still provides the authorization decision. ```go AdminConfig{User: "users"} ``` ## AdminLocalizationConfig Canonical URL: https://riducms.com/reference/core/admin-localization-config/ Kind: type Admin interface languages and editor timezone choices. ```go type AdminLocalizationConfig struct { Languages []AdminLanguage DefaultLanguage string TimeZones []AdminTimeZone DefaultTimeZone string } ``` ## AdminLanguage Canonical URL: https://riducms.com/reference/core/admin-language/ Kind: type One statically bundled admin interface language. ```go type AdminLanguage struct { Code string Label string LabelTranslations map[string]string RTL bool } ``` ## AdminTimeZone Canonical URL: https://riducms.com/reference/core/admin-time-zone/ Kind: type One timezone offered by the admin interface. ```go type AdminTimeZone struct { ID string Label string LabelTranslations map[string]string } ``` ## CollectionLabels Canonical URL: https://riducms.com/reference/core/collection-labels/ Kind: type Author-facing singular and plural collection names. ```go type CollectionLabels struct { // Singular is used when referring to one document. Singular string // SingularTranslations overrides Singular for configured admin languages. SingularTranslations map[string]string // Plural is used in navigation and collection lists. Plural string // PluralTranslations overrides Plural for configured admin languages. PluralTranslations map[string]string } ``` ## CollectionIndex Canonical URL: https://riducms.com/reference/core/collection-index/ Kind: type One ordered compound database index. ```go type CollectionIndex struct { Fields []string Unique bool } ``` ```go CollectionIndex{Fields: []string{"tenant", "slug"}, Unique: true} ``` ## GlobalAdmin Canonical URL: https://riducms.com/reference/core/global-admin/ Kind: type Serializable presentation metadata for a global. ```go type GlobalAdmin struct { Group string GroupTranslations map[string]string Description string DescriptionTranslations map[string]string LivePreview LivePreviewConfig } ``` ## DocumentLockConfig Canonical URL: https://riducms.com/reference/core/document-lock-config/ Kind: type Expiration policy for coordinated authoring locks. ```go type DocumentLockConfig struct { Duration time.Duration } ``` ## PasswordPolicy Canonical URL: https://riducms.com/reference/core/password-policy/ Kind: type Built-in local password validation and hashing policy. ```go type PasswordPolicy struct { // MinLength is the minimum password length in Unicode code points. Zero // defaults to 8. MinLength int // MaxBytes is the maximum UTF-8 encoded password length. Zero defaults to 72, // bcrypt's safe input limit. MaxBytes int // BcryptCost controls bcrypt work. Zero uses bcrypt.DefaultCost. Increasing // it transparently upgrades older hashes after a successful login. Values // above 16 are rejected because they can make startup and login impractical. BcryptCost int // Validate adds application-specific password rules. Return a user-safe error // explaining how the candidate must change. Validate func(password string) error } ``` Ridu deliberately uses length-based defaults rather than mandatory character classes. The custom validator runs only in trusted Go code and is never serialized. ## PasswordResetConfig Canonical URL: https://riducms.com/reference/core/password-reset-config/ Kind: type Password-recovery token lifetime and delivery callback. ```go type PasswordResetConfig struct { // TokenDuration is the lifetime of a reset token. Zero defaults to one hour. TokenDuration time.Duration // Send delivers a newly issued token. It should enqueue or send the message // before returning; returning an error prevents a success response. Send func(context.Context, PasswordResetNotification) error } ``` ## VerifyEmailConfig Canonical URL: https://riducms.com/reference/core/verify-email-config/ Kind: type Mandatory email-verification token lifetime and delivery callback. ```go type VerifyEmailConfig struct { // TokenDuration is the lifetime of a verification token. Zero defaults to 24 hours. TokenDuration time.Duration // Send delivers a newly issued verification token. Send func(context.Context, VerifyEmailNotification) error } ``` ## PasswordResetNotification Canonical URL: https://riducms.com/reference/core/password-reset-notification/ Kind: type Trusted password-reset delivery payload. ```go type PasswordResetNotification struct { Collection schema.CollectionSlug User store.Document Token string ExpiresAt time.Time } ``` Token is shown once and must never be logged. Build and deliver the application-owned reset link inside the trusted callback. ## VerifyEmailNotification Canonical URL: https://riducms.com/reference/core/verify-email-notification/ Kind: type Trusted email-verification delivery payload. ```go type VerifyEmailNotification struct { Collection schema.CollectionSlug User store.Document Token string ExpiresAt time.Time } ``` Token is shown once and must never be logged. Build and deliver the application-owned verification link inside the trusted callback. ## AuthAccess Canonical URL: https://riducms.com/reference/core/auth-access/ Kind: type Authorization rules for authentication operations outside document CRUD. ```go type AuthAccess struct { Login AuthAccessRule PasswordReset AuthAccessRule Verification AuthAccessRule APIKey AuthAccessRule Session AuthAccessRule } ``` A nil rule allows its operation. These rules complement collection CRUD access; they do not replace it. ## AuthContext Canonical URL: https://riducms.com/reference/core/auth-context/ Kind: type Request and actor state supplied to an authentication rule or hook. ```go type AuthContext struct { Context context.Context Operation AuthOperation CollectionID schema.StableID User *store.Document Identity string IPAddress string UserAgent string Local *LocalAPI } ``` Passwords, bearer tokens, reset tokens, and API keys are intentionally never included. ## AuthHooks Canonical URL: https://riducms.com/reference/core/auth-hooks/ Kind: type Authentication lifecycle callbacks grouped by phase. ```go type AuthHooks struct { BeforeLogin []AuthHook AfterLogin []AuthHook AfterMe []AuthHook BeforeLogout []AuthHook AfterLogout []AuthHook BeforeRefresh []AuthHook AfterRefresh []AuthHook BeforeForgotPassword []AuthHook AfterForgotPassword []AuthHook BeforePasswordReset []AuthHook AfterPasswordReset []AuthHook BeforeVerification []AuthHook AfterVerification []AuthHook BeforeAPIKey []AuthHook AfterAPIKey []AuthHook } ``` Before hooks can reject an operation. If an after-login or after-refresh hook fails, Ridu revokes the newly issued credential before returning the error. ## AuthStrategy Canonical URL: https://riducms.com/reference/core/auth-strategy/ Kind: type One compiled application-owned request authentication strategy. ```go type AuthStrategy struct { // Name is a stable lowercase kebab-case identifier used in diagnostics. Name string // Authenticate returns Authenticated false when the request does not belong // to this strategy. It must not return raw credentials or untrusted user data. Authenticate func(AuthStrategyContext) (AuthStrategyResult, error) } ``` Strategies run in declaration order after built-in session and API-key authentication. Return Authenticated false when the request does not belong to the strategy. ## AuthStrategyContext Canonical URL: https://riducms.com/reference/core/auth-strategy-context/ Kind: type Normalized request input for a custom authentication strategy. ```go type AuthStrategyContext struct { Context context.Context CollectionID schema.StableID Headers map[string][]string Local *LocalAPI } ``` ## AuthStrategyResult Canonical URL: https://riducms.com/reference/core/auth-strategy-result/ Kind: type Result of one custom authentication strategy. ```go type AuthStrategyResult struct { Authenticated bool UserID string } ``` An authenticated result must supply UserID. A false result means “not applicable,” allowing the next strategy to run. ## AuthAccessRule Canonical URL: https://riducms.com/reference/core/auth-access-rule/ Kind: type Allow or deny one authentication operation. ```go type AuthAccessRule func(AuthContext) (bool, error) ``` ## AuthHook Canonical URL: https://riducms.com/reference/core/auth-hook/ Kind: type Observe or reject one authentication lifecycle phase. ```go type AuthHook func(AuthContext) error ``` ## AuthOperation Canonical URL: https://riducms.com/reference/core/auth-operation/ Kind: type Stable authentication lifecycle discriminant. ```go type AuthOperation string ``` ## AuthSessionInfo Canonical URL: https://riducms.com/reference/core/auth-session-info/ Kind: type Safe metadata for an active session or device. ```go type AuthSessionInfo struct { ID string CreatedAt time.Time LastSeenAt time.Time ExpiresAt time.Time IPAddress string UserAgent string Current bool } ``` ## APIKey Canonical URL: https://riducms.com/reference/core/api-key/ Kind: type A newly minted API key and its one-time secret. ```go type APIKey struct { ID string Name string Key string CreatedAt time.Time ExpiresAt time.Time } ``` Key is a bearer secret. Persist it in the caller’s secret store because Ridu cannot display it again. ## APIKeyInfo Canonical URL: https://riducms.com/reference/core/api-key-info/ Kind: type Safe metadata for an existing API key. ```go type APIKeyInfo struct { ID string Name string CreatedAt time.Time LastUsedAt time.Time ExpiresAt time.Time } ``` ## ImageSize Canonical URL: https://riducms.com/reference/core/image-size/ Kind: type One named derived image variant and fit policy. ```go type ImageSize struct { // Name is the stable key used to address the generated variant. Name string // Width is the target width in pixels. Width int // Height is the target height in pixels. Height int // Fit controls resizing and must be either "cover" or "contain". Fit string } ``` ## ReconcileResult Canonical URL: https://riducms.com/reference/core/reconcile-result/ Kind: type Result counters from upload reconciliation. ```go type ReconcileResult struct { // Scanned is the number of stored objects inspected. Scanned int // Candidates is the number of unreferenced objects older than the safety window. Candidates int // Deleted is the number of unreferenced objects removed. Deleted int } ``` ## ReadinessCheck Canonical URL: https://riducms.com/reference/core/readiness-check/ Kind: type One repeatable required-dependency readiness check. ```go type ReadinessCheck func(context.Context) error ``` Checks must be read-only, repeatable, and honor context cancellation. Add them through HandlerOptions.ReadinessChecks. ## AuditEvent Canonical URL: https://riducms.com/reference/core/audit-event/ Kind: type Security-relevant application event metadata. ```go type AuditEvent struct { // Time is when the event occurred. Time time.Time // RequestID correlates the event with logs and observations. RequestID string // ClientIP is the resolved direct or trusted-forwarded client address. ClientIP string // Action names the operation, such as login, create, or delete. Action string // Collection is the affected collection slug when applicable. Collection string // DocumentID is the affected document identity when applicable. DocumentID string // ActorID is the authenticated document identity when available. ActorID string // ActorCollection disambiguates ActorID across auth collections. ActorCollection schema.CollectionSlug } ``` ## RequestObservation Canonical URL: https://riducms.com/reference/core/request-observation/ Kind: type Transport timing and response metadata for one completed request. ```go type RequestObservation struct { // Time is when the observation was recorded. Time time.Time // RequestID correlates the observation with audit events and logs. RequestID string // Method is the HTTP request method. Method string // Path is the requested URL path. Path string // Status is the HTTP response status code. Status int // ErrorCode is the stable public Ridu code for a failed request. ErrorCode string // ResponseBytes is the number of response-body bytes written. ResponseBytes int64 // Duration is the total handler execution time. Duration time.Duration } ``` ## RequestErrorEvent Canonical URL: https://riducms.com/reference/core/request-error-event/ Kind: type Trusted internal diagnostics for a failed request or recovered panic. ```go type RequestErrorEvent struct { Time time.Time RequestID string Method string Path string Error error Panic bool Stack string } ``` This value is for trusted diagnostics and may contain dependency detail. Never forward Error or Stack to an untrusted client. ## OperationError Canonical URL: https://riducms.com/reference/core/operation-error/ Kind: type Structured operation-boundary failure. ```go type OperationError = operationengine.Error ``` When CommitAttempted is true, retain and reconcile external resources instead of eagerly rolling them back. OperationError implements Error and Unwrap. ## AccessDecisionKind Canonical URL: https://riducms.com/reference/core/access-decision-kind/ Kind: type Allow, deny, or filtered access-decision discriminant. ```go type AccessDecisionKind string ``` ## ComputedContext Canonical URL: https://riducms.com/reference/core/computed-context/ Kind: type Runtime input for one virtual field resolver. ```go type ComputedContext struct { Context context.Context Operation Operation CollectionID schema.StableID GlobalID schema.StableID Actor *store.Document // ActorCollection identifies the exact auth collection that owns Actor. ActorCollection schema.CollectionSlug Document store.Document Local *LocalAPI Locale schema.LocaleCode AllLocales bool } ``` ## OperationCapabilities Canonical URL: https://riducms.com/reference/core/operation-capabilities/ Kind: type Non-secret permission summary for resource operations. ```go type OperationCapabilities struct { Admin bool Create bool Read bool ReadVersions bool Update bool Delete bool Duplicate bool Publish bool Unpublish bool RestoreDeleted bool DeletePermanent bool SelectAll bool Unlock bool } ``` The summary deliberately excludes executable rules and filtered-access predicates. Treat it as UI capability data, never as authorization. ## FieldCapabilities Canonical URL: https://riducms.com/reference/core/field-capabilities/ Kind: type Evaluated permissions for one authored field path. ```go type FieldCapabilities struct { Read bool Create bool Update bool } ``` ## JoinMutationResult Canonical URL: https://riducms.com/reference/core/join-mutation-result/ Kind: type Result of one atomic inverse-relationship mutation. ```go type JoinMutationResult struct { Document store.Document Added int Removed int } ``` ## PreviewBreakpoint Canonical URL: https://riducms.com/reference/core/preview-breakpoint/ Kind: type One named authoring viewport offered by live preview. ```go type PreviewBreakpoint struct { Name string Label string LabelTranslations map[string]string Width int Height int } ``` ## PluginHookContribution Canonical URL: https://riducms.com/reference/core/plugin-hook-contribution/ Kind: type Ordered collection or field hooks contributed by a plugin. ```go type PluginHookContribution struct { // Collection identifies the collection receiving Hooks. Collection schema.CollectionSlug // FieldPath optionally limits Hooks to one canonical field path. FieldPath string // Hooks are appended after application-authored hooks. Hooks CollectionHooks } ``` ## PluginFieldValidationContext Canonical URL: https://riducms.com/reference/core/plugin-field-validation-context/ Kind: type Resolved plugin field and candidate value supplied to validation. ```go type PluginFieldValidationContext struct { // Field is the resolved manifest definition owned by the plugin. Field schema.Field // RuntimePath identifies this concrete value occurrence. Unlike Field.Path, // it includes array and block indexes and omits block schema discriminators. RuntimePath string // Value is the candidate document value to validate. Value store.Value } ``` ## PluginFieldValidator Canonical URL: https://riducms.com/reference/core/plugin-field-validator/ Kind: type Return path-aware issues for one plugin-owned value. ```go type PluginFieldValidator func(PluginFieldValidationContext) []schema.Issue ``` ## Endpoint Canonical URL: https://riducms.com/reference/core/endpoint/ Kind: type One application-authored method and path handler mounted at root, collection, or global scope. ```go type Endpoint struct { // Method is one supported HTTP method. Matching is case-insensitive during // config resolution and the manifest stores its uppercase form. Method string // Path begins with / and may contain named :parameter segments. Path string // Summary appears in the generated OpenAPI operation. When empty, Ridu // supplies a deterministic generic summary. Summary string // MaxBodyBytes bounds the raw request body before Handler receives it. Zero // inherits HandlerOptions.MaxBodyBytes; a negative value opts trusted // streaming code out of that bound. MaxBodyBytes int64 // Handler is trusted compiled application code and is never serialized. Handler EndpointHandler } ``` Root endpoints mount below /api. Collection and global endpoints mount below their resource route and run before a matching built-in route for the same method. Custom endpoints are anonymous by default. Handler must enforce endpoint-specific authorization. ## EndpointContext Canonical URL: https://riducms.com/reference/core/endpoint-context/ Kind: type Raw HTTP, route parameters, verified actor identity, and LocalAPI supplied to a custom endpoint. ```go type EndpointContext struct { Writer http.ResponseWriter Request *http.Request // RequestID is the framework request ID also returned in X-Request-ID. RequestID string // ClientIP is resolved through the configured trusted-proxy policy. ClientIP string // RouteParams contains decoded named path parameters. RouteParams map[string]string // Collection identifies the owning collection endpoint, when applicable. Collection schema.CollectionSlug // Global identifies the owning global endpoint, when applicable. Global schema.CollectionSlug // Actor is the authenticated user, or nil for an anonymous request. Actor *store.Document // ActorCollection identifies the auth collection that owns Actor. ActorCollection schema.CollectionSlug // Local enters the same access-controlled operation engine as REST and the // generated SDK. Local *LocalAPI // AdmitAuthAttempt applies the distributed authentication-attempt policy for // endpoints implementing an authentication flow. AdmitAuthAttempt func(context.Context, string, string) error // ReportError records a stable code and sends trusted detail to // HandlerOptions.RequestError without exposing it to the client. ReportError func(error, string) } ``` ## EndpointHandler Canonical URL: https://riducms.com/reference/core/endpoint-handler/ Kind: type Trusted compiled custom endpoint handler. ```go type EndpointHandler func(EndpointContext) ``` ## PluginEndpoint Canonical URL: https://riducms.com/reference/core/plugin-endpoint/ Kind: type One exact method-specific namespaced plugin REST endpoint. ```go type PluginEndpoint struct { // Method is an exact supported HTTP method such as GET or POST. Method string // Path is relative to the plugin's namespaced API prefix. Path string // Summary appears in generated OpenAPI. Summary string // MaxBodyBytes bounds the raw request body before Handler receives it. Zero // inherits HandlerOptions.MaxBodyBytes; a negative value explicitly opts a // trusted streaming endpoint out of that byte bound. MaxBodyBytes int64 // Handler is trusted compiled endpoint code. Handler PluginEndpointHandler } ``` ## PluginEndpointContext Canonical URL: https://riducms.com/reference/core/plugin-endpoint-context/ Kind: type Authenticated HTTP and LocalAPI context for a plugin endpoint. ```go type PluginEndpointContext struct { // Writer receives the endpoint response. Writer http.ResponseWriter // Request is the original namespaced HTTP request. Request *http.Request // ClientIP is the direct or trusted-forwarded client address resolved by // the framework HTTP boundary. Authentication transports should use this // value instead of interpreting forwarding headers independently. ClientIP string // Actor is the authenticated user, or nil for an anonymous request. Actor *store.Document // ActorCollection identifies the auth collection that owns Actor. ActorCollection schema.CollectionSlug // Local enters the same access-controlled operation engine as other APIs. Local *LocalAPI // AdmitAuthAttempt applies the application's distributed IP and identity // admission policy. Authentication transports must call it before work that // can be amplified by aliases or repeated requests. AdmitAuthAttempt func(context.Context, string, string) error // ReportError records a stable transport error code and sends trusted error // detail to HandlerOptions.RequestError without exposing it to the client. // Plugins that implement their own error envelopes should call this for // internal failures. Passing nil records only Code in request observations. ReportError func(error, string) } ``` ## PluginEndpointHandler Canonical URL: https://riducms.com/reference/core/plugin-endpoint-handler/ Kind: type Trusted compiled namespaced endpoint handler. ```go type PluginEndpointHandler func(PluginEndpointContext) ``` ## PluginTransport Canonical URL: https://riducms.com/reference/core/plugin-transport/ Kind: type One exact application-level HTTP protocol route. ```go type PluginTransport struct { Method string Path string Summary string MaxBodyBytes int64 Handler PluginEndpointHandler } ``` Unlike PluginEndpoint, a transport is not placed below a plugin namespace. Use it for established protocol locations, not ordinary plugin REST endpoints. ## PluginTransportContext Canonical URL: https://riducms.com/reference/core/plugin-transport-context/ Kind: type Initialized application state supplied while a plugin binds transports. ```go type PluginTransportContext struct { Manifest schema.Manifest Local *LocalAPI // App exposes public authentication and other application-owned operations // that do not belong to LocalAPI. It is fully initialized before binding. App *App } ``` ## TaskBackoff Canonical URL: https://riducms.com/reference/core/task-backoff/ Kind: type Deterministic durable-task retry schedule. ```go type TaskBackoff = store.TaskBackoff ``` ## TaskHandler Canonical URL: https://riducms.com/reference/core/task-handler/ Kind: type Compiled typed durable-task handler. ```go type TaskHandler[Input, Output any] func(TaskContext, Input) (Output, error) ``` Handlers must honor cancellation and make external side effects idempotent because a process crash or lease expiry can cause another attempt. ## TaskReconciler Canonical URL: https://riducms.com/reference/core/task-reconciler/ Kind: type Bounded recovery scan for a durable task admission gap. ```go type TaskReconciler func(context.Context, *App) error ``` Reconcilers run before every selected task claim cycle, including startup, and must be bounded, idempotent, and safe across concurrent instances. ## TaskContext Canonical URL: https://riducms.com/reference/core/task-context/ Kind: type Request-scoped view of one leased durable-task attempt. ```go type TaskContext struct { Context context.Context ID string Attempt int Local *LocalAPI actor *store.Document } ``` Tasks do not receive a privileged content path. ## TaskOption Canonical URL: https://riducms.com/reference/core/task-option/ Kind: type Opaque policy applied by NewTask. ```go type TaskOption func(*taskConfig) ``` Application code cannot inspect or implement TaskOption because taskConfig is private. Use TaskQueue, TaskRetries, TaskTimeout, TaskRetention, and TaskAdmissionReconciler to construct values. ## TaskDefinition Canonical URL: https://riducms.com/reference/core/task-definition/ Kind: interface Non-generic compiled task boundary stored in Config.Tasks. ```go type TaskDefinition interface { TaskSlug() string taskRuntime() taskRuntime } ``` Only values returned by NewTask can implement this sealed interface, so serialized input can never select or supply executable code. ## TaskEnqueueOptions Canonical URL: https://riducms.com/reference/core/task-enqueue-options/ Kind: type Admission and scheduling controls for one durable task. ```go type TaskEnqueueOptions struct { RunAt time.Time Queue string ConcurrencyKey string Target *store.DocumentReference RequestedBy *store.DocumentReference } ``` ## TaskReceipt Canonical URL: https://riducms.com/reference/core/task-receipt/ Kind: type Stable typed handle returned after durable admission. ```go type TaskReceipt[Output any] struct { ID string Slug string Queue string RunAt time.Time } ``` ## TaskResult Canonical URL: https://riducms.com/reference/core/task-result/ Kind: type Typed local status view for one durable task. ```go type TaskResult[Output any] struct { ID string Slug string Queue string State store.TaskState Attempts int MaxAttempts int LastErrorCode string LastError string CreatedAt time.Time UpdatedAt time.Time CompletedAt *time.Time Output Output HasOutput bool } ``` ## TaskErrorCode Canonical URL: https://riducms.com/reference/core/task-error-code/ Kind: type Stable framework durable-task failure category. ```go type TaskErrorCode string ``` ## TaskError Canonical URL: https://riducms.com/reference/core/task-error/ Kind: type Stable local durable-task boundary error. ```go type TaskError struct { Code TaskErrorCode Message string Cause error } ``` TaskError implements Error and Unwrap for local runtime, store, and codec failures. Handler failures use RetryTask, RetryTaskAfter, or AbortTask; their bounded messages are persisted on durable task state instead. ## TaskRunSummary Canonical URL: https://riducms.com/reference/core/task-run-summary/ Kind: type Counters for one bounded worker claim cycle. ```go type TaskRunSummary struct { Claimed int Succeeded int Retried int Failed int Released int Pruned int } ``` Handler failures are persisted as retry or dead-letter state and do not become infrastructure errors. ## Config Canonical URL: https://riducms.com/reference/core/config/ Kind: type Executable application-owned Ridu configuration. ```go type Config struct { // Name is the author-facing application name shown by framework tooling. Name string // NameTranslations overrides Name for configured admin interface languages. NameTranslations map[string]string // Admin configures the framework-owned administration interface. Admin AdminConfig // Localization configures content locales. The zero value disables content // localization without affecting admin interface language. Localization LocalizationConfig // AllowIDOnCreate lets ordinary create operations accept a caller-supplied // canonical string ID. It is disabled by default; migration imports retain // their separate identity-preserving path regardless of this setting. AllowIDOnCreate bool // Collections declares every document collection owned by the application. Collections []Collection // Globals declares singleton documents with their own API and admin routes. Globals []Global // Endpoints declares application-level custom HTTP endpoints below /api. // Handlers are anonymous by default and must enforce their own policy. Endpoints []Endpoint // Tasks registers compiled durable task handlers. Executable handlers are // runtime-only and are intentionally excluded from the schema manifest. Tasks []TaskDefinition // Hooks observes application-wide lifecycle failures. Hooks RootHooks // Plugins lists compiled extensions in deterministic execution order. Plugins []Plugin // AfterCommit dispatches effects only after a successful transaction commits. AfterCommit AfterCommitDispatcher // Storage provides the application-wide object-storage adapter when App is // constructed directly with New. Applications run through Execute should // prefer WithUploadStorage so external clients are opened only at runtime. // Storage is never serialized into the schema manifest. Storage storage.Backend // StorageNamespace is the stable, deployment-owned prefix for upload objects. // It must remain unchanged when the display Name changes and must be unique // among applications sharing one backend. StorageNamespace string pluginEndpoints []runtimePluginEndpoint } ``` Resolve applies compiled plugin transforms to a defensive copy of the executable Go config before validation and manifest generation. ## LocalizationConfig Canonical URL: https://riducms.com/reference/core/localization-config/ Kind: type Application content-locale configuration. ```go type LocalizationConfig struct { Locales []Locale DefaultLocale schema.LocaleCode DisableFallback bool // AvailableLocales may reduce the locale list exposed to an admin request. // It does not weaken API validation or authorization and is never serialized. AvailableLocales LocaleAvailability } ``` Leave Locales empty to disable content localization. When localization is enabled, DefaultLocale must name one configured locale and every fallback must also be configured. FallbackLocales are checked in order after the requested locale unless DisableFallback is true. AvailableLocales only narrows the locale picker for the current admin request; it cannot add locales, change API validation, or grant access, and executable callbacks are never serialized into the schema manifest. ```go LocalizationConfig{ Locales: []Locale{ {Code: "en", Label: "English"}, { Code: "fr", Label: "Français", FallbackLocales: []schema.LocaleCode{"en"}, }, }, DefaultLocale: "en", } ``` ## LocaleAvailability Canonical URL: https://riducms.com/reference/core/locale-availability/ Kind: type Dynamically limit content locales shown to one author. ```go type LocaleAvailability func(LocaleAvailabilityContext) ([]schema.LocaleCode, error) ``` This callback runs for an admin request and controls only which already-configured locales the author can select. It is presentation, not authorization: API clients may still request any configured locale, and ordinary access rules remain authoritative. Return a non-empty list of unique configured codes in display order. Unknown or duplicate codes and an empty result fail the request with locale_availability_failed. Fallbacks outside the returned set are removed, and if the configured default is absent, the first returned locale becomes the request schema default. ```go AvailableLocales: func( input core.LocaleAvailabilityContext, ) ([]schema.LocaleCode, error) { if input.Actor == nil { return []schema.LocaleCode{"en"}, nil } return []schema.LocaleCode{"en", "fr"}, nil } ``` ## LocaleAvailabilityContext Canonical URL: https://riducms.com/reference/core/locale-availability-context/ Kind: type Request input for dynamic admin locale visibility. ```go type LocaleAvailabilityContext struct { Context context.Context Actor *store.Document ActorCollection schema.CollectionSlug Local *LocalAPI } ``` Use Actor and ActorCollection to make request-scoped presentation choices. Local enters the same access-controlled operation engine as other local API calls; the callback does not receive a privileged database handle. ## Locale Canonical URL: https://riducms.com/reference/core/locale/ Kind: type One content locale and its ordered fallback chain. ```go type Locale struct { Code schema.LocaleCode Label string RTL bool FallbackLocales []schema.LocaleCode } ``` Code is the stable wire and storage identity; changing it is a data migration. Label and RTL affect authoring presentation. Fallback chains must be acyclic and may name only configured locales. ## Collection Canonical URL: https://riducms.com/reference/core/collection/ Kind: type Executable authoring configuration for one document collection. ```go type Collection struct { // Slug is the URL-safe collection name used by APIs, relationships, and the admin. Slug schema.CollectionSlug // Labels override the singular and plural names shown to authors. Labels CollectionLabels // Admin configures collection presentation and editorial organization. Admin CollectionAdmin // Fields defines the collection's stored values and admin presentation. Fields []field.Definition // Indexes defines ordered multi-field indexes. Unique indexes enforce tuple // uniqueness while allowing multiple rows containing null. Indexes []CollectionIndex // Auth enables identities, passwords, and sessions for this collection. Auth bool // AuthConfig customizes behavior that applies when Auth is enabled. AuthConfig AuthConfig // Upload enables file metadata and storage behavior for this collection. Upload bool // UploadConfig customizes validation, privacy, and image variants for uploads. UploadConfig UploadConfig // Versions enables document revisions for this collection. Versions bool // Trash keeps deleted documents recoverable until they are permanently deleted. Trash bool // LockDocuments coordinates exclusive document editing with timeout and takeover. LockDocuments bool // DocumentLockConfig customizes lock expiry when LockDocuments is enabled. DocumentLockConfig DocumentLockConfig // VersionConfig customizes drafts, retention, and autosave behavior. VersionConfig VersionConfig // Access defines collection-level authorization for each operation. Access CollectionAccess // FieldAccess maps field paths to field-level read and write authorization. FieldAccess map[string]FieldAccess // FieldHooks maps field paths to lifecycle hooks scoped to those values. FieldHooks map[string]CollectionHooks // Hooks defines collection-wide lifecycle behavior. Hooks CollectionHooks // Computed resolves virtual field values after an operation has produced a document. Computed map[string]Computed // Endpoints declares custom HTTP endpoints below // /api/collections/. They run before matching built-in collection // routes for the same method. Endpoints []Endpoint } ``` ## CollectionAdmin Canonical URL: https://riducms.com/reference/core/collection-admin/ Kind: type Serializable collection presentation metadata. ```go type CollectionAdmin struct { UseAsTitle string DefaultColumns []string Group string GroupTranslations map[string]string Description string DescriptionTranslations map[string]string FolderField string ParentField string LivePreview LivePreviewConfig } ``` ## LivePreviewConfig Canonical URL: https://riducms.com/reference/core/live-preview-config/ Kind: type Serializable same- or cross-origin editor preview configuration. ```go type LivePreviewConfig struct { URL string Breakpoints []PreviewBreakpoint } ``` ## Global Canonical URL: https://riducms.com/reference/core/global/ Kind: type Executable authoring configuration for one singleton document. ```go type Global struct { // Slug is the URL-safe global name used by APIs and the admin. Slug schema.CollectionSlug // Label overrides the author-facing name shown in navigation and headings. Label string // LabelTranslations overrides Label for configured admin interface languages. LabelTranslations map[string]string // Admin is serializable presentation metadata consumed by the framework admin. Admin GlobalAdmin // Fields defines the global's stored values and admin presentation. Fields []field.Definition // Versions enables revisions for this global. Versions bool // VersionConfig customizes drafts, retention, and autosave behavior. VersionConfig VersionConfig // Access defines read and update authorization. Access GlobalAccess // FieldAccess maps field paths to field-level read and update authorization. FieldAccess map[string]FieldAccess // FieldHooks maps field paths to lifecycle hooks scoped to those values. FieldHooks map[string]CollectionHooks // Hooks defines global-wide lifecycle behavior. Hooks CollectionHooks // Computed resolves virtual field values after an operation has produced the singleton. Computed map[string]Computed // Endpoints declares custom HTTP endpoints below /api/globals/. // They run before matching built-in global routes for the same method. Endpoints []Endpoint } ``` ## AuthConfig Canonical URL: https://riducms.com/reference/core/auth-config/ Kind: type Session, credentials, recovery, and custom-strategy policy for an auth collection. ```go type AuthConfig struct { // SessionDuration is how long a login remains valid. Zero defaults to 24 hours. SessionDuration time.Duration // Password controls local password validation and hashing. Zero values use // the secure framework defaults documented on PasswordPolicy. Password PasswordPolicy // MaxLoginAttempts is the number of consecutive credential failures allowed // before the account is temporarily locked. Zero defaults to 5; a negative // value disables account lockout. MaxLoginAttempts int // LockDuration is how long an account remains locked after MaxLoginAttempts. // Zero defaults to 10 minutes. LockDuration time.Duration // PasswordReset enables the forgot/reset-password flow when Send is set. // The raw single-use token is delivered only to this trusted callback. PasswordReset PasswordResetConfig // Verify enables email verification. When non-nil, newly provisioned // credentials cannot log in until a verification token is consumed. Verify *VerifyEmailConfig // APIKeys allows users to mint revocable, session-independent bearer // credentials. API keys are disabled by default. APIKeys bool // Access contains authorization rules for auth operations that are not CRUD. Access AuthAccess // Hooks contains authentication lifecycle callbacks. Hooks AuthHooks // Strategies adds application-owned request authentication in declaration order. Strategies []AuthStrategy } ``` ## UploadConfig Canonical URL: https://riducms.com/reference/core/upload-config/ Kind: type Validation and object-storage behavior for an upload collection. ```go type UploadConfig struct { // MaxFileSize is the maximum accepted upload size in bytes. Zero uses the // framework default; values above 256 MiB are rejected so one request cannot // bypass the process-wide upload work budget. MaxFileSize int64 // MimeTypes restricts uploads to the listed media types. Empty accepts any supported type. MimeTypes []string // Private requires authorized delivery instead of exposing storage objects publicly. Private bool // ImageSizes declares derived image variants generated from supported image uploads. ImageSizes []ImageSize } ``` ## VersionConfig Canonical URL: https://riducms.com/reference/core/version-config/ Kind: type Revision and draft behavior for a versioned resource. ```go type VersionConfig struct { // Drafts allows unpublished document states. Drafts bool // MaxPerDocument limits retained revisions per document. Zero uses the framework default. MaxPerDocument int // AutosaveInterval controls draft autosave frequency. Zero disables autosave. AutosaveInterval time.Duration } ``` ## Computed Canonical URL: https://riducms.com/reference/core/computed/ Kind: type Resolve one validated virtual field value. ```go type Computed func(ComputedContext) (store.Value, error) ``` ## TypedGlobal Canonical URL: https://riducms.com/reference/core/typed-global/ Kind: type Generated typed definition for one global. ```go type TypedGlobal[Document, Update any] struct { slug string } ``` ## TypedTask Canonical URL: https://riducms.com/reference/core/typed-task/ Kind: type Compiled typed durable-task definition. ```go type TypedTask[Input, Output any] struct{ runtime taskRuntime } ``` Only NewTask constructs a valid definition. Add it to Config.Tasks before using its runtime methods. ## UpdateUploadImageInput Canonical URL: https://riducms.com/reference/core/update-upload-image-input/ Kind: type Focal point and optional crop for regenerating image variants. ```go type UpdateUploadImageInput struct { // FocalX is the horizontal focal coordinate from 0 (left) to 100 (right). FocalX float64 // FocalY is the vertical focal coordinate from 0 (top) to 100 (bottom). FocalY float64 // CropX and CropY are the top-left of an optional normalized crop rectangle. CropX float64 CropY float64 // CropWidth and CropHeight are zero to clear the crop, otherwise each must // be positive and the rectangle must remain within the original image. CropWidth float64 CropHeight float64 // ExpectedRevision rejects changes based on a stale document revision. ExpectedRevision int // Actor is the authenticated document used by read and update access rules. Actor *store.Document // ActorCollection identifies the exact auth collection that owns Actor. ActorCollection schema.CollectionSlug } ``` ## HandlerOptions Canonical URL: https://riducms.com/reference/core/handler-options/ Kind: type HTTP API, embedded admin, observability, security, and worker configuration. ```go type HandlerOptions struct { developmentReadiness bool allowUnverifiableReadiness bool // AdminAssets overrides the framework's embedded admin asset filesystem. AdminAssets fs.FS // MaxBodyBytes limits decoded request bodies. Zero uses the framework default. MaxBodyBytes int64 // SecureCookies restricts auth cookies to HTTPS requests. SecureCookies bool // AllowedOrigins lists browser origins permitted by CORS. AllowedOrigins []string // AllowedRequestHeaders appends application-owned CORS request headers to // Ridu's SDK headers. Invalid HTTP token names are ignored. AllowedRequestHeaders []string // AllowedHosts restricts the HTTP Host header. Entries are exact hostnames // with an optional port; an entry without a port accepts any port. Empty // accepts every syntactically valid host for development. Production // deployments should set their public hostnames. AllowedHosts []string // TrustedProxyCIDRs lists proxies whose forwarded client addresses are trusted. TrustedProxyCIDRs []string // AuthRateLimit is the maximum auth attempts per identity and client window. AuthRateLimit int // AuthRateWindow is the duration over which AuthRateLimit is enforced. AuthRateWindow time.Duration // Audit receives security-relevant application events. Audit func(AuditEvent) // Observe receives timing and status metadata for completed requests. Observe func(RequestObservation) // RequestError receives trusted diagnostic detail for internal failures and // recovered panics. The HTTP response remains redacted. RequestError func(RequestErrorEvent) // RequestTimeout limits request execution. Zero uses the framework default; // a negative duration disables the handler deadline for streaming plugins. RequestTimeout time.Duration // ReadinessChecks add application/plugin dependencies to /readyz. Checks // must be read-only, repeatable, and honor Context cancellation. ReadinessChecks []ReadinessCheck // ReadinessTimeout bounds the complete database, storage, and custom // readiness probe. Zero uses five seconds; a negative duration disables it. ReadinessTimeout time.Duration // ContentSecurityPolicy overrides the framework admin policy. Empty uses a // conservative default compatible with live-preview frames. ContentSecurityPolicy string // DisableContentSecurityPolicy explicitly disables the admin CSP when an // upstream gateway owns it. DisableContentSecurityPolicy bool // StrictTransportSecurity is emitted verbatim when non-empty. Configure it // only when every public request is HTTPS, normally at the TLS terminator. StrictTransportSecurity string // TaskInterval controls how often the durable task queues are polled. Zero // uses the framework default. TaskInterval time.Duration // TaskBatch limits durable task leases claimed during one polling cycle. TaskBatch int // TaskQueues optionally restricts this process to named queues. An empty // list consumes every queue, including unknown task slugs so they can be // moved to a stable terminal failure. TaskQueues []string // TaskLeaseDuration is extended by heartbeats while a handler is running. TaskLeaseDuration time.Duration // TaskHeartbeatInterval must remain shorter than TaskLeaseDuration. TaskHeartbeatInterval time.Duration // TaskPruneBatch bounds terminal records removed after their retention. TaskPruneBatch int // AuthPruneBatch bounds expired sessions and API keys removed from each // durable credential family during one background maintenance cycle. AuthPruneBatch int // JobError receives failures from scheduled background work. JobError func(error) } ``` Pass this value to App.Handler when embedding Ridu, or install it with WithHandlerOptions when Execute owns the server. ## ServerOptions Canonical URL: https://riducms.com/reference/core/server-options/ Kind: type Production socket bounds, readiness admission, and graceful drain. ```go type ServerOptions struct { ReadHeaderTimeout time.Duration ReadTimeout time.Duration WriteTimeout time.Duration IdleTimeout time.Duration MaxHeaderBytes int ShutdownTimeout time.Duration WorkerDrainTimeout time.Duration ReadinessDrainDelay time.Duration // AllowUnverifiableReadiness permits Execute with custom database or upload // adapters that cannot prove readiness. It is an explicit production safety // escape hatch; official adapters do not require it. AllowUnverifiableReadiness bool // SkipReadinessPreflight lets a development server bind before dependency // verification. Its /readyz probe still checks database connectivity, // storage, and custom checks, but permits an unapplied migration ledger // while ridu dev owns non-destructive schema synchronization. SkipReadinessPreflight bool } ``` Zero values use conservative defaults. Negative socket timeouts disable that individual bound; non-positive shutdown and worker-drain timeouts still use bounded defaults. ## StoreFactory Canonical URL: https://riducms.com/reference/core/store-factory/ Kind: type Lazy lifecycle-owned document-store constructor. ```go type StoreFactory func(context.Context) (store.Store, error) ``` Project commands resolve configuration without calling this factory. Execute closes the returned store during shutdown. ## StorageFactory Canonical URL: https://riducms.com/reference/core/storage-factory/ Kind: type Lazy lifecycle-owned upload-storage constructor. ```go type StorageFactory func(context.Context) (storage.Backend, error) ``` This is runtime infrastructure, not a plugin. Execute closes closable storage before the document store. ## ExecuteOption Canonical URL: https://riducms.com/reference/core/execute-option/ Kind: type Opaque production lifecycle option accepted by Execute. ```go type ExecuteOption func(*executeOptions) ``` Applications cannot implement this type because its input is private. Use WithStore, WithProjectMigrations, WithUploadStorage, WithAddress, WithHandlerOptions, and WithServerOptions; later duplicate options replace earlier values. ## Resolve Canonical URL: https://riducms.com/reference/core/resolve/ Kind: function Resolve executable config into the immutable canonical schema manifest. ```go func Resolve(applicationConfig Config) (schema.Manifest, error) ``` Resolve applies plugin config transforms in declaration order to a defensive copy. It does not open the document database or object storage. ## New Canonical URL: https://riducms.com/reference/core/new/ Kind: function Resolve an application and bind it to an already-open document store. ```go func New(applicationConfig Config, backend store.Store) (*App, error) ``` Use this when embedding Ridu into an existing Go process. Execute is the ordinary framework-owned server lifecycle. An application compiled by ridu build receives the exact ordered migration-history fingerprint. The caller owns the pre-traffic readiness barrier for an application-owned HTTP server. ## Allow Canonical URL: https://riducms.com/reference/core/allow/ Kind: function Authorize an operation without a document predicate. ```go func Allow() AccessDecision ``` ## Deny Canonical URL: https://riducms.com/reference/core/deny/ Kind: function Reject an operation. ```go func Deny() AccessDecision ``` ## Where Canonical URL: https://riducms.com/reference/core/where/ Kind: function Authorize only documents matching an atomic predicate. ```go func Where(expression query.Expression) AccessDecision ``` Where panics for a nil expression. Returning a predicate never authorizes a separate read-then-write check. ## WithUploadStorage Canonical URL: https://riducms.com/reference/core/with-upload-storage/ Kind: function Install optional lifecycle-owned upload storage. ```go func WithUploadStorage(factory StorageFactory) ExecuteOption ``` ## WithStore Canonical URL: https://riducms.com/reference/core/with-store/ Kind: function Install the required lifecycle-owned document store. ```go func WithStore(factory StoreFactory) ExecuteOption ``` ## WithProjectMigrations Canonical URL: https://riducms.com/reference/core/with-project-migrations/ Kind: function Register the selected adapter’s compiled project migration driver. ```go func WithProjectMigrations(driver migration.ProjectDriver) ExecuteOption ``` ## WithAddress Canonical URL: https://riducms.com/reference/core/with-address/ Kind: function Set the HTTP listen address. ```go func WithAddress(address string) ExecuteOption ``` ## WithHandlerOptions Canonical URL: https://riducms.com/reference/core/with-handler-options/ Kind: function Configure the framework HTTP handler and background workers. ```go func WithHandlerOptions(handler HandlerOptions) ExecuteOption ``` ## WithServerOptions Canonical URL: https://riducms.com/reference/core/with-server-options/ Kind: function Configure production socket and graceful-drain bounds. ```go func WithServerOptions(server ServerOptions) ExecuteOption ``` ## Execute Canonical URL: https://riducms.com/reference/core/execute/ Kind: function Run project commands or the framework-owned production server lifecycle. ```go func Execute(applicationConfig Config, supplied ...ExecuteOption) (result error) ``` When command-line arguments select a project command, Execute resolves config and returns without invoking store or storage factories. With no command it owns startup, readiness, serving, workers, drain, and resource close order. ## TaskQueue Canonical URL: https://riducms.com/reference/core/task-queue/ Kind: function Select a durable task definition’s default worker queue. ```go func TaskQueue(queue string) TaskOption ``` ## TaskRetries Canonical URL: https://riducms.com/reference/core/task-retries/ Kind: function Configure total attempts and deterministic retry delay. ```go func TaskRetries(maxAttempts int, delay, maxDelay time.Duration, backoff TaskBackoff) TaskOption ``` ## TaskTimeout Canonical URL: https://riducms.com/reference/core/task-timeout/ Kind: function Limit one cooperative durable-task attempt. ```go func TaskTimeout(timeout time.Duration) TaskOption ``` ## TaskRetention Canonical URL: https://riducms.com/reference/core/task-retention/ Kind: function Control how long terminal task status and output remain inspectable. ```go func TaskRetention(retention time.Duration) TaskOption ``` ## TaskAdmissionReconciler Canonical URL: https://riducms.com/reference/core/task-admission-reconciler/ Kind: function Register runtime-only recovery for a domain commit-to-enqueue gap. ```go func TaskAdmissionReconciler(reconcile TaskReconciler) TaskOption ``` Failures are surfaced with the worker cycle error while already queued tasks remain eligible to run. ## NewTask Canonical URL: https://riducms.com/reference/core/new-task/ Kind: function Define one compiled typed durable task. ```go func NewTask[Input, Output any](slug string, handler TaskHandler[Input, Output], options ...TaskOption) TypedTask[Input, Output] ``` ## RetryTask Canonical URL: https://riducms.com/reference/core/retry-task/ Kind: function Mark a handler failure retryable with configured backoff. ```go func RetryTask(code string, cause error) error ``` ## RetryTaskAfter Canonical URL: https://riducms.com/reference/core/retry-task-after/ Kind: function Mark a handler failure retryable after an explicit minimum delay. ```go func RetryTaskAfter(code string, cause error, delay time.Duration) error ``` ## AbortTask Canonical URL: https://riducms.com/reference/core/abort-task/ Kind: function Mark a handler failure terminal. ```go func AbortTask(code string, cause error) error ``` ## AccessAllow Canonical URL: https://riducms.com/reference/core/access-allow/ Kind: constant Public constant AccessAllow from github.com/riducms/ridu/core. ```go const AccessAllow AccessDecisionKind = "allow" ``` ## AccessDecision.Filter Canonical URL: https://riducms.com/reference/core/access-decision-filter-method/ Kind: method Filter returns a detached predicate for a filtered decision. ```go func (decision AccessDecision) Filter() (query.Node, bool) ``` ## AccessDecision.Kind Canonical URL: https://riducms.com/reference/core/access-decision-kind-method/ Kind: method Kind reports whether the decision allows, denies, or filters the operation. ```go func (decision AccessDecision) Kind() AccessDecisionKind ``` ## AccessDeny Canonical URL: https://riducms.com/reference/core/access-deny/ Kind: constant Public constant AccessDeny from github.com/riducms/ridu/core. ```go const AccessDeny AccessDecisionKind = "deny" ``` ## AccessWhere Canonical URL: https://riducms.com/reference/core/access-where/ Kind: constant Public constant AccessWhere from github.com/riducms/ridu/core. ```go const AccessWhere AccessDecisionKind = "where" ``` ## AuthOperationAPIKey Canonical URL: https://riducms.com/reference/core/auth-operation-api-key/ Kind: constant Public constant AuthOperationAPIKey from github.com/riducms/ridu/core. ```go const AuthOperationAPIKey AuthOperation = "api_key" ``` ## AuthOperationEmailVerification Canonical URL: https://riducms.com/reference/core/auth-operation-email-verification/ Kind: constant Public constant AuthOperationEmailVerification from github.com/riducms/ridu/core. ```go const AuthOperationEmailVerification AuthOperation = "email_verification" ``` ## AuthOperationExternalStrategy Canonical URL: https://riducms.com/reference/core/auth-operation-external-strategy/ Kind: constant Public constant AuthOperationExternalStrategy from github.com/riducms/ridu/core. ```go const AuthOperationExternalStrategy AuthOperation = "external_strategy" ``` ## AuthOperationForgotPassword Canonical URL: https://riducms.com/reference/core/auth-operation-forgot-password/ Kind: constant Public constant AuthOperationForgotPassword from github.com/riducms/ridu/core. ```go const AuthOperationForgotPassword AuthOperation = "forgot_password" ``` ## AuthOperationLogin Canonical URL: https://riducms.com/reference/core/auth-operation-login/ Kind: constant Public constant AuthOperationLogin from github.com/riducms/ridu/core. ```go const AuthOperationLogin AuthOperation = "login" ``` ## AuthOperationLogout Canonical URL: https://riducms.com/reference/core/auth-operation-logout/ Kind: constant Public constant AuthOperationLogout from github.com/riducms/ridu/core. ```go const AuthOperationLogout AuthOperation = "logout" ``` ## AuthOperationMe Canonical URL: https://riducms.com/reference/core/auth-operation-me/ Kind: constant Public constant AuthOperationMe from github.com/riducms/ridu/core. ```go const AuthOperationMe AuthOperation = "me" ``` ## AuthOperationPasswordReset Canonical URL: https://riducms.com/reference/core/auth-operation-password-reset/ Kind: constant Public constant AuthOperationPasswordReset from github.com/riducms/ridu/core. ```go const AuthOperationPasswordReset AuthOperation = "password_reset" ``` ## AuthOperationRefresh Canonical URL: https://riducms.com/reference/core/auth-operation-refresh/ Kind: constant Public constant AuthOperationRefresh from github.com/riducms/ridu/core. ```go const AuthOperationRefresh AuthOperation = "refresh" ``` ## BoundTypedCollection.Create Canonical URL: https://riducms.com/reference/core/bound-typed-collection-create-method/ Kind: method Public method BoundTypedCollection.Create from github.com/riducms/ridu/core. ```go func (collection BoundTypedCollection[Document, Create, Update]) Create(ctx context.Context, input Create, actor *store.Document) (Document, error) ``` ## BoundTypedCollection.Delete Canonical URL: https://riducms.com/reference/core/bound-typed-collection-delete-method/ Kind: method Public method BoundTypedCollection.Delete from github.com/riducms/ridu/core. ```go func (collection BoundTypedCollection[Document, Create, Update]) Delete(ctx context.Context, id string, actor *store.Document) (Document, error) ``` ## BoundTypedCollection.Find Canonical URL: https://riducms.com/reference/core/bound-typed-collection-find-method/ Kind: method Public method BoundTypedCollection.Find from github.com/riducms/ridu/core. ```go func (collection BoundTypedCollection[Document, Create, Update]) Find(ctx context.Context, id string, actor *store.Document) (Document, error) ``` ## BoundTypedCollection.Import Canonical URL: https://riducms.com/reference/core/bound-typed-collection-import-method/ Kind: method Public method BoundTypedCollection.Import from github.com/riducms/ridu/core. ```go func (collection BoundTypedCollection[Document, Create, Update]) Import(ctx context.Context, input Create, options ImportOptions, actor *store.Document) (Document, error) ``` ## BoundTypedCollection.List Canonical URL: https://riducms.com/reference/core/bound-typed-collection-list-method/ Kind: method Public method BoundTypedCollection.List from github.com/riducms/ridu/core. ```go func (collection BoundTypedCollection[Document, Create, Update]) List(ctx context.Context, options TypedListOptions) (TypedPage[Document], error) ``` ## BoundTypedCollection.Update Canonical URL: https://riducms.com/reference/core/bound-typed-collection-update-method/ Kind: method Public method BoundTypedCollection.Update from github.com/riducms/ridu/core. ```go func (collection BoundTypedCollection[Document, Create, Update]) Update(ctx context.Context, id string, input Update, actor *store.Document) (Document, error) ``` ## BoundTypedCollection.UpdateRevision Canonical URL: https://riducms.com/reference/core/bound-typed-collection-update-revision-method/ Kind: method Public method BoundTypedCollection.UpdateRevision from github.com/riducms/ridu/core. ```go func (collection BoundTypedCollection[Document, Create, Update]) UpdateRevision(ctx context.Context, id string, input Update, expectedRevision int, actor *store.Document) (Document, error) ``` ## BoundTypedGlobal.Find Canonical URL: https://riducms.com/reference/core/bound-typed-global-find-method/ Kind: method Public method BoundTypedGlobal.Find from github.com/riducms/ridu/core. ```go func (global BoundTypedGlobal[Document, Update]) Find(ctx context.Context, actor *store.Document) (Document, error) ``` ## BoundTypedGlobal.Publish Canonical URL: https://riducms.com/reference/core/bound-typed-global-publish-method/ Kind: method Public method BoundTypedGlobal.Publish from github.com/riducms/ridu/core. ```go func (global BoundTypedGlobal[Document, Update]) Publish(ctx context.Context, expectedRevision int, actor *store.Document) (Document, error) ``` ## BoundTypedGlobal.Restore Canonical URL: https://riducms.com/reference/core/bound-typed-global-restore-method/ Kind: method Public method BoundTypedGlobal.Restore from github.com/riducms/ridu/core. ```go func (global BoundTypedGlobal[Document, Update]) Restore(ctx context.Context, revision, expectedRevision int, actor *store.Document) (Document, error) ``` ## BoundTypedGlobal.RestoreAsDraft Canonical URL: https://riducms.com/reference/core/bound-typed-global-restore-as-draft-method/ Kind: method Public method BoundTypedGlobal.RestoreAsDraft from github.com/riducms/ridu/core. ```go func (global BoundTypedGlobal[Document, Update]) RestoreAsDraft(ctx context.Context, revision, expectedRevision int, actor *store.Document) (Document, error) ``` ## BoundTypedGlobal.Unpublish Canonical URL: https://riducms.com/reference/core/bound-typed-global-unpublish-method/ Kind: method Public method BoundTypedGlobal.Unpublish from github.com/riducms/ridu/core. ```go func (global BoundTypedGlobal[Document, Update]) Unpublish(ctx context.Context, expectedRevision int, actor *store.Document) (Document, error) ``` ## BoundTypedGlobal.Update Canonical URL: https://riducms.com/reference/core/bound-typed-global-update-method/ Kind: method Public method BoundTypedGlobal.Update from github.com/riducms/ridu/core. ```go func (global BoundTypedGlobal[Document, Update]) Update(ctx context.Context, input Update, expectedRevision int, actor *store.Document) (Document, error) ``` ## Input.MarshalJSON Canonical URL: https://riducms.com/reference/core/input-marshal-json-method/ Kind: method MarshalJSON implements json.Marshaler. Nil *Input fields are omitted by the generated parent struct's omitempty tag before this method is called. ```go func (input Input[T]) MarshalJSON() ([]byte, error) ``` ## NonNullInput.MarshalJSON Canonical URL: https://riducms.com/reference/core/non-null-input-marshal-json-method/ Kind: method MarshalJSON implements json.Marshaler and rejects an encoded JSON null. ```go func (input NonNullInput[T]) MarshalJSON() ([]byte, error) ``` ## OperationAdmin Canonical URL: https://riducms.com/reference/core/operation-admin/ Kind: constant Public constant OperationAdmin from github.com/riducms/ridu/core. ```go const OperationAdmin Operation = "admin" ``` ## OperationCreate Canonical URL: https://riducms.com/reference/core/operation-create/ Kind: constant Public constant OperationCreate from github.com/riducms/ridu/core. ```go const OperationCreate Operation = "create" ``` ## OperationDelete Canonical URL: https://riducms.com/reference/core/operation-delete/ Kind: constant Public constant OperationDelete from github.com/riducms/ridu/core. ```go const OperationDelete Operation = "delete" ``` ## OperationDeletePermanent Canonical URL: https://riducms.com/reference/core/operation-delete-permanent/ Kind: constant Public constant OperationDeletePermanent from github.com/riducms/ridu/core. ```go const OperationDeletePermanent Operation = "delete-permanent" ``` ## OperationDuplicate Canonical URL: https://riducms.com/reference/core/operation-duplicate/ Kind: constant Public constant OperationDuplicate from github.com/riducms/ridu/core. ```go const OperationDuplicate Operation = "duplicate" ``` ## OperationPublish Canonical URL: https://riducms.com/reference/core/operation-publish/ Kind: constant Public constant OperationPublish from github.com/riducms/ridu/core. ```go const OperationPublish Operation = "publish" ``` ## OperationRead Canonical URL: https://riducms.com/reference/core/operation-read/ Kind: constant Public constant OperationRead from github.com/riducms/ridu/core. ```go const OperationRead Operation = "read" ``` ## OperationReadVersions Canonical URL: https://riducms.com/reference/core/operation-read-versions/ Kind: constant Public constant OperationReadVersions from github.com/riducms/ridu/core. ```go const OperationReadVersions Operation = "read-versions" ``` ## OperationRestoreDeleted Canonical URL: https://riducms.com/reference/core/operation-restore-deleted/ Kind: constant Public constant OperationRestoreDeleted from github.com/riducms/ridu/core. ```go const OperationRestoreDeleted Operation = "restore-deleted" ``` ## OperationUnlock Canonical URL: https://riducms.com/reference/core/operation-unlock/ Kind: constant Public constant OperationUnlock from github.com/riducms/ridu/core. ```go const OperationUnlock Operation = "unlock" ``` ## OperationUnpublish Canonical URL: https://riducms.com/reference/core/operation-unpublish/ Kind: constant Public constant OperationUnpublish from github.com/riducms/ridu/core. ```go const OperationUnpublish Operation = "unpublish" ``` ## OperationUpdate Canonical URL: https://riducms.com/reference/core/operation-update/ Kind: constant Public constant OperationUpdate from github.com/riducms/ridu/core. ```go const OperationUpdate Operation = "update" ``` ## PluginDatabaseAdapterPostgres Canonical URL: https://riducms.com/reference/core/plugin-database-adapter-postgres/ Kind: constant PluginDatabaseAdapterPostgres selects PostgreSQL-specific SQL. ```go const PluginDatabaseAdapterPostgres = schema.PluginDatabaseAdapterPostgres ``` ## PluginDatabaseAdapterSQLite Canonical URL: https://riducms.com/reference/core/plugin-database-adapter-sq-lite/ Kind: constant PluginDatabaseAdapterSQLite selects SQLite-specific SQL. ```go const PluginDatabaseAdapterSQLite = schema.PluginDatabaseAdapterSQLite ``` ## TaskBackoffExponential Canonical URL: https://riducms.com/reference/core/task-backoff-exponential/ Kind: constant Public constant TaskBackoffExponential from github.com/riducms/ridu/core. ```go const TaskBackoffExponential = store.TaskBackoffExponential ``` ## TaskBackoffFixed Canonical URL: https://riducms.com/reference/core/task-backoff-fixed/ Kind: constant Public constant TaskBackoffFixed from github.com/riducms/ridu/core. ```go const TaskBackoffFixed = store.TaskBackoffFixed ``` ## TaskBackoffLinear Canonical URL: https://riducms.com/reference/core/task-backoff-linear/ Kind: constant Public constant TaskBackoffLinear from github.com/riducms/ridu/core. ```go const TaskBackoffLinear = store.TaskBackoffLinear ``` ## TaskError.Error Canonical URL: https://riducms.com/reference/core/task-error-error-method/ Kind: method Public method TaskError.Error from github.com/riducms/ridu/core. ```go func (err *TaskError) Error() string ``` ## TaskError.Unwrap Canonical URL: https://riducms.com/reference/core/task-error-unwrap-method/ Kind: method Public method TaskError.Unwrap from github.com/riducms/ridu/core. ```go func (err *TaskError) Unwrap() error ``` ## TaskErrorInvalidInput Canonical URL: https://riducms.com/reference/core/task-error-invalid-input/ Kind: constant Public constant TaskErrorInvalidInput from github.com/riducms/ridu/core. ```go const TaskErrorInvalidInput TaskErrorCode = "task_input_invalid" ``` ## TaskErrorInvalidOutput Canonical URL: https://riducms.com/reference/core/task-error-invalid-output/ Kind: constant Public constant TaskErrorInvalidOutput from github.com/riducms/ridu/core. ```go const TaskErrorInvalidOutput TaskErrorCode = "task_output_invalid" ``` ## TaskErrorLeaseLost Canonical URL: https://riducms.com/reference/core/task-error-lease-lost/ Kind: constant Public constant TaskErrorLeaseLost from github.com/riducms/ridu/core. ```go const TaskErrorLeaseLost TaskErrorCode = "task_lease_lost" ``` ## TaskErrorNotFound Canonical URL: https://riducms.com/reference/core/task-error-not-found/ Kind: constant Public constant TaskErrorNotFound from github.com/riducms/ridu/core. ```go const TaskErrorNotFound TaskErrorCode = "task_not_found" ``` ## TaskErrorNotRegistered Canonical URL: https://riducms.com/reference/core/task-error-not-registered/ Kind: constant Public constant TaskErrorNotRegistered from github.com/riducms/ridu/core. ```go const TaskErrorNotRegistered TaskErrorCode = "task_not_registered" ``` ## TaskErrorStoreFailed Canonical URL: https://riducms.com/reference/core/task-error-store-failed/ Kind: constant Public constant TaskErrorStoreFailed from github.com/riducms/ridu/core. ```go const TaskErrorStoreFailed TaskErrorCode = "task_store_failed" ``` ## TaskErrorUnavailable Canonical URL: https://riducms.com/reference/core/task-error-unavailable/ Kind: constant Public constant TaskErrorUnavailable from github.com/riducms/ridu/core. ```go const TaskErrorUnavailable TaskErrorCode = "task_unavailable" ``` ## TypedCollection.Slug Canonical URL: https://riducms.com/reference/core/typed-collection-slug-method/ Kind: method Slug returns the collection's public API address. ```go func (collection TypedCollection[Document, Create, Update]) Slug() string ``` ## TypedCollection.With Canonical URL: https://riducms.com/reference/core/typed-collection-with-method/ Kind: method With binds a generated collection definition to a running application. ```go func (collection TypedCollection[Document, Create, Update]) With(local *LocalAPI) BoundTypedCollection[Document, Create, Update] ``` ## TypedGlobal.Slug Canonical URL: https://riducms.com/reference/core/typed-global-slug-method/ Kind: method Slug returns the global's public API address. ```go func (global TypedGlobal[Document, Update]) Slug() string ``` ## TypedGlobal.With Canonical URL: https://riducms.com/reference/core/typed-global-with-method/ Kind: method With binds a generated global definition to a running application. ```go func (global TypedGlobal[Document, Update]) With(local *LocalAPI) BoundTypedGlobal[Document, Update] ``` ## TypedTask.Cancel Canonical URL: https://riducms.com/reference/core/typed-task-cancel-method/ Kind: method Cancel atomically prevents a queued task from starting and fences a running attempt so its later heartbeat/completion cannot win. ```go func (task TypedTask[Input, Output]) Cancel(ctx context.Context, application *App, id string) error ``` ## TypedTask.Enqueue Canonical URL: https://riducms.com/reference/core/typed-task-enqueue-method/ Kind: method Enqueue validates and durably stores typed input. The task must be the same slug/type contract registered in the running application's Config.Tasks. ```go func (task TypedTask[Input, Output]) Enqueue(ctx context.Context, application *App, input Input, options TaskEnqueueOptions) (TaskReceipt[Output], error) ``` ## TypedTask.Result Canonical URL: https://riducms.com/reference/core/typed-task-result-method/ Kind: method Result loads and decodes one task created by this typed definition. ```go func (task TypedTask[Input, Output]) Result(ctx context.Context, application *App, id string) (TaskResult[Output], error) ``` ## TypedTask.TaskSlug Canonical URL: https://riducms.com/reference/core/typed-task-task-slug-method/ Kind: method Public method TypedTask.TaskSlug from github.com/riducms/ridu/core. ```go func (task TypedTask[Input, Output]) TaskSlug() string ``` --- # API Reference: field Canonical URL: https://riducms.com/reference/field/ Package: github.com/riducms/ridu/field Type-safe field builders and presentation options. Incompatible options fail at Go compile time; semantic issues are reported by ridu.Resolve. ## Definition Canonical URL: https://riducms.com/reference/field/definition/ Kind: type An immutable authored field definition. ```go type Definition struct { name string kind Kind label string labelTranslations map[string]string required bool unique bool index bool localized bool minLength *int maxLength *int minimum *float64 maximum *float64 step *float64 defaultValue *DefaultValue slugSource string slugConfigured bool choices []Choice selectMany bool selectDefaults []string relationTo []string relationMany bool fields []Definition blocks []Block tabs []TabDefinition pluginKey string pluginConfig json.RawMessage pluginReferenceKeys []string adminPluginKey string adminComponent string adminComponentConfig json.RawMessage adminComponentConfigured bool description string descriptionTranslations map[string]string placeholder string placeholderTranslations map[string]string readOnly bool hidden bool sidebar bool columns int tab string tabTranslations map[string]string condition *Condition codeLanguage string datePickerAppearance DatePickerAppearance minRows int maxRows int rowLabel string rowLabelAdminPluginKey string rowLabelComponent string rowLabelComponentConfig json.RawMessage rowLabelComponentConfigured bool rowLabels RowLabels initiallyCollapsed bool joinCollection string joinOn string joinLimit int joinDefaultColumns []string joinDefaultSort string joinAllowCreate bool joinCreateConfigured bool valueType ValueType relationshipFilters []RelationshipFilterRule referenceDeleteAction ReferenceDeleteAction issues []Issue } ``` Definitions defensively copy nested fields, blocks, tabs, plugin JSON, and option slices. Construct them with package builders rather than struct literals. Read-only methods expose all builder input to config resolvers and plugins: labels, validation and index flags, defaults, choices, nested definitions, relationship metadata, presentation, scalar bounds, join metadata, plugin config, and reference keys. ## Kind Canonical URL: https://riducms.com/reference/field/kind/ Kind: type The built-in field discriminator. ```go type Kind string ``` ## Choice Canonical URL: https://riducms.com/reference/field/choice/ Kind: type One select or radio value and optional label. ```go type Choice struct { // Value is the exact string stored in documents and sent over APIs. Value string // Label is the author-facing name shown in selection controls. Label string // LabelTranslations overrides Label for configured admin interface languages. LabelTranslations map[string]string } ``` ## RowLabels Canonical URL: https://riducms.com/reference/field/row-labels/ Kind: type Singular and plural author-facing array-row labels with interface translations. ```go type RowLabels struct { Singular string Plural string SingularTranslations map[string]string PluralTranslations map[string]string } ``` ## Block Canonical URL: https://riducms.com/reference/field/block/ Kind: type One discriminated blocks layout. ```go type Block struct { // Key is the stable discriminator stored with block values. Key string // Label is the author-facing block type name. Label string // LabelTranslations overrides Label for configured admin interface languages. LabelTranslations map[string]string // Fields defines the values stored by this block type. Fields []Definition } ``` ## TabDefinition Canonical URL: https://riducms.com/reference/field/tab-definition/ Kind: type One named data-bearing or unnamed presentation-only tab. ```go type TabDefinition struct { // Name is the optional document property contributed by a data-bearing tab. Name string // Label is the author-facing tab trigger. Label string // LabelTranslations overrides Label for configured admin interface languages. LabelTranslations map[string]string // Fields defines the values shown inside the tab. Fields []Definition } ``` ## ValueType Canonical URL: https://riducms.com/reference/field/value-type/ Kind: type The output type promised by a virtual field. ```go type ValueType string ``` ## DatePickerAppearance Canonical URL: https://riducms.com/reference/field/date-picker-appearance/ Kind: type The date editor mode. ```go type DatePickerAppearance string ``` ## ReferenceDeleteAction Canonical URL: https://riducms.com/reference/field/reference-delete-action/ Kind: type How a current reference reacts when its target is permanently deleted. ```go type ReferenceDeleteAction string ``` Constants: ReferenceDeleteNullify and ReferenceDeleteRestrict. Required references resolve to restrict; retained versions are never rewritten. ## RelationshipFilterRule Canonical URL: https://riducms.com/reference/field/relationship-filter-rule/ Kind: type A server-enforced relationship picker predicate derived from the current document. ```go type RelationshipFilterRule struct { Collection string TargetPath string Operator RelationshipFilterOperator SourcePath string Literal *DefaultValue } ``` Collection scopes a rule to one polymorphic target. Operator uses the exact RelationshipFilterOperator constants. ## Category Canonical URL: https://riducms.com/reference/field/category/ Kind: type Whether a field is stored, presentation-only, computed, or plugin-owned. ```go type Category string ``` ## Issue Canonical URL: https://riducms.com/reference/field/issue/ Kind: type One stable field-builder issue found before config resolution. ```go type Issue struct { // Code is a stable machine-readable problem identifier. Code string // Path locates the invalid property within the field definition. Path string // Message explains how to correct the problem. Message string } ``` ## Condition Canonical URL: https://riducms.com/reference/field/condition/ Kind: type An immutable presentation-only logical or scalar condition. ```go type Condition struct { kind ConditionKind conditions []Condition scope ConditionScope path string operator ConditionOperator values []DefaultValue issues []Issue } ``` Condition visibility never grants access or removes hidden document values. ## ConditionKind Canonical URL: https://riducms.com/reference/field/condition-kind/ Kind: type The recursive condition-node discriminator. ```go type ConditionKind string ``` ## ConditionScope Canonical URL: https://riducms.com/reference/field/condition-scope/ Kind: type The root used to resolve a condition path. ```go type ConditionScope string ``` ## ConditionOperator Canonical URL: https://riducms.com/reference/field/condition-operator/ Kind: type The finite scalar condition vocabulary. ```go type ConditionOperator string ``` ## ConditionScalar Canonical URL: https://riducms.com/reference/field/condition-scalar/ Kind: interface The string, boolean, integer, or floating-point operands accepted by conditions. ```go type ConditionScalar interface { ~string | ~bool | ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64 } ``` ## DefaultValue Canonical URL: https://riducms.com/reference/field/default-value/ Kind: type The immutable typed scalar held by a Default option. ```go type DefaultValue struct { kind DefaultKind text string } ``` Kind distinguishes string, number, and boolean. String returns the canonical representation. ## DefaultKind Canonical URL: https://riducms.com/reference/field/default-kind/ Kind: type The typed default-value discriminant. ```go type DefaultKind string ``` ## RelationshipFilterOperator Canonical URL: https://riducms.com/reference/field/relationship-filter-operator/ Kind: type The finite operator vocabulary for relationship choices. ```go type RelationshipFilterOperator string ``` ## Option Canonical URL: https://riducms.com/reference/field/option/ Kind: interface The sealed base interface for field options. ```go type Option interface{ apply(*builder) } ``` Builders accept narrower exported interfaces—StringOption, NumberOption, CheckboxOption, JSONOption, SelectOption, RelationshipOption, UploadOption, GroupOption, ArrayOption, BlocksOption, JoinOption, and PluginOption—so unsupported combinations do not compile. CommonOption applies to every kind. LocalizedOption, UniqueOption, DefaultOption, RelationshipOrUploadOption, and NestedOption describe compatible subsets. Unexported methods intentionally prevent third-party implementations. ## StringOption Canonical URL: https://riducms.com/reference/field/string-option/ Kind: interface Options accepted by Text, Slug, Textarea, Email, Code, and Date. ```go type StringOption interface { Option stringOption() } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## NumberOption Canonical URL: https://riducms.com/reference/field/number-option/ Kind: interface Options accepted by Number. ```go type NumberOption interface { Option numberOption() } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## CheckboxOption Canonical URL: https://riducms.com/reference/field/checkbox-option/ Kind: interface Options accepted by Checkbox. ```go type CheckboxOption interface { Option checkboxOption() } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## JSONOption Canonical URL: https://riducms.com/reference/field/json-option/ Kind: interface Options accepted by JSON and Point. ```go type JSONOption interface { Option jsonOption() } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## SelectOption Canonical URL: https://riducms.com/reference/field/select-option/ Kind: interface Options accepted by Select and Radio. ```go type SelectOption interface { Option selectOption() } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## RelationshipOption Canonical URL: https://riducms.com/reference/field/relationship-option/ Kind: interface Options accepted by Relationship. ```go type RelationshipOption interface { Option relationshipOption() } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## UploadOption Canonical URL: https://riducms.com/reference/field/upload-option/ Kind: interface Options accepted by Upload. ```go type UploadOption interface { Option uploadOption() } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## GroupOption Canonical URL: https://riducms.com/reference/field/group-option/ Kind: interface Options accepted by Group. ```go type GroupOption interface { Option groupOption() } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## ArrayOption Canonical URL: https://riducms.com/reference/field/array-option/ Kind: interface Options accepted by Array. ```go type ArrayOption interface { Option arrayOption() } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## BlocksOption Canonical URL: https://riducms.com/reference/field/blocks-option/ Kind: interface Options accepted by Blocks. ```go type BlocksOption interface { Option blocksOption() } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## RowLabelComponentOption Canonical URL: https://riducms.com/reference/field/row-label-component-option/ Kind: interface Options accepted by Array and Blocks. ```go type RowLabelComponentOption interface { ArrayOption BlocksOption } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## JoinOption Canonical URL: https://riducms.com/reference/field/join-option/ Kind: interface Options accepted by Join. ```go type JoinOption interface { Option joinOption() } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## PluginOption Canonical URL: https://riducms.com/reference/field/plugin-option/ Kind: interface Options accepted by Plugin fields. ```go type PluginOption interface { Option pluginOption() } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## CommonOption Canonical URL: https://riducms.com/reference/field/common-option/ Kind: interface Options accepted by every built-in and plugin field. ```go type CommonOption interface { StringOption NumberOption CheckboxOption JSONOption SelectOption RelationshipOption UploadOption GroupOption ArrayOption BlocksOption JoinOption PluginOption } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## LocalizedOption Canonical URL: https://riducms.com/reference/field/localized-option/ Kind: interface Options accepted by stored field kinds. ```go type LocalizedOption interface { StringOption NumberOption CheckboxOption JSONOption SelectOption RelationshipOption UploadOption GroupOption ArrayOption BlocksOption PluginOption } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## UniqueOption Canonical URL: https://riducms.com/reference/field/unique-option/ Kind: interface Options accepted by indexable scalar and reference fields. ```go type UniqueOption interface { StringOption NumberOption CheckboxOption SelectOption RelationshipOption UploadOption } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## DefaultOption Canonical URL: https://riducms.com/reference/field/default-option/ Kind: interface Options accepted by scalar fields with defaults. ```go type DefaultOption interface { StringOption NumberOption CheckboxOption SelectOption } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## RelationshipOrUploadOption Canonical URL: https://riducms.com/reference/field/relationship-or-upload-option/ Kind: interface Options accepted by relationship and upload references. ```go type RelationshipOrUploadOption interface { RelationshipOption UploadOption } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## NestedOption Canonical URL: https://riducms.com/reference/field/nested-option/ Kind: interface Options accepted by Group and Array. ```go type NestedOption interface { GroupOption ArrayOption } ``` Only option values returned by this package implement the sealed marker. The narrow interface makes incompatible builder options a compile-time error. ## Text Canonical URL: https://riducms.com/reference/field/text/ Kind: function Define a single-line text field. ```go func Text(name string, options ...StringOption) Definition ``` ```go field.Text("title", field.Required(), field.MinLength(3), field.Index()) ``` ## Slug Canonical URL: https://riducms.com/reference/field/slug/ Kind: function Define a required, unique, indexed text slug derived from another string field. ```go func Slug(name, sourcePath string, options ...StringOption) Definition ``` The server normalizes create and update values, follows source changes while generated, and preserves manual overrides. Sources may traverse non-repeated groups but cannot be localized. ```go field.Slug("slug", "title", field.Label("URL slug")) ``` ## NormalizeSlug Canonical URL: https://riducms.com/reference/field/normalize-slug/ Kind: function Normalize a source or manual value with the deterministic server slug contract. ```go func NormalizeSlug(value string) string ``` ASCII letters are lowercased, digits and underscores retained, whitespace and hyphen runs collapsed, and other characters removed. ## Textarea Canonical URL: https://riducms.com/reference/field/textarea/ Kind: function Define multi-line plain text. ```go func Textarea(name string, options ...StringOption) Definition ``` ## Email Canonical URL: https://riducms.com/reference/field/email/ Kind: function Define a string validated as an email address. ```go func Email(name string, options ...StringOption) Definition ``` ## Code Canonical URL: https://riducms.com/reference/field/code/ Kind: function Define source-code text with an editor language hint. ```go func Code(name string, options ...StringOption) Definition ``` ## Date Canonical URL: https://riducms.com/reference/field/date/ Kind: function Define a normalized date, time, or timestamp string. ```go func Date(name string, options ...StringOption) Definition ``` ## Number Canonical URL: https://riducms.com/reference/field/number/ Kind: function Define a numeric field. ```go func Number(name string, options ...NumberOption) Definition ``` ```go field.Number("rating", field.Min(0), field.Max(5), field.Step(0.5)) ``` ## Checkbox Canonical URL: https://riducms.com/reference/field/checkbox/ Kind: function Define a boolean rendered as an on/off control. ```go func Checkbox(name string, options ...CheckboxOption) Definition ``` ## JSON Canonical URL: https://riducms.com/reference/field/json/ Kind: function Define arbitrary JSON-compatible stored data. ```go func JSON(name string, options ...JSONOption) Definition ``` ## Select Canonical URL: https://riducms.com/reference/field/select/ Kind: function Define a string constrained to configured choices. ```go func Select(name string, options ...SelectOption) Definition ``` ```go field.Select( "status", field.OneOf("draft", "published"), field.Default("draft"), ) ``` ## Radio Canonical URL: https://riducms.com/reference/field/radio/ Kind: function Define a choice-constrained string rendered as radios. ```go func Radio(name string, options ...SelectOption) Definition ``` ## Point Canonical URL: https://riducms.com/reference/field/point/ Kind: function Define a GeoJSON-style longitude/latitude tuple. ```go func Point(name string, options ...JSONOption) Definition ``` ## Relationship Canonical URL: https://riducms.com/reference/field/relationship/ Kind: function Define a singular, many, or polymorphic document reference. ```go func Relationship(name string, options ...RelationshipOption) Definition ``` Use To for one target, ToAny for polymorphism, and HasMany or ToMany for a list. ```go field.Relationship( "authors", field.To("users"), field.HasMany(), field.OnDelete(field.ReferenceDeleteRestrict), ) ``` ## Upload Canonical URL: https://riducms.com/reference/field/upload/ Kind: function Define a reference to an upload-enabled collection. ```go func Upload(name string, options ...UploadOption) Definition ``` This stores a document reference, not file bytes. ## Group Canonical URL: https://riducms.com/reference/field/group/ Kind: function Define a nested stored object. ```go func Group(name string, options ...GroupOption) Definition ``` ```go field.Group( "seo", field.Fields( field.Text("title"), field.Textarea("description"), ), ) ``` ## Array Canonical URL: https://riducms.com/reference/field/array/ Kind: function Define a repeatable list of nested objects. ```go func Array(name string, options ...ArrayOption) Definition ``` ```go field.Array( "links", field.MinRows(1), field.RowLabel("label"), field.Fields( field.Text("label"), field.Text("href"), ), ) ``` ## Blocks Canonical URL: https://riducms.com/reference/field/blocks/ Kind: function Define repeatable discriminated layouts. ```go func Blocks(name string, options ...BlocksOption) Definition ``` ## BlockType Canonical URL: https://riducms.com/reference/field/block-type/ Kind: function Construct one allowed block layout. ```go func BlockType(key, label string, fields ...Definition) Block ``` ## NamedTab Canonical URL: https://riducms.com/reference/field/named-tab/ Kind: function Define a tab stored beneath name. ```go func NamedTab(name, label string, fields ...Definition) TabDefinition ``` ## UnnamedTab Canonical URL: https://riducms.com/reference/field/unnamed-tab/ Kind: function Define a presentation-only tab. ```go func UnnamedTab(label string, fields ...Definition) TabDefinition ``` ## Tabs Canonical URL: https://riducms.com/reference/field/tabs/ Kind: function Group named and unnamed tabs. ```go func Tabs(tabs ...TabDefinition) Definition ``` ## Row Canonical URL: https://riducms.com/reference/field/row/ Kind: function Arrange fields in a presentation-only admin row. ```go func Row(fields ...Definition) Definition ``` Children retain their ordinary document paths. ## Collapsible Canonical URL: https://riducms.com/reference/field/collapsible/ Kind: function Group fields in a presentation-only disclosure. ```go func Collapsible(name string, initiallyCollapsed bool, fields ...Definition) Definition ``` ## UI Canonical URL: https://riducms.com/reference/field/ui/ Kind: function Declare presentation-only admin content. ```go func UI(name string, options ...CommonOption) Definition ``` Omitted from stored and generated document values. Rendering requires an admin/plugin implementation. ## Join Canonical URL: https://riducms.com/reference/field/join/ Kind: function Define a read-only inverse relationship. ```go func Join(name, collection, on string, options ...JoinOption) Definition ``` Default population limit: 10. Inline target creation defaults on. ## Virtual Canonical URL: https://riducms.com/reference/field/virtual/ Kind: function Declare a computed, non-stored output field. ```go func Virtual(name string, valueType ValueType, options ...CommonOption) Definition ``` Provide the resolver in Collection.Computed or Global.Computed. ## Plugin Canonical URL: https://riducms.com/reference/field/plugin/ Kind: function Declare a custom field owned by a compiled plugin. ```go func Plugin(name, pluginKey string, config json.RawMessage, options ...PluginOption) Definition ``` ## AdminComponent Canonical URL: https://riducms.com/reference/field/admin-component/ Kind: function Select an exact renderer from a statically paired admin plugin without changing built-in field semantics. ```go func AdminComponent(pluginKey, component string, config json.RawMessage) CommonOption ``` Config must be empty or a deterministic JSON object safe to expose in the public manifest. Resolution rejects invalid identities and owners without a paired admin package. ## Label Canonical URL: https://riducms.com/reference/field/label/ Kind: function Override the author-facing label. ```go func Label(label string) CommonOption ``` ## LabelTranslations Canonical URL: https://riducms.com/reference/field/label-translations/ Kind: function Add field labels for configured admin languages. ```go func LabelTranslations(translations map[string]string) CommonOption ``` ## Description Canonical URL: https://riducms.com/reference/field/description/ Kind: function Add authoring help text. ```go func Description(value string) CommonOption ``` ## DescriptionTranslations Canonical URL: https://riducms.com/reference/field/description-translations/ Kind: function Add translated authoring help text. ```go func DescriptionTranslations(translations map[string]string) CommonOption ``` ## Placeholder Canonical URL: https://riducms.com/reference/field/placeholder/ Kind: function Set the canonical empty-state prompt for compatible admin controls. ```go func Placeholder(value string) CommonOption ``` ## PlaceholderTranslations Canonical URL: https://riducms.com/reference/field/placeholder-translations/ Kind: function Add translated empty-state prompts for configured admin languages. ```go func PlaceholderTranslations(translations map[string]string) CommonOption ``` ## Required Canonical URL: https://riducms.com/reference/field/required/ Kind: function Reject missing, null, and type-specific empty values. ```go func Required() CommonOption ``` ## ReadOnly Canonical URL: https://riducms.com/reference/field/read-only/ Kind: function Prevent editing in the admin. ```go func ReadOnly() CommonOption ``` Presentation only; use ridu.FieldAccess for authorization. ## Hidden Canonical URL: https://riducms.com/reference/field/hidden/ Kind: function Omit a field from admin presentation without changing stored values. ```go func Hidden() CommonOption ``` Presentation only; use field access for authorization. ## Sidebar Canonical URL: https://riducms.com/reference/field/sidebar/ Kind: function Place a root field in the responsive document editor side rail. ```go func Sidebar() CommonOption ``` ## Columns Canonical URL: https://riducms.com/reference/field/columns/ Kind: function Assign one to twelve columns in an admin row. ```go func Columns(value int) CommonOption ``` ## Tab Canonical URL: https://riducms.com/reference/field/tab/ Kind: function Place a field in a named admin tab. ```go func Tab(label string) CommonOption ``` ## TabTranslations Canonical URL: https://riducms.com/reference/field/tab-translations/ Kind: function Add translations for the direct tab label. ```go func TabTranslations(translations map[string]string) CommonOption ``` ## ArrayRowLabels Canonical URL: https://riducms.com/reference/field/array-row-labels/ Kind: function Configure singular and plural names for repeating array rows. ```go func ArrayRowLabels(labels RowLabels) ArrayOption ``` ## All Canonical URL: https://riducms.com/reference/field/condition-all/ Kind: function Require every child condition to match. ```go func All(conditions ...Condition) Condition ``` ## Any Canonical URL: https://riducms.com/reference/field/condition-any/ Kind: function Require at least one child condition to match. ```go func Any(conditions ...Condition) Condition ``` ## Not Canonical URL: https://riducms.com/reference/field/condition-not/ Kind: function Negate one condition. ```go func Not(condition Condition) Condition ``` ## Document Canonical URL: https://riducms.com/reference/field/condition-document/ Kind: function Build a typed predicate whose path starts at the document root. ```go func Document[Value ConditionScalar](path string, operator ConditionOperator, values ...Value) Condition ``` ## Sibling Canonical URL: https://riducms.com/reference/field/condition-sibling/ Kind: function Build a typed predicate relative to the current object or repeating row. ```go func Sibling[Value ConditionScalar](path string, operator ConditionOperator, values ...Value) Condition ``` Attach the returned condition with ShowWhenCondition. Sibling scope starts beside the field being shown, not at the document root, and controls admin presentation only. ```go field.Text( "videoURL", field.ShowWhenCondition( field.Sibling("format", field.ConditionEquals, "video"), ), ) ``` ## ShowWhenCondition Canonical URL: https://riducms.com/reference/field/show-when-condition/ Kind: function Attach a typed recursive condition expression. ```go func ShowWhenCondition(condition Condition) CommonOption ``` Presentation only; never grants access or removes hidden values. ## ShowWhen Canonical URL: https://riducms.com/reference/field/show-when/ Kind: function Show a field when one sibling-scoped string value matches. ```go func ShowWhen(path, equals string) CommonOption ``` This is the concise equality form of ShowWhenCondition. At the root, sibling scope is the document root. ## Localized Canonical URL: https://riducms.com/reference/field/localized/ Kind: function Store one value per configured locale. ```go func Localized() LocalizedOption ``` Required and unique constraints are per locale. ## Unique Canonical URL: https://riducms.com/reference/field/unique/ Kind: function Require supported scalar or reference values to be distinct. ```go func Unique() UniqueOption ``` ## Index Canonical URL: https://riducms.com/reference/field/index/ Kind: function Request a non-unique database index. ```go func Index() UniqueOption ``` Unique already implies an index. ## Default Canonical URL: https://riducms.com/reference/field/default/ Kind: function Set a typed string, number, or boolean default. ```go func Default[Value ~string | ~bool | ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64](value Value) DefaultOption ``` ## MinLength Canonical URL: https://riducms.com/reference/field/min-length/ Kind: function Set an inclusive Unicode code-point minimum. ```go func MinLength(value int) StringOption ``` ## MaxLength Canonical URL: https://riducms.com/reference/field/max-length/ Kind: function Set an inclusive Unicode code-point maximum. ```go func MaxLength(value int) StringOption ``` ## Min Canonical URL: https://riducms.com/reference/field/min/ Kind: function Set an inclusive numeric minimum. ```go func Min(value float64) NumberOption ``` ## Max Canonical URL: https://riducms.com/reference/field/max/ Kind: function Set an inclusive numeric maximum. ```go func Max(value float64) NumberOption ``` ## Step Canonical URL: https://riducms.com/reference/field/step/ Kind: function Set the positive number-input increment. ```go func Step(value float64) NumberOption ``` Editor metadata; not server-side divisibility validation. ## Choices Canonical URL: https://riducms.com/reference/field/choices/ Kind: function Supply explicit value/label choices. ```go func Choices(choices ...Choice) SelectOption ``` ## OneOf Canonical URL: https://riducms.com/reference/field/one-of/ Kind: function Build concise choices from values. ```go func OneOf(values ...string) SelectOption ``` ## Multiple Canonical URL: https://riducms.com/reference/field/multiple/ Kind: function Change a select from one choice to an ordered list of choices. ```go func Multiple() SelectOption ``` ## DefaultChoices Canonical URL: https://riducms.com/reference/field/default-choices/ Kind: function Set the detached ordered default for a multi-select. ```go func DefaultChoices(values ...string) SelectOption ``` ## Language Canonical URL: https://riducms.com/reference/field/language/ Kind: function Set a code editor syntax hint. ```go func Language(value string) StringOption ``` ## PickerAppearance Canonical URL: https://riducms.com/reference/field/picker-appearance/ Kind: function Choose the date editor shape. ```go func PickerAppearance(value DatePickerAppearance) StringOption ``` ## To Canonical URL: https://riducms.com/reference/field/to/ Kind: function Set one target collection. ```go func To(collectionSlug string) RelationshipOrUploadOption ``` ## ToAny Canonical URL: https://riducms.com/reference/field/to-any/ Kind: function Allow any listed relationship target. ```go func ToAny(collectionSlugs ...string) RelationshipOption ``` ## HasMany Canonical URL: https://riducms.com/reference/field/has-many/ Kind: function Change a reference into a list. ```go func HasMany() RelationshipOrUploadOption ``` ## ToMany Canonical URL: https://riducms.com/reference/field/to-many/ Kind: function Set one target and list cardinality. ```go func ToMany(collectionSlug string) RelationshipOrUploadOption ``` ## OnDelete Canonical URL: https://riducms.com/reference/field/on-delete/ Kind: function Choose nullify or restrict on permanent target deletion. ```go func OnDelete(action ReferenceDeleteAction) RelationshipOrUploadOption ``` ## OptionFilter Canonical URL: https://riducms.com/reference/field/option-filter/ Kind: function Construct a relationship-choice predicate. ```go func OptionFilter(targetPath string, operator RelationshipFilterOperator, sourcePath string) RelationshipFilterRule ``` ## OptionFilterFor Canonical URL: https://riducms.com/reference/field/option-filter-for/ Kind: function Scope a predicate to a polymorphic target. ```go func OptionFilterFor(collection, targetPath string, operator RelationshipFilterOperator, sourcePath string) RelationshipFilterRule ``` ## OptionFilterValue Canonical URL: https://riducms.com/reference/field/option-filter-value/ Kind: function Construct a relationship-choice predicate from a typed literal value. ```go func OptionFilterValue[Value ~string | ~bool | ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64](targetPath string, operator RelationshipFilterOperator, value Value) RelationshipFilterRule ``` ## OptionFilterValueFor Canonical URL: https://riducms.com/reference/field/option-filter-value-for/ Kind: function Construct a target-scoped relationship-choice predicate from a typed literal value. ```go func OptionFilterValueFor[Value ~string | ~bool | ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64](collection, targetPath string, operator RelationshipFilterOperator, value Value) RelationshipFilterRule ``` ## FilterOptionRules Canonical URL: https://riducms.com/reference/field/filter-option-rules/ Kind: function Attach combinable relationship-choice predicates. ```go func FilterOptionRules(rules ...RelationshipFilterRule) RelationshipOrUploadOption ``` ## Fields Canonical URL: https://riducms.com/reference/field/fields/ Kind: function Set group or array children. ```go func Fields(fields ...Definition) NestedOption ``` ## MinRows Canonical URL: https://riducms.com/reference/field/min-rows/ Kind: function Set the minimum array length. ```go func MinRows(value int) ArrayOption ``` ## MaxRows Canonical URL: https://riducms.com/reference/field/max-rows/ Kind: function Set the maximum array length. ```go func MaxRows(value int) ArrayOption ``` ## RowLabel Canonical URL: https://riducms.com/reference/field/row-label/ Kind: function Select a child path for array headings. ```go func RowLabel(path string) ArrayOption ``` ## RowLabelComponent Canonical URL: https://riducms.com/reference/field/row-label-component/ Kind: function Select an exact paired-plugin Svelte component for array or blocks row headings. ```go func RowLabelComponent(pluginKey, component string, config json.RawMessage) RowLabelComponentOption ``` Config must be an empty value or a JSON object. It is defensively copied into the definition and manifest. This is presentation only. It does not change validation, storage, access, or operation behavior. ## BlockTypes Canonical URL: https://riducms.com/reference/field/block-types/ Kind: function Set allowed blocks layouts. ```go func BlockTypes(blocks ...Block) BlocksOption ``` ## JoinLimit Canonical URL: https://riducms.com/reference/field/join-limit/ Kind: function Bound inverse-join rows from 1 to 100. ```go func JoinLimit(value int) JoinOption ``` ## JoinColumns Canonical URL: https://riducms.com/reference/field/join-columns/ Kind: function Choose inverse-join table fields. ```go func JoinColumns(paths ...string) JoinOption ``` ## JoinDefaultSort Canonical URL: https://riducms.com/reference/field/join-default-sort/ Kind: function Set initial join ordering. ```go func JoinDefaultSort(value string) JoinOption ``` Prefix the path with - for descending. ## JoinAllowCreate Canonical URL: https://riducms.com/reference/field/join-allow-create/ Kind: function Control inline target creation. ```go func JoinAllowCreate(value bool) JoinOption ``` ## CollectionReferenceKeys Canonical URL: https://riducms.com/reference/field/collection-reference-keys/ Kind: function Declare plugin JSON keys containing collection slugs. ```go func CollectionReferenceKeys(keys ...string) PluginOption ``` Used for safe renames across current data and version history; arbitrary plugin JSON is never guessed. ## Block.WithLabelTranslations Canonical URL: https://riducms.com/reference/field/block-with-label-translations-method/ Kind: method WithLabelTranslations returns a detached block type with localized display labels. ```go func (block Block) WithLabelTranslations(translations map[string]string) Block ``` ## CategoryNested Canonical URL: https://riducms.com/reference/field/category-nested/ Kind: constant Public constant CategoryNested from github.com/riducms/ridu/field. ```go const CategoryNested Category = "nested" ``` ## CategoryPlugin Canonical URL: https://riducms.com/reference/field/category-plugin/ Kind: constant Public constant CategoryPlugin from github.com/riducms/ridu/field. ```go const CategoryPlugin Category = "plugin" ``` ## CategoryPresentation Canonical URL: https://riducms.com/reference/field/category-presentation/ Kind: constant Public constant CategoryPresentation from github.com/riducms/ridu/field. ```go const CategoryPresentation Category = "presentation" ``` ## CategoryRelationship Canonical URL: https://riducms.com/reference/field/category-relationship/ Kind: constant Public constant CategoryRelationship from github.com/riducms/ridu/field. ```go const CategoryRelationship Category = "relationship" ``` ## CategoryScalar Canonical URL: https://riducms.com/reference/field/category-scalar/ Kind: constant Public constant CategoryScalar from github.com/riducms/ridu/field. ```go const CategoryScalar Category = "scalar" ``` ## CategoryUpload Canonical URL: https://riducms.com/reference/field/category-upload/ Kind: constant Public constant CategoryUpload from github.com/riducms/ridu/field. ```go const CategoryUpload Category = "upload" ``` ## Choice.WithLabelTranslations Canonical URL: https://riducms.com/reference/field/choice-with-label-translations-method/ Kind: method WithLabelTranslations returns a detached choice with localized display labels. ```go func (choice Choice) WithLabelTranslations(translations map[string]string) Choice ``` ## Condition.Conditions Canonical URL: https://riducms.com/reference/field/condition-conditions-method/ Kind: method Conditions returns detached child expressions for All, Any, and Not nodes. ```go func (condition Condition) Conditions() []Condition ``` ## Condition.Kind Canonical URL: https://riducms.com/reference/field/condition-kind-method/ Kind: method Kind reports whether this node is a logical group, negation, or predicate. ```go func (condition Condition) Kind() ConditionKind ``` ## Condition.Operator Canonical URL: https://riducms.com/reference/field/condition-operator-method/ Kind: method Operator returns the predicate's scalar comparison operator. ```go func (condition Condition) Operator() ConditionOperator ``` ## Condition.Path Canonical URL: https://riducms.com/reference/field/condition-path-method/ Kind: method Path returns the predicate path relative to its configured scope. ```go func (condition Condition) Path() string ``` ## Condition.Scope Canonical URL: https://riducms.com/reference/field/condition-scope-method/ Kind: method Scope reports which value tree a predicate reads. ```go func (condition Condition) Scope() ConditionScope ``` ## Condition.Values Canonical URL: https://riducms.com/reference/field/condition-values-method/ Kind: method Values returns detached, canonically encoded predicate operands. ```go func (condition Condition) Values() []DefaultValue ``` ## ConditionEquals Canonical URL: https://riducms.com/reference/field/condition-equals/ Kind: constant Public constant ConditionEquals from github.com/riducms/ridu/field. ```go const ConditionEquals ConditionOperator = "equals" ``` ## ConditionKindAll Canonical URL: https://riducms.com/reference/field/condition-kind-all/ Kind: constant Public constant ConditionKindAll from github.com/riducms/ridu/field. ```go const ConditionKindAll ConditionKind = "all" ``` ## ConditionKindAny Canonical URL: https://riducms.com/reference/field/condition-kind-any/ Kind: constant Public constant ConditionKindAny from github.com/riducms/ridu/field. ```go const ConditionKindAny ConditionKind = "any" ``` ## ConditionKindNot Canonical URL: https://riducms.com/reference/field/condition-kind-not/ Kind: constant Public constant ConditionKindNot from github.com/riducms/ridu/field. ```go const ConditionKindNot ConditionKind = "not" ``` ## ConditionKindPredicate Canonical URL: https://riducms.com/reference/field/condition-kind-predicate/ Kind: constant Public constant ConditionKindPredicate from github.com/riducms/ridu/field. ```go const ConditionKindPredicate ConditionKind = "predicate" ``` ## ConditionNotEquals Canonical URL: https://riducms.com/reference/field/condition-not-equals/ Kind: constant Public constant ConditionNotEquals from github.com/riducms/ridu/field. ```go const ConditionNotEquals ConditionOperator = "notEquals" ``` ## ConditionOneOf Canonical URL: https://riducms.com/reference/field/condition-one-of/ Kind: constant Public constant ConditionOneOf from github.com/riducms/ridu/field. ```go const ConditionOneOf ConditionOperator = "oneOf" ``` ## ConditionScopeDocument Canonical URL: https://riducms.com/reference/field/condition-scope-document/ Kind: constant ConditionScopeDocument resolves paths from the document root. ```go const ConditionScopeDocument ConditionScope = "document" ``` ## ConditionScopeSibling Canonical URL: https://riducms.com/reference/field/condition-scope-sibling/ Kind: constant ConditionScopeSibling resolves paths from the current field's parent object or row. ```go const ConditionScopeSibling ConditionScope = "sibling" ``` ## DatePickerDayAndTime Canonical URL: https://riducms.com/reference/field/date-picker-day-and-time/ Kind: constant Public constant DatePickerDayAndTime from github.com/riducms/ridu/field. ```go const DatePickerDayAndTime DatePickerAppearance = "dayAndTime" ``` ## DatePickerDayOnly Canonical URL: https://riducms.com/reference/field/date-picker-day-only/ Kind: constant Public constant DatePickerDayOnly from github.com/riducms/ridu/field. ```go const DatePickerDayOnly DatePickerAppearance = "dayOnly" ``` ## DatePickerTimeOnly Canonical URL: https://riducms.com/reference/field/date-picker-time-only/ Kind: constant Public constant DatePickerTimeOnly from github.com/riducms/ridu/field. ```go const DatePickerTimeOnly DatePickerAppearance = "timeOnly" ``` ## DefaultBoolean Canonical URL: https://riducms.com/reference/field/default-boolean/ Kind: constant Public constant DefaultBoolean from github.com/riducms/ridu/field. ```go const DefaultBoolean DefaultKind = "boolean" ``` ## DefaultNumber Canonical URL: https://riducms.com/reference/field/default-number/ Kind: constant Public constant DefaultNumber from github.com/riducms/ridu/field. ```go const DefaultNumber DefaultKind = "number" ``` ## DefaultString Canonical URL: https://riducms.com/reference/field/default-string/ Kind: constant Public constant DefaultString from github.com/riducms/ridu/field. ```go const DefaultString DefaultKind = "string" ``` ## DefaultValue.Kind Canonical URL: https://riducms.com/reference/field/default-value-kind-method/ Kind: method Kind reports whether the normalized default is a string, number, or boolean. ```go func (value DefaultValue) Kind() DefaultKind ``` ## DefaultValue.String Canonical URL: https://riducms.com/reference/field/default-value-string-method/ Kind: method String returns the canonical textual encoding written to the manifest. ```go func (value DefaultValue) String() string ``` ## Definition.AdminComponent Canonical URL: https://riducms.com/reference/field/definition-admin-component-method/ Kind: method AdminComponent returns the optional statically registered admin plugin renderer selected for this field. The returned configuration is detached from the immutable definition. ```go func (d Definition) AdminComponent() (pluginKey, component string, config json.RawMessage, ok bool) ``` ## Definition.Blocks Canonical URL: https://riducms.com/reference/field/definition-blocks-method/ Kind: method Blocks returns a deep copy of the allowed block types. ```go func (d Definition) Blocks() []Block ``` ## Definition.Category Canonical URL: https://riducms.com/reference/field/definition-category-method/ Kind: method Category returns the behavioral category for the definition's field kind. ```go func (d Definition) Category() Category ``` ## Definition.Choices Canonical URL: https://riducms.com/reference/field/definition-choices-method/ Kind: method Choices returns a copy of the select choices. ```go func (d Definition) Choices() []Choice ``` ## Definition.CodeLanguage Canonical URL: https://riducms.com/reference/field/definition-code-language-method/ Kind: method CodeLanguage is the editor language hint for a code field. ```go func (d Definition) CodeLanguage() string ``` ## Definition.Columns Canonical URL: https://riducms.com/reference/field/definition-columns-method/ Kind: method Columns returns the requested one-to-twelve-column admin grid width, or zero. ```go func (d Definition) Columns() int ``` ## Definition.Condition Canonical URL: https://riducms.com/reference/field/definition-condition-method/ Kind: method Condition returns a copy of the configured presentation condition, if any. ```go func (d Definition) Condition() *Condition ``` ## Definition.DatePickerAppearance Canonical URL: https://riducms.com/reference/field/definition-date-picker-appearance-method/ Kind: method DatePickerAppearance returns the configured date control, defaulting to day-only. ```go func (d Definition) DatePickerAppearance() DatePickerAppearance ``` ## Definition.Default Canonical URL: https://riducms.com/reference/field/definition-default-method/ Kind: method Default returns the configured typed scalar default. ```go func (d Definition) Default() (DefaultValue, bool) ``` ## Definition.Description Canonical URL: https://riducms.com/reference/field/definition-description-method/ Kind: method Description returns the configured author-facing supporting text. ```go func (d Definition) Description() string ``` ## Definition.DescriptionTranslations Canonical URL: https://riducms.com/reference/field/definition-description-translations-method/ Kind: method DescriptionTranslations returns localized supporting text by admin language. ```go func (d Definition) DescriptionTranslations() map[string]string ``` ## Definition.Fields Canonical URL: https://riducms.com/reference/field/definition-fields-method/ Kind: method Fields returns a deep copy of the nested child definitions. ```go func (d Definition) Fields() []Definition ``` ## Definition.Hidden Canonical URL: https://riducms.com/reference/field/definition-hidden-method/ Kind: method Hidden reports whether the admin should omit this field from presentation. ```go func (d Definition) Hidden() bool ``` ## Definition.Index Canonical URL: https://riducms.com/reference/field/definition-index-method/ Kind: method Index reports whether the field should have a non-unique database index. Unique fields already receive a unique index even when this is false. ```go func (d Definition) Index() bool ``` ## Definition.InitiallyCollapsed Canonical URL: https://riducms.com/reference/field/definition-initially-collapsed-method/ Kind: method InitiallyCollapsed reports whether a collapsible presentation group starts closed. ```go func (d Definition) InitiallyCollapsed() bool ``` ## Definition.Issues Canonical URL: https://riducms.com/reference/field/definition-issues-method/ Kind: method Issues returns a copy of constructor and option compatibility issues. ```go func (d Definition) Issues() []Issue ``` ## Definition.JoinAllowCreate Canonical URL: https://riducms.com/reference/field/definition-join-allow-create-method/ Kind: method JoinAllowCreate reports whether the admin may offer inline target creation. ```go func (d Definition) JoinAllowCreate() bool ``` ## Definition.JoinCollection Canonical URL: https://riducms.com/reference/field/definition-join-collection-method/ Kind: method JoinCollection is the collection queried by an inverse join. ```go func (d Definition) JoinCollection() string ``` ## Definition.JoinDefaultColumns Canonical URL: https://riducms.com/reference/field/definition-join-default-columns-method/ Kind: method JoinDefaultColumns returns the target fields shown by the inverse-join table. ```go func (d Definition) JoinDefaultColumns() []string ``` ## Definition.JoinDefaultSort Canonical URL: https://riducms.com/reference/field/definition-join-default-sort-method/ Kind: method JoinDefaultSort returns the target sort expression, including an optional descending prefix. ```go func (d Definition) JoinDefaultSort() string ``` ## Definition.JoinLimit Canonical URL: https://riducms.com/reference/field/definition-join-limit-method/ Kind: method JoinLimit is the maximum related documents returned for an inverse join. ```go func (d Definition) JoinLimit() int ``` ## Definition.JoinOn Canonical URL: https://riducms.com/reference/field/definition-join-on-method/ Kind: method JoinOn is the target relationship path matched against the source document ID. ```go func (d Definition) JoinOn() string ``` ## Definition.Kind Canonical URL: https://riducms.com/reference/field/definition-kind-method/ Kind: method Kind returns the concrete authoring field kind. ```go func (d Definition) Kind() Kind ``` ## Definition.Label Canonical URL: https://riducms.com/reference/field/definition-label-method/ Kind: method Label returns the explicit author-facing label, if one was configured. ```go func (d Definition) Label() string ``` ## Definition.LabelTranslations Canonical URL: https://riducms.com/reference/field/definition-label-translations-method/ Kind: method LabelTranslations returns localized author-facing labels by admin language. ```go func (d Definition) LabelTranslations() map[string]string ``` ## Definition.Localized Canonical URL: https://riducms.com/reference/field/definition-localized-method/ Kind: method Localized reports whether the field stores an independent value for each configured application locale. ```go func (d Definition) Localized() bool ``` ## Definition.Max Canonical URL: https://riducms.com/reference/field/definition-max-method/ Kind: method Max returns the inclusive maximum accepted by a number field. ```go func (d Definition) Max() (float64, bool) ``` ## Definition.MaxLength Canonical URL: https://riducms.com/reference/field/definition-max-length-method/ Kind: method MaxLength returns the maximum accepted Unicode code-point length. ```go func (d Definition) MaxLength() (int, bool) ``` ## Definition.MaxRows Canonical URL: https://riducms.com/reference/field/definition-max-rows-method/ Kind: method MaxRows is the maximum accepted length for an array, or zero when unbounded. ```go func (d Definition) MaxRows() int ``` ## Definition.Min Canonical URL: https://riducms.com/reference/field/definition-min-method/ Kind: method Min returns the inclusive minimum accepted by a number field. ```go func (d Definition) Min() (float64, bool) ``` ## Definition.MinLength Canonical URL: https://riducms.com/reference/field/definition-min-length-method/ Kind: method MinLength returns the minimum accepted Unicode code-point length. ```go func (d Definition) MinLength() (int, bool) ``` ## Definition.MinRows Canonical URL: https://riducms.com/reference/field/definition-min-rows-method/ Kind: method MinRows is the minimum accepted length for an array. ```go func (d Definition) MinRows() int ``` ## Definition.Name Canonical URL: https://riducms.com/reference/field/definition-name-method/ Kind: method Name returns the document property name authored for the field. ```go func (d Definition) Name() string ``` ## Definition.Placeholder Canonical URL: https://riducms.com/reference/field/definition-placeholder-method/ Kind: method Placeholder returns the canonical empty-state prompt for compatible admin controls. ```go func (d Definition) Placeholder() string ``` ## Definition.PlaceholderTranslations Canonical URL: https://riducms.com/reference/field/definition-placeholder-translations-method/ Kind: method PlaceholderTranslations returns localized placeholder text by admin language. ```go func (d Definition) PlaceholderTranslations() map[string]string ``` ## Definition.PluginConfig Canonical URL: https://riducms.com/reference/field/definition-plugin-config-method/ Kind: method PluginConfig returns a copy of the plugin-owned serialized configuration. ```go func (d Definition) PluginConfig() json.RawMessage ``` ## Definition.PluginKey Canonical URL: https://riducms.com/reference/field/definition-plugin-key-method/ Kind: method PluginKey returns the compiled plugin responsible for a custom field. ```go func (d Definition) PluginKey() string ``` ## Definition.PluginReferenceKeys Canonical URL: https://riducms.com/reference/field/definition-plugin-reference-keys-method/ Kind: method PluginReferenceKeys returns JSON property names whose string values contain public collection slugs and therefore participate in content renames and persisted reference-shape migration safety. ```go func (d Definition) PluginReferenceKeys() []string ``` ## Definition.ReadOnly Canonical URL: https://riducms.com/reference/field/definition-read-only-method/ Kind: method ReadOnly reports whether the admin should prevent editing this field. ```go func (d Definition) ReadOnly() bool ``` ## Definition.ReferenceDeleteAction Canonical URL: https://riducms.com/reference/field/definition-reference-delete-action-method/ Kind: method ReferenceDeleteAction returns the explicitly authored hard-delete policy. An empty action means config resolution must apply the deterministic default for the reference shape. ```go func (d Definition) ReferenceDeleteAction() ReferenceDeleteAction ``` ## Definition.RelationshipFilters Canonical URL: https://riducms.com/reference/field/definition-relationship-filters-method/ Kind: method RelationshipFilters returns configured multi-rule and polymorphic option filters. ```go func (d Definition) RelationshipFilters() []RelationshipFilterRule ``` ## Definition.RelationshipHasMany Canonical URL: https://riducms.com/reference/field/definition-relationship-has-many-method/ Kind: method RelationshipHasMany reports whether the field stores multiple references. ```go func (d Definition) RelationshipHasMany() bool ``` ## Definition.RelationshipTarget Canonical URL: https://riducms.com/reference/field/definition-relationship-target-method/ Kind: method RelationshipTarget returns the first configured target slug, or an empty string. ```go func (d Definition) RelationshipTarget() string ``` ## Definition.RelationshipTargets Canonical URL: https://riducms.com/reference/field/definition-relationship-targets-method/ Kind: method RelationshipTargets returns a copy of all configured target slugs. ```go func (d Definition) RelationshipTargets() []string ``` ## Definition.Required Canonical URL: https://riducms.com/reference/field/definition-required-method/ Kind: method Required reports whether validation rejects a missing, null, or field-type-specific empty value. ```go func (d Definition) Required() bool ``` ## Definition.RowLabel Canonical URL: https://riducms.com/reference/field/definition-row-label-method/ Kind: method RowLabel is the child property used to label array rows in the admin. ```go func (d Definition) RowLabel() string ``` ## Definition.RowLabelComponent Canonical URL: https://riducms.com/reference/field/definition-row-label-component-method/ Kind: method RowLabelComponent returns the optional statically registered admin plugin component selected for array or blocks row headings. The returned configuration is detached from the immutable definition. ```go func (d Definition) RowLabelComponent() (pluginKey, component string, config json.RawMessage, ok bool) ``` ## Definition.RowLabels Canonical URL: https://riducms.com/reference/field/definition-row-labels-method/ Kind: method RowLabels returns optional singular and plural author-facing array row names. ```go func (d Definition) RowLabels() RowLabels ``` ## Definition.SelectDefaults Canonical URL: https://riducms.com/reference/field/definition-select-defaults-method/ Kind: method SelectDefaults returns the configured ordered default choices for a multi-select. ```go func (d Definition) SelectDefaults() []string ``` ## Definition.SelectHasMany Canonical URL: https://riducms.com/reference/field/definition-select-has-many-method/ Kind: method SelectHasMany reports whether a select stores an ordered list of choices. ```go func (d Definition) SelectHasMany() bool ``` ## Definition.Sidebar Canonical URL: https://riducms.com/reference/field/definition-sidebar-method/ Kind: method Sidebar reports whether a root field belongs in the document editor's right rail. ```go func (d Definition) Sidebar() bool ``` ## Definition.SlugSource Canonical URL: https://riducms.com/reference/field/definition-slug-source-method/ Kind: method SlugSource returns the source field path for a text-backed slug helper. The boolean distinguishes an invalid empty source from an ordinary text field. ```go func (d Definition) SlugSource() (string, bool) ``` ## Definition.Step Canonical URL: https://riducms.com/reference/field/definition-step-method/ Kind: method Step returns the positive admin input increment for a number field. It is presentation metadata and does not impose divisibility validation. ```go func (d Definition) Step() (float64, bool) ``` ## Definition.Tab Canonical URL: https://riducms.com/reference/field/definition-tab-method/ Kind: method Tab returns the named admin form tab, or an empty string. ```go func (d Definition) Tab() string ``` ## Definition.Tabs Canonical URL: https://riducms.com/reference/field/definition-tabs-method/ Kind: method Tabs returns a deep copy of the configured named and unnamed tabs. ```go func (d Definition) Tabs() []TabDefinition ``` ## Definition.TabTranslations Canonical URL: https://riducms.com/reference/field/definition-tab-translations-method/ Kind: method TabTranslations returns localized direct-tab labels by admin language. ```go func (d Definition) TabTranslations() map[string]string ``` ## Definition.Unique Canonical URL: https://riducms.com/reference/field/definition-unique-method/ Kind: method Unique reports whether values must be distinct within the collection. ```go func (d Definition) Unique() bool ``` ## Definition.ValueType Canonical URL: https://riducms.com/reference/field/definition-value-type-method/ Kind: method ValueType is the declared output contract for a virtual field. ```go func (d Definition) ValueType() ValueType ``` ## Definition.WithLabelTranslations Canonical URL: https://riducms.com/reference/field/definition-with-label-translations-method/ Kind: method WithLabelTranslations returns an immutable copy with localized labels. It is useful for presentation definitions such as Collapsible that do not accept options. ```go func (d Definition) WithLabelTranslations(translations map[string]string) Definition ``` ## FilterContains Canonical URL: https://riducms.com/reference/field/filter-contains/ Kind: constant Public constant FilterContains from github.com/riducms/ridu/field. ```go const FilterContains RelationshipFilterOperator = "contains" ``` ## FilterEquals Canonical URL: https://riducms.com/reference/field/filter-equals/ Kind: constant Public constant FilterEquals from github.com/riducms/ridu/field. ```go const FilterEquals RelationshipFilterOperator = "equals" ``` ## FilterGreaterThan Canonical URL: https://riducms.com/reference/field/filter-greater-than/ Kind: constant Public constant FilterGreaterThan from github.com/riducms/ridu/field. ```go const FilterGreaterThan RelationshipFilterOperator = "greaterThan" ``` ## FilterGreaterThanEqual Canonical URL: https://riducms.com/reference/field/filter-greater-than-equal/ Kind: constant Public constant FilterGreaterThanEqual from github.com/riducms/ridu/field. ```go const FilterGreaterThanEqual RelationshipFilterOperator = "greaterThanEqual" ``` ## FilterLessThan Canonical URL: https://riducms.com/reference/field/filter-less-than/ Kind: constant Public constant FilterLessThan from github.com/riducms/ridu/field. ```go const FilterLessThan RelationshipFilterOperator = "lessThan" ``` ## FilterLessThanEqual Canonical URL: https://riducms.com/reference/field/filter-less-than-equal/ Kind: constant Public constant FilterLessThanEqual from github.com/riducms/ridu/field. ```go const FilterLessThanEqual RelationshipFilterOperator = "lessThanEqual" ``` ## FilterLike Canonical URL: https://riducms.com/reference/field/filter-like/ Kind: constant Public constant FilterLike from github.com/riducms/ridu/field. ```go const FilterLike RelationshipFilterOperator = "like" ``` ## FilterNotEquals Canonical URL: https://riducms.com/reference/field/filter-not-equals/ Kind: constant Public constant FilterNotEquals from github.com/riducms/ridu/field. ```go const FilterNotEquals RelationshipFilterOperator = "notEquals" ``` ## KindArray Canonical URL: https://riducms.com/reference/field/kind-array/ Kind: constant Public constant KindArray from github.com/riducms/ridu/field. ```go const KindArray Kind = "array" ``` ## KindBlocks Canonical URL: https://riducms.com/reference/field/kind-blocks/ Kind: constant Public constant KindBlocks from github.com/riducms/ridu/field. ```go const KindBlocks Kind = "blocks" ``` ## KindCheckbox Canonical URL: https://riducms.com/reference/field/kind-checkbox/ Kind: constant Public constant KindCheckbox from github.com/riducms/ridu/field. ```go const KindCheckbox Kind = "checkbox" ``` ## KindCode Canonical URL: https://riducms.com/reference/field/kind-code/ Kind: constant Public constant KindCode from github.com/riducms/ridu/field. ```go const KindCode Kind = "code" ``` ## KindCollapsible Canonical URL: https://riducms.com/reference/field/kind-collapsible/ Kind: constant Public constant KindCollapsible from github.com/riducms/ridu/field. ```go const KindCollapsible Kind = "collapsible" ``` ## KindDate Canonical URL: https://riducms.com/reference/field/kind-date/ Kind: constant Public constant KindDate from github.com/riducms/ridu/field. ```go const KindDate Kind = "date" ``` ## KindEmail Canonical URL: https://riducms.com/reference/field/kind-email/ Kind: constant Public constant KindEmail from github.com/riducms/ridu/field. ```go const KindEmail Kind = "email" ``` ## KindGroup Canonical URL: https://riducms.com/reference/field/kind-group/ Kind: constant Public constant KindGroup from github.com/riducms/ridu/field. ```go const KindGroup Kind = "group" ``` ## KindJoin Canonical URL: https://riducms.com/reference/field/kind-join/ Kind: constant Public constant KindJoin from github.com/riducms/ridu/field. ```go const KindJoin Kind = "join" ``` ## KindJSON Canonical URL: https://riducms.com/reference/field/kind-json/ Kind: constant Public constant KindJSON from github.com/riducms/ridu/field. ```go const KindJSON Kind = "json" ``` ## KindNumber Canonical URL: https://riducms.com/reference/field/kind-number/ Kind: constant Public constant KindNumber from github.com/riducms/ridu/field. ```go const KindNumber Kind = "number" ``` ## KindPlugin Canonical URL: https://riducms.com/reference/field/kind-plugin/ Kind: constant Public constant KindPlugin from github.com/riducms/ridu/field. ```go const KindPlugin Kind = "plugin" ``` ## KindPoint Canonical URL: https://riducms.com/reference/field/kind-point/ Kind: constant Public constant KindPoint from github.com/riducms/ridu/field. ```go const KindPoint Kind = "point" ``` ## KindRadio Canonical URL: https://riducms.com/reference/field/kind-radio/ Kind: constant Public constant KindRadio from github.com/riducms/ridu/field. ```go const KindRadio Kind = "radio" ``` ## KindRelationship Canonical URL: https://riducms.com/reference/field/kind-relationship/ Kind: constant Public constant KindRelationship from github.com/riducms/ridu/field. ```go const KindRelationship Kind = "relationship" ``` ## KindRow Canonical URL: https://riducms.com/reference/field/kind-row/ Kind: constant Public constant KindRow from github.com/riducms/ridu/field. ```go const KindRow Kind = "row" ``` ## KindSelect Canonical URL: https://riducms.com/reference/field/kind-select/ Kind: constant Public constant KindSelect from github.com/riducms/ridu/field. ```go const KindSelect Kind = "select" ``` ## KindTabs Canonical URL: https://riducms.com/reference/field/kind-tabs/ Kind: constant Public constant KindTabs from github.com/riducms/ridu/field. ```go const KindTabs Kind = "tabs" ``` ## KindText Canonical URL: https://riducms.com/reference/field/kind-text/ Kind: constant Public constant KindText from github.com/riducms/ridu/field. ```go const KindText Kind = "text" ``` ## KindTextarea Canonical URL: https://riducms.com/reference/field/kind-textarea/ Kind: constant Public constant KindTextarea from github.com/riducms/ridu/field. ```go const KindTextarea Kind = "textarea" ``` ## KindUI Canonical URL: https://riducms.com/reference/field/kind-ui/ Kind: constant Public constant KindUI from github.com/riducms/ridu/field. ```go const KindUI Kind = "ui" ``` ## KindUpload Canonical URL: https://riducms.com/reference/field/kind-upload/ Kind: constant Public constant KindUpload from github.com/riducms/ridu/field. ```go const KindUpload Kind = "upload" ``` ## KindVirtual Canonical URL: https://riducms.com/reference/field/kind-virtual/ Kind: constant Public constant KindVirtual from github.com/riducms/ridu/field. ```go const KindVirtual Kind = "virtual" ``` ## ReferenceDeleteNullify Canonical URL: https://riducms.com/reference/field/reference-delete-nullify/ Kind: constant ReferenceDeleteNullify clears a singular reference or removes matching members from a has-many reference. ```go const ReferenceDeleteNullify ReferenceDeleteAction = "nullify" ``` ## ReferenceDeleteRestrict Canonical URL: https://riducms.com/reference/field/reference-delete-restrict/ Kind: constant ReferenceDeleteRestrict rejects the target hard delete while a current document still references it. ```go const ReferenceDeleteRestrict ReferenceDeleteAction = "restrict" ``` ## TabDefinition.WithLabelTranslations Canonical URL: https://riducms.com/reference/field/tab-definition-with-label-translations-method/ Kind: method WithLabelTranslations returns a detached tab with localized trigger labels. ```go func (tab TabDefinition) WithLabelTranslations(translations map[string]string) TabDefinition ``` ## ValueBoolean Canonical URL: https://riducms.com/reference/field/value-boolean/ Kind: constant Public constant ValueBoolean from github.com/riducms/ridu/field. ```go const ValueBoolean ValueType = "boolean" ``` ## ValueJSON Canonical URL: https://riducms.com/reference/field/value-json/ Kind: constant Public constant ValueJSON from github.com/riducms/ridu/field. ```go const ValueJSON ValueType = "json" ``` ## ValueNumber Canonical URL: https://riducms.com/reference/field/value-number/ Kind: constant Public constant ValueNumber from github.com/riducms/ridu/field. ```go const ValueNumber ValueType = "number" ``` ## ValueString Canonical URL: https://riducms.com/reference/field/value-string/ Kind: constant Public constant ValueString from github.com/riducms/ridu/field. ```go const ValueString ValueType = "string" ``` --- # API Reference: query Canonical URL: https://riducms.com/reference/query/ Package: github.com/riducms/ridu/query Immutable filters, validated document paths, stable sorting, and relationship population controls. ## Path Canonical URL: https://riducms.com/reference/query/path/ Kind: type An immutable, validated document field path. ```go type Path struct { segments []string } ``` Segments begin with a lowercase letter and may contain letters, digits, underscores, or hyphens. Paths are limited to MaxPathSegments (64) and MaxPathBytes (4096). Path implements JSON encoding as its canonical dot-separated string. ## NewPath Canonical URL: https://riducms.com/reference/query/new-path/ Kind: function Validate and build a path from segments. ```go func NewPath(segments ...string) (Path, error) ``` ```go authorEmail, err := query.NewPath("author", "email") if err != nil { return err } ``` ## ParsePath Canonical URL: https://riducms.com/reference/query/parse-path/ Kind: function Validate a dot-separated path. ```go func ParsePath(value string) (Path, error) ``` ```go titlePath, err := query.ParsePath("seo.title") ``` ## Expression Canonical URL: https://riducms.com/reference/query/expression/ Kind: interface A sealed immutable predicate consumed atomically by stores. ```go type Expression interface { Kind() ExpressionKind Node() Node expression() } ``` Use Node only at adapter and protocol boundaries. Application code should compose Expression values with the constructors below. ## ExpressionKind Canonical URL: https://riducms.com/reference/query/expression-kind/ Kind: type The recursive expression shape. ```go type ExpressionKind string ``` ## Node Canonical URL: https://riducms.com/reference/query/node/ Kind: type A detached recursive expression snapshot for stores and transports. ```go type Node struct { Kind ExpressionKind Comparison *Comparison Children []Node } ``` Mutating a Node does not mutate the originating Expression. Adapters should treat malformed nodes as invalid input, not silently broaden a query. ## Comparison Canonical URL: https://riducms.com/reference/query/comparison/ Kind: type One path/operator/value predicate snapshot. ```go type Comparison struct { Path Path Operator Operator Value Value } ``` ## Operator Canonical URL: https://riducms.com/reference/query/operator/ Kind: type The finite comparison vocabulary. ```go type Operator string ``` ## Compare Canonical URL: https://riducms.com/reference/query/compare/ Kind: function Construct a comparison while returning validation errors. ```go func Compare(path Path, operator Operator, value Value) (Expression, error) ``` Prefer this form when the operator is dynamic. Convenience comparison functions panic only if called with an incompatible Value kind; with their documented inputs they are safe. ## Equal Canonical URL: https://riducms.com/reference/query/equal/ Kind: function Match an equal scalar or null. ```go func Equal(path Path, value Value) Expression ``` ## NotEqual Canonical URL: https://riducms.com/reference/query/not-equal/ Kind: function Exclude an equal scalar or null. ```go func NotEqual(path Path, value Value) Expression ``` ## In Canonical URL: https://riducms.com/reference/query/in/ Kind: function Match any supplied operand. ```go func In(path Path, values ...Value) Expression ``` ## GreaterThan Canonical URL: https://riducms.com/reference/query/greater-than/ Kind: function Match a string or number above the operand. ```go func GreaterThan(path Path, value Value) Expression ``` ## GreaterThanEqual Canonical URL: https://riducms.com/reference/query/greater-than-equal/ Kind: function Match a string or number at or above the operand. ```go func GreaterThanEqual(path Path, value Value) Expression ``` ## LessThan Canonical URL: https://riducms.com/reference/query/less-than/ Kind: function Match a string or number below the operand. ```go func LessThan(path Path, value Value) Expression ``` ## LessThanEqual Canonical URL: https://riducms.com/reference/query/less-than-equal/ Kind: function Match a string or number at or below the operand. ```go func LessThanEqual(path Path, value Value) Expression ``` ## Contains Canonical URL: https://riducms.com/reference/query/contains/ Kind: function Match a string containing the supplied text. ```go func Contains(path Path, value string) Expression ``` ## Like Canonical URL: https://riducms.com/reference/query/like/ Kind: function Match using the store-supported string pattern operator. ```go func Like(path Path, value string) Expression ``` ## And Canonical URL: https://riducms.com/reference/query/and/ Kind: function Require every child expression. ```go func And(expressions ...Expression) (Expression, error) ``` Requires at least two non-nil children. ```go where, err := query.And( query.Equal(status, query.String("published")), query.GreaterThan(score, query.Number(10)), ) ``` ## Or Canonical URL: https://riducms.com/reference/query/or/ Kind: function Require at least one child expression. ```go func Or(expressions ...Expression) (Expression, error) ``` Requires at least two non-nil children. ## Not Canonical URL: https://riducms.com/reference/query/not/ Kind: function Negate one expression. ```go func Not(child Expression) (Expression, error) ``` ## Value Canonical URL: https://riducms.com/reference/query/value/ Kind: type An immutable scalar or list comparison operand. ```go type Value struct { kind ValueKind text string number float64 boolean bool items []Value } ``` Explicit constructors prevent arbitrary application values from leaking into the query contract. Value implements JSON encoding. ## ValueKind Canonical URL: https://riducms.com/reference/query/value-kind/ Kind: type The query operand discriminant. ```go type ValueKind string ``` ## String Canonical URL: https://riducms.com/reference/query/string/ Kind: function Construct a string query operand. ```go func String(value string) Value ``` ## Number Canonical URL: https://riducms.com/reference/query/number/ Kind: function Construct a float64 query operand. ```go func Number(value float64) Value ``` ## Boolean Canonical URL: https://riducms.com/reference/query/boolean/ Kind: function Construct a bool query operand. ```go func Boolean(value bool) Value ``` ## Null Canonical URL: https://riducms.com/reference/query/null/ Kind: function Construct a null query operand. ```go func Null() Value ``` ## List Canonical URL: https://riducms.com/reference/query/list/ Kind: function Construct a defensively copied list operand. ```go func List(values ...Value) Value ``` ## Direction Canonical URL: https://riducms.com/reference/query/direction/ Kind: type A sort direction. ```go type Direction string ``` ## Sort Canonical URL: https://riducms.com/reference/query/sort/ Kind: type One validated ordered field term. ```go type Sort struct { Path Path Direction Direction } ``` Stores append document ID as a stable tiebreaker when it is not supplied explicitly. Construct with NewSort when direction is not a compile-time constant. ## NewSort Canonical URL: https://riducms.com/reference/query/new-sort/ Kind: function Validate a path and asc/desc direction. ```go func NewSort(path Path, direction Direction) (Sort, error) ``` ## Population Canonical URL: https://riducms.com/reference/query/population/ Kind: type Expand one relationship path into projected target documents. ```go type Population struct { Path Path Depth int // Select is nil for the complete populated target. A non-nil empty slice // returns only document metadata. Select []Path } ``` Population is access-aware at every target collection and is also bounded by a store materialization budget. ## Ascending Canonical URL: https://riducms.com/reference/query/ascending/ Kind: constant Public constant Ascending from github.com/riducms/ridu/query. ```go const Ascending Direction = "asc" ``` ## Descending Canonical URL: https://riducms.com/reference/query/descending/ Kind: constant Public constant Descending from github.com/riducms/ridu/query. ```go const Descending Direction = "desc" ``` ## ExpressionAnd Canonical URL: https://riducms.com/reference/query/expression-and/ Kind: constant Public constant ExpressionAnd from github.com/riducms/ridu/query. ```go const ExpressionAnd ExpressionKind = "and" ``` ## ExpressionComparison Canonical URL: https://riducms.com/reference/query/expression-comparison/ Kind: constant Public constant ExpressionComparison from github.com/riducms/ridu/query. ```go const ExpressionComparison ExpressionKind = "comparison" ``` ## ExpressionNot Canonical URL: https://riducms.com/reference/query/expression-not/ Kind: constant Public constant ExpressionNot from github.com/riducms/ridu/query. ```go const ExpressionNot ExpressionKind = "not" ``` ## ExpressionOr Canonical URL: https://riducms.com/reference/query/expression-or/ Kind: constant Public constant ExpressionOr from github.com/riducms/ridu/query. ```go const ExpressionOr ExpressionKind = "or" ``` ## MaxPathBytes Canonical URL: https://riducms.com/reference/query/max-path-bytes/ Kind: constant MaxPathBytes bounds user-supplied filter/sort/population path allocation. ```go const MaxPathBytes = 4096 ``` ## MaxPathSegments Canonical URL: https://riducms.com/reference/query/max-path-segments/ Kind: constant MaxPathSegments bounds recursive query compilation and schema traversal. Ridu's operation engine supports substantially shallower authored models, leaving this ceiling as a fail-safe rather than a practical restriction. ```go const MaxPathSegments = 64 ``` ## OperatorContains Canonical URL: https://riducms.com/reference/query/operator-contains/ Kind: constant Public constant OperatorContains from github.com/riducms/ridu/query. ```go const OperatorContains Operator = "contains" ``` ## OperatorEqual Canonical URL: https://riducms.com/reference/query/operator-equal/ Kind: constant Public constant OperatorEqual from github.com/riducms/ridu/query. ```go const OperatorEqual Operator = "equal" ``` ## OperatorExists Canonical URL: https://riducms.com/reference/query/operator-exists/ Kind: constant Public constant OperatorExists from github.com/riducms/ridu/query. ```go const OperatorExists Operator = "exists" ``` ## OperatorGreaterThan Canonical URL: https://riducms.com/reference/query/operator-greater-than/ Kind: constant Public constant OperatorGreaterThan from github.com/riducms/ridu/query. ```go const OperatorGreaterThan Operator = "greater_than" ``` ## OperatorGreaterThanEqual Canonical URL: https://riducms.com/reference/query/operator-greater-than-equal/ Kind: constant Public constant OperatorGreaterThanEqual from github.com/riducms/ridu/query. ```go const OperatorGreaterThanEqual Operator = "greater_than_equal" ``` ## OperatorIn Canonical URL: https://riducms.com/reference/query/operator-in/ Kind: constant Public constant OperatorIn from github.com/riducms/ridu/query. ```go const OperatorIn Operator = "in" ``` ## OperatorLessThan Canonical URL: https://riducms.com/reference/query/operator-less-than/ Kind: constant Public constant OperatorLessThan from github.com/riducms/ridu/query. ```go const OperatorLessThan Operator = "less_than" ``` ## OperatorLessThanEqual Canonical URL: https://riducms.com/reference/query/operator-less-than-equal/ Kind: constant Public constant OperatorLessThanEqual from github.com/riducms/ridu/query. ```go const OperatorLessThanEqual Operator = "less_than_equal" ``` ## OperatorLike Canonical URL: https://riducms.com/reference/query/operator-like/ Kind: constant Public constant OperatorLike from github.com/riducms/ridu/query. ```go const OperatorLike Operator = "like" ``` ## OperatorNotEqual Canonical URL: https://riducms.com/reference/query/operator-not-equal/ Kind: constant Public constant OperatorNotEqual from github.com/riducms/ridu/query. ```go const OperatorNotEqual Operator = "not_equal" ``` ## Path.MarshalJSON Canonical URL: https://riducms.com/reference/query/path-marshal-json-method/ Kind: method MarshalJSON encodes a path in its canonical dot-separated form. ```go func (path Path) MarshalJSON() ([]byte, error) ``` ## Path.Segments Canonical URL: https://riducms.com/reference/query/path-segments-method/ Kind: method Segments returns a copy of the path segments. ```go func (path Path) Segments() []string ``` ## Path.String Canonical URL: https://riducms.com/reference/query/path-string-method/ Kind: method Public method Path.String from github.com/riducms/ridu/query. ```go func (path Path) String() string ``` ## Path.UnmarshalJSON Canonical URL: https://riducms.com/reference/query/path-unmarshal-json-method/ Kind: method UnmarshalJSON validates the canonical string before replacing the path. ```go func (path *Path) UnmarshalJSON(encoded []byte) error ``` ## Value.BooleanValue Canonical URL: https://riducms.com/reference/query/value-boolean-value-method/ Kind: method BooleanValue returns the boolean and true when this is a boolean operand. ```go func (value Value) BooleanValue() (bool, bool) ``` ## Value.Kind Canonical URL: https://riducms.com/reference/query/value-kind-method/ Kind: method Kind returns the operand's discriminant. ```go func (value Value) Kind() ValueKind ``` ## Value.MarshalJSON Canonical URL: https://riducms.com/reference/query/value-marshal-json-method/ Kind: method Public method Value.MarshalJSON from github.com/riducms/ridu/query. ```go func (value Value) MarshalJSON() ([]byte, error) ``` ## Value.NumberValue Canonical URL: https://riducms.com/reference/query/value-number-value-method/ Kind: method NumberValue returns the number and true when this is a number operand. ```go func (value Value) NumberValue() (float64, bool) ``` ## Value.StringValue Canonical URL: https://riducms.com/reference/query/value-string-value-method/ Kind: method StringValue returns the string and true when this is a string operand. ```go func (value Value) StringValue() (string, bool) ``` ## Value.Values Canonical URL: https://riducms.com/reference/query/value-values-method/ Kind: method Values returns a deep copy for a list operand. ```go func (value Value) Values() []Value ``` ## ValueBoolean Canonical URL: https://riducms.com/reference/query/value-boolean/ Kind: constant Public constant ValueBoolean from github.com/riducms/ridu/query. ```go const ValueBoolean ValueKind = "boolean" ``` ## ValueList Canonical URL: https://riducms.com/reference/query/value-list/ Kind: constant Public constant ValueList from github.com/riducms/ridu/query. ```go const ValueList ValueKind = "list" ``` ## ValueNull Canonical URL: https://riducms.com/reference/query/value-null/ Kind: constant Public constant ValueNull from github.com/riducms/ridu/query. ```go const ValueNull ValueKind = "null" ``` ## ValueNumber Canonical URL: https://riducms.com/reference/query/value-number/ Kind: constant Public constant ValueNumber from github.com/riducms/ridu/query. ```go const ValueNumber ValueKind = "number" ``` ## ValueString Canonical URL: https://riducms.com/reference/query/value-string/ Kind: constant Public constant ValueString from github.com/riducms/ridu/query. ```go const ValueString ValueKind = "string" ``` --- # API Reference: schema Canonical URL: https://riducms.com/reference/schema/ Package: github.com/riducms/ridu/schema The immutable generated schema manifest, stable identifiers, and advanced generator/plugin contracts. ## Manifest Canonical URL: https://riducms.com/reference/schema/manifest/ Kind: type An immutable versioned schema contract. ```go type Manifest struct { snapshot Snapshot } ``` Manifest owns a deep copy. Its bytes are deterministic for the same resolved config; public accessors never expose mutable internal state. ## NewManifest Canonical URL: https://riducms.com/reference/schema/new-manifest/ Kind: function Create a manifest from a detached snapshot. ```go func NewManifest(snapshot Snapshot) Manifest ``` ## Parse Canonical URL: https://riducms.com/reference/schema/parse/ Kind: function Parse and validate encoded manifest JSON. ```go func Parse(encoded []byte) (Manifest, error) ``` ## IsSupportedEndpointMethod Canonical URL: https://riducms.com/reference/schema/is-supported-endpoint-method/ Kind: function Report whether a method belongs to the custom endpoint contract. ```go func IsSupportedEndpointMethod(method string) bool ``` CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, and PUT are accepted case-insensitively after trimming. ## IsValidEndpointPath Canonical URL: https://riducms.com/reference/schema/is-valid-endpoint-path/ Kind: function Validate the deterministic custom endpoint path grammar. ```go func IsValidEndpointPath(path string) bool ``` Paths begin with / and may contain complete unique :parameter segments. Query strings, fragments, traversal, empty segments, wildcards, braces, percent escapes, whitespace, and partial parameters are rejected. ## Snapshot Canonical URL: https://riducms.com/reference/schema/snapshot/ Kind: type The serializable application and content schema. ```go type Snapshot struct { Version Version `json:"version"` Application Application `json:"application"` Collections []Collection `json:"collections"` Globals []Global `json:"globals,omitempty"` Plugins []Plugin `json:"plugins"` } ``` This is a detached serialization model, not executable application configuration. Access rules, hooks, task handlers, secrets, and dynamic locale-availability callbacks are deliberately absent. ## Version Canonical URL: https://riducms.com/reference/schema/version/ Kind: type The manifest wire-format version. ```go type Version uint32 ``` CurrentVersion (1) is the only version accepted by Parse. This greenfield contract has no legacy manifest branch; do not persist it as an application feature version. ## CurrentVersion Canonical URL: https://riducms.com/reference/schema/current-version/ Kind: constant The schema-manifest format version produced and accepted by this build. ```go const CurrentVersion Version = 1 ``` ## Application Canonical URL: https://riducms.com/reference/schema/application/ Kind: type Resolved application metadata safe for tooling and the admin. ```go type Application struct { // Name is the resolved author-facing application name. Name string `json:"name"` // NameTranslations overrides Name for configured admin interface languages. NameTranslations map[string]string `json:"nameTranslations,omitempty"` // AllowIDOnCreate permits callers to supply a validated canonical string ID // on ordinary creates. Migration imports preserve source IDs independently. AllowIDOnCreate bool `json:"allowIDOnCreate,omitempty"` // Admin contains admin authentication policy when auth is enabled. Admin *AdminSettings `json:"admin,omitempty"` // AdminLocalization is the deterministic interface language and timezone // contract. Catalog text is supplied by the statically built admin. AdminLocalization *AdminLocalizationSettings `json:"adminLocalization,omitempty"` // Localization is the deterministic content-locale contract, when enabled. Localization *LocalizationSettings `json:"localization,omitempty"` // Endpoints lists application-level custom endpoint metadata. Executable // handlers remain in Go runtime configuration. Endpoints []Endpoint `json:"endpoints,omitempty"` } ``` ## Endpoint Canonical URL: https://riducms.com/reference/schema/endpoint/ Kind: type Deterministic public metadata for one application-authored custom endpoint. ```go type Endpoint struct { Method string `json:"method"` Path string `json:"path"` Summary string `json:"summary,omitempty"` } ``` Executable handler code and request body limits remain in Go runtime configuration and are never serialized. ## AdminLocalizationSettings Canonical URL: https://riducms.com/reference/schema/admin-localization-settings/ Kind: type Deterministic admin interface language and timezone configuration. ```go type AdminLocalizationSettings struct { Languages []AdminLanguage `json:"languages"` DefaultLanguage string `json:"defaultLanguage"` TimeZones []AdminTimeZone `json:"timeZones,omitempty"` DefaultTimeZone string `json:"defaultTimeZone,omitempty"` } ``` ## AdminLanguage Canonical URL: https://riducms.com/reference/schema/admin-language/ Kind: type One statically bundled admin interface language. ```go type AdminLanguage struct { Code string `json:"code"` Label string `json:"label"` LabelTranslations map[string]string `json:"labelTranslations,omitempty"` RTL bool `json:"rtl,omitempty"` } ``` ## AdminTimeZone Canonical URL: https://riducms.com/reference/schema/admin-time-zone/ Kind: type One browser-safe timezone offered to editors. ```go type AdminTimeZone struct { ID string `json:"id"` Label string `json:"label"` LabelTranslations map[string]string `json:"labelTranslations,omitempty"` } ``` ## LocalizationSettings Canonical URL: https://riducms.com/reference/schema/localization-settings/ Kind: type Deterministic content-locale configuration. ```go type LocalizationSettings struct { Locales []Locale `json:"locales"` DefaultLocale LocaleCode `json:"defaultLocale"` Fallback bool `json:"fallback"` } ``` LocaleCodes returns locale identities in authoring order. Executable per-request availability rules remain in Go and are not serialized. ## Collection Canonical URL: https://riducms.com/reference/schema/collection/ Kind: type The resolved contract for a collection. ```go type Collection struct { ID StableID `json:"id"` Slug CollectionSlug `json:"slug"` Labels CollectionLabels `json:"labels"` Admin CollectionAdmin `json:"admin"` Capabilities Capabilities `json:"capabilities"` Auth *AuthSettings `json:"authSettings,omitempty"` Upload *UploadSettings `json:"uploadSettings,omitempty"` Versions *VersionSettings `json:"versionSettings,omitempty"` DocumentLock *DocumentLockSettings `json:"documentLockSettings,omitempty"` Fields []Field `json:"fields"` Indexes []CollectionIndex `json:"indexes,omitempty"` Endpoints []Endpoint `json:"endpoints,omitempty"` } ``` ## Field Canonical URL: https://riducms.com/reference/schema/field/ Kind: type The resolved contract for one field. ```go type Field struct { ID StableID `json:"id"` Name string `json:"name"` Path query.Path `json:"path"` Type FieldType `json:"type"` Category FieldCategory `json:"category"` Required bool `json:"required"` Unique bool `json:"unique"` Index bool `json:"index,omitempty"` Localized bool `json:"localized,omitempty"` Default *string `json:"default,omitempty"` Admin FieldAdmin `json:"admin"` Text *TextField `json:"text,omitempty"` Textarea *TextField `json:"textarea,omitempty"` Code *CodeField `json:"code,omitempty"` Number *NumberField `json:"number,omitempty"` Date *DateField `json:"date,omitempty"` Select *SelectField `json:"select,omitempty"` Point *PointField `json:"point,omitempty"` UI *UIField `json:"ui,omitempty"` Join *JoinField `json:"join,omitempty"` Virtual *VirtualField `json:"virtual,omitempty"` Relationship *RelationshipField `json:"relationship,omitempty"` Upload *UploadField `json:"upload,omitempty"` Nested *NestedField `json:"nested,omitempty"` Blocks *BlocksField `json:"blocks,omitempty"` Plugin *PluginField `json:"plugin,omitempty"` } ``` Exactly one matching detail is set for typed kinds: Text, Textarea, Code, Number, Date, Select, Point, UI, Join, Virtual, Relationship, Upload, Nested, Blocks, or Plugin. Checkbox, email, and simple JSON fields need no extra detail. ## FieldType Canonical URL: https://riducms.com/reference/schema/field-type/ Kind: type The resolved field discriminator shared with generated contracts. ```go type FieldType string ``` ## Capabilities Canonical URL: https://riducms.com/reference/schema/capabilities/ Kind: type Resolved feature flags for one collection or global. ```go type Capabilities struct { Auth bool `json:"auth"` Upload bool `json:"upload"` Versions bool `json:"versions"` Trash bool `json:"trash"` Locking bool `json:"locking,omitempty"` Global bool `json:"global,omitempty"` } ``` ## AuthSettings Canonical URL: https://riducms.com/reference/schema/auth-settings/ Kind: type Public resolved authentication policy. ```go type AuthSettings struct { IdentityField string `json:"identityField"` SessionDurationSeconds int64 `json:"sessionDurationSeconds"` PasswordMinLength int `json:"passwordMinLength"` PasswordMaxBytes int `json:"passwordMaxBytes"` PasswordBcryptCost int `json:"passwordBcryptCost"` MaxLoginAttempts int `json:"maxLoginAttempts"` LockDurationSeconds int64 `json:"lockDurationSeconds"` PasswordReset bool `json:"passwordReset"` PasswordResetTokenDurationSeconds int64 `json:"passwordResetTokenDurationSeconds"` VerifyEmail bool `json:"verifyEmail"` VerificationTokenDurationSeconds int64 `json:"verificationTokenDurationSeconds"` APIKeys bool `json:"apiKeys"` } ``` ## UploadSettings Canonical URL: https://riducms.com/reference/schema/upload-settings/ Kind: type Resolved media validation and delivery policy. ```go type UploadSettings struct { MaxFileSize int64 `json:"maxFileSize"` MimeTypes []string `json:"mimeTypes"` Private bool `json:"private"` ImageSizes []ImageSize `json:"imageSizes,omitempty"` } ``` ## VersionSettings Canonical URL: https://riducms.com/reference/schema/version-settings/ Kind: type Resolved drafts, snapshot retention, and autosave policy. ```go type VersionSettings struct { Drafts bool `json:"drafts"` MaxPerDocument int `json:"maxPerDocument"` AutosaveIntervalSeconds int64 `json:"autosaveIntervalSeconds"` } ``` ## DocumentLockSettings Canonical URL: https://riducms.com/reference/schema/document-lock-settings/ Kind: type Resolved authoring lock lease. ```go type DocumentLockSettings struct { DurationSeconds int64 `json:"durationSeconds"` } ``` ## CollectionIndex Canonical URL: https://riducms.com/reference/schema/collection-index/ Kind: type An ordered compound index over supported field paths. ```go type CollectionIndex struct { Fields []query.Path `json:"fields"` Unique bool `json:"unique,omitempty"` } ``` Official stores use NULLS DISTINCT semantics for unique compound indexes. ## AdminSettings Canonical URL: https://riducms.com/reference/schema/admin-settings/ Kind: type The durable ID and current slug of the auth collection trusted by the admin. ```go type AdminSettings struct { // UserCollectionID is the durable identity of the selected auth collection. UserCollectionID StableID `json:"userCollectionId"` // UserCollectionSlug is the API-facing slug of the selected auth collection. UserCollectionSlug CollectionSlug `json:"userCollectionSlug"` } ``` ## Locale Canonical URL: https://riducms.com/reference/schema/locale/ Kind: type One resolved locale in deterministic authoring order. ```go type Locale struct { Code LocaleCode `json:"code"` Label string `json:"label"` RTL bool `json:"rtl,omitempty"` FallbackLocales []LocaleCode `json:"fallbackLocale,omitempty"` } ``` ## CollectionAdmin Canonical URL: https://riducms.com/reference/schema/collection-admin/ Kind: type Resolved collection presentation, hierarchy, and live-preview metadata. ```go type CollectionAdmin struct { UseAsTitle string `json:"useAsTitle,omitempty"` DefaultColumns []string `json:"defaultColumns,omitempty"` Group string `json:"group,omitempty"` GroupTranslations map[string]string `json:"groupTranslations,omitempty"` Description string `json:"description,omitempty"` DescriptionTranslations map[string]string `json:"descriptionTranslations,omitempty"` FolderField string `json:"folderField,omitempty"` ParentField string `json:"parentField,omitempty"` LivePreview *LivePreview `json:"livePreview,omitempty"` } ``` Presentation metadata never authorizes an operation. ## CollectionLabels Canonical URL: https://riducms.com/reference/schema/collection-labels/ Kind: type Normalized singular and plural labels. ```go type CollectionLabels struct { Singular string `json:"singular"` SingularTranslations map[string]string `json:"singularTranslations,omitempty"` Plural string `json:"plural"` PluralTranslations map[string]string `json:"pluralTranslations,omitempty"` } ``` ## Global Canonical URL: https://riducms.com/reference/schema/global/ Kind: type The resolved singleton schema alias. ```go type Global = Collection ``` Globals live in a separate manifest namespace and API route while sharing fields, versions, capabilities, and presentation contracts. ## LivePreview Canonical URL: https://riducms.com/reference/schema/live-preview/ Kind: type A serializable preview URL template and viewports. ```go type LivePreview struct { URL string `json:"url"` Breakpoints []PreviewBreakpoint `json:"breakpoints,omitempty"` } ``` ## PreviewBreakpoint Canonical URL: https://riducms.com/reference/schema/preview-breakpoint/ Kind: type One named live-preview viewport. ```go type PreviewBreakpoint struct { Name string `json:"name"` Label string `json:"label"` LabelTranslations map[string]string `json:"labelTranslations,omitempty"` Width int `json:"width"` Height int `json:"height"` } ``` ## ImageSize Canonical URL: https://riducms.com/reference/schema/image-size/ Kind: type One named derived upload image variant. ```go type ImageSize struct { Name string `json:"name"` Width int `json:"width"` Height int `json:"height"` Fit string `json:"fit"` } ``` ## FieldAdmin Canonical URL: https://riducms.com/reference/schema/field-admin/ Kind: type Serializable field presentation metadata. ```go type FieldAdmin struct { Label string `json:"label"` LabelTranslations map[string]string `json:"labelTranslations,omitempty"` Description string `json:"description,omitempty"` DescriptionTranslations map[string]string `json:"descriptionTranslations,omitempty"` Placeholder string `json:"placeholder,omitempty"` PlaceholderTranslations map[string]string `json:"placeholderTranslations,omitempty"` ReadOnly bool `json:"readOnly,omitempty"` Hidden bool `json:"hidden,omitempty"` Sidebar bool `json:"sidebar,omitempty"` Columns int `json:"columns,omitempty"` Row *FieldRow `json:"row,omitempty"` Collapsible *FieldCollapsible `json:"collapsible,omitempty"` Tab string `json:"tab,omitempty"` TabTranslations map[string]string `json:"tabTranslations,omitempty"` TabGroup *FieldTabGroup `json:"tabGroup,omitempty"` NamedTab bool `json:"namedTab,omitempty"` Condition *FieldCondition `json:"condition,omitempty"` Component *FieldAdminComponent `json:"component,omitempty"` } ``` Admin visibility, read-only presentation, and renderer selection are never authorization. ## FieldAdminComponent Canonical URL: https://riducms.com/reference/schema/field-admin-component/ Kind: type An exact built-in field renderer owned by a paired static admin plugin. ```go type FieldAdminComponent struct { Plugin string `json:"plugin"` Component string `json:"component"` Config json.RawMessage `json:"config,omitempty"` } ``` Component metadata changes authoring presentation only. Storage, validation, access, migrations, and generated value types still follow the field’s built-in kind. ## FieldCategory Canonical URL: https://riducms.com/reference/schema/field-category/ Kind: type Stored, presentation, computed, or plugin field ownership. ```go type FieldCategory string ``` ## FieldRow Canonical URL: https://riducms.com/reference/schema/field-row/ Kind: type Stable identity of a presentation-only row. ```go type FieldRow struct { ID StableID `json:"id"` } ``` ## FieldCollapsible Canonical URL: https://riducms.com/reference/schema/field-collapsible/ Kind: type Stable identity and presentation state of a flattened disclosure. ```go type FieldCollapsible struct { ID StableID `json:"id"` Label string `json:"label"` LabelTranslations map[string]string `json:"labelTranslations,omitempty"` InitiallyCollapsed bool `json:"initiallyCollapsed,omitempty"` } ``` ## FieldTabGroup Canonical URL: https://riducms.com/reference/schema/field-tab-group/ Kind: type Stable identity of one presentation tabs definition. ```go type FieldTabGroup struct { ID StableID `json:"id"` } ``` ## FieldCondition Canonical URL: https://riducms.com/reference/schema/field-condition/ Kind: type One recursive node in a resolved presentation-only condition. ```go type FieldCondition struct { Kind FieldConditionKind `json:"kind"` Conditions []FieldCondition `json:"conditions,omitempty"` Predicate *FieldConditionPredicate `json:"predicate,omitempty"` } ``` ## FieldConditionKind Canonical URL: https://riducms.com/reference/schema/field-condition-kind/ Kind: type The resolved logical or predicate node kind. ```go type FieldConditionKind string ``` ## FieldConditionScope Canonical URL: https://riducms.com/reference/schema/field-condition-scope/ Kind: type The value root used by a predicate. ```go type FieldConditionScope string ``` ## FieldConditionOperator Canonical URL: https://riducms.com/reference/schema/field-condition-operator/ Kind: type The resolved scalar comparison vocabulary. ```go type FieldConditionOperator string ``` ## FieldConditionPredicate Canonical URL: https://riducms.com/reference/schema/field-condition-predicate/ Kind: type One scoped scalar comparison in a field condition. ```go type FieldConditionPredicate struct { Scope FieldConditionScope `json:"scope"` Path query.Path `json:"path"` Operator FieldConditionOperator `json:"operator"` Values []FieldConditionValue `json:"values"` } ``` ## FieldConditionValue Canonical URL: https://riducms.com/reference/schema/field-condition-value/ Kind: type One canonically encoded string, number, or boolean condition operand. ```go type FieldConditionValue struct { Type ValueType `json:"type"` Value string `json:"value"` } ``` ## TextField Canonical URL: https://riducms.com/reference/schema/text-field/ Kind: type Inclusive Unicode code-point length bounds and optional slug behavior. ```go type TextField struct { MinLength *int `json:"minLength,omitempty"` MaxLength *int `json:"maxLength,omitempty"` Slug *SlugField `json:"slug,omitempty"` } ``` ## SlugField Canonical URL: https://riducms.com/reference/schema/slug-field/ Kind: type First-class slug derivation from one non-repeated string source path. ```go type SlugField struct { SourcePath query.Path `json:"sourcePath"` } ``` ## CodeField Canonical URL: https://riducms.com/reference/schema/code-field/ Kind: type Code editor language plus string length bounds. ```go type CodeField struct { Language string `json:"language,omitempty"` MinLength *int `json:"minLength,omitempty"` MaxLength *int `json:"maxLength,omitempty"` } ``` ## NumberField Canonical URL: https://riducms.com/reference/schema/number-field/ Kind: type Inclusive numeric bounds and presentation step. ```go type NumberField struct { Min *float64 `json:"min,omitempty"` Max *float64 `json:"max,omitempty"` Step *float64 `json:"step,omitempty"` } ``` Step is admin metadata, not a divisibility constraint. ## DateField Canonical URL: https://riducms.com/reference/schema/date-field/ Kind: type Resolved date editor appearance. ```go type DateField struct { PickerAppearance DatePickerAppearance `json:"pickerAppearance"` } ``` ## DatePickerAppearance Canonical URL: https://riducms.com/reference/schema/date-picker-appearance/ Kind: type The finite date-control vocabulary. ```go type DatePickerAppearance string ``` ## PointField Canonical URL: https://riducms.com/reference/schema/point-field/ Kind: type Marker for a longitude/latitude tuple. ```go type PointField struct{} ``` ## UIField Canonical URL: https://riducms.com/reference/schema/ui-field/ Kind: type Marker for presentation-only content omitted from values. ```go type UIField struct{} ``` ## ValueType Canonical URL: https://riducms.com/reference/schema/value-type/ Kind: type Generated output vocabulary for virtual fields. ```go type ValueType string ``` ## VirtualField Canonical URL: https://riducms.com/reference/schema/virtual-field/ Kind: type The promised serialized type of a computed value. ```go type VirtualField struct { ValueType ValueType `json:"valueType"` } ``` ## SelectField Canonical URL: https://riducms.com/reference/schema/select-field/ Kind: type Normalized finite choices, cardinality, and ordered multi-select defaults. ```go type SelectField struct { Choices []SelectChoice `json:"choices"` HasMany bool `json:"hasMany,omitempty"` DefaultValues []string `json:"defaultValues,omitempty"` } ``` ## SelectChoice Canonical URL: https://riducms.com/reference/schema/select-choice/ Kind: type One normalized select value and label. ```go type SelectChoice struct { Value string `json:"value"` Label string `json:"label"` LabelTranslations map[string]string `json:"labelTranslations,omitempty"` } ``` ## RelationshipFilter Canonical URL: https://riducms.com/reference/schema/relationship-filter/ Kind: type A resolved choice predicate derived from document data. ```go type RelationshipFilter struct { CollectionSlug CollectionSlug `json:"collectionSlug,omitempty"` TargetPath query.Path `json:"targetPath"` Operator string `json:"operator,omitempty"` SourcePath *query.Path `json:"sourcePath,omitempty"` Value *RelationshipFilterValue `json:"value,omitempty"` } ``` ## RelationshipFilterValue Canonical URL: https://riducms.com/reference/schema/relationship-filter-value/ Kind: type One canonically encoded typed literal used by a relationship option filter. ```go type RelationshipFilterValue struct { Type ValueType `json:"type"` Value string `json:"value"` } ``` ## RelationshipTarget Canonical URL: https://riducms.com/reference/schema/relationship-target/ Kind: type Stable ID and current slug of one polymorphic target. ```go type RelationshipTarget struct { CollectionID StableID `json:"collectionId"` CollectionSlug CollectionSlug `json:"collectionSlug"` } ``` ## UploadField Canonical URL: https://riducms.com/reference/schema/upload-field/ Kind: type Resolved upload reference, filters, cardinality, and deletion policy. ```go type UploadField struct { CollectionID StableID `json:"collectionId"` CollectionSlug CollectionSlug `json:"collectionSlug"` HasMany bool `json:"hasMany,omitempty"` OptionFilters []RelationshipFilter `json:"optionFilters,omitempty"` OnDelete ReferenceDeleteAction `json:"onDelete"` } ``` ## ReferenceDeleteAction Canonical URL: https://riducms.com/reference/schema/reference-delete-action/ Kind: type Resolved nullify or restrict policy for permanent target deletion. ```go type ReferenceDeleteAction string ``` ## BlockType Canonical URL: https://riducms.com/reference/schema/block-type/ Kind: type One normalized discriminated block layout. ```go type BlockType struct { Key string `json:"key"` Label string `json:"label"` LabelTranslations map[string]string `json:"labelTranslations,omitempty"` Fields []Field `json:"fields"` } ``` ## RelationshipField Canonical URL: https://riducms.com/reference/schema/relationship-field/ Kind: type Resolved singular, many, or polymorphic reference metadata. ```go type RelationshipField struct { CollectionID StableID `json:"collectionId,omitempty"` CollectionSlug CollectionSlug `json:"collectionSlug,omitempty"` Targets []RelationshipTarget `json:"targets,omitempty"` HasMany bool `json:"hasMany,omitempty"` Polymorphic bool `json:"polymorphic,omitempty"` OptionFilters []RelationshipFilter `json:"optionFilters,omitempty"` OnDelete ReferenceDeleteAction `json:"onDelete"` } ``` ## JoinField Canonical URL: https://riducms.com/reference/schema/join-field/ Kind: type Resolved inverse-relationship presentation and population metadata. ```go type JoinField struct { CollectionID StableID `json:"collectionId"` CollectionSlug CollectionSlug `json:"collectionSlug"` On query.Path `json:"on"` Limit int `json:"limit"` DefaultColumns []string `json:"defaultColumns,omitempty"` DefaultSort string `json:"defaultSort,omitempty"` AllowCreate *bool `json:"allowCreate,omitempty"` } ``` ## NestedField Canonical URL: https://riducms.com/reference/schema/nested-field/ Kind: type Resolved group, array, or blocks children, row constraints, and row-label presentation. ```go type NestedField struct { Fields []Field `json:"fields"` MinRows int `json:"minRows,omitempty"` MaxRows int `json:"maxRows,omitempty"` RowLabel string `json:"rowLabel,omitempty"` RowLabelComponent *FieldAdminComponent `json:"rowLabelComponent,omitempty"` RowLabels *ArrayRowLabels `json:"rowLabels,omitempty"` } ``` ## ArrayRowLabels Canonical URL: https://riducms.com/reference/schema/array-row-labels/ Kind: type Singular and plural array-row labels with admin interface translations. ```go type ArrayRowLabels struct { Singular string `json:"singular"` SingularTranslations map[string]string `json:"singularTranslations,omitempty"` Plural string `json:"plural"` PluralTranslations map[string]string `json:"pluralTranslations,omitempty"` } ``` ## BlocksField Canonical URL: https://riducms.com/reference/schema/blocks-field/ Kind: type The allowed discriminated layouts for a blocks field. ```go type BlocksField struct { Types []BlockType `json:"types"` } ``` ## PluginField Canonical URL: https://riducms.com/reference/schema/plugin-field/ Kind: type One plugin field key, public JSON config, and declared reference keys. ```go type PluginField struct { Key string `json:"key"` Config json.RawMessage `json:"config"` ReferenceKeys []string `json:"referenceKeys,omitempty"` } ``` ## CurrentPluginAPIVersion Canonical URL: https://riducms.com/reference/schema/current-plugin-api-version/ Kind: constant The compiled backend plugin contract represented by this manifest version. ```go const CurrentPluginAPIVersion uint32 = 1 ``` A plugin descriptor with any other APIVersion is rejected during config resolution. ## CurrentAdminPluginAPIVersion Canonical URL: https://riducms.com/reference/schema/current-admin-plugin-api-version/ Kind: constant The static backend/admin plugin contract represented by this manifest version. ```go const CurrentAdminPluginAPIVersion uint32 = 1 ``` Generated admin registries reject packages that declare a different API version. ## Plugin Canonical URL: https://riducms.com/reference/schema/plugin/ Kind: type A compiled plugin that participated in config resolution. ```go type Plugin struct { Key string `json:"key"` Version string `json:"version,omitempty"` GoPackage string `json:"goPackage,omitempty"` APIVersion uint32 `json:"apiVersion,omitempty"` Ridu *PluginCompatibility `json:"ridu,omitempty"` Admin *PluginAdmin `json:"admin,omitempty"` FieldTypes []PluginFieldType `json:"fieldTypes,omitempty"` DatabaseContributions []PluginDatabaseContribution `json:"databaseContributions,omitempty"` Endpoints []PluginEndpoint `json:"endpoints,omitempty"` } ``` Contains public build and generation metadata only—never executable code or secrets. ## PluginAdmin Canonical URL: https://riducms.com/reference/schema/plugin-admin/ Kind: type Static admin-package pairing metadata. ```go type PluginAdmin struct { Package string `json:"package"` Export string `json:"export"` APIVersion uint32 `json:"apiVersion"` PairingVersion uint32 `json:"pairingVersion"` Routes []string `json:"routes,omitempty"` Assets []string `json:"assets,omitempty"` } ``` ## PluginCompatibility Canonical URL: https://riducms.com/reference/schema/plugin-compatibility/ Kind: type A half-open supported Ridu semantic-version interval. ```go type PluginCompatibility struct { Minimum string `json:"minimum"` MaximumExclusive string `json:"maximumExclusive,omitempty"` } ``` ## PluginFieldType Canonical URL: https://riducms.com/reference/schema/plugin-field-type/ Kind: type Generated Go, TypeScript, and JSON Schema contracts for a plugin field. ```go type PluginFieldType struct { Key string `json:"key"` TypeScriptPackage string `json:"typescriptPackage"` TypeScriptOutput string `json:"typescriptOutput"` TypeScriptInput string `json:"typescriptInput"` TypeScriptWhere string `json:"typescriptWhere,omitempty"` GoPackage string `json:"goPackage,omitempty"` GoType string `json:"goType,omitempty"` JSONSchema json.RawMessage `json:"jsonSchema,omitempty"` } ``` ## PluginDatabaseAdapter Canonical URL: https://riducms.com/reference/schema/plugin-database-adapter/ Kind: type PostgreSQL or SQLite identity for private plugin schema. ```go type PluginDatabaseAdapter string ``` ## PluginDatabaseContribution Canonical URL: https://riducms.com/reference/schema/plugin-database-contribution/ Kind: type One adapter-specific migration history and owned-table list. ```go type PluginDatabaseContribution struct { Adapter PluginDatabaseAdapter `json:"adapter"` Migrations []PluginMigration `json:"migrations,omitempty"` Tables []string `json:"tables,omitempty"` } ``` ## PluginMigration Canonical URL: https://riducms.com/reference/schema/plugin-migration/ Kind: type One declarative contiguous adapter-specific migration transition contributed by a plugin. ```go type PluginMigration struct { Version uint32 `json:"version"` Name string `json:"name"` UpSQL []string `json:"upSQL"` DownSQL []string `json:"downSQL"` } ``` ## PluginEndpoint Canonical URL: https://riducms.com/reference/schema/plugin-endpoint/ Kind: type Public method, path, and summary for one compiled plugin endpoint. ```go type PluginEndpoint struct { Method string `json:"method"` Path string `json:"path"` Summary string `json:"summary"` } ``` ## StableID Canonical URL: https://riducms.com/reference/schema/stable-id/ Kind: type A deterministic identifier for schema evolution. ```go type StableID string ``` ## CollectionSlug Canonical URL: https://riducms.com/reference/schema/collection-slug/ Kind: type A validated collection or global slug. ```go type CollectionSlug string ``` ## LocaleCode Canonical URL: https://riducms.com/reference/schema/locale-code/ Kind: type A validated locale identity used by operations, manifests, and storage. ```go type LocaleCode string ``` ```go ridu.LocalizationConfig{ DefaultLocale: "en", Locales: []ridu.Locale{ {Code: schema.LocaleCode("en"), Label: "English"}, {Code: schema.LocaleCode("fr"), Label: "Français"}, }, } ``` ## ValidationError Canonical URL: https://riducms.com/reference/schema/validation-error/ Kind: type A path-aware set of schema issues. ```go type ValidationError struct { Issues []Issue `json:"issues"` } ``` Use errors.As to inspect every stable code/path/message issue rather than parsing Error text. NewValidationError defensively copies and orders supplied issues. ## Issue Canonical URL: https://riducms.com/reference/schema/issue/ Kind: type One stable path-aware schema problem. ```go type Issue struct { Code string `json:"code"` Path string `json:"path"` Message string `json:"message"` } ``` ## NewValidationError Canonical URL: https://riducms.com/reference/schema/new-validation-error/ Kind: function Create a path-aware validation error from issues. ```go func NewValidationError(issues []Issue) *ValidationError ``` ## IsValidStableID Canonical URL: https://riducms.com/reference/schema/is-valid-stable-id/ Kind: function Check canonical deterministic schema identity syntax. ```go func IsValidStableID(value string) bool ``` ## IsValidCollectionSlug Canonical URL: https://riducms.com/reference/schema/is-valid-collection-slug/ Kind: function Check URL- and API-facing collection slug syntax. ```go func IsValidCollectionSlug(value string) bool ``` ## IsValidLocaleCode Canonical URL: https://riducms.com/reference/schema/is-valid-locale-code/ Kind: function Check locale codes accepted by URLs, contracts, and storage. ```go func IsValidLocaleCode(value string) bool ``` ## IsValidFieldName Canonical URL: https://riducms.com/reference/schema/is-valid-field-name/ Kind: function Check unquoted generated property and query-path syntax. ```go func IsValidFieldName(value string) bool ``` ## IsValidPluginKey Canonical URL: https://riducms.com/reference/schema/is-valid-plugin-key/ Kind: function Check a plugin’s stable manifest key. ```go func IsValidPluginKey(value string) bool ``` ## IsValidPluginMigrationSQL Canonical URL: https://riducms.com/reference/schema/is-valid-plugin-migration-sql/ Kind: function Check the shared plugin migration execution boundary. ```go func IsValidPluginMigrationSQL(adapter PluginDatabaseAdapter, value string) bool ``` ## IsValidAdminPluginPackage Canonical URL: https://riducms.com/reference/schema/is-valid-admin-plugin-package/ Kind: function Check a static JavaScript package specifier. ```go func IsValidAdminPluginPackage(value string) bool ``` ## IsValidAdminPluginExport Canonical URL: https://riducms.com/reference/schema/is-valid-admin-plugin-export/ Kind: function Check a named JavaScript export identifier. ```go func IsValidAdminPluginExport(value string) bool ``` ## IsValidSemanticVersion Canonical URL: https://riducms.com/reference/schema/is-valid-semantic-version/ Kind: function Check a complete unprefixed semantic version. ```go func IsValidSemanticVersion(value string) bool ``` ## IsValidSemanticVersionRange Canonical URL: https://riducms.com/reference/schema/is-valid-semantic-version-range/ Kind: function Check a non-empty half-open semantic-version interval. ```go func IsValidSemanticVersionRange(minimum, maximumExclusive string) bool ``` ## SemanticVersionInRange Canonical URL: https://riducms.com/reference/schema/semantic-version-in-range/ Kind: function Test a version against a validated half-open interval. ```go func SemanticVersionInRange(version, minimum, maximumExclusive string) bool ``` ## IsValidAdminPluginRoute Canonical URL: https://riducms.com/reference/schema/is-valid-admin-plugin-route/ Kind: function Check a package-relative admin plugin route. ```go func IsValidAdminPluginRoute(value string) bool ``` ## IsValidAdminPluginAsset Canonical URL: https://riducms.com/reference/schema/is-valid-admin-plugin-asset/ Kind: function Check a package-relative static admin side-effect import. ```go func IsValidAdminPluginAsset(value string) bool ``` ## IsValidGoPackage Canonical URL: https://riducms.com/reference/schema/is-valid-go-package/ Kind: function Check a portable Go import path. ```go func IsValidGoPackage(value string) bool ``` ## IsValidPluginTable Canonical URL: https://riducms.com/reference/schema/is-valid-plugin-table/ Kind: function Check an unquoted adapter-owned plugin table identifier. ```go func IsValidPluginTable(value string) bool ``` ## DatePickerDayAndTime Canonical URL: https://riducms.com/reference/schema/date-picker-day-and-time/ Kind: constant Public constant DatePickerDayAndTime from github.com/riducms/ridu/schema. ```go const DatePickerDayAndTime DatePickerAppearance = "dayAndTime" ``` ## DatePickerDayOnly Canonical URL: https://riducms.com/reference/schema/date-picker-day-only/ Kind: constant Public constant DatePickerDayOnly from github.com/riducms/ridu/schema. ```go const DatePickerDayOnly DatePickerAppearance = "dayOnly" ``` ## DatePickerTimeOnly Canonical URL: https://riducms.com/reference/schema/date-picker-time-only/ Kind: constant Public constant DatePickerTimeOnly from github.com/riducms/ridu/schema. ```go const DatePickerTimeOnly DatePickerAppearance = "timeOnly" ``` ## FieldCategoryNested Canonical URL: https://riducms.com/reference/schema/field-category-nested/ Kind: constant Public constant FieldCategoryNested from github.com/riducms/ridu/schema. ```go const FieldCategoryNested FieldCategory = "nested" ``` ## FieldCategoryPlugin Canonical URL: https://riducms.com/reference/schema/field-category-plugin/ Kind: constant Public constant FieldCategoryPlugin from github.com/riducms/ridu/schema. ```go const FieldCategoryPlugin FieldCategory = "plugin" ``` ## FieldCategoryPresentation Canonical URL: https://riducms.com/reference/schema/field-category-presentation/ Kind: constant Public constant FieldCategoryPresentation from github.com/riducms/ridu/schema. ```go const FieldCategoryPresentation FieldCategory = "presentation" ``` ## FieldCategoryRelationship Canonical URL: https://riducms.com/reference/schema/field-category-relationship/ Kind: constant Public constant FieldCategoryRelationship from github.com/riducms/ridu/schema. ```go const FieldCategoryRelationship FieldCategory = "relationship" ``` ## FieldCategoryScalar Canonical URL: https://riducms.com/reference/schema/field-category-scalar/ Kind: constant Public constant FieldCategoryScalar from github.com/riducms/ridu/schema. ```go const FieldCategoryScalar FieldCategory = "scalar" ``` ## FieldCategoryUpload Canonical URL: https://riducms.com/reference/schema/field-category-upload/ Kind: constant Public constant FieldCategoryUpload from github.com/riducms/ridu/schema. ```go const FieldCategoryUpload FieldCategory = "upload" ``` ## FieldConditionDocument Canonical URL: https://riducms.com/reference/schema/field-condition-document/ Kind: constant Public constant FieldConditionDocument from github.com/riducms/ridu/schema. ```go const FieldConditionDocument FieldConditionScope = "document" ``` ## FieldConditionEquals Canonical URL: https://riducms.com/reference/schema/field-condition-equals/ Kind: constant Public constant FieldConditionEquals from github.com/riducms/ridu/schema. ```go const FieldConditionEquals FieldConditionOperator = "equals" ``` ## FieldConditionKindAll Canonical URL: https://riducms.com/reference/schema/field-condition-kind-all/ Kind: constant Public constant FieldConditionKindAll from github.com/riducms/ridu/schema. ```go const FieldConditionKindAll FieldConditionKind = "all" ``` ## FieldConditionKindAny Canonical URL: https://riducms.com/reference/schema/field-condition-kind-any/ Kind: constant Public constant FieldConditionKindAny from github.com/riducms/ridu/schema. ```go const FieldConditionKindAny FieldConditionKind = "any" ``` ## FieldConditionKindNot Canonical URL: https://riducms.com/reference/schema/field-condition-kind-not/ Kind: constant Public constant FieldConditionKindNot from github.com/riducms/ridu/schema. ```go const FieldConditionKindNot FieldConditionKind = "not" ``` ## FieldConditionKindPredicate Canonical URL: https://riducms.com/reference/schema/field-condition-kind-predicate/ Kind: constant Public constant FieldConditionKindPredicate from github.com/riducms/ridu/schema. ```go const FieldConditionKindPredicate FieldConditionKind = "predicate" ``` ## FieldConditionNotEquals Canonical URL: https://riducms.com/reference/schema/field-condition-not-equals/ Kind: constant Public constant FieldConditionNotEquals from github.com/riducms/ridu/schema. ```go const FieldConditionNotEquals FieldConditionOperator = "notEquals" ``` ## FieldConditionOneOf Canonical URL: https://riducms.com/reference/schema/field-condition-one-of/ Kind: constant Public constant FieldConditionOneOf from github.com/riducms/ridu/schema. ```go const FieldConditionOneOf FieldConditionOperator = "oneOf" ``` ## FieldConditionSibling Canonical URL: https://riducms.com/reference/schema/field-condition-sibling/ Kind: constant Public constant FieldConditionSibling from github.com/riducms/ridu/schema. ```go const FieldConditionSibling FieldConditionScope = "sibling" ``` ## FieldTypeArray Canonical URL: https://riducms.com/reference/schema/field-type-array/ Kind: constant Public constant FieldTypeArray from github.com/riducms/ridu/schema. ```go const FieldTypeArray FieldType = "array" ``` ## FieldTypeBlocks Canonical URL: https://riducms.com/reference/schema/field-type-blocks/ Kind: constant Public constant FieldTypeBlocks from github.com/riducms/ridu/schema. ```go const FieldTypeBlocks FieldType = "blocks" ``` ## FieldTypeCheckbox Canonical URL: https://riducms.com/reference/schema/field-type-checkbox/ Kind: constant Public constant FieldTypeCheckbox from github.com/riducms/ridu/schema. ```go const FieldTypeCheckbox FieldType = "checkbox" ``` ## FieldTypeCode Canonical URL: https://riducms.com/reference/schema/field-type-code/ Kind: constant Public constant FieldTypeCode from github.com/riducms/ridu/schema. ```go const FieldTypeCode FieldType = "code" ``` ## FieldTypeDate Canonical URL: https://riducms.com/reference/schema/field-type-date/ Kind: constant Public constant FieldTypeDate from github.com/riducms/ridu/schema. ```go const FieldTypeDate FieldType = "date" ``` ## FieldTypeEmail Canonical URL: https://riducms.com/reference/schema/field-type-email/ Kind: constant Public constant FieldTypeEmail from github.com/riducms/ridu/schema. ```go const FieldTypeEmail FieldType = "email" ``` ## FieldTypeGroup Canonical URL: https://riducms.com/reference/schema/field-type-group/ Kind: constant Public constant FieldTypeGroup from github.com/riducms/ridu/schema. ```go const FieldTypeGroup FieldType = "group" ``` ## FieldTypeJoin Canonical URL: https://riducms.com/reference/schema/field-type-join/ Kind: constant Public constant FieldTypeJoin from github.com/riducms/ridu/schema. ```go const FieldTypeJoin FieldType = "join" ``` ## FieldTypeJSON Canonical URL: https://riducms.com/reference/schema/field-type-json/ Kind: constant Public constant FieldTypeJSON from github.com/riducms/ridu/schema. ```go const FieldTypeJSON FieldType = "json" ``` ## FieldTypeNumber Canonical URL: https://riducms.com/reference/schema/field-type-number/ Kind: constant Public constant FieldTypeNumber from github.com/riducms/ridu/schema. ```go const FieldTypeNumber FieldType = "number" ``` ## FieldTypePlugin Canonical URL: https://riducms.com/reference/schema/field-type-plugin/ Kind: constant Public constant FieldTypePlugin from github.com/riducms/ridu/schema. ```go const FieldTypePlugin FieldType = "plugin" ``` ## FieldTypePoint Canonical URL: https://riducms.com/reference/schema/field-type-point/ Kind: constant Public constant FieldTypePoint from github.com/riducms/ridu/schema. ```go const FieldTypePoint FieldType = "point" ``` ## FieldTypeRadio Canonical URL: https://riducms.com/reference/schema/field-type-radio/ Kind: constant Public constant FieldTypeRadio from github.com/riducms/ridu/schema. ```go const FieldTypeRadio FieldType = "radio" ``` ## FieldTypeRelationship Canonical URL: https://riducms.com/reference/schema/field-type-relationship/ Kind: constant Public constant FieldTypeRelationship from github.com/riducms/ridu/schema. ```go const FieldTypeRelationship FieldType = "relationship" ``` ## FieldTypeSelect Canonical URL: https://riducms.com/reference/schema/field-type-select/ Kind: constant Public constant FieldTypeSelect from github.com/riducms/ridu/schema. ```go const FieldTypeSelect FieldType = "select" ``` ## FieldTypeText Canonical URL: https://riducms.com/reference/schema/field-type-text/ Kind: constant Public constant FieldTypeText from github.com/riducms/ridu/schema. ```go const FieldTypeText FieldType = "text" ``` ## FieldTypeTextarea Canonical URL: https://riducms.com/reference/schema/field-type-textarea/ Kind: constant Public constant FieldTypeTextarea from github.com/riducms/ridu/schema. ```go const FieldTypeTextarea FieldType = "textarea" ``` ## FieldTypeUI Canonical URL: https://riducms.com/reference/schema/field-type-ui/ Kind: constant Public constant FieldTypeUI from github.com/riducms/ridu/schema. ```go const FieldTypeUI FieldType = "ui" ``` ## FieldTypeUpload Canonical URL: https://riducms.com/reference/schema/field-type-upload/ Kind: constant Public constant FieldTypeUpload from github.com/riducms/ridu/schema. ```go const FieldTypeUpload FieldType = "upload" ``` ## FieldTypeVirtual Canonical URL: https://riducms.com/reference/schema/field-type-virtual/ Kind: constant Public constant FieldTypeVirtual from github.com/riducms/ridu/schema. ```go const FieldTypeVirtual FieldType = "virtual" ``` ## LocalizationSettings.LocaleCodes Canonical URL: https://riducms.com/reference/schema/localization-settings-locale-codes-method/ Kind: method LocaleCodes returns configured locale identities in deterministic authoring order. ```go func (settings LocalizationSettings) LocaleCodes() []LocaleCode ``` ## Manifest.Bytes Canonical URL: https://riducms.com/reference/schema/manifest-bytes-method/ Kind: method Bytes returns the canonical indented manifest encoding with one trailing newline, suitable for generated artifacts and golden fixtures. ```go func (manifest Manifest) Bytes() ([]byte, error) ``` ## Manifest.Equal Canonical URL: https://riducms.com/reference/schema/manifest-equal-method/ Kind: method Equal reports whether two manifests have byte-identical canonical encodings. ```go func (manifest Manifest) Equal(other Manifest) bool ``` ## Manifest.MarshalJSON Canonical URL: https://riducms.com/reference/schema/manifest-marshal-json-method/ Kind: method MarshalJSON implements json.Marshaler without exposing mutable internals. ```go func (manifest Manifest) MarshalJSON() ([]byte, error) ``` ## Manifest.Snapshot Canonical URL: https://riducms.com/reference/schema/manifest-snapshot-method/ Kind: method Snapshot returns a deep copy of the manifest. ```go func (manifest Manifest) Snapshot() Snapshot ``` ## Manifest.UnmarshalJSON Canonical URL: https://riducms.com/reference/schema/manifest-unmarshal-json-method/ Kind: method UnmarshalJSON replaces a manifest only after Parse validates the complete encoded value. ```go func (manifest *Manifest) UnmarshalJSON(encoded []byte) error ``` ## Plugin.DatabaseContribution Canonical URL: https://riducms.com/reference/schema/plugin-database-contribution-method/ Kind: method DatabaseContribution returns the private-schema bundle for adapter. ```go func (plugin Plugin) DatabaseContribution(adapter PluginDatabaseAdapter) (PluginDatabaseContribution, bool) ``` ## Plugin.HasDatabaseContributions Canonical URL: https://riducms.com/reference/schema/plugin-has-database-contributions-method/ Kind: method HasDatabaseContributions reports whether a plugin requires private physical schema outside ordinary Ridu collections and fields. ```go func (plugin Plugin) HasDatabaseContributions() bool ``` ## PluginDatabaseAdapterPostgres Canonical URL: https://riducms.com/reference/schema/plugin-database-adapter-postgres/ Kind: constant Public constant PluginDatabaseAdapterPostgres from github.com/riducms/ridu/schema. ```go const PluginDatabaseAdapterPostgres PluginDatabaseAdapter = "postgres" ``` ## PluginDatabaseAdapterSQLite Canonical URL: https://riducms.com/reference/schema/plugin-database-adapter-sq-lite/ Kind: constant Public constant PluginDatabaseAdapterSQLite from github.com/riducms/ridu/schema. ```go const PluginDatabaseAdapterSQLite PluginDatabaseAdapter = "sqlite" ``` ## ReferenceDeleteNullify Canonical URL: https://riducms.com/reference/schema/reference-delete-nullify/ Kind: constant Public constant ReferenceDeleteNullify from github.com/riducms/ridu/schema. ```go const ReferenceDeleteNullify ReferenceDeleteAction = "nullify" ``` ## ReferenceDeleteRestrict Canonical URL: https://riducms.com/reference/schema/reference-delete-restrict/ Kind: constant Public constant ReferenceDeleteRestrict from github.com/riducms/ridu/schema. ```go const ReferenceDeleteRestrict ReferenceDeleteAction = "restrict" ``` ## ValidationError.Error Canonical URL: https://riducms.com/reference/schema/validation-error-error-method/ Kind: method Public method ValidationError.Error from github.com/riducms/ridu/schema. ```go func (validationError *ValidationError) Error() string ``` ## ValueTypeBoolean Canonical URL: https://riducms.com/reference/schema/value-type-boolean/ Kind: constant Public constant ValueTypeBoolean from github.com/riducms/ridu/schema. ```go const ValueTypeBoolean ValueType = "boolean" ``` ## ValueTypeJSON Canonical URL: https://riducms.com/reference/schema/value-type-json/ Kind: constant Public constant ValueTypeJSON from github.com/riducms/ridu/schema. ```go const ValueTypeJSON ValueType = "json" ``` ## ValueTypeNumber Canonical URL: https://riducms.com/reference/schema/value-type-number/ Kind: constant Public constant ValueTypeNumber from github.com/riducms/ridu/schema. ```go const ValueTypeNumber ValueType = "number" ``` ## ValueTypeString Canonical URL: https://riducms.com/reference/schema/value-type-string/ Kind: constant Public constant ValueTypeString from github.com/riducms/ridu/schema. ```go const ValueTypeString ValueType = "string" ``` --- # API Reference: store Canonical URL: https://riducms.com/reference/store/ Package: github.com/riducms/ridu/store Advanced adapter contracts for transactional documents, auth, preferences, locks, publishing, uploads, and durable tasks. ## Store Canonical URL: https://riducms.com/reference/store/store/ Kind: interface Starts atomic transactions for operations. ```go type Store interface { Begin(context.Context) (Transaction, error) } ``` All operation-engine reads and mutations, including read-only operations, run through a transaction. ## Transaction Canonical URL: https://riducms.com/reference/store/transaction/ Kind: interface Atomic document reads and mutations. ```go type Transaction interface { Create(context.Context, CreateRequest) (Document, error) Find(context.Context, Request) (Document, error) List(context.Context, Request) (Page, error) ResolveFilteredSelection(context.Context, FilteredSelectionRequest) (FilteredSelection, error) Update(context.Context, UpdateRequest) (Document, error) Trash(context.Context, Request) (Document, error) Restore(context.Context, Request) (Document, error) Delete(context.Context, Request) (Document, error) // ApplyReferenceDelete atomically plans incoming current-document // references, rejects when any restrict policy matches, and otherwise // nullifies/removes those values. Version snapshots remain immutable. ApplyReferenceDelete(context.Context, ReferenceDeleteRequest) error // DeleteDocumentState idempotently removes framework-owned database state // where the document is either the target or the owning principal. DeleteDocumentState(context.Context, DocumentReference) error Commit(context.Context) error Rollback(context.Context) error } ``` ## Request Canonical URL: https://riducms.com/reference/store/request/ Kind: type Collection schema, predicates, pagination, locale, projection, and lock controls. ```go type Request struct { Collection schema.Collection Collections map[schema.StableID]schema.Collection ID string Filter *query.Node Access *query.Node Page int Limit int Sort []query.Sort // IndexWindow is set only for a count-free range read over one direct, // unique, indexed text field. Adapters must not broaden this range into a // count or offset query. IndexWindow *IndexWindow // Select is nil for all authored fields. A non-nil empty slice returns only // document metadata. Select []query.Path Populate []query.Population PopulationAccess map[schema.StableID]*query.Node // PopulationBudget is shared by every recursive population read that // contributes to one response. Official adapters initialize a default when // callers omit it so direct store use cannot bypass the materialization cap. PopulationBudget *PopulationBudget // PublishedOnly restricts every versioned collection read participating in // this request, including populated targets. Unversioned collections ignore it. PublishedOnly bool Deletion DeletionMode ExpectedRevision int // Locales is the complete configured locale order used to decode canonical // localized storage. LocaleChain starts with the requested locale and then // contains effective fallbacks used by atomic filtering and sorting. Locales []schema.LocaleCode LocaleChain []schema.LocaleCode AllLocales bool // Lock identifies the row lock required by a semantic read. Ordinary reads // use LockNone; relationship validation uses LockReference to keep an // accepted target from changing or being deleted before the enclosing write // commits. Coordinated framework mutations use LockMutation and acquire all // participants in deterministic reference order. Lock LockMode } ``` ## CreateRequest Canonical URL: https://riducms.com/reference/store/create-request/ Kind: type Validated values and metadata for one document insertion. ```go type CreateRequest struct { Collection schema.Collection ID string Values Values Status Status CreatedAt time.Time UpdatedAt time.Time Locales []schema.LocaleCode } ``` ## UpdateRequest Canonical URL: https://riducms.com/reference/store/update-request/ Kind: type An authorized request plus values and an optional publish status. ```go type UpdateRequest struct { Request Values Values Status *Status // ReplaceValues treats Values as the complete canonical authored document // state, including locale maps. Omitted fields and locales are removed. The // default remains a patch so ordinary updates preserve omitted values. // Framework version restore uses replacement after access, validation, hooks, // and reference checks have produced the canonical snapshot candidate. ReplaceValues bool } ``` ## Document Canonical URL: https://riducms.com/reference/store/document/ Kind: type A stored document with status and version metadata. ```go type Document struct { ID string CreatedAt time.Time UpdatedAt time.Time DeletedAt *time.Time Status Status Revision int Values Values // LocalizationSources records the locale that supplied each projected // localized field path. It is response metadata and is never persisted. LocalizationSources map[string]schema.LocaleCode } ``` ## DocumentReference Canonical URL: https://riducms.com/reference/store/document-reference/ Kind: type Collection and document identity for framework-owned cleanup. ```go type DocumentReference struct { CollectionID schema.StableID DocumentID string } ``` ## Values Canonical URL: https://riducms.com/reference/store/values/ Kind: type A map of field names to typed values. ```go type Values map[string]Value ``` ```go values := store.Values{ "title": store.String("Hello, Ridu"), "featured": store.Boolean(true), "viewCount": store.Number(42), } ``` ## Value Canonical URL: https://riducms.com/reference/store/value/ Kind: type A scalar, object, list, or populated document value. ```go type Value struct { kind ValueKind text string object Values document *Document number float64 boolean bool list []Value } ``` ## ValueKind Canonical URL: https://riducms.com/reference/store/value-kind/ Kind: type The adapter-neutral stored value discriminant. ```go type ValueKind string ``` ## CloneValues Canonical URL: https://riducms.com/reference/store/clone-values/ Kind: function Deep-copy a field value map. ```go func CloneValues(values Values) Values ``` ## CloneDocument Canonical URL: https://riducms.com/reference/store/clone-document/ Kind: function Deep-copy document values and localization metadata. ```go func CloneDocument(document Document) Document ``` ## String Canonical URL: https://riducms.com/reference/store/string/ Kind: function Construct a typed string field value. ```go func String(value string) Value ``` ```go ctx.Data["title"] = store.String(strings.TrimSpace(title)) ``` ## Number Canonical URL: https://riducms.com/reference/store/number/ Kind: function Construct a typed number field value. ```go func Number(value float64) Value ``` ## Boolean Canonical URL: https://riducms.com/reference/store/boolean/ Kind: function Construct a typed boolean field value. ```go func Boolean(value bool) Value ``` ## Null Canonical URL: https://riducms.com/reference/store/null/ Kind: function Construct an explicit null field value. ```go func Null() Value ``` ## Object Canonical URL: https://riducms.com/reference/store/object/ Kind: function Construct a defensively copied nested object value. ```go func Object(value Values) Value ``` ## List Canonical URL: https://riducms.com/reference/store/list/ Kind: function Construct a defensively copied list value. ```go func List(values ...Value) Value ``` ## Populated Canonical URL: https://riducms.com/reference/store/populated/ Kind: function Wrap a populated relationship document. ```go func Populated(document Document) Value ``` Populated values are response materializations and must not be persisted as authored reference values. ## Value.StringValue Canonical URL: https://riducms.com/reference/store/value-string-value/ Kind: method Read the string payload when this value has string kind. ```go func (value Value) StringValue() (string, bool) ``` ```go title, ok := ctx.Data["title"].StringValue() if !ok { return nil } ``` ## Status Canonical URL: https://riducms.com/reference/store/status/ Kind: type Draft or published document state. ```go type Status string ``` Constants: StatusDraft and StatusPublished. ## DeletionMode Canonical URL: https://riducms.com/reference/store/deletion-mode/ Kind: type Choose active, trashed, or all documents in a store request. ```go type DeletionMode string ``` Constants: DeletionActive, DeletionTrash, and DeletionAll. ## LockMode Canonical URL: https://riducms.com/reference/store/lock-mode/ Kind: type Row-lock strength required by a semantic read. ```go type LockMode string ``` Constants: LockNone, LockReference, and LockMutation. ## Version Canonical URL: https://riducms.com/reference/store/version/ Kind: type One retained version snapshot for a document. ```go type Version struct { ID string DocumentID string Revision int Status Status Snapshot Document CreatedAt time.Time } ``` ## Page Canonical URL: https://riducms.com/reference/store/page/ Kind: type A paginated result and total count. ```go type Page struct { Documents []Document Page int Limit int Total int } ``` ## DistinctRequest Canonical URL: https://riducms.com/reference/store/distinct-request/ Kind: type One access-filtered unique-value query over a direct field. ```go type DistinctRequest struct { Collection schema.Collection Field query.Path Filter *query.Node Access *query.Node Page int Limit int PublishedOnly bool Deletion DeletionMode Locales []schema.LocaleCode LocaleChain []schema.LocaleCode } ``` ## DistinctPage Canonical URL: https://riducms.com/reference/store/distinct-page/ Kind: type Ascending unique values with ordinary page metadata. ```go type DistinctPage struct { Values []Value Page int Limit int Total int } ``` ## IndexWindow Canonical URL: https://riducms.com/reference/store/index-window/ Kind: type One half-open range over a direct unique index. ```go type IndexWindow struct { Path query.Path LowerBound string UpperBound string } ``` The unique key is the complete deterministic ordering. ## Window Canonical URL: https://riducms.com/reference/store/window/ Kind: type A count-free bounded range result. ```go type Window struct { Documents []Document HasMore bool } ``` ## VersionRequest Canonical URL: https://riducms.com/reference/store/version-request/ Kind: type An access-filtered version-history query. ```go type VersionRequest struct { Collection schema.Collection DocumentID string Access *query.Node Locales []schema.LocaleCode LocaleChain []schema.LocaleCode AllLocales bool } ``` Adapters must apply Access to each stored snapshot before returning it. ## VersionTransaction Canonical URL: https://riducms.com/reference/store/version-transaction/ Kind: interface Same-transaction snapshot persistence and access-filtered history reads. ```go type VersionTransaction interface { SaveVersion(context.Context, schema.Collection, Document, int) (Version, error) ListVersions(context.Context, VersionRequest) ([]Version, error) FindVersion(context.Context, schema.Collection, string, int) (Version, error) } ``` ## SnapshotStore Canonical URL: https://riducms.com/reference/store/snapshot-store/ Kind: interface Begin reads against one stable database snapshot. ```go type SnapshotStore interface { BeginSnapshot(context.Context) (Transaction, error) } ``` Destructive upload reconciliation requires this stronger boundary so pagination cannot skip live references. ## WindowTransaction Canonical URL: https://riducms.com/reference/store/window-transaction/ Kind: interface Optional count-free bounded unique-index range reads. ```go type WindowTransaction interface { ListWindow(context.Context, Request) (Window, error) } ``` LocalAPI.ListWindow requires this capability. Production adapters must preserve the bounded range semantics enforced by ValidateListWindowRequest. ## DistinctTransaction Canonical URL: https://riducms.com/reference/store/distinct-transaction/ Kind: interface Optional access-filtered unique-value reads. ```go type DistinctTransaction interface { Distinct(context.Context, DistinctRequest) (DistinctPage, error) } ``` LocalAPI.Distinct requires this focused capability. ## UploadReferenceTransaction Canonical URL: https://riducms.com/reference/store/upload-reference-transaction/ Kind: interface Find requested upload keys referenced by current, trashed, or versioned documents. ```go type UploadReferenceTransaction interface { ReferencedUploadObjects(context.Context, UploadReferenceRequest) ([]string, error) } ``` Framework-owned cleanup deliberately bypasses document access rules but may return only requested keys. Candidate sets are bounded by MaxUploadReferenceCandidates (65). ## UploadObjectLocker Canonical URL: https://riducms.com/reference/store/upload-object-locker/ Kind: interface Serialize object-key adoption and destructive deletion across processes. ```go type UploadObjectLocker interface { LockUploadObjects(context.Context, []string) (release func(), err error) } ``` Upload-enabled applications require this capability. Acquire keys deterministically and hold them until release or transaction completion. ## HealthStore Canonical URL: https://riducms.com/reference/store/health-store/ Kind: interface Connectivity health check. ```go type HealthStore interface { Ping(context.Context) error } ``` ## ReadinessStore Canonical URL: https://riducms.com/reference/store/readiness-store/ Kind: interface Verify the database is usable by an exact manifest and internally complete migration state. ```go type ReadinessStore interface { Ready(context.Context, schema.Manifest) error } ``` This method does not receive the executable artifact history. Production runtimes use MigrationReadinessStore when the adapter provides it. ## MigrationReadinessStore Canonical URL: https://riducms.com/reference/store/migration-readiness-store/ Kind: interface Verify the complete applied migration ledger against executable history. ```go type MigrationReadinessStore interface { ReadyWithMigrationHistory(context.Context, schema.Manifest, string) error } ``` The string is the exact ordered artifact-history fingerprint embedded by ridu build. Official adapters implement this stronger production contract in addition to ReadinessStore. ## PreferenceStore Canonical URL: https://riducms.com/reference/store/preference-store/ Kind: interface Persist opaque per-user application/admin settings. ```go type PreferenceStore interface { GetPreference(context.Context, schema.StableID, string, string) (Preference, error) SetPreference(context.Context, Preference) (Preference, error) DeletePreference(context.Context, schema.StableID, string, string) error DeletePreferences(context.Context, schema.StableID, string) error } ``` The contract supports both key-scoped deletion and resetting one identity. ## DocumentLockStore Canonical URL: https://riducms.com/reference/store/document-lock-store/ Kind: interface Atomically acquire, refresh, take over, and release authoring locks. ```go type DocumentLockStore interface { FindDocumentLock(context.Context, schema.StableID, string, time.Time) (DocumentLock, error) AcquireDocumentLock(context.Context, DocumentLock, time.Time, bool) (DocumentLock, bool, error) ReleaseDocumentLock(context.Context, schema.StableID, string, schema.StableID, string) error } ``` Lock-enabled collections require this capability. Lock ownership includes both auth collection and actor ID. ## ReferenceDeleteRequest Canonical URL: https://riducms.com/reference/store/reference-delete-request/ Kind: type One permanent-delete reconciliation request. ```go type ReferenceDeleteRequest struct { Target DocumentReference Collections map[schema.StableID]schema.Collection IgnoreOwners []DocumentReference } ``` Transaction.ApplyReferenceDelete must atomically reject restrict policies or nullify/remove current references. Version snapshots remain immutable. ## DeleteRestrictedError Canonical URL: https://riducms.com/reference/store/delete-restricted-error/ Kind: type Deterministic schema constraints preventing permanent deletion. ```go type DeleteRestrictedError struct { Constraints []ReferenceConstraint } ``` It matches ErrDeleteRestricted with errors.Is. Document IDs are omitted to avoid a cross-document existence oracle. ## AuthStore Canonical URL: https://riducms.com/reference/store/auth-store/ Kind: interface Persistence required by auth-enabled collections. ```go type AuthStore interface { // SetPasswordHash replaces a user-controlled password and atomically revokes // every session and API key for that user. SetPasswordHash(context.Context, schema.Collection, string, []byte, bool) error // ChangePasswordHash replaces a password only while its exact stored hash is // the hash verified by the caller. A successful change revokes every session // and API key. Exact hash comparison also fences hard-delete/same-ID // credential recreation because bcrypt salts make each incarnation unique. ChangePasswordHash(context.Context, schema.Collection, string, []byte, []byte) error // UpgradePasswordHash raises the hash work factor after a successful login // without revoking otherwise-valid sessions. The exact-hash compare-and-set // prevents a slow bcrypt upgrade from overwriting a concurrent reset. UpgradePasswordHash(context.Context, schema.Collection, string, []byte, []byte) error FindAuthCredential(context.Context, schema.Collection, string) (AuthCredential, error) RecordFailedLogin(context.Context, schema.StableID, string, time.Time, int, time.Duration) (AuthCredential, error) ResetLoginAttempts(context.Context, schema.StableID, string, time.Time) (bool, error) // CreateSession atomically verifies the exact password hash observed by // password authentication before persisting the new bearer session. CreateSession(context.Context, AuthSession, []byte) error RotateSession(context.Context, string, AuthSession, time.Time) error DeleteSession(context.Context, string) error DeleteUserSession(context.Context, schema.StableID, string, string) error DeleteUserSessions(context.Context, schema.StableID, string) error FindSession(context.Context, string, time.Time) (AuthSession, error) ListSessions(context.Context, schema.StableID, string, time.Time) ([]AuthSession, error) CreateAuthToken(context.Context, AuthToken) error ResetPasswordWithToken(context.Context, schema.StableID, string, []byte, time.Time) (string, error) VerifyEmailWithToken(context.Context, schema.StableID, string, time.Time) (string, error) // CreateAPIKey inserts the key only while the authorizing session remains // active. Password replacement serializes through the same credential row // and therefore cannot leave a late-created key behind. CreateAPIKey(context.Context, AuthAPIKey, string, time.Time) error FindAPIKey(context.Context, string, time.Time) (AuthAPIKey, error) TouchAPIKey(context.Context, string, time.Time) error ListAPIKeys(context.Context, schema.StableID, string, time.Time) ([]AuthAPIKey, error) DeleteAPIKey(context.Context, schema.StableID, string, string) error AllowAuthAttempt(context.Context, string, time.Time, time.Duration, int) (bool, error) } ``` Implementations must make failed-attempt updates and session rotation atomic across processes. Password hashes and token digests are private state and never enter document values, hooks, manifests, or protocol responses. AuthTransaction and AuthBootstrapTransaction bind credential creation to content transactions. ## AuthMaintenanceStore Canonical URL: https://riducms.com/reference/store/auth-maintenance-store/ Kind: interface Bounded pruning of expired auth state. ```go type AuthMaintenanceStore interface { PruneExpiredAuth(context.Context, int) (AuthPruneResult, error) } ``` The implementation uses its authoritative clock, removes at most limit sessions and limit API keys, and must not double-count across concurrent callers. The batch is capped by MaxAuthPruneBatch (500). ## Task Canonical URL: https://riducms.com/reference/store/task/ Kind: type Adapter-neutral durable task data. ```go type Task struct { ID string Slug string Queue string ConcurrencyKey string Input json.RawMessage Output json.RawMessage State TaskState RunAt time.Time Attempts int MaxAttempts int RetryDelay time.Duration MaxRetryDelay time.Duration Backoff TaskBackoff Timeout time.Duration Retention time.Duration LeaseToken string LeaseExpiresAt *time.Time Target *DocumentReference RequestedBy *DocumentReference LastErrorCode string LastError string CreatedAt time.Time UpdatedAt time.Time CompletedAt *time.Time RetainUntil *time.Time } ``` Input/output are data only. Executable typed handlers are compiled into the application and selected from the validated registry by Slug. ## TaskStore Canonical URL: https://riducms.com/reference/store/task-store/ Kind: interface General-purpose durable queue persistence. ```go type TaskStore interface { EnqueueTask(context.Context, Task) (Task, error) FindTask(context.Context, string) (Task, error) ListTasks(context.Context, TaskList) ([]Task, error) CancelTask(context.Context, string) error // DismissTaskForTarget removes one task only when its slug and target match. // This powers target-scoped action lists such as scheduled publishing: every // listed queued, running, failed, or canceled item remains dismissible while // general CancelTask keeps retained cancellation status for typed callers. DismissTaskForTarget(context.Context, string, string, DocumentReference) error ClaimTasks(context.Context, TaskClaim) ([]Task, error) HeartbeatTask(context.Context, string, string, time.Duration) error CompleteTask(context.Context, string, string, json.RawMessage) error FailTask(context.Context, TaskFailure) error ReleaseTask(context.Context, string, string, time.Duration, string, string) error PruneTasks(context.Context, int) (int, error) } ``` Use an authoritative store clock, reclaim expired leases, enforce concurrency keys atomically, and return ErrTaskLeaseLost when the opaque lease token no longer owns running work. Public ValidateTask* functions validate every request boundary. ## TaskState Canonical URL: https://riducms.com/reference/store/task-state/ Kind: type Persisted task lifecycle. ```go type TaskState string ``` ## AuthCredential Canonical URL: https://riducms.com/reference/store/auth-credential/ Kind: type Private password and lockout state associated with one user document. ```go type AuthCredential struct { User Document PasswordHash []byte FailedLoginAttempts int LockedUntil time.Time Verified bool } ``` Never crosses API or manifest boundaries. ## AuthToken Canonical URL: https://riducms.com/reference/store/auth-token/ Kind: type A persisted one-way digest of a single-use recovery secret. ```go type AuthToken struct { TokenHash string Purpose AuthTokenPurpose CollectionID schema.StableID UserID string ExpiresAt time.Time CreatedAt time.Time } ``` ## AuthSession Canonical URL: https://riducms.com/reference/store/auth-session/ Kind: type A persisted opaque session digest and safe metadata. ```go type AuthSession struct { ID string TokenHash string CollectionID schema.StableID UserID string ExpiresAt time.Time CreatedAt time.Time LastSeenAt time.Time IPAddress string UserAgent string } ``` ## AuthAPIKey Canonical URL: https://riducms.com/reference/store/auth-api-key/ Kind: type A persisted API-key digest and safe metadata. ```go type AuthAPIKey struct { ID string TokenHash string CollectionID schema.StableID UserID string Name string CreatedAt time.Time LastUsedAt time.Time ExpiresAt time.Time } ``` ## AuthTransaction Canonical URL: https://riducms.com/reference/store/auth-transaction/ Kind: interface Create private credentials in the owning document transaction. ```go type AuthTransaction interface { CreateAuthCredential(context.Context, schema.Collection, string, []byte, bool) error } ``` ## AuthBootstrapTransaction Canonical URL: https://riducms.com/reference/store/auth-bootstrap-transaction/ Kind: interface Serialize and atomically create the first admin credential. ```go type AuthBootstrapTransaction interface { CreateFirstAuthCredential(context.Context, schema.Collection, string, []byte, bool) error } ``` Must atomically confirm that the new document is the only active user before commit. ## AuthUnlockStore Canonical URL: https://riducms.com/reference/store/auth-unlock-store/ Kind: interface Optional authorized account-lock reset. ```go type AuthUnlockStore interface { ForceUnlock(context.Context, schema.StableID, string) error } ``` ## AuthUnlockTransaction Canonical URL: https://riducms.com/reference/store/auth-unlock-transaction/ Kind: interface Reset account lockout in an already-authorized document transaction. ```go type AuthUnlockTransaction interface { ForceUnlockAuth(context.Context, schema.StableID, string) error } ``` ## AuthPruneResult Canonical URL: https://riducms.com/reference/store/auth-prune-result/ Kind: type Expired session and API-key counts removed by one bounded cycle. ```go type AuthPruneResult struct { Sessions int APIKeys int } ``` Total returns their sum. ## ScheduledPublish Canonical URL: https://riducms.com/reference/store/scheduled-publish/ Kind: type Adapter-neutral revision-fenced future publish record. ```go type ScheduledPublish struct { ID string CollectionID schema.StableID DocumentID string ExpectedRevision int RunAt time.Time Attempts int RequestedByCollectionID schema.StableID RequestedByUserID string LastError string CreatedAt time.Time } ``` ## TaskBackoff Canonical URL: https://riducms.com/reference/store/task-backoff/ Kind: type Persisted deterministic retry schedule. ```go type TaskBackoff string ``` ## TaskClaim Canonical URL: https://riducms.com/reference/store/task-claim/ Kind: type A bounded SKIP LOCKED claim filter and lease. ```go type TaskClaim struct { Limit int Queues []string Slugs []string LeaseDuration time.Duration } ``` ## TaskList Canonical URL: https://riducms.com/reference/store/task-list/ Kind: type Bounded local task inspection filter. ```go type TaskList struct { Slug string Target *DocumentReference States []TaskState Limit int } ``` ## TaskFailure Canonical URL: https://riducms.com/reference/store/task-failure/ Kind: type One lease-fenced attempt failure and optional retry delay. ```go type TaskFailure struct { ID string LeaseToken string Code string Message string // RetryAfter is relative to the store's authoritative clock. Nil makes the // failure terminal; a non-nil duration returns the task to the queue. RetryAfter *time.Duration } ``` Nil RetryAfter is terminal; non-nil returns the task to the queue using the store clock. ## Preference Canonical URL: https://riducms.com/reference/store/preference/ Kind: type One opaque per-user setting. ```go type Preference struct { CollectionID schema.StableID UserID string Key string Value json.RawMessage UpdatedAt time.Time } ``` ## DocumentLock Canonical URL: https://riducms.com/reference/store/document-lock/ Kind: type One expiring exclusive authoring lease. ```go type DocumentLock struct { CollectionID schema.StableID DocumentID string OwnerCollectionID schema.StableID OwnerID string OwnerLabel string CreatedAt time.Time UpdatedAt time.Time ExpiresAt time.Time } ``` ## FilteredSelectionRequest Canonical URL: https://riducms.com/reference/store/filtered-selection-request/ Kind: type Caller and access filters for one bounded frozen selection. ```go type FilteredSelectionRequest struct { Collection schema.Collection Filter *query.Node Access *query.Node Deletion DeletionMode Limit int Locales []schema.LocaleCode LocaleChain []schema.LocaleCode AllLocales bool } ``` ## FilteredSelection Canonical URL: https://riducms.com/reference/store/filtered-selection/ Kind: type Canonical ascending IDs and explicit overflow state. ```go type FilteredSelection struct { IDs []string Overflow bool } ``` ## UploadReferenceRequest Canonical URL: https://riducms.com/reference/store/upload-reference-request/ Kind: type A bounded object-key reference query across upload schemas. ```go type UploadReferenceRequest struct { Collections []schema.Collection ObjectKeys []string } ``` ## ReferenceConstraint Canonical URL: https://riducms.com/reference/store/reference-constraint/ Kind: type The schema owner and field that restrict a hard delete. ```go type ReferenceConstraint struct { OwnerCollectionID schema.StableID FieldID schema.StableID } ``` ## PopulationBudget Canonical URL: https://riducms.com/reference/store/population-budget/ Kind: type A shared recursive population materialization budget. ```go type PopulationBudget struct { mu sync.Mutex remaining int } ``` NewPopulationBudget creates a concurrency-safe budget. ConsumeDocument counts nested populated documents and returns ErrPopulationLimit above the bound. Official adapters initialize the default MaxPopulationMaterializedDocuments (4096) when omitted. ## MaxListWindowDocuments Canonical URL: https://riducms.com/reference/store/max-list-window-documents/ Kind: constant The maximum documents returned by one bounded unique-index window. ```go const MaxListWindowDocuments = 100 ``` ## MaxUploadReferenceCandidates Canonical URL: https://riducms.com/reference/store/max-upload-reference-candidates/ Kind: constant The maximum object-key set accepted by one upload-reference query. ```go const MaxUploadReferenceCandidates = 65 ``` ## MaxPopulationMaterializedDocuments Canonical URL: https://riducms.com/reference/store/max-population-materialized-documents/ Kind: constant The default maximum number of nested documents materialized by one populated response. ```go const MaxPopulationMaterializedDocuments = 4096 ``` ## MaxAuthPruneBatch Canonical URL: https://riducms.com/reference/store/max-auth-prune-batch/ Kind: constant The maximum expired-session or API-key maintenance batch. ```go const MaxAuthPruneBatch = 500 ``` ## MaxTaskPayloadBytes Canonical URL: https://riducms.com/reference/store/max-task-payload-bytes/ Kind: constant The maximum encoded JSON size for durable task input or output. ```go const MaxTaskPayloadBytes = 1 << 20 ``` The limit is 1 MiB. Large files should be stored externally and referenced from the payload. ## MaxTaskErrorBytes Canonical URL: https://riducms.com/reference/store/max-task-error-bytes/ Kind: constant The maximum persisted UTF-8 task failure message size. ```go const MaxTaskErrorBytes = 4096 ``` ## MaxTaskBatch Canonical URL: https://riducms.com/reference/store/max-task-batch/ Kind: constant The maximum task claim, list, prune, queue-filter, or slug-filter batch. ```go const MaxTaskBatch = 500 ``` ## MaxTaskAttempts Canonical URL: https://riducms.com/reference/store/max-task-attempts/ Kind: constant The maximum configured durable task attempt count. ```go const MaxTaskAttempts = 100 ``` ## MaxTaskConcurrencyKeyBytes Canonical URL: https://riducms.com/reference/store/max-task-concurrency-key-bytes/ Kind: constant The maximum UTF-8 byte length of a durable task concurrency key. ```go const MaxTaskConcurrencyKeyBytes = 256 ``` ## MaxTaskReferenceIDBytes Canonical URL: https://riducms.com/reference/store/max-task-reference-id-bytes/ Kind: constant The maximum UTF-8 byte length of each collection or document ID in a task reference. ```go const MaxTaskReferenceIDBytes = MaxDocumentIDBytes ``` ## MaxTaskRetryDelay Canonical URL: https://riducms.com/reference/store/max-task-retry-delay/ Kind: constant The maximum durable task retry delay. ```go const MaxTaskRetryDelay = 30 * 24 * time.Hour ``` The limit is 30 days and must be expressed in whole milliseconds. ## MaxTaskTimeout Canonical URL: https://riducms.com/reference/store/max-task-timeout/ Kind: constant The maximum configured durable task handler timeout. ```go const MaxTaskTimeout = 24 * time.Hour ``` The timeout must be at least one millisecond and use whole milliseconds. ## MinTaskRetention Canonical URL: https://riducms.com/reference/store/min-task-retention/ Kind: constant The minimum retention period for a terminal durable task record. ```go const MinTaskRetention = time.Hour ``` ## MaxTaskRetention Canonical URL: https://riducms.com/reference/store/max-task-retention/ Kind: constant The maximum retention period for a terminal durable task record. ```go const MaxTaskRetention = 365 * 24 * time.Hour ``` The limit is 365 days. ## MaxTaskLeaseDuration Canonical URL: https://riducms.com/reference/store/max-task-lease-duration/ Kind: constant The maximum lease duration for one claimed durable task. ```go const MaxTaskLeaseDuration = 24 * time.Hour ``` Lease durations must be at least one millisecond and use whole milliseconds. ## NewPopulationBudget Canonical URL: https://riducms.com/reference/store/new-population-budget/ Kind: function Create a concurrency-safe recursive population budget. ```go func NewPopulationBudget(limit int) *PopulationBudget ``` A non-positive limit uses MaxPopulationMaterializedDocuments (4096). ## ValidateAuthPruneBatch Canonical URL: https://riducms.com/reference/store/validate-auth-prune-batch/ Kind: function Validate a maintenance batch from 1 through 500. ```go func ValidateAuthPruneBatch(limit int) error ``` ## ValidateListWindowRequest Canonical URL: https://riducms.com/reference/store/validate-list-window-request/ Kind: function Validate one bounded unique-index range request. ```go func ValidateListWindowRequest(request Request) error ``` It rejects IDs, paging offsets, predicates, custom sorting, population, published-only, versioned, and trash reads. ## CanonicalAuthIdentity Canonical URL: https://riducms.com/reference/store/canonical-auth-identity/ Kind: function Normalize an authentication identity to its adapter-neutral storage and lookup key. ```go func CanonicalAuthIdentity(value string) string ``` Adapters must compare this canonical value exactly rather than substituting database collation or case-folding rules. ## ValidateDistinctRequest Canonical URL: https://riducms.com/reference/store/validate-distinct-request/ Kind: function Validate the bounded direct-field distinct contract. ```go func ValidateDistinctRequest(request DistinctRequest) error ``` ## ListPageBounds Canonical URL: https://riducms.com/reference/store/list-page-bounds/ Kind: function Normalize list paging and calculate safe half-open result bounds. ```go func ListPageBounds(page, limit, total int) (normalizedPage, normalizedLimit, start, end int) ``` ## ValidateDocumentID Canonical URL: https://riducms.com/reference/store/validate-document-id/ Kind: function Validate one canonical adapter-neutral document ID. ```go func ValidateDocumentID(id string) error ``` ## Store errors Canonical URL: https://riducms.com/reference/store/store-errors/ Kind: type Stable adapter error sentinels. ```go var ErrNotFound, ErrConflict, ErrAuthInitialized, ErrDeleteRestricted, ErrPopulationLimit, ErrTaskLeaseLost error ``` Adapters must translate native errors to these sentinels so the operation runtime can preserve stable behavior. Use errors.Is rather than matching text. ## AuthTokenPurpose Canonical URL: https://riducms.com/reference/store/auth-token-purpose/ Kind: type Stable single-use authentication token purpose. ```go type AuthTokenPurpose string ``` ## ValidateTaskAdmission Canonical URL: https://riducms.com/reference/store/validate-task-admission/ Kind: function Validate a complete durable task before admission. ```go func ValidateTaskAdmission(task Task) error ``` Custom TaskStore implementations should call this at their direct public boundary and still enforce the corresponding database invariants atomically. ## ValidateTaskPayload Canonical URL: https://riducms.com/reference/store/validate-task-payload/ Kind: function Validate a bounded non-empty JSON task payload. ```go func ValidateTaskPayload(payload json.RawMessage) error ``` Custom TaskStore implementations should call this at their direct public boundary and still enforce the corresponding database invariants atomically. ## ValidateTaskClaim Canonical URL: https://riducms.com/reference/store/validate-task-claim/ Kind: function Validate one worker lease request. ```go func ValidateTaskClaim(request TaskClaim) error ``` Custom TaskStore implementations should call this at their direct public boundary and still enforce the corresponding database invariants atomically. ## ValidateTaskList Canonical URL: https://riducms.com/reference/store/validate-task-list/ Kind: function Validate one task-list query. ```go func ValidateTaskList(request TaskList) error ``` Custom TaskStore implementations should call this at their direct public boundary and still enforce the corresponding database invariants atomically. ## ValidateTaskReference Canonical URL: https://riducms.com/reference/store/validate-task-reference/ Kind: function Validate a lifecycle-safe document reference. ```go func ValidateTaskReference(reference DocumentReference) error ``` Custom TaskStore implementations should call this at their direct public boundary and still enforce the corresponding database invariants atomically. ## ValidateTaskBatch Canonical URL: https://riducms.com/reference/store/validate-task-batch/ Kind: function Validate a prune or adapter batch bound. ```go func ValidateTaskBatch(limit int) error ``` Custom TaskStore implementations should call this at their direct public boundary and still enforce the corresponding database invariants atomically. ## ValidateTaskLeaseDuration Canonical URL: https://riducms.com/reference/store/validate-task-lease-duration/ Kind: function Validate an operationally bounded task lease. ```go func ValidateTaskLeaseDuration(duration time.Duration) error ``` Custom TaskStore implementations should call this at their direct public boundary and still enforce the corresponding database invariants atomically. ## ValidateTaskFailure Canonical URL: https://riducms.com/reference/store/validate-task-failure/ Kind: function Validate persisted failure and retry metadata. ```go func ValidateTaskFailure(failure TaskFailure) error ``` Custom TaskStore implementations should call this at their direct public boundary and still enforce the corresponding database invariants atomically. ## ValidateTaskRelease Canonical URL: https://riducms.com/reference/store/validate-task-release/ Kind: function Validate worker lease-release delay and failure metadata. ```go func ValidateTaskRelease(delay time.Duration, code, message string) error ``` Custom TaskStore implementations should call this at their direct public boundary and preserve lease ownership atomically. ## AuthPruneResult.Total Canonical URL: https://riducms.com/reference/store/auth-prune-result-total-method/ Kind: method Total returns the complete number of expired records removed by the cycle. ```go func (result AuthPruneResult) Total() int ``` ## AuthTokenPasswordReset Canonical URL: https://riducms.com/reference/store/auth-token-password-reset/ Kind: constant Public constant AuthTokenPasswordReset from github.com/riducms/ridu/store. ```go const AuthTokenPasswordReset AuthTokenPurpose = "password_reset" ``` ## AuthTokenVerifyEmail Canonical URL: https://riducms.com/reference/store/auth-token-verify-email/ Kind: constant Public constant AuthTokenVerifyEmail from github.com/riducms/ridu/store. ```go const AuthTokenVerifyEmail AuthTokenPurpose = "verify_email" ``` ## DeleteRestrictedError.Error Canonical URL: https://riducms.com/reference/store/delete-restricted-error-error-method/ Kind: method Public method DeleteRestrictedError.Error from github.com/riducms/ridu/store. ```go func (err *DeleteRestrictedError) Error() string ``` ## DeleteRestrictedError.Is Canonical URL: https://riducms.com/reference/store/delete-restricted-error-is-method/ Kind: method Public method DeleteRestrictedError.Is from github.com/riducms/ridu/store. ```go func (err *DeleteRestrictedError) Is(target error) bool ``` ## DeletionActive Canonical URL: https://riducms.com/reference/store/deletion-active/ Kind: constant Public constant DeletionActive from github.com/riducms/ridu/store. ```go const DeletionActive DeletionMode = "" ``` ## DeletionAll Canonical URL: https://riducms.com/reference/store/deletion-all/ Kind: constant Public constant DeletionAll from github.com/riducms/ridu/store. ```go const DeletionAll DeletionMode = "all" ``` ## DeletionTrash Canonical URL: https://riducms.com/reference/store/deletion-trash/ Kind: constant Public constant DeletionTrash from github.com/riducms/ridu/store. ```go const DeletionTrash DeletionMode = "trash" ``` ## ErrAuthInitialized Canonical URL: https://riducms.com/reference/store/err-auth-initialized/ Kind: variable Public variable ErrAuthInitialized from github.com/riducms/ridu/store. ```go var ErrAuthInitialized = errors.New("auth collection is already initialized") ``` ## ErrConflict Canonical URL: https://riducms.com/reference/store/err-conflict/ Kind: variable Public variable ErrConflict from github.com/riducms/ridu/store. ```go var ErrConflict = errors.New("document conflict") ``` ## ErrDeleteRestricted Canonical URL: https://riducms.com/reference/store/err-delete-restricted/ Kind: variable Public variable ErrDeleteRestricted from github.com/riducms/ridu/store. ```go var ErrDeleteRestricted = errors.New("document deletion is restricted by references") ``` ## ErrNotFound Canonical URL: https://riducms.com/reference/store/err-not-found/ Kind: variable Public variable ErrNotFound from github.com/riducms/ridu/store. ```go var ErrNotFound = errors.New("document not found") ``` ## ErrPopulationLimit Canonical URL: https://riducms.com/reference/store/err-population-limit/ Kind: variable Public variable ErrPopulationLimit from github.com/riducms/ridu/store. ```go var ErrPopulationLimit = errors.New("population materialization limit exceeded") ``` ## ErrTaskLeaseLost Canonical URL: https://riducms.com/reference/store/err-task-lease-lost/ Kind: variable Public variable ErrTaskLeaseLost from github.com/riducms/ridu/store. ```go var ErrTaskLeaseLost = errors.New("task lease was lost") ``` ## LockMutation Canonical URL: https://riducms.com/reference/store/lock-mutation/ Kind: constant Public constant LockMutation from github.com/riducms/ridu/store. ```go const LockMutation LockMode = "mutation" ``` ## LockNone Canonical URL: https://riducms.com/reference/store/lock-none/ Kind: constant Public constant LockNone from github.com/riducms/ridu/store. ```go const LockNone LockMode = "" ``` ## LockReference Canonical URL: https://riducms.com/reference/store/lock-reference/ Kind: constant Public constant LockReference from github.com/riducms/ridu/store. ```go const LockReference LockMode = "reference" ``` ## MaxDocumentIDBytes Canonical URL: https://riducms.com/reference/store/max-document-id-bytes/ Kind: constant MaxDocumentIDBytes keeps canonical IDs representable anywhere Ridu persists a document reference, including scheduled publishing and auth-owned tasks. ```go const MaxDocumentIDBytes = 512 ``` ## PopulationBudget.ConsumeDocument Canonical URL: https://riducms.com/reference/store/population-budget-consume-document-method/ Kind: method ConsumeDocument reserves enough budget for document and every populated document already nested beneath it. The reservation happens before an adapter deep-clones the document into its parent response. ```go func (budget *PopulationBudget) ConsumeDocument(document Document) error ``` ## StatusDraft Canonical URL: https://riducms.com/reference/store/status-draft/ Kind: constant Public constant StatusDraft from github.com/riducms/ridu/store. ```go const StatusDraft Status = "draft" ``` ## StatusPublished Canonical URL: https://riducms.com/reference/store/status-published/ Kind: constant Public constant StatusPublished from github.com/riducms/ridu/store. ```go const StatusPublished Status = "published" ``` ## TaskBackoffExponential Canonical URL: https://riducms.com/reference/store/task-backoff-exponential/ Kind: constant Public constant TaskBackoffExponential from github.com/riducms/ridu/store. ```go const TaskBackoffExponential TaskBackoff = "exponential" ``` ## TaskBackoffFixed Canonical URL: https://riducms.com/reference/store/task-backoff-fixed/ Kind: constant Public constant TaskBackoffFixed from github.com/riducms/ridu/store. ```go const TaskBackoffFixed TaskBackoff = "fixed" ``` ## TaskBackoffLinear Canonical URL: https://riducms.com/reference/store/task-backoff-linear/ Kind: constant Public constant TaskBackoffLinear from github.com/riducms/ridu/store. ```go const TaskBackoffLinear TaskBackoff = "linear" ``` ## TaskStateCanceled Canonical URL: https://riducms.com/reference/store/task-state-canceled/ Kind: constant Public constant TaskStateCanceled from github.com/riducms/ridu/store. ```go const TaskStateCanceled TaskState = "canceled" ``` ## TaskStateFailed Canonical URL: https://riducms.com/reference/store/task-state-failed/ Kind: constant Public constant TaskStateFailed from github.com/riducms/ridu/store. ```go const TaskStateFailed TaskState = "failed" ``` ## TaskStateQueued Canonical URL: https://riducms.com/reference/store/task-state-queued/ Kind: constant Public constant TaskStateQueued from github.com/riducms/ridu/store. ```go const TaskStateQueued TaskState = "queued" ``` ## TaskStateRunning Canonical URL: https://riducms.com/reference/store/task-state-running/ Kind: constant Public constant TaskStateRunning from github.com/riducms/ridu/store. ```go const TaskStateRunning TaskState = "running" ``` ## TaskStateSucceeded Canonical URL: https://riducms.com/reference/store/task-state-succeeded/ Kind: constant Public constant TaskStateSucceeded from github.com/riducms/ridu/store. ```go const TaskStateSucceeded TaskState = "succeeded" ``` ## Value.BooleanValue Canonical URL: https://riducms.com/reference/store/value-boolean-value-method/ Kind: method Public method Value.BooleanValue from github.com/riducms/ridu/store. ```go func (value Value) BooleanValue() (bool, bool) ``` ## Value.DocumentValue Canonical URL: https://riducms.com/reference/store/value-document-value-method/ Kind: method Public method Value.DocumentValue from github.com/riducms/ridu/store. ```go func (value Value) DocumentValue() (Document, bool) ``` ## Value.Kind Canonical URL: https://riducms.com/reference/store/value-kind-method/ Kind: method Public method Value.Kind from github.com/riducms/ridu/store. ```go func (value Value) Kind() ValueKind ``` ## Value.MarshalJSON Canonical URL: https://riducms.com/reference/store/value-marshal-json-method/ Kind: method Public method Value.MarshalJSON from github.com/riducms/ridu/store. ```go func (value Value) MarshalJSON() ([]byte, error) ``` ## Value.NumberValue Canonical URL: https://riducms.com/reference/store/value-number-value-method/ Kind: method Public method Value.NumberValue from github.com/riducms/ridu/store. ```go func (value Value) NumberValue() (float64, bool) ``` ## Value.ObjectValue Canonical URL: https://riducms.com/reference/store/value-object-value-method/ Kind: method Public method Value.ObjectValue from github.com/riducms/ridu/store. ```go func (value Value) ObjectValue() (Values, bool) ``` ## Value.UnmarshalJSON Canonical URL: https://riducms.com/reference/store/value-unmarshal-json-method/ Kind: method Public method Value.UnmarshalJSON from github.com/riducms/ridu/store. ```go func (value *Value) UnmarshalJSON(encoded []byte) error ``` ## Value.Values Canonical URL: https://riducms.com/reference/store/value-values-method/ Kind: method Public method Value.Values from github.com/riducms/ridu/store. ```go func (value Value) Values() ([]Value, bool) ``` ## ValueBoolean Canonical URL: https://riducms.com/reference/store/value-boolean/ Kind: constant Public constant ValueBoolean from github.com/riducms/ridu/store. ```go const ValueBoolean ValueKind = "boolean" ``` ## ValueDocument Canonical URL: https://riducms.com/reference/store/value-document/ Kind: constant Public constant ValueDocument from github.com/riducms/ridu/store. ```go const ValueDocument ValueKind = "document" ``` ## ValueList Canonical URL: https://riducms.com/reference/store/value-list/ Kind: constant Public constant ValueList from github.com/riducms/ridu/store. ```go const ValueList ValueKind = "list" ``` ## ValueNull Canonical URL: https://riducms.com/reference/store/value-null/ Kind: constant Public constant ValueNull from github.com/riducms/ridu/store. ```go const ValueNull ValueKind = "null" ``` ## ValueNumber Canonical URL: https://riducms.com/reference/store/value-number/ Kind: constant Public constant ValueNumber from github.com/riducms/ridu/store. ```go const ValueNumber ValueKind = "number" ``` ## ValueObject Canonical URL: https://riducms.com/reference/store/value-object/ Kind: constant Public constant ValueObject from github.com/riducms/ridu/store. ```go const ValueObject ValueKind = "object" ``` ## ValueString Canonical URL: https://riducms.com/reference/store/value-string/ Kind: constant Public constant ValueString from github.com/riducms/ridu/store. ```go const ValueString ValueKind = "string" ``` --- # API Reference: storage Canonical URL: https://riducms.com/reference/storage/ Package: github.com/riducms/ridu/storage Object-storage contracts used by upload collections. Implement this package only when the official local and S3 backends do not fit. ## Backend Canonical URL: https://riducms.com/reference/storage/backend/ Kind: interface Store, open, list, and delete upload objects. ```go type Backend interface { Put(context.Context, string, io.Reader, int64, string) error Open(context.Context, string) (io.ReadCloser, Object, error) Delete(context.Context, string) error List(context.Context, ListRequest) (ListPage, error) } ``` Put must atomically replace an existing key. Delete of a missing key must succeed. List returns a bounded, unique, key-ordered page under the requested prefix and every result has an authoritative non-zero ModifiedAt. Ridu revalidates namespace ownership and committed upload references immediately before orphan cleanup. Return storage.ErrNotFound from Open when appropriate. ## MaxListPageSize Canonical URL: https://riducms.com/reference/storage/max-list-page-size/ Kind: constant The maximum number of objects one List response may contain. ```go const MaxListPageSize = 1_000 ``` ## ListRequest Canonical URL: https://riducms.com/reference/storage/list-request/ Kind: type A bounded object-listing request. ```go type ListRequest struct { Prefix string Cursor string Limit int } ``` Cursor is opaque and must come unchanged from the preceding ListPage. ## ListPage Canonical URL: https://riducms.com/reference/storage/list-page/ Kind: type One stable page of object metadata. ```go type ListPage struct { Objects []Object NextCursor string } ``` NextCursor is empty only on the final page. ## Object Canonical URL: https://riducms.com/reference/storage/object/ Kind: type Object identity and authoritative content metadata. ```go type Object struct { Key string Size int64 ContentType string // ModifiedAt must be non-zero for every object returned by List. Ridu uses // it to enforce the reconciliation grace period and refuses cleanup when it // is unavailable. ModifiedAt time.Time } ``` ## ErrNotFound Canonical URL: https://riducms.com/reference/storage/err-not-found/ Kind: variable The sentinel returned when an object does not exist. ```go var ErrNotFound = errors.New("object not found") ``` ## HealthBackend Canonical URL: https://riducms.com/reference/storage/health-backend/ Kind: interface Optional production readiness check for the storage dependency. ```go type HealthBackend interface { Ping(context.Context) error } ``` Ridu includes Ping in /readyz when available. Keep it context-bounded, read-only, and safe to call repeatedly. ## URLSigner Canonical URL: https://riducms.com/reference/storage/url-signer/ Kind: interface Create explicit, time-limited direct-download URLs. ```go type URLSigner interface { SignedURL(context.Context, string, time.Duration) (string, error) } ``` Private delivery is normally mediated by Ridu. URLSigner is optional and intended only for deliberate direct-download flows. --- # API Reference: migration Canonical URL: https://riducms.com/reference/migration/ Package: github.com/riducms/ridu/migration Advanced, database-independent vocabulary for immutable and reviewable migration artifacts. ## Artifact Canonical URL: https://riducms.com/reference/migration/artifact/ Kind: type The immutable definition of one migration. ```go type Artifact struct { // Version identifies this Ridu artifact JSON format. Version uint32 `json:"version"` // Name is the lowercase author-supplied migration name. Name string `json:"name"` // Planner records the exact planner and version used at creation. Planner Planner `json:"planner"` // MinimumRunnerContract is the lowest execution contract that may run // every phase and executor in this artifact. MinimumRunnerContract uint32 `json:"minimumRunnerContract,omitempty"` // PreviousArtifactDigest binds this artifact to the exact preceding artifact, // including data-only transitions whose manifest digest does not change. // It is empty only for the initial artifact. PreviousArtifactDigest string `json:"previousArtifactDigest"` // FromDigest and ToDigest establish immutable manifest lineage. FromDigest string `json:"fromDigest"` ToDigest string `json:"toDigest"` // Before is absent only for an initial migration from an empty schema. Before *schema.Snapshot `json:"before,omitempty"` // After is the complete desired manifest after every step succeeds. After schema.Snapshot `json:"after"` // Phases are the resumable execution plan. Phases []Phase `json:"phases"` // Risks retains machine-readable planner and linter findings for review. Risks []Risk `json:"risks"` codec *artifactCodecState } ``` ArtifactVersion is 1. Incompatible historical formats are intentionally unsupported. Application authors normally use ridu migrate commands and review the artifact rather than construct it by hand. ## ArtifactVersion Canonical URL: https://riducms.com/reference/migration/artifact-version/ Kind: constant The immutable migration artifact format emitted by this release. ```go const ArtifactVersion uint32 = 1 ``` ## ArtifactIdentity Canonical URL: https://riducms.com/reference/migration/artifact-identity/ Kind: type One migration file identity used to bind an executable to committed history. ```go type ArtifactIdentity struct { Name string `json:"name"` Digest string `json:"digest"` } ``` Name is the ordered filename stored by the adapter ledger. Digest is the lowercase SHA-256 identity of the canonical artifact. ## DigestArtifactHistory Canonical URL: https://riducms.com/reference/migration/digest-artifact-history/ Kind: function Hash one complete ordered migration filename/digest history. ```go func DigestArtifactHistory(identities []ArtifactIdentity) (string, error) ``` Rejects empty, malformed, duplicate, or out-of-order identities before returning the deterministic SHA-256 fingerprint embedded by ridu build. ## NewArtifact Canonical URL: https://riducms.com/reference/migration/new-artifact/ Kind: function Create an artifact shell with embedded manifest lineage. ```go func NewArtifact(name string, planner Planner, before *schema.Manifest, after schema.Manifest) (Artifact, error) ``` Store adapters populate reviewed physical and semantic execution steps after construction. ## DecodeArtifact Canonical URL: https://riducms.com/reference/migration/decode-artifact/ Kind: function Strictly decode and validate supported artifact JSON. ```go func DecodeArtifact(encoded []byte) (Artifact, error) ``` Rejects unknown fields, duplicate JSON keys, and embedded manifests that do not use the current schema contract. ## DigestManifest Canonical URL: https://riducms.com/reference/migration/digest-manifest/ Kind: function Hash canonical manifest bytes with SHA-256. ```go func DigestManifest(manifest schema.Manifest) (string, error) ``` ## Risk Canonical URL: https://riducms.com/reference/migration/risk/ Kind: type A stable machine-readable planning finding. ```go type Risk struct { // Code is a stable identifier suitable for CI policy. Code string `json:"code"` // Level classifies whether the finding is informational, risky, or destructive. Level RiskLevel `json:"level"` // Message explains the concrete impact and required review. Message string `json:"message"` } ``` Risk levels are notice, warning, and destructive. CI can use Code and Level; Message explains the concrete review requirement. ## RiskLevel Canonical URL: https://riducms.com/reference/migration/risk-level/ Kind: type Notice, warning, or destructive operational impact. ```go type RiskLevel string ``` ## StepKind Canonical URL: https://riducms.com/reference/migration/step-kind/ Kind: type The closed migration executor vocabulary. ```go type StepKind string ``` ## Rename Canonical URL: https://riducms.com/reference/migration/rename/ Kind: type Explicit committed content-identity intent. ```go type Rename struct { // CollectionBefore and CollectionAfter are current public slugs. CollectionBefore schema.CollectionSlug `json:"collectionBefore"` CollectionAfter schema.CollectionSlug `json:"collectionAfter"` // FieldBefore and FieldAfter are canonical field paths. Empty paths mean the // rename applies to the collection itself. FieldBefore string `json:"fieldBefore,omitempty"` FieldAfter string `json:"fieldAfter,omitempty"` // Fields records every nested or top-level field path whose identity changed // as part of a collection rename. Fields []FieldRename `json:"fields,omitempty"` } ``` Inference may propose a rename, but runners execute only persisted intent. Collection renames include all nested/top-level field identity changes. ## FieldRename Canonical URL: https://riducms.com/reference/migration/field-rename/ Kind: type One explicit authored field-path continuity inside a collection rename. ```go type FieldRename struct { // Before is the canonical field path in the before manifest. Before string `json:"before"` // After is the canonical field path in the after manifest. After string `json:"after"` } ``` ## Operation Canonical URL: https://riducms.com/reference/migration/operation/ Kind: type One physical or semantic planner operation before checkpointed phases are built. ```go type Operation struct { // Kind selects the runner behavior. Kind StepKind `json:"kind"` // Name is a stable, review-friendly operation label. Name string `json:"name"` // SQL is present only for StepSQL. SQL string `json:"sql,omitempty"` // Rename is present only for StepRenameContent. Rename *Rename `json:"rename,omitempty"` // Plugin is present only for StepPluginSQL. Plugin *PluginStep `json:"plugin,omitempty"` // ResourceIDs is present only while planning a StepRetireResources step. ResourceIDs []schema.StableID `json:"resourceIds,omitempty"` // PurgeVersionOwnerIDs identifies surviving resources whose complete // historical version rows could otherwise restore references to a retired // resource. It is present only while planning StepRetireResources. PurgeVersionOwnerIDs []schema.StableID `json:"purgeVersionOwnerIds,omitempty"` // AuthIdentities is present only while planning a // StepCanonicalizeAuthIdentities step. AuthIdentities []AuthIdentityResource `json:"authIdentities,omitempty"` } ``` Store adapters convert operations into immutable Phase and Step values before writing an artifact. ## AuthIdentityResource Canonical URL: https://riducms.com/reference/migration/auth-identity-resource/ Kind: type One authored authentication identity field bound to immutable schema identity. ```go type AuthIdentityResource struct { CollectionID schema.StableID `json:"collectionId"` FieldID schema.StableID `json:"fieldId"` FieldName string `json:"fieldName"` } ``` Collection and field IDs keep the migration bound to the same resource while FieldName addresses JSON-document adapters. ## PluginStep Canonical URL: https://riducms.com/reference/migration/plugin-step/ Kind: type One checksum-protected direction of a plugin-owned migration. ```go type PluginStep struct { Adapter schema.PluginDatabaseAdapter `json:"adapter"` Plugin string `json:"plugin"` Version uint32 `json:"version"` Direction string `json:"direction"` Checksum string `json:"checksum"` SQL []string `json:"sql"` } ``` ## PluginStepChecksum Canonical URL: https://riducms.com/reference/migration/plugin-step-checksum/ Kind: function Compute the stable identity of ordered plugin SQL. ```go func PluginStepChecksum(adapter schema.PluginDatabaseAdapter, plugin string, version uint32, direction string, statements []string) string ``` ## DataTransformDescriptor Canonical URL: https://riducms.com/reference/migration/data-transform-descriptor/ Kind: type Immutable artifact identity for one compiled migration callback. ```go type DataTransformDescriptor struct { Name string `json:"name"` Checksum string `json:"checksum"` } ``` ## DataTransaction Canonical URL: https://riducms.com/reference/migration/data-transaction/ Kind: interface Transaction-bound content operations available to a compiled migration callback. ```go type DataTransaction interface { Create(context.Context, store.CreateRequest) (store.Document, error) Find(context.Context, store.Request) (store.Document, error) List(context.Context, store.Request) (store.Page, error) Update(context.Context, store.UpdateRequest) (store.Document, error) Trash(context.Context, store.Request) (store.Document, error) Restore(context.Context, store.Request) (store.Document, error) Delete(context.Context, store.Request) (store.Document, error) } ``` ## DataTransformCallback Canonical URL: https://riducms.com/reference/migration/data-transform-callback/ Kind: type One compiled direction of a reviewed data migration. ```go type DataTransformCallback func(context.Context, DataTransaction) error ``` ## DataTransform Canonical URL: https://riducms.com/reference/migration/data-transform/ Kind: type Executable up and down callbacks bound to an immutable descriptor. ```go type DataTransform struct { DataTransformDescriptor Up DataTransformCallback Down DataTransformCallback } ``` ## DataTransformChecksum Canonical URL: https://riducms.com/reference/migration/data-transform-checksum/ Kind: function Compute the lowercase SHA-256 identity of reviewed callback source bytes. ```go func DataTransformChecksum(source []byte) string ``` ## ProjectAction Canonical URL: https://riducms.com/reference/migration/project-action/ Kind: type Lifecycle operation delegated to an application’s compiled migration driver. ```go type ProjectAction string ``` ## ProjectRequest Canonical URL: https://riducms.com/reference/migration/project-request/ Kind: type Structural paths selected by a portable project migration command. ```go type ProjectRequest struct { Action ProjectAction DatabasePath string DatabaseURL string Directory string AllowInsecureDatabase bool AllowMaintenance bool AllowUnbounded bool LockWait time.Duration OperationTimeout time.Duration LockTimeout time.Duration StatementTimeout time.Duration BatchTimeout time.Duration IdleTransactionTimeout time.Duration StopAfterPhase string StopAfterStep string } ``` ## ProjectDriver Canonical URL: https://riducms.com/reference/migration/project-driver/ Kind: interface Application-compiled callbacks behind adapter-owned project migration commands. ```go type ProjectDriver interface { // Validate checks the complete executable registration before a project // command resolves config or changes database state. Validate() error DataTransforms() []DataTransformDescriptor // RunProjectMigration receives the exact manifest resolved by the process // that will execute the request. The driver must validate it against the // selected artifact history before opening or changing the database. RunProjectMigration(context.Context, ProjectRequest, schema.Manifest) error } ``` ## Phase Canonical URL: https://riducms.com/reference/migration/phase/ Kind: type One resumable execution boundary. ```go type Phase struct { ID string `json:"id"` Mode PhaseMode `json:"mode"` PhysicalContractVersion uint32 `json:"physicalContractVersion"` BeforePhysicalDigest string `json:"beforePhysicalDigest"` AfterPhysicalDigest string `json:"afterPhysicalDigest"` Steps []Step `json:"steps"` } ``` Modes are transaction, batch, and no_transaction. Batch and no-transaction phases contain exactly one typed step. ## Planner Canonical URL: https://riducms.com/reference/migration/planner/ Kind: type Planner name and version recorded on a migration artifact. ```go type Planner struct { Name string `json:"name"` Version string `json:"version"` } ``` ## PhaseMode Canonical URL: https://riducms.com/reference/migration/phase-mode/ Kind: type The transaction boundary for a resumable phase. ```go type PhaseMode string ``` ## SQLPayload Canonical URL: https://riducms.com/reference/migration/sql-payload/ Kind: type One transactional SQL statement. ```go type SQLPayload struct { SQL string `json:"sql"` } ``` ## RenamePayload Canonical URL: https://riducms.com/reference/migration/rename-payload/ Kind: type Explicit content-identity continuity payload. ```go type RenamePayload struct { Rename Rename `json:"rename"` } ``` ## PluginPayload Canonical URL: https://riducms.com/reference/migration/plugin-payload/ Kind: type Checksum-protected plugin SQL payload. ```go type PluginPayload struct { Plugin PluginStep `json:"plugin"` } ``` ## DataTransformPayload Canonical URL: https://riducms.com/reference/migration/data-transform-payload/ Kind: type Artifact-safe identity for one application-compiled callback. ```go type DataTransformPayload struct { Transform DataTransformDescriptor `json:"transform"` } ``` ## BackfillReferencesPayload Canonical URL: https://riducms.com/reference/migration/backfill-references-payload/ Kind: type Resumable keyset-batch reference backfill settings. ```go type BackfillReferencesPayload struct { BatchSize uint32 `json:"batchSize"` } ``` ## RetireResourcesPayload Canonical URL: https://riducms.com/reference/migration/retire-resources-payload/ Kind: type Stable resource identities retired by one bounded cleanup. ```go type RetireResourcesPayload struct { ResourceIDs []schema.StableID `json:"resourceIds"` PurgeVersionOwnerIDs []schema.StableID `json:"purgeVersionOwnerIds,omitempty"` } ``` IDs are artifact-reviewed stable identities, not mutable collection slugs. ## CanonicalizeAuthIdentitiesPayload Canonical URL: https://riducms.com/reference/migration/canonicalize-auth-identities-payload/ Kind: type Auth identity fields moved to the shared canonical-key contract. ```go type CanonicalizeAuthIdentitiesPayload struct { Resources []AuthIdentityResource `json:"resources"` } ``` ## AssertSchemaPayload Canonical URL: https://riducms.com/reference/migration/assert-schema-payload/ Kind: type The closed marker payload for a reviewed physical-schema assertion. ```go type AssertSchemaPayload struct{} ``` ## ConcurrentIndexAction Canonical URL: https://riducms.com/reference/migration/concurrent-index-action/ Kind: type A closed create or drop action for a non-transactional index phase. ```go type ConcurrentIndexAction string ``` ## ConcurrentIndexPayload Canonical URL: https://riducms.com/reference/migration/concurrent-index-payload/ Kind: type A structured concurrent-index operation without free-form non-transaction SQL. ```go type ConcurrentIndexPayload struct { Action ConcurrentIndexAction `json:"action"` Name string `json:"name"` Table string `json:"table,omitempty"` Unique bool `json:"unique,omitempty"` Method string `json:"method,omitempty"` Parts []string `json:"parts,omitempty"` Predicate string `json:"predicate,omitempty"` } ``` ## MongoDBCreateIndexPayload Canonical URL: https://riducms.com/reference/migration/mongodb-create-index-payload/ Kind: type Physical identity for one planner-owned MongoDB index. ```go type MongoDBCreateIndexPayload struct { Collection string `json:"collection"` Index string `json:"index"` } ``` The adapter reconstructs the exact index definition from the embedded manifest and versioned planner; BSON commands are not serialized into the artifact. ## MongoDBDropIndexPayload Canonical URL: https://riducms.com/reference/migration/mongodb-drop-index-payload/ Kind: type Physical identity for one exact planner-owned MongoDB index removal. ```go type MongoDBDropIndexPayload struct { CollectionID schema.StableID `json:"collectionId"` Version bool `json:"version,omitempty"` Index string `json:"index"` } ``` The adapter derives the content or version collection from the stable resource identity and reconstructs the reviewed index from the embedded manifests. ## MongoDBRenameResourcePayload Canonical URL: https://riducms.com/reference/migration/mongodb-rename-resource-payload/ Kind: type One confirmed MongoDB collection-identity move without serialized namespace names. ```go type MongoDBRenameResourcePayload struct { BeforeID schema.StableID `json:"beforeId"` AfterID schema.StableID `json:"afterId"` } ``` The adapter derives the exact current-content and version namespaces from the immutable before and after manifests. ## MongoDBDropResourcesPayload Canonical URL: https://riducms.com/reference/migration/mongodb-drop-resources-payload/ Kind: type The exact reviewed stable identities whose MongoDB namespaces are retired. ```go type MongoDBDropResourcesPayload struct { ResourceIDs []schema.StableID `json:"resourceIds"` } ``` The IDs must match the preceding typed semantic-retirement step; arbitrary collection names cannot enter the artifact. ## Step Canonical URL: https://riducms.com/reference/migration/step/ Kind: type One stable independently ledgered executor invocation. ```go type Step struct { ID string `json:"id"` Kind StepKind `json:"kind"` ExecutorVersion uint32 `json:"executorVersion"` Name string `json:"name"` Payload json.RawMessage `json:"payload"` } ``` Payloads are typed: SQL, rename, plugin SQL, reference backfill, resource retirement, schema assertion, or closed concurrent-index operations. Arbitrary SQL is never admitted outside a transaction. ## MarshalStepPayload Canonical URL: https://riducms.com/reference/migration/marshal-step-payload/ Kind: function Encode a compact deterministic typed step payload. ```go func MarshalStepPayload(value any) (json.RawMessage, error) ``` ## PhysicalDigestSeed Canonical URL: https://riducms.com/reference/migration/physical-digest-seed/ Kind: function Create the initial reviewed physical-contract digest. ```go func PhysicalDigestSeed(fromManifestDigest string) string ``` ## PhasePhysicalDigest Canonical URL: https://riducms.com/reference/migration/phase-physical-digest/ Kind: function Advance the physical contract through one complete phase. ```go func PhasePhysicalDigest(before string, mode PhaseMode, steps []Step) (string, error) ``` ## Runner contracts Canonical URL: https://riducms.com/reference/migration/runner-contracts/ Kind: type Execution contract constants. ```go const RunnerContractVersion = 1; const PhysicalContractVersion = 1 ``` Artifacts require the current deterministic runner and physical contract. ## AuthIdentityResources Canonical URL: https://riducms.com/reference/migration/auth-identity-resources/ Kind: function Return the deterministic complete authentication-identity field scope for a manifest snapshot. ```go func AuthIdentityResources(snapshot schema.Snapshot) []AuthIdentityResource ``` ## RetainedAuthIdentityResources Canonical URL: https://riducms.com/reference/migration/retained-auth-identity-resources/ Kind: function Return identity fields unchanged across two manifest snapshots. ```go func RetainedAuthIdentityResources(before, after schema.Snapshot) []AuthIdentityResource ``` Forward canonicalization excludes newly introduced authentication resources until adapter-owned physical storage exists. ## Artifact.AfterManifest Canonical URL: https://riducms.com/reference/migration/artifact-after-manifest-method/ Kind: method AfterManifest returns the validated immutable after snapshot. ```go func (artifact Artifact) AfterManifest() (schema.Manifest, error) ``` ## Artifact.BeforeManifest Canonical URL: https://riducms.com/reference/migration/artifact-before-manifest-method/ Kind: method BeforeManifest returns the validated immutable before snapshot. Initial artifacts return an error because they intentionally have no parent state. ```go func (artifact Artifact) BeforeManifest() (schema.Manifest, error) ``` ## Artifact.Digest Canonical URL: https://riducms.com/reference/migration/artifact-digest-method/ Kind: method Digest returns the SHA-256 digest of the canonical artifact JSON. ```go func (artifact Artifact) Digest() (string, error) ``` ## Artifact.MarshalJSON Canonical URL: https://riducms.com/reference/migration/artifact-marshal-json-method/ Kind: method MarshalJSON emits the frozen artifact wire contract. ```go func (artifact Artifact) MarshalJSON() ([]byte, error) ``` ## Artifact.UnmarshalJSON Canonical URL: https://riducms.com/reference/migration/artifact-unmarshal-json-method/ Kind: method UnmarshalJSON uses the same fail-closed versioned decoder as artifact files. ```go func (artifact *Artifact) UnmarshalJSON(encoded []byte) error ``` ## Artifact.Validate Canonical URL: https://riducms.com/reference/migration/artifact-validate-method/ Kind: method Validate checks the planner-owned structure and manifest lineage of an artifact plan. Publication binds a non-initial plan to its exact predecessor; serialization and digesting reject the plan until that binding exists. ```go func (artifact Artifact) Validate() error ``` ## ConcurrentIndexCreate Canonical URL: https://riducms.com/reference/migration/concurrent-index-create/ Kind: constant Public constant ConcurrentIndexCreate from github.com/riducms/ridu/migration. ```go const ConcurrentIndexCreate ConcurrentIndexAction = "create" ``` ## ConcurrentIndexDrop Canonical URL: https://riducms.com/reference/migration/concurrent-index-drop/ Kind: constant Public constant ConcurrentIndexDrop from github.com/riducms/ridu/migration. ```go const ConcurrentIndexDrop ConcurrentIndexAction = "drop" ``` ## DataTransform.Validate Canonical URL: https://riducms.com/reference/migration/data-transform-validate-method/ Kind: method Validate checks the immutable and executable portions of a registration. ```go func (transform DataTransform) Validate() error ``` ## DataTransformDescriptor.Validate Canonical URL: https://riducms.com/reference/migration/data-transform-descriptor-validate-method/ Kind: method Validate checks one artifact-safe callback descriptor. ```go func (descriptor DataTransformDescriptor) Validate() error ``` ## PhaseBatch Canonical URL: https://riducms.com/reference/migration/phase-batch/ Kind: constant PhaseBatch executes one typed keyset executor in bounded transactions. ```go const PhaseBatch PhaseMode = "batch" ``` ## PhaseNoTransaction Canonical URL: https://riducms.com/reference/migration/phase-no-transaction/ Kind: constant PhaseNoTransaction executes one typed physical operation which cannot run inside a database transaction. Each operation is its own resumable phase. ```go const PhaseNoTransaction PhaseMode = "no_transaction" ``` ## PhaseTransaction Canonical URL: https://riducms.com/reference/migration/phase-transaction/ Kind: constant PhaseTransaction executes every phase step and its ledger completion in one database transaction. ```go const PhaseTransaction PhaseMode = "transaction" ``` ## PhysicalContractVersion Canonical URL: https://riducms.com/reference/migration/physical-contract-version/ Kind: constant PhysicalContractVersion identifies the meaning of intermediate physical digests. ```go const PhysicalContractVersion uint32 = 1 ``` ## ProjectApply Canonical URL: https://riducms.com/reference/migration/project-apply/ Kind: constant Public constant ProjectApply from github.com/riducms/ridu/migration. ```go const ProjectApply ProjectAction = "up" ``` ## ProjectDown Canonical URL: https://riducms.com/reference/migration/project-down/ Kind: constant Public constant ProjectDown from github.com/riducms/ridu/migration. ```go const ProjectDown ProjectAction = "down" ``` ## ProjectFresh Canonical URL: https://riducms.com/reference/migration/project-fresh/ Kind: constant Public constant ProjectFresh from github.com/riducms/ridu/migration. ```go const ProjectFresh ProjectAction = "fresh" ``` ## ProjectRefresh Canonical URL: https://riducms.com/reference/migration/project-refresh/ Kind: constant Public constant ProjectRefresh from github.com/riducms/ridu/migration. ```go const ProjectRefresh ProjectAction = "refresh" ``` ## ProjectRequest.Validate Canonical URL: https://riducms.com/reference/migration/project-request-validate-method/ Kind: method Validate rejects incomplete or unknown project migration requests. ```go func (request ProjectRequest) Validate() error ``` ## ProjectReset Canonical URL: https://riducms.com/reference/migration/project-reset/ Kind: constant Public constant ProjectReset from github.com/riducms/ridu/migration. ```go const ProjectReset ProjectAction = "reset" ``` ## ProjectVerify Canonical URL: https://riducms.com/reference/migration/project-verify/ Kind: constant Public constant ProjectVerify from github.com/riducms/ridu/migration. ```go const ProjectVerify ProjectAction = "verify" ``` ## RiskDestructive Canonical URL: https://riducms.com/reference/migration/risk-destructive/ Kind: constant RiskDestructive records a change that can permanently remove stored data. ```go const RiskDestructive RiskLevel = "destructive" ``` ## RiskNotice Canonical URL: https://riducms.com/reference/migration/risk-notice/ Kind: constant RiskNotice records operational context that does not require intervention. ```go const RiskNotice RiskLevel = "notice" ``` ## RiskWarning Canonical URL: https://riducms.com/reference/migration/risk-warning/ Kind: constant RiskWarning records a change that deserves explicit deployment review. ```go const RiskWarning RiskLevel = "warning" ``` ## RunnerContractVersion Canonical URL: https://riducms.com/reference/migration/runner-contract-version/ Kind: constant RunnerContractVersion is the execution contract implemented by this build. ```go const RunnerContractVersion uint32 = 1 ``` ## StepAssertSchema Canonical URL: https://riducms.com/reference/migration/step-assert-schema/ Kind: constant StepAssertSchema verifies the resulting physical schema fingerprint. ```go const StepAssertSchema StepKind = "assert_schema" ``` ## StepBackfillReferences Canonical URL: https://riducms.com/reference/migration/step-backfill-references/ Kind: constant StepBackfillReferences derives the current-document reference index after its physical table has been created. Version snapshots are not indexed. ```go const StepBackfillReferences StepKind = "backfill_references" ``` ## StepCanonicalizeAuthIdentities Canonical URL: https://riducms.com/reference/migration/step-canonicalize-auth-identities/ Kind: constant StepCanonicalizeAuthIdentities rewrites authored authentication identity values to store.CanonicalAuthIdentity before an adapter replaces its legacy uniqueness contract. ```go const StepCanonicalizeAuthIdentities StepKind = "canonicalize_auth_identities" ``` ## StepConcurrentIndex Canonical URL: https://riducms.com/reference/migration/step-concurrent-index/ Kind: constant StepConcurrentIndex executes one structured PostgreSQL concurrent-index operation outside a database transaction. ```go const StepConcurrentIndex StepKind = "concurrent_index" ``` ## StepDataTransform Canonical URL: https://riducms.com/reference/migration/step-data-transform/ Kind: constant StepDataTransform invokes one application-compiled, checksum-bound callback inside the adapter's migration transaction. ```go const StepDataTransform StepKind = "data_transform" ``` ## StepMongoDBAssertSchema Canonical URL: https://riducms.com/reference/migration/step-mongo-db-assert-schema/ Kind: constant StepMongoDBAssertSchema verifies the complete planner-owned MongoDB catalog outside a database transaction after every physical step has completed. ```go const StepMongoDBAssertSchema StepKind = "mongodb_assert_schema" ``` ## StepMongoDBCreateIndex Canonical URL: https://riducms.com/reference/migration/step-mongo-db-create-index/ Kind: constant StepMongoDBCreateIndex creates one planner-owned MongoDB index outside a database transaction. The payload freezes physical identity only; the adapter must reconstruct and exactly match the definition from the embedded manifest and versioned planner before touching a database. ```go const StepMongoDBCreateIndex StepKind = "mongodb_create_index" ``` ## StepMongoDBDropIndex Canonical URL: https://riducms.com/reference/migration/step-mongo-db-drop-index/ Kind: constant StepMongoDBDropIndex removes one planner-owned MongoDB index outside a database transaction. The adapter reconstructs the exact physical collection and index definition from the embedded manifests; the payload never carries an arbitrary command. ```go const StepMongoDBDropIndex StepKind = "mongodb_drop_index" ``` ## StepMongoDBDropResources Canonical URL: https://riducms.com/reference/migration/step-mongo-db-drop-resources/ Kind: constant StepMongoDBDropResources removes the content and version namespaces for one exact, sorted set of reviewed retired stable identities. Framework-owned shared state is removed by the preceding transactional retirement step. ```go const StepMongoDBDropResources StepKind = "mongodb_drop_resources" ``` ## StepMongoDBRenameResource Canonical URL: https://riducms.com/reference/migration/step-mongo-db-rename-resource/ Kind: constant StepMongoDBRenameResource moves one collection identity to another outside a database transaction. Only stable manifest identities are persisted; the MongoDB adapter derives the exact content and version namespaces. ```go const StepMongoDBRenameResource StepKind = "mongodb_rename_resource" ``` ## StepPluginSQL Canonical URL: https://riducms.com/reference/migration/step-plugin-sql/ Kind: constant StepPluginSQL executes one checksum-protected plugin migration. ```go const StepPluginSQL StepKind = "plugin_sql" ``` ## StepRenameContent Canonical URL: https://riducms.com/reference/migration/step-rename-content/ Kind: constant StepRenameContent rewrites schema-addressed content after physical renames. ```go const StepRenameContent StepKind = "rename_content" ``` ## StepRetireResources Canonical URL: https://riducms.com/reference/migration/step-retire-resources/ Kind: constant StepRetireResources removes framework-owned shared state for resources that a reviewed destructive migration removes. It is a typed semantic executor and must run before the corresponding physical tables are dropped. ```go const StepRetireResources StepKind = "retire_resources" ``` ## StepSQL Canonical URL: https://riducms.com/reference/migration/step-sql/ Kind: constant StepSQL executes one physical schema statement. ```go const StepSQL StepKind = "sql" ``` --- # API Reference: migration/payload Canonical URL: https://riducms.com/reference/migration-payload/ Package: github.com/riducms/ridu/migration/payload Optional public import boundary for normalized Payload CMS exports; source-specific database extraction is deliberately out of scope. ## Export Canonical URL: https://riducms.com/reference/migration-payload/export/ Kind: type A normalized, source-independent Payload export. ```go type Export struct { Collections []Collection } ``` An extractor must produce this shape. Ridu does not couple the importer to Payload database tables or internal storage conventions. ## Collection Canonical URL: https://riducms.com/reference/migration-payload/collection/ Kind: type One source collection slug and its normalized documents. ```go type Collection struct { Slug string Documents []Record } ``` ## Record Canonical URL: https://riducms.com/reference/migration-payload/record/ Kind: type One source document and its available retained versions. ```go type Record struct { ID ID Data json.RawMessage Status store.Status CreatedAt time.Time UpdatedAt time.Time Versions []Version SelectedRevision int } ``` SelectedRevision zero imports current Data. A non-zero value must name a supplied version and the Ridu target must support versions. ## Version Canonical URL: https://riducms.com/reference/migration-payload/version/ Kind: type One available source revision. ```go type Version struct { Revision int Data json.RawMessage Status store.Status CreatedAt time.Time UpdatedAt time.Time } ``` ## Assessment Canonical URL: https://riducms.com/reference/migration-payload/assessment/ Kind: type Preflight counts and sorted blockers. ```go type Assessment struct { Collections int Documents int Versions int Issues []string } ``` ## Assess Canonical URL: https://riducms.com/reference/migration-payload/assess/ Kind: function Count records and report deterministic import blockers without writing. ```go func Assess(manifest schema.Manifest, source Export) Assessment ``` Checks collection presence, IDs, selected revisions, and version capability. Issues are sorted strings intended for preflight review. It does not deeply validate every field value. ## Target Canonical URL: https://riducms.com/reference/migration-payload/target/ Kind: interface The narrow destination contract used by Import. ```go type Target interface { Import(context.Context, string, store.Values, ridu.ImportOptions, *store.Document) (store.Document, error) } ``` *core.LocalAPI satisfies this contract. Writes still enter Ridu access, validation, hooks, transaction, upload-reference, and version handling. ## Import Canonical URL: https://riducms.com/reference/migration-payload/import/ Kind: function Import each chosen record through Ridu operations. ```go func Import(ctx context.Context, target Target, source Export, actor *store.Document) (Result, error) ``` Stops on the first failed record and returns the partial Result. IDs maps source collection and source ID to the created Ridu ID. This is a normalized content importer, not automatic Payload project or database compatibility. ## Result Canonical URL: https://riducms.com/reference/migration-payload/result/ Kind: type Completed import count and source-to-target ID mapping. ```go type Result struct { Imported int IDs map[string]map[string]string } ``` ## ID Canonical URL: https://riducms.com/reference/migration-payload/id/ Kind: type ID is a normalized Payload document ID. JSON strings are preserved exactly; integer JSON numbers are converted to their exact base-10 spelling so Payload's numeric, UUID, and custom IDs share Ridu's canonical string wire representation without passing through float64. ```go type ID string ``` ## ID.MarshalJSON Canonical URL: https://riducms.com/reference/migration-payload/id-marshal-json-method/ Kind: method Public method ID.MarshalJSON from github.com/riducms/ridu/migration/payload. ```go func (id ID) MarshalJSON() ([]byte, error) ``` ## ID.String Canonical URL: https://riducms.com/reference/migration-payload/id-string-method/ Kind: method Public method ID.String from github.com/riducms/ridu/migration/payload. ```go func (id ID) String() string ``` ## ID.UnmarshalJSON Canonical URL: https://riducms.com/reference/migration-payload/id-unmarshal-json-method/ Kind: method Public method ID.UnmarshalJSON from github.com/riducms/ridu/migration/payload. ```go func (id *ID) UnmarshalJSON(encoded []byte) error ``` --- # API Reference: protocol (Go) Canonical URL: https://riducms.com/reference/go-protocol/ Package: github.com/riducms/ridu/protocol Advanced stable REST wire envelopes shared by the HTTP runtime, generators, SDK, admin, and transport tests. ## CurrentVersion Canonical URL: https://riducms.com/reference/go-protocol/current-version/ Kind: constant The framework REST wire-protocol version. ```go const CurrentVersion uint32 = 1 ``` Changes independently from schema manifest and project-command protocols. Application clients should consume generated contracts rather than pinning this constant manually. ## ErrorCode Canonical URL: https://riducms.com/reference/go-protocol/error-code/ Kind: type A stable machine-readable failure category. ```go type ErrorCode string ``` Codes cover validation, access denied, not found, conflict, delete restricted, bad request, internal, rate limited, email not verified, disabled auth, invalid auth/preview tokens, and oversized selections. ## ErrorEnvelope Canonical URL: https://riducms.com/reference/go-protocol/error-envelope/ Kind: type The response returned by every failed HTTP operation. ```go type ErrorEnvelope struct { Error ErrorPayload `json:"error"` } ``` ## ErrorPayload Canonical URL: https://riducms.com/reference/go-protocol/error-payload/ Kind: type Stable structured error data. ```go type ErrorPayload struct { Code ErrorCode `json:"code"` Status int `json:"status"` Message string `json:"message"` RequestID string `json:"requestId,omitempty"` Issues []ValidationIssue `json:"issues"` Details json.RawMessage `json:"details,omitempty"` } ``` Details is endpoint-specific public JSON. It must never expose internal causes or secrets. Consumers branch on Code and Issues, not Message text. ## ValidationIssue Canonical URL: https://riducms.com/reference/go-protocol/validation-issue/ Kind: type One invalid input path. ```go type ValidationIssue struct { Code string `json:"code"` Path string `json:"path"` Message string `json:"message"` } ``` ## Pagination Canonical URL: https://riducms.com/reference/go-protocol/pagination/ Kind: type Stable page metadata independent of document type. ```go type Pagination struct { Page int `json:"page"` Limit int `json:"limit"` TotalDocs int `json:"totalDocs"` TotalPages int `json:"totalPages"` HasNextPage bool `json:"hasNextPage"` HasPrevPage bool `json:"hasPrevPage"` } ``` ## PageEnvelope Canonical URL: https://riducms.com/reference/go-protocol/page-envelope/ Kind: type One typed document page. ```go type PageEnvelope[Document any] struct { Docs []Document `json:"docs"` Pagination Pagination `json:"pagination"` } ``` ## DocumentEnvelope Canonical URL: https://riducms.com/reference/go-protocol/document-envelope/ Kind: type One typed document. ```go type DocumentEnvelope[Document any] struct { Doc Document `json:"doc"` } ``` ## BulkEnvelope Canonical URL: https://riducms.com/reference/go-protocol/bulk-envelope/ Kind: type Documents changed by one atomic bulk operation. ```go type BulkEnvelope[Document any] struct { Docs []Document `json:"docs"` } ``` ## CountEnvelope Canonical URL: https://riducms.com/reference/go-protocol/count-envelope/ Kind: type Exact cardinality after caller and access filters. ```go type CountEnvelope struct { TotalDocs int `json:"totalDocs"` } ``` ## JoinMutationInput Canonical URL: https://riducms.com/reference/go-protocol/join-mutation-input/ Kind: type Explicit inverse-relation additions and removals. ```go type JoinMutationInput struct { Additions []string `json:"additions"` Removals []string `json:"removals"` } ``` Deltas deliberately do not imply that the caller loaded the complete relationship set. ## JoinMutationEnvelope Canonical URL: https://riducms.com/reference/go-protocol/join-mutation-envelope/ Kind: type The refreshed source document and applied inverse-relation delta counts. ```go type JoinMutationEnvelope[Document any] struct { Doc Document `json:"doc"` Added int `json:"added"` Removed int `json:"removed"` } ``` ## PreferenceEnvelope Canonical URL: https://riducms.com/reference/go-protocol/preference-envelope/ Kind: type One typed actor-owned admin preference value. ```go type PreferenceEnvelope[Value any] struct { Value Value `json:"value"` } ``` Preferences are scoped to the exact auth collection, user, and application-owned key by the runtime; this envelope contains only the decoded value. ## AccessCapabilitiesEnvelope Canonical URL: https://riducms.com/reference/go-protocol/access-capabilities-envelope/ Kind: type Evaluated operation and field access for one actor and optional document/input. ```go type AccessCapabilitiesEnvelope struct { Operations OperationCapabilities `json:"operations"` Fields map[string]FieldCapabilities `json:"fields"` } ``` Contains booleans only—never access predicates or executable rules. Field keys are authored or concrete runtime paths. ## OperationCapabilities Canonical URL: https://riducms.com/reference/go-protocol/operation-capabilities/ Kind: type Boolean operation permissions for one evaluated resource state. ```go type OperationCapabilities struct { Admin bool `json:"admin"` Create bool `json:"create"` Read bool `json:"read"` ReadVersions bool `json:"readVersions"` Update bool `json:"update"` Delete bool `json:"delete"` Duplicate bool `json:"duplicate"` Publish bool `json:"publish"` Unpublish bool `json:"unpublish"` RestoreDeleted bool `json:"restoreDeleted"` DeletePermanent bool `json:"deletePermanent"` SelectAll bool `json:"selectAll"` } ``` A later mutation always reauthorizes; these booleans are not a permission lease. ## FieldCapabilities Canonical URL: https://riducms.com/reference/go-protocol/field-capabilities/ Kind: type Boolean create, read, and update permissions for one field path. ```go type FieldCapabilities struct { Read bool `json:"read"` Create bool `json:"create"` Update bool `json:"update"` } ``` ## CollectionSelectionInput Canonical URL: https://riducms.com/reference/go-protocol/collection-selection-input/ Kind: type A caller filter and optional trash mode for bounded selection preflight. ```go type CollectionSelectionInput struct { Where json.RawMessage `json:"where,omitempty"` Trash bool `json:"trash,omitempty"` } ``` ## CollectionSelectionItem Canonical URL: https://riducms.com/reference/go-protocol/collection-selection-item/ Kind: type One frozen document ID and its evaluated authoring capabilities. ```go type CollectionSelectionItem struct { ID string `json:"id"` Access AccessCapabilitiesEnvelope `json:"access"` } ``` ## CollectionSelectionEnvelope Canonical URL: https://riducms.com/reference/go-protocol/collection-selection-envelope/ Kind: type One complete bounded read-visible selection. ```go type CollectionSelectionEnvelope struct { Items []CollectionSelectionItem `json:"items"` TotalDocs int `json:"totalDocs"` } ``` The server freezes IDs and per-item authoring capabilities. Oversized selections fail instead of truncating silently. ## DocumentLockEnvelope Canonical URL: https://riducms.com/reference/go-protocol/document-lock-envelope/ Kind: type Current authoring lock and current-actor state. ```go type DocumentLockEnvelope struct { Lock *DocumentLock `json:"lock"` Owned bool `json:"owned"` Acquired bool `json:"acquired"` CanTakeOver bool `json:"canTakeOver"` } ``` Exposes safe owner label and lease timestamps, never auth collection identity or credentials. ## DocumentLock Canonical URL: https://riducms.com/reference/go-protocol/document-lock/ Kind: type Safe persisted editor-lock metadata. ```go type DocumentLock struct { DocumentID string `json:"documentId"` OwnerID string `json:"ownerId"` OwnerLabel string `json:"ownerLabel"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` ExpiresAt string `json:"expiresAt"` } ``` OwnerLabel is resolved for display. Exact auth collection identity stays server-side. ## DeleteEnvelope Canonical URL: https://riducms.com/reference/go-protocol/delete-envelope/ Kind: type A stable acknowledgement for deleting one owned resource. ```go type DeleteEnvelope struct { ID string `json:"id"` Deleted bool `json:"deleted"` } ``` ## ScheduledPublish Canonical URL: https://riducms.com/reference/go-protocol/scheduled-publish/ Kind: type Safe queued-publish metadata. ```go type ScheduledPublish struct { ID string `json:"id"` DocumentID string `json:"documentId"` ExpectedRevision int `json:"expectedRevision"` RunAt string `json:"runAt"` Attempts int `json:"attempts"` LastError string `json:"lastError,omitempty"` CreatedAt string `json:"createdAt"` } ``` Requesting identities are deliberately omitted. ## ScheduledPublishEnvelope Canonical URL: https://riducms.com/reference/go-protocol/scheduled-publish-envelope/ Kind: type One created scheduled-publish record. ```go type ScheduledPublishEnvelope struct { ScheduledPublish ScheduledPublish `json:"scheduledPublish"` } ``` ## ScheduledPublishesEnvelope Canonical URL: https://riducms.com/reference/go-protocol/scheduled-publishes-envelope/ Kind: type Queued, running, and actionable failed publish records for one document. ```go type ScheduledPublishesEnvelope struct { ScheduledPublishes []ScheduledPublish `json:"scheduledPublishes"` } ``` ## AuthSession Canonical URL: https://riducms.com/reference/go-protocol/auth-session/ Kind: type Framework session metadata plus a typed authenticated user. ```go type AuthSession[User any] struct { // ID is the safe, non-secret identifier used for session management. ID string `json:"id"` // Collection is the auth-enabled collection that owns the user identity. Collection string `json:"collection"` // User is the current authenticated document. User User `json:"user"` // ExpiresAt is the session's RFC 3339 expiry timestamp. ExpiresAt string `json:"expiresAt"` } ``` ID is a safe management identifier, not a bearer token. Collection disambiguates identities when several auth collections exist. ## AuthSessionInfo Canonical URL: https://riducms.com/reference/go-protocol/auth-session-info/ Kind: type Safe device/session metadata. ```go type AuthSessionInfo struct { ID string `json:"id"` CreatedAt string `json:"createdAt"` LastSeenAt string `json:"lastSeenAt"` ExpiresAt string `json:"expiresAt"` IPAddress string `json:"ipAddress,omitempty"` UserAgent string `json:"userAgent,omitempty"` Current bool `json:"current"` } ``` Never contains a bearer token or token digest. ## AuthSessionsEnvelope Canonical URL: https://riducms.com/reference/go-protocol/auth-sessions-envelope/ Kind: type Safe session metadata owned by the current identity. ```go type AuthSessionsEnvelope struct { Sessions []AuthSessionInfo `json:"sessions"` } ``` ## SessionEnvelope Canonical URL: https://riducms.com/reference/go-protocol/session-envelope/ Kind: type One typed current or newly rotated session. ```go type SessionEnvelope[User any] struct { Session AuthSession[User] `json:"session"` } ``` ## LogoutEnvelope Canonical URL: https://riducms.com/reference/go-protocol/logout-envelope/ Kind: type A successful session logout acknowledgement. ```go type LogoutEnvelope struct { LoggedOut bool `json:"loggedOut"` } ``` ## AuthActionEnvelope Canonical URL: https://riducms.com/reference/go-protocol/auth-action-envelope/ Kind: type A non-secret success acknowledgement for an auth lifecycle action. ```go type AuthActionEnvelope struct { Success bool `json:"success"` } ``` ## AuthBootstrapEnvelope Canonical URL: https://riducms.com/reference/go-protocol/auth-bootstrap-envelope/ Kind: type A non-secret indication that the configured admin collection still allows first-user setup. ```go type AuthBootstrapEnvelope struct { Available bool `json:"available"` } ``` ## APIKey Canonical URL: https://riducms.com/reference/go-protocol/api-key/ Kind: type A newly minted API key including its one-time bearer secret. ```go type APIKey struct { ID string `json:"id"` Name string `json:"name"` Key string `json:"key"` CreatedAt string `json:"createdAt"` ExpiresAt string `json:"expiresAt,omitempty"` } ``` Key is returned only at creation. Later lists use APIKeyInfo and never recover the secret. ## APIKeyInfo Canonical URL: https://riducms.com/reference/go-protocol/api-key-info/ Kind: type Retrievable API-key metadata without its bearer secret. ```go type APIKeyInfo struct { ID string `json:"id"` Name string `json:"name"` CreatedAt string `json:"createdAt"` LastUsedAt string `json:"lastUsedAt,omitempty"` ExpiresAt string `json:"expiresAt,omitempty"` } ``` ## APIKeyEnvelope Canonical URL: https://riducms.com/reference/go-protocol/api-key-envelope/ Kind: type One newly created API key including its one-time secret. ```go type APIKeyEnvelope struct { APIKey APIKey `json:"apiKey"` } ``` ## APIKeysEnvelope Canonical URL: https://riducms.com/reference/go-protocol/api-keys-envelope/ Kind: type Safe metadata for the current identity's API keys. ```go type APIKeysEnvelope struct { APIKeys []APIKeyInfo `json:"apiKeys"` } ``` ## PreviewToken Canonical URL: https://riducms.com/reference/go-protocol/preview-token/ Kind: type A short-lived read-only resource capability. ```go type PreviewToken struct { Token string `json:"token"` Resource string `json:"resource"` Slug string `json:"slug"` DocumentID string `json:"documentId"` ExpiresAt string `json:"expiresAt"` } ``` Token is returned only when minted and is scoped to one collection document or global. ## PreviewTokenEnvelope Canonical URL: https://riducms.com/reference/go-protocol/preview-token-envelope/ Kind: type One newly minted exact-resource preview capability. ```go type PreviewTokenEnvelope struct { PreviewToken PreviewToken `json:"previewToken"` } ``` ## SchemaEnvelope Canonical URL: https://riducms.com/reference/go-protocol/schema-envelope/ Kind: type Resolved declarative schema for trusted tooling and the admin. ```go type SchemaEnvelope struct { Schema schema.Snapshot `json:"schema"` } ``` Never contains executable authorization, hooks, task handlers, or secrets. ## ErrorAccess Canonical URL: https://riducms.com/reference/go-protocol/error-access/ Kind: constant Public constant ErrorAccess from github.com/riducms/ridu/protocol. ```go const ErrorAccess ErrorCode = "access_denied" ``` ## ErrorAuthFeatureDisabled Canonical URL: https://riducms.com/reference/go-protocol/error-auth-feature-disabled/ Kind: constant Public constant ErrorAuthFeatureDisabled from github.com/riducms/ridu/protocol. ```go const ErrorAuthFeatureDisabled ErrorCode = "auth_feature_disabled" ``` ## ErrorBadRequest Canonical URL: https://riducms.com/reference/go-protocol/error-bad-request/ Kind: constant Public constant ErrorBadRequest from github.com/riducms/ridu/protocol. ```go const ErrorBadRequest ErrorCode = "bad_request" ``` ## ErrorConflict Canonical URL: https://riducms.com/reference/go-protocol/error-conflict/ Kind: constant Public constant ErrorConflict from github.com/riducms/ridu/protocol. ```go const ErrorConflict ErrorCode = "conflict" ``` ## ErrorDeleteRestricted Canonical URL: https://riducms.com/reference/go-protocol/error-delete-restricted/ Kind: constant Public constant ErrorDeleteRestricted from github.com/riducms/ridu/protocol. ```go const ErrorDeleteRestricted ErrorCode = "delete_restricted" ``` ## ErrorEmailNotVerified Canonical URL: https://riducms.com/reference/go-protocol/error-email-not-verified/ Kind: constant Public constant ErrorEmailNotVerified from github.com/riducms/ridu/protocol. ```go const ErrorEmailNotVerified ErrorCode = "email_not_verified" ``` ## ErrorInternal Canonical URL: https://riducms.com/reference/go-protocol/error-internal/ Kind: constant Public constant ErrorInternal from github.com/riducms/ridu/protocol. ```go const ErrorInternal ErrorCode = "internal" ``` ## ErrorInvalidAuthToken Canonical URL: https://riducms.com/reference/go-protocol/error-invalid-auth-token/ Kind: constant Public constant ErrorInvalidAuthToken from github.com/riducms/ridu/protocol. ```go const ErrorInvalidAuthToken ErrorCode = "invalid_auth_token" ``` ## ErrorInvalidPreviewToken Canonical URL: https://riducms.com/reference/go-protocol/error-invalid-preview-token/ Kind: constant Public constant ErrorInvalidPreviewToken from github.com/riducms/ridu/protocol. ```go const ErrorInvalidPreviewToken ErrorCode = "invalid_preview_token" ``` ## ErrorNotFound Canonical URL: https://riducms.com/reference/go-protocol/error-not-found/ Kind: constant Public constant ErrorNotFound from github.com/riducms/ridu/protocol. ```go const ErrorNotFound ErrorCode = "not_found" ``` ## ErrorRateLimited Canonical URL: https://riducms.com/reference/go-protocol/error-rate-limited/ Kind: constant Public constant ErrorRateLimited from github.com/riducms/ridu/protocol. ```go const ErrorRateLimited ErrorCode = "rate_limited" ``` ## ErrorSelectionTooLarge Canonical URL: https://riducms.com/reference/go-protocol/error-selection-too-large/ Kind: constant Public constant ErrorSelectionTooLarge from github.com/riducms/ridu/protocol. ```go const ErrorSelectionTooLarge ErrorCode = "selection_too_large" ``` ## ErrorValidation Canonical URL: https://riducms.com/reference/go-protocol/error-validation/ Kind: constant Public constant ErrorValidation from github.com/riducms/ridu/protocol. ```go const ErrorValidation ErrorCode = "validation" ``` --- # API Reference: plugintest Canonical URL: https://riducms.com/reference/plugintest/ Package: github.com/riducms/ridu/plugintest Stable backend conformance tests for third-party compiled Ridu plugins. ## Fixture Canonical URL: https://riducms.com/reference/plugintest/fixture/ Kind: type The application inputs needed for plugin conformance tests. ```go type Fixture struct { Plugin ridu.Plugin Fields []field.Definition // ValidData and InvalidData opt into runtime storage, local API, REST, and // validator conformance. InvalidData must be rejected as validation. ValidData store.Values InvalidData store.Values // Compatibility records the Ridu releases the plugin author promises to // test. Published plugin packages should retain old rows as they release. Compatibility []CompatibilityCase } ``` ValidData enables runtime Local API and REST checks. InvalidData must be rejected as validation. Compatibility records the Ridu versions the plugin author promises to test. ## CompatibilityCase Canonical URL: https://riducms.com/reference/plugintest/compatibility-case/ Kind: type One expected descriptor result in a cross-release matrix. ```go type CompatibilityCase struct { RiduVersion string Compatible bool } ``` ## Run Canonical URL: https://riducms.com/reference/plugintest/run/ Kind: function Run deterministic manifest, capability, compatibility, runtime, transport, and validator checks. ```go func Run(t *testing.T, fixture Fixture) ``` Call from an external-package _test.go file. That catches import cycles and accidental reliance on Ridu internals. Runtime checks use the strict in-memory store and application HTTP handler. --- # API Reference: postgres Canonical URL: https://riducms.com/reference/postgres/ Package: github.com/riducms/ridu/adapters/postgres The official PostgreSQL store, safe development schema sync, and immutable production migration runner. ## Open Canonical URL: https://riducms.com/reference/postgres/open/ Kind: function Open the PostgreSQL store with bounded default pool settings. ```go func Open(ctx context.Context, databaseURL string) (*Store, error) ``` ```go backend, err := postgres.Open(ctx, os.Getenv("DATABASE_URL")) if err != nil { return err } defer backend.Close() ``` ## OpenWithConfig Canonical URL: https://riducms.com/reference/postgres/open-with-config/ Kind: function Open the store with explicit pool and PostgreSQL session bounds. ```go func OpenWithConfig(ctx context.Context, options PoolConfig) (*Store, error) ``` ## PoolConfig Canonical URL: https://riducms.com/reference/postgres/pool-config/ Kind: type Production connection-pool, upload-lock-pool, lifetime, health, and server timeout controls. ```go type PoolConfig struct { DatabaseURL string // AllowInsecureTransport explicitly permits plaintext PostgreSQL connections. // Keep this false in production; it exists for local Unix sockets and // development databases whose transport is secured outside PostgreSQL. AllowInsecureTransport bool ApplicationName string MaxConnections int32 // MaxUploadLockConnections bounds the separate advisory-lock pool used // while object storage and document transactions are coordinated. Keeping // this pool separate prevents staged uploads from starving their own // document transactions. Zero selects four connections. MaxUploadLockConnections int32 MinConnections int32 MaxConnectionLifetime time.Duration MaxConnectionLifetimeJitter time.Duration MaxConnectionIdleTime time.Duration HealthCheckPeriod time.Duration ConnectTimeout time.Duration StatementTimeout time.Duration LockTimeout time.Duration IdleInTransactionSessionTimeout time.Duration } ``` Zero values select bounded Ridu defaults. Negative duration values explicitly disable the corresponding timeout. AllowInsecureTransport is for local sockets or externally secured development transport; keep it false in production. The upload lock pool defaults to four connections and stays separate so staged uploads cannot starve their own document transactions. ## Store Canonical URL: https://riducms.com/reference/postgres/store/ Kind: type A PostgreSQL implementation of Ridu’s document, snapshot, auth, preference, task, job, lock, upload-reference, and migration store contracts. ```go type Store struct { pool *pgxpool.Pool uploadLockPool *pgxpool.Pool uploadLockWait time.Duration } ``` Use the application and Local API for content operations. These capability interfaces are primarily useful to framework/runtime integrations. Transactions returned by Begin implement store.Transaction, AuthTransaction, AuthBootstrapTransaction, AuthUnlockTransaction, VersionTransaction, UploadReferenceTransaction, and transaction-level UploadObjectLocker. ## Store.Close Canonical URL: https://riducms.com/reference/postgres/store-close/ Kind: method Close both the document pool and dedicated upload-lock pool. ```go func (backend *Store) Close() ``` ## Store.Ping Canonical URL: https://riducms.com/reference/postgres/store-ping/ Kind: method Check database connectivity. ```go func (backend *Store) Ping(ctx context.Context) error ``` ## Store.Ready Canonical URL: https://riducms.com/reference/postgres/store-ready/ Kind: method Prove connectivity and completed migration state for the running manifest. ```go func (backend *Store) Ready(ctx context.Context, manifest schema.Manifest) error ``` In-progress phased work is not ready even if an older completed manifest digest matches. ## Store.ReadyWithMigrationHistory Canonical URL: https://riducms.com/reference/postgres/store-ready-with-migration-history/ Kind: method Prove ordinary readiness and exact agreement with executable migration history. ```go func (backend *Store) ReadyWithMigrationHistory(ctx context.Context, manifest schema.Manifest, expectedHistoryDigest string) error ``` Compares every ordered ledger filename and artifact digest with the fingerprint embedded by ridu build. ## Store.Begin Canonical URL: https://riducms.com/reference/postgres/store-begin/ Kind: method Begin a read-write document transaction. ```go func (backend *Store) Begin(ctx context.Context) (store.Transaction, error) ``` ## Store.BeginSnapshot Canonical URL: https://riducms.com/reference/postgres/store-begin-snapshot/ Kind: method Begin a stable read snapshot. ```go func (backend *Store) BeginSnapshot(ctx context.Context) (store.Transaction, error) ``` ## Store.Plan Canonical URL: https://riducms.com/reference/postgres/store-plan/ Kind: method Inspect the live database and plan only a safe development synchronization. ```go func (backend *Store) Plan(ctx context.Context, manifest schema.Manifest) ([]Statement, error) ``` This is for ridu dev. Production changes use reviewed migration artifacts. ## Store.ApplyPlan Canonical URL: https://riducms.com/reference/postgres/store-apply-plan/ Kind: method Apply a non-destructive development plan in one transaction. ```go func (backend *Store) ApplyPlan(ctx context.Context, statements []Statement) error ``` ## Statement Canonical URL: https://riducms.com/reference/postgres/statement/ Kind: type One ordered development schema change. ```go type Statement struct { // Kind is a stable, human-readable description of the planned change. Kind string // SQL is the complete PostgreSQL statement to apply. SQL string // CollectionID identifies the collection affected by the statement, when any. CollectionID schema.StableID // FieldID identifies the top-level field affected by the statement, when any. FieldID schema.StableID } ``` ## BuildArtifact Canonical URL: https://riducms.com/reference/postgres/build-artifact/ Kind: function Use embedded Atlas planning plus confirmed semantic rename intent to build an immutable migration artifact. ```go func BuildArtifact(ctx context.Context, name string, before *schema.Manifest, after schema.Manifest, renames []Rename, allowDestructive bool) (ridumigration.Artifact, error) ``` allowDestructive admits reviewed Atlas-confirmed destructive work; some unsafe semantic transitions still fail closed. Prefer ridu migrate create, which records and reviews this contract. ## BuildArtifactWithPreviousPlanner Canonical URL: https://riducms.com/reference/postgres/build-artifact-with-previous-planner/ Kind: function Plan a reviewed migration against the exact physical planner contract recorded by its predecessor. ```go func BuildArtifactWithPreviousPlanner(ctx context.Context, name string, before *schema.Manifest, after schema.Manifest, renames []Rename, allowDestructive bool, previousPlannerVersion string) (ridumigration.Artifact, error) ``` Ordinary callers should use BuildArtifact. Migration-history creation uses this entry point only when a reviewed planner upgrade must emit semantic data work. ## Rename Canonical URL: https://riducms.com/reference/postgres/rename/ Kind: type Confirmed collection or field identity continuity used during migration planning. ```go type Rename struct { // Kind selects collection or field rename planning. Kind RenameKind // BeforeCollection is the collection embedded in the previous artifact. BeforeCollection schema.Collection // AfterCollection is its collection in current executable config. AfterCollection schema.Collection // BeforeField and AfterField are set for a standalone field rename. BeforeField *schema.Field AfterField *schema.Field // Fields contains all physical and nested field pairs for a collection rename. Fields []FieldRename } ``` ## FieldRename Canonical URL: https://riducms.com/reference/postgres/field-rename/ Kind: type One migration-time field identity match confirmed by the application author. ```go type FieldRename struct { // Before is the field embedded in the previous migration artifact. Before schema.Field // After is its confirmed match in current executable config. After schema.Field } ``` ## MigrationStepStatus Canonical URL: https://riducms.com/reference/postgres/migration-step-status/ Kind: type Durable status and checkpoint for one production migration step. ```go type MigrationStepStatus struct { ID string `json:"id"` Kind ridumigration.StepKind `json:"kind"` State string `json:"state"` Checkpoint json.RawMessage `json:"checkpoint,omitempty"` } ``` ## RenameKind Canonical URL: https://riducms.com/reference/postgres/rename-kind/ Kind: type The migration address being renamed. ```go type RenameKind string ``` ## SafetyError Canonical URL: https://riducms.com/reference/postgres/safety-error/ Kind: type A valid transition that needs destructive approval or cannot be determined safe. ```go type SafetyError struct { Risks []ridumigration.Risk } ``` ## VerifyArtifacts Canonical URL: https://riducms.com/reference/postgres/verify-artifacts/ Kind: function Replay complete history in an isolated temporary schema, then always drop it. ```go func VerifyArtifacts(ctx context.Context, databaseURL, directory string) (resultError error) ``` Verification never touches application tables. ## VerifyArtifactsWithOptions Canonical URL: https://riducms.com/reference/postgres/verify-artifacts-with-options/ Kind: function Verify history using the same operational admissions and timeouts as application. ```go func VerifyArtifactsWithOptions(ctx context.Context, databaseURL, directory string, options RunnerOptions) (resultError error) ``` ## Store.ApplyArtifacts Canonical URL: https://riducms.com/reference/postgres/store-apply-artifacts/ Kind: method Validate all immutable history, take an advisory lock, and apply each pending artifact. ```go func (backend *Store) ApplyArtifacts(ctx context.Context, directory string) error ``` ## Store.ApplyArtifactsWithOptions Canonical URL: https://riducms.com/reference/postgres/store-apply-artifacts-with-options/ Kind: method Apply artifacts with explicit maintenance, timeout, and stop-boundary controls. ```go func (backend *Store) ApplyArtifactsWithOptions(ctx context.Context, directory string, options RunnerOptions) error ``` ## Store.ArtifactStatus Canonical URL: https://riducms.com/reference/postgres/store-artifact-status/ Kind: method Report applied/pending artifacts and durable phased progress. ```go func (backend *Store) ArtifactStatus(ctx context.Context, directory string) ([]MigrationStatus, error) ``` ## Store.ArtifactPlan Canonical URL: https://riducms.com/reference/postgres/store-artifact-plan/ Kind: method Return immutable execution topology and checkpoints without applying work. ```go func (backend *Store) ArtifactPlan(ctx context.Context, directory string) ([]MigrationStatus, error) ``` ## RunnerOptions Canonical URL: https://riducms.com/reference/postgres/runner-options/ Kind: type Explicit operational admissions, bounded timeouts, and resumable boundaries. ```go type RunnerOptions struct { // AllowInsecureDatabase explicitly permits a PostgreSQL connection that can // fall back to plaintext. It is intended only for local migration drills. AllowInsecureDatabase bool // AllowMaintenance admits traffic-sensitive semantic steps such as content // rewrites, compiled data transforms, resource retirement, and // reference-index rebuilds. Every old writer must be stopped while they run. // It does not relax artifact validation. AllowMaintenance bool // AllowUnbounded permits a zero operational timeout. Without this explicit // admission, zero selects the runner's bounded production default. AllowUnbounded bool // AdvisoryLockWait bounds how long this runner waits for another migrator. AdvisoryLockWait time.Duration // LockTimeout bounds PostgreSQL lock acquisition inside a phase. LockTimeout time.Duration // StatementTimeout bounds one transactional SQL statement. StatementTimeout time.Duration // BatchTimeout bounds the complete execution of one checkpoint batch. BatchTimeout time.Duration // ConcurrentIndexTimeout bounds one CREATE/DROP INDEX CONCURRENTLY command. ConcurrentIndexTimeout time.Duration // IdleInTransactionTimeout protects a paused transactional phase. IdleInTransactionTimeout time.Duration // StopAfterPhase and StopAfterStep are explicit, successfully committed // rollout boundaries. A transaction phase can stop only at its final step. StopAfterPhase string StopAfterStep string // Notice receives non-blocking execution provenance after the complete // pending history has passed preflight. Notice func(MigrationNotice) // afterBatch is an internal deterministic interruption seam used to prove // that committed data and checkpoints resume together. Production callers // cannot configure it. afterBatch func(artifact, phase, step string, checkpoint json.RawMessage) error } ``` AllowMaintenance admits traffic-sensitive steps only after every old writer and worker is stopped; it does not relax artifact validation. Zero timeouts use bounded defaults unless AllowUnbounded is explicit. ## MigrationStatus Canonical URL: https://riducms.com/reference/postgres/migration-status/ Kind: type One artifact’s ledger state and optional phased progress. ```go type MigrationStatus struct { // Name is the complete artifact filename. Name string `json:"name"` // Checksum is the canonical artifact SHA-256 digest. Checksum string `json:"checksum"` // Version is the frozen artifact wire version. Version uint32 `json:"version"` // Applied reports whether the database ledger contains this artifact. Applied bool `json:"applied"` // Phases exposes resumable progress. Phases []MigrationPhaseStatus `json:"phases,omitempty"` } ``` ## MigrationPhaseStatus Canonical URL: https://riducms.com/reference/postgres/migration-phase-status/ Kind: type One immutable phase and its step checkpoints. ```go type MigrationPhaseStatus struct { ID string `json:"id"` Mode ridumigration.PhaseMode `json:"mode"` State string `json:"state"` Steps []MigrationStepStatus `json:"steps"` } ``` ## MaintenanceRequiredError Canonical URL: https://riducms.com/reference/postgres/maintenance-required-error/ Kind: type Lists artifacts refused before mutation because maintenance admission is required. ```go type MaintenanceRequiredError struct { Artifacts []string } ``` ## MigrationNotice Canonical URL: https://riducms.com/reference/postgres/migration-notice/ Kind: type Machine-readable non-blocking runner context. ```go type MigrationNotice struct { Code string Artifact string Message string } ``` ## AtlasVersion Canonical URL: https://riducms.com/reference/postgres/atlas-version/ Kind: constant The embedded Atlas planner version persisted into migration artifacts. ```go const AtlasVersion = "1.1.0" ``` ## Migration boundary codes Canonical URL: https://riducms.com/reference/postgres/migration-boundary-codes/ Kind: type Stable operator-facing code and sentinel error for migration admission and reproducibility failures. ```go const CodeMigrationPlanMismatch = "RIDU_MIGRATION_PLAN_MISMATCH"; var ErrMaintenanceRequired error ``` ## CodeMigrationPlanMismatch Canonical URL: https://riducms.com/reference/postgres/code-migration-plan-mismatch/ Kind: constant CodeMigrationPlanMismatch is the stable boundary code for an artifact whose contract cannot be reproduced from its embedded immutable inputs. ```go const CodeMigrationPlanMismatch = "RIDU_MIGRATION_PLAN_MISMATCH" ``` ## ErrMaintenanceRequired Canonical URL: https://riducms.com/reference/postgres/err-maintenance-required/ Kind: variable ErrMaintenanceRequired identifies pending whole-dataset work that requires an explicit maintenance window admission. ```go var ErrMaintenanceRequired = errors.New("migration maintenance admission is required") ``` ## MaintenanceRequiredError.Error Canonical URL: https://riducms.com/reference/postgres/maintenance-required-error-error-method/ Kind: method Public method MaintenanceRequiredError.Error from github.com/riducms/ridu/adapters/postgres. ```go func (err *MaintenanceRequiredError) Error() string ``` ## MaintenanceRequiredError.Is Canonical URL: https://riducms.com/reference/postgres/maintenance-required-error-is-method/ Kind: method Public method MaintenanceRequiredError.Is from github.com/riducms/ridu/adapters/postgres. ```go func (err *MaintenanceRequiredError) Is(target error) bool ``` ## NoticeAtlasProvenance Canonical URL: https://riducms.com/reference/postgres/notice-atlas-provenance/ Kind: constant NoticeAtlasProvenance identifies replay by an Atlas runner version other than the one that planned the frozen artifact SQL. ```go const NoticeAtlasProvenance = "RIDU_ATLAS_PROVENANCE" ``` ## ProjectMigrations Canonical URL: https://riducms.com/reference/postgres/project-migrations/ Kind: function ProjectMigrations binds checksum-protected callbacks into the compiled project while PostgreSQL retains ownership of every migration transaction and the credential-bearing connection boundary. ```go func ProjectMigrations(transforms ...ridumigration.DataTransform) ridumigration.ProjectDriver ``` ## RenameCollection Canonical URL: https://riducms.com/reference/postgres/rename-collection/ Kind: constant RenameCollection preserves a collection while changing its derived identity. ```go const RenameCollection RenameKind = "collection" ``` ## RenameField Canonical URL: https://riducms.com/reference/postgres/rename-field/ Kind: constant RenameField preserves a field while changing its derived identity. ```go const RenameField RenameKind = "field" ``` ## SafetyError.Error Canonical URL: https://riducms.com/reference/postgres/safety-error-error-method/ Kind: method Public method SafetyError.Error from github.com/riducms/ridu/adapters/postgres. ```go func (err *SafetyError) Error() string ``` ## Store.AcquireDocumentLock Canonical URL: https://riducms.com/reference/postgres/store-acquire-document-lock-method/ Kind: method Public method Store.AcquireDocumentLock from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) AcquireDocumentLock(ctx context.Context, candidate store.DocumentLock, now time.Time, takeover bool) (store.DocumentLock, bool, error) ``` ## Store.AllowAuthAttempt Canonical URL: https://riducms.com/reference/postgres/store-allow-auth-attempt-method/ Kind: method Public method Store.AllowAuthAttempt from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) AllowAuthAttempt(ctx context.Context, keyHash string, now time.Time, window time.Duration, maximum int) (bool, error) ``` ## Store.CancelTask Canonical URL: https://riducms.com/reference/postgres/store-cancel-task-method/ Kind: method Public method Store.CancelTask from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) CancelTask(ctx context.Context, id string) error ``` ## Store.ChangePasswordHash Canonical URL: https://riducms.com/reference/postgres/store-change-password-hash-method/ Kind: method Public method Store.ChangePasswordHash from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) ChangePasswordHash(ctx context.Context, collection schema.Collection, userID string, expectedPasswordHash, hash []byte) error ``` ## Store.ClaimTasks Canonical URL: https://riducms.com/reference/postgres/store-claim-tasks-method/ Kind: method Public method Store.ClaimTasks from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) ClaimTasks(ctx context.Context, request store.TaskClaim) ([]store.Task, error) ``` ## Store.CompleteTask Canonical URL: https://riducms.com/reference/postgres/store-complete-task-method/ Kind: method Public method Store.CompleteTask from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) CompleteTask(ctx context.Context, id, leaseToken string, output json.RawMessage) error ``` ## Store.CreateAPIKey Canonical URL: https://riducms.com/reference/postgres/store-create-api-key-method/ Kind: method Public method Store.CreateAPIKey from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) CreateAPIKey(ctx context.Context, key store.AuthAPIKey, sessionTokenHash string, now time.Time) error ``` ## Store.CreateAuthToken Canonical URL: https://riducms.com/reference/postgres/store-create-auth-token-method/ Kind: method Public method Store.CreateAuthToken from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) CreateAuthToken(ctx context.Context, token store.AuthToken) error ``` ## Store.CreateSession Canonical URL: https://riducms.com/reference/postgres/store-create-session-method/ Kind: method Public method Store.CreateSession from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) CreateSession(ctx context.Context, session store.AuthSession, expectedPasswordHash []byte) error ``` ## Store.DeleteAPIKey Canonical URL: https://riducms.com/reference/postgres/store-delete-api-key-method/ Kind: method Public method Store.DeleteAPIKey from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) DeleteAPIKey(ctx context.Context, collectionID schema.StableID, userID, id string) error ``` ## Store.DeletePreference Canonical URL: https://riducms.com/reference/postgres/store-delete-preference-method/ Kind: method Public method Store.DeletePreference from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) DeletePreference(ctx context.Context, collectionID schema.StableID, userID, key string) error ``` ## Store.DeletePreferences Canonical URL: https://riducms.com/reference/postgres/store-delete-preferences-method/ Kind: method Public method Store.DeletePreferences from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) DeletePreferences(ctx context.Context, collectionID schema.StableID, userID string) error ``` ## Store.DeleteSession Canonical URL: https://riducms.com/reference/postgres/store-delete-session-method/ Kind: method Public method Store.DeleteSession from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) DeleteSession(ctx context.Context, tokenHash string) error ``` ## Store.DeleteUserSession Canonical URL: https://riducms.com/reference/postgres/store-delete-user-session-method/ Kind: method Public method Store.DeleteUserSession from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) DeleteUserSession(ctx context.Context, collectionID schema.StableID, userID, sessionID string) error ``` ## Store.DeleteUserSessions Canonical URL: https://riducms.com/reference/postgres/store-delete-user-sessions-method/ Kind: method Public method Store.DeleteUserSessions from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) DeleteUserSessions(ctx context.Context, collectionID schema.StableID, userID string) error ``` ## Store.DismissTaskForTarget Canonical URL: https://riducms.com/reference/postgres/store-dismiss-task-for-target-method/ Kind: method Public method Store.DismissTaskForTarget from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) DismissTaskForTarget(ctx context.Context, id, slug string, target store.DocumentReference) error ``` ## Store.EnqueueTask Canonical URL: https://riducms.com/reference/postgres/store-enqueue-task-method/ Kind: method Public method Store.EnqueueTask from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) EnqueueTask(ctx context.Context, task store.Task) (store.Task, error) ``` ## Store.FailTask Canonical URL: https://riducms.com/reference/postgres/store-fail-task-method/ Kind: method Public method Store.FailTask from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) FailTask(ctx context.Context, failure store.TaskFailure) error ``` ## Store.FindAPIKey Canonical URL: https://riducms.com/reference/postgres/store-find-api-key-method/ Kind: method Public method Store.FindAPIKey from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) FindAPIKey(ctx context.Context, id string, now time.Time) (store.AuthAPIKey, error) ``` ## Store.FindAuthCredential Canonical URL: https://riducms.com/reference/postgres/store-find-auth-credential-method/ Kind: method Public method Store.FindAuthCredential from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) FindAuthCredential(ctx context.Context, collection schema.Collection, identity string) (store.AuthCredential, error) ``` ## Store.FindDocumentLock Canonical URL: https://riducms.com/reference/postgres/store-find-document-lock-method/ Kind: method Public method Store.FindDocumentLock from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) FindDocumentLock(ctx context.Context, collectionID schema.StableID, documentID string, now time.Time) (store.DocumentLock, error) ``` ## Store.FindSession Canonical URL: https://riducms.com/reference/postgres/store-find-session-method/ Kind: method Public method Store.FindSession from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) FindSession(ctx context.Context, tokenHash string, now time.Time) (store.AuthSession, error) ``` ## Store.FindTask Canonical URL: https://riducms.com/reference/postgres/store-find-task-method/ Kind: method Public method Store.FindTask from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) FindTask(ctx context.Context, id string) (store.Task, error) ``` ## Store.ForceUnlock Canonical URL: https://riducms.com/reference/postgres/store-force-unlock-method/ Kind: method Public method Store.ForceUnlock from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) ForceUnlock(ctx context.Context, collectionID schema.StableID, userID string) error ``` ## Store.GetPreference Canonical URL: https://riducms.com/reference/postgres/store-get-preference-method/ Kind: method Public method Store.GetPreference from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) GetPreference(ctx context.Context, collectionID schema.StableID, userID, key string) (store.Preference, error) ``` ## Store.HeartbeatTask Canonical URL: https://riducms.com/reference/postgres/store-heartbeat-task-method/ Kind: method Public method Store.HeartbeatTask from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) HeartbeatTask(ctx context.Context, id, leaseToken string, leaseDuration time.Duration) error ``` ## Store.ListAPIKeys Canonical URL: https://riducms.com/reference/postgres/store-list-api-keys-method/ Kind: method Public method Store.ListAPIKeys from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) ListAPIKeys(ctx context.Context, collectionID schema.StableID, userID string, now time.Time) ([]store.AuthAPIKey, error) ``` ## Store.ListSessions Canonical URL: https://riducms.com/reference/postgres/store-list-sessions-method/ Kind: method Public method Store.ListSessions from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) ListSessions(ctx context.Context, collectionID schema.StableID, userID string, now time.Time) ([]store.AuthSession, error) ``` ## Store.ListTasks Canonical URL: https://riducms.com/reference/postgres/store-list-tasks-method/ Kind: method Public method Store.ListTasks from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) ListTasks(ctx context.Context, request store.TaskList) ([]store.Task, error) ``` ## Store.LockUploadObjects Canonical URL: https://riducms.com/reference/postgres/store-lock-upload-objects-method/ Kind: method LockUploadObjects uses session advisory locks so object-store deletion and migration-owned adoption of an existing key cannot pass each other between database transactions or application processes. ```go func (backend *Store) LockUploadObjects(ctx context.Context, objectKeys []string) (func(), error) ``` ## Store.PruneExpiredAuth Canonical URL: https://riducms.com/reference/postgres/store-prune-expired-auth-method/ Kind: method PruneExpiredAuth removes one bounded batch from each expiring durable credential family. The candidate ordering matches the lifecycle indexes; row locks let every process run the same maintenance cycle without duplicate work or an application-wide coordinator. ```go func (backend *Store) PruneExpiredAuth(ctx context.Context, limit int) (store.AuthPruneResult, error) ``` ## Store.PruneTasks Canonical URL: https://riducms.com/reference/postgres/store-prune-tasks-method/ Kind: method Public method Store.PruneTasks from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) PruneTasks(ctx context.Context, limit int) (int, error) ``` ## Store.RecordFailedLogin Canonical URL: https://riducms.com/reference/postgres/store-record-failed-login-method/ Kind: method Public method Store.RecordFailedLogin from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) RecordFailedLogin(ctx context.Context, collectionID schema.StableID, userID string, now time.Time, maximum int, lockDuration time.Duration) (store.AuthCredential, error) ``` ## Store.ReleaseDocumentLock Canonical URL: https://riducms.com/reference/postgres/store-release-document-lock-method/ Kind: method Public method Store.ReleaseDocumentLock from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) ReleaseDocumentLock(ctx context.Context, collectionID schema.StableID, documentID string, ownerCollectionID schema.StableID, ownerID string) error ``` ## Store.ReleaseTask Canonical URL: https://riducms.com/reference/postgres/store-release-task-method/ Kind: method Public method Store.ReleaseTask from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) ReleaseTask(ctx context.Context, id, leaseToken string, delay time.Duration, code, message string) error ``` ## Store.ResetLoginAttempts Canonical URL: https://riducms.com/reference/postgres/store-reset-login-attempts-method/ Kind: method Public method Store.ResetLoginAttempts from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) ResetLoginAttempts(ctx context.Context, collectionID schema.StableID, userID string, now time.Time) (bool, error) ``` ## Store.ResetPasswordWithToken Canonical URL: https://riducms.com/reference/postgres/store-reset-password-with-token-method/ Kind: method Public method Store.ResetPasswordWithToken from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) ResetPasswordWithToken(ctx context.Context, collectionID schema.StableID, tokenHash string, hash []byte, now time.Time) (string, error) ``` ## Store.RotateSession Canonical URL: https://riducms.com/reference/postgres/store-rotate-session-method/ Kind: method Public method Store.RotateSession from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) RotateSession(ctx context.Context, currentHash string, replacement store.AuthSession, now time.Time) error ``` ## Store.SetPasswordHash Canonical URL: https://riducms.com/reference/postgres/store-set-password-hash-method/ Kind: method Public method Store.SetPasswordHash from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) SetPasswordHash(ctx context.Context, collection schema.Collection, userID string, hash []byte, initiallyVerified bool) error ``` ## Store.SetPreference Canonical URL: https://riducms.com/reference/postgres/store-set-preference-method/ Kind: method Public method Store.SetPreference from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) SetPreference(ctx context.Context, preference store.Preference) (store.Preference, error) ``` ## Store.TouchAPIKey Canonical URL: https://riducms.com/reference/postgres/store-touch-api-key-method/ Kind: method Public method Store.TouchAPIKey from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) TouchAPIKey(ctx context.Context, id string, now time.Time) error ``` ## Store.UpgradePasswordHash Canonical URL: https://riducms.com/reference/postgres/store-upgrade-password-hash-method/ Kind: method Public method Store.UpgradePasswordHash from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) UpgradePasswordHash(ctx context.Context, collection schema.Collection, userID string, expectedPasswordHash, hash []byte) error ``` ## Store.VerifyEmailWithToken Canonical URL: https://riducms.com/reference/postgres/store-verify-email-with-token-method/ Kind: method Public method Store.VerifyEmailWithToken from github.com/riducms/ridu/adapters/postgres. ```go func (backend *Store) VerifyEmailWithToken(ctx context.Context, collectionID schema.StableID, tokenHash string, now time.Time) (string, error) ``` --- # API Reference: sqlite Canonical URL: https://riducms.com/reference/sqlite/ Package: github.com/riducms/ridu/adapters/sqlite The official embedded SQLite store and its immutable, reversible migration lifecycle. ## Open Canonical URL: https://riducms.com/reference/sqlite/open/ Kind: function Open a SQLite store at a filesystem path, file URI, or private in-memory database. ```go func Open(ctx context.Context, path string) (*Store, error) ``` ```go backend, err := sqlite.Open(ctx, os.Getenv("RIDU_SQLITE_PATH")) if err != nil { return err } defer backend.Close() ``` ## OpenWithConfig Canonical URL: https://riducms.com/reference/sqlite/open-with-config/ Kind: function Open a SQLite store with explicit busy-timeout, WAL, and connection bounds. ```go func OpenWithConfig(ctx context.Context, config Config) (*Store, error) ``` ## Config Canonical URL: https://riducms.com/reference/sqlite/config/ Kind: type Bounded connection behavior for the embedded SQLite store. ```go type Config struct { // Path is a filesystem path, a file: SQLite URI, or :memory:. Path string // BusyTimeout bounds how long SQLite waits for another writer. Zero selects // ten seconds. Negative values and values above SQLite's signed 32-bit // millisecond limit are rejected. BusyTimeout time.Duration // DisableWAL keeps file databases in their existing journal mode. WAL is // enabled by default because it permits readers while the single writer is // active. SQLite memory databases ignore WAL mode. DisableWAL bool // MaxConnections bounds pooled readers. Operation transactions still use // BEGIN IMMEDIATE and SQLite's single-writer contract. MaxConnections int } ``` Zero values select safe local defaults. File databases enable WAL unless DisableWAL is set; SQLite still has one writer. ## Store Canonical URL: https://riducms.com/reference/sqlite/store/ Kind: type A SQLite implementation of Ridu’s document, snapshot, auth, preference, task, lock, version, and migration store contracts. ```go type Store struct { db *sql.DB anchor *sql.Conn dsn string filePath string lockPath string now func() time.Time writeGate chan struct{} uploadGate chan struct{} } ``` Use the application and Local API for content operations. SQLite is supported on a local filesystem and one application host; it is not a shared-network-filesystem or multi-host store. ## Store.Close Canonical URL: https://riducms.com/reference/sqlite/store-close/ Kind: method Release every pooled SQLite connection. ```go func (backend *Store) Close() error ``` ## Store.Ping Canonical URL: https://riducms.com/reference/sqlite/store-ping/ Kind: method Check connectivity and foreign-key enforcement. ```go func (backend *Store) Ping(ctx context.Context) error ``` ## Store.Ready Canonical URL: https://riducms.com/reference/sqlite/store-ready/ Kind: method Prove connectivity and an exact applied manifest. ```go func (backend *Store) Ready(ctx context.Context, manifest schema.Manifest) error ``` ## Store.ReadyWithMigrationHistory Canonical URL: https://riducms.com/reference/sqlite/store-ready-with-migration-history/ Kind: method Prove ordinary readiness and exact agreement with executable migration history. ```go func (backend *Store) ReadyWithMigrationHistory(ctx context.Context, manifest schema.Manifest, expectedHistoryDigest string) error ``` Compares every ordered ledger filename and artifact digest with the fingerprint embedded by ridu build inside the readiness read transaction. ## Store.Begin Canonical URL: https://riducms.com/reference/sqlite/store-begin/ Kind: method Begin a write-capable transaction with an immediate writer reservation. ```go func (backend *Store) Begin(ctx context.Context) (store.Transaction, error) ``` ## Store.BeginSnapshot Canonical URL: https://riducms.com/reference/sqlite/store-begin-snapshot/ Kind: method Begin a stable deferred read snapshot. ```go func (backend *Store) BeginSnapshot(ctx context.Context) (store.Transaction, error) ``` ## Store.Migrate Canonical URL: https://riducms.com/reference/sqlite/store-migrate/ Kind: method Install adapter-owned tables and record the manifest for development or bootstrap use. ```go func (backend *Store) Migrate(ctx context.Context, manifest schema.Manifest) error ``` ## CreateArtifact Canonical URL: https://riducms.com/reference/sqlite/create-artifact/ Kind: function Plan and atomically write one immutable SQLite migration artifact. ```go func CreateArtifact(ctx context.Context, directory, name string, after schema.Manifest, now time.Time, allowDestructive bool, transforms ...ridumigration.DataTransformDescriptor) (CreatedArtifact, error) ``` ## InspectArtifacts Canonical URL: https://riducms.com/reference/sqlite/inspect-artifacts/ Kind: function Report immutable migration state without creating or changing the selected SQLite database. ```go func InspectArtifacts(ctx context.Context, path, directory string, executableManifest schema.Manifest) ([]MigrationStatus, error) ``` A missing database is reported with every artifact pending. Existing databases are opened read-only without adapter write pragmas or journal sidecars. ## VerifyArtifacts Canonical URL: https://riducms.com/reference/sqlite/verify-artifacts/ Kind: function Replay complete immutable history in an isolated temporary SQLite database. ```go func VerifyArtifacts(ctx context.Context, directory string, transforms ...ridumigration.DataTransform) error ``` ## ProjectMigrations Canonical URL: https://riducms.com/reference/sqlite/project-migrations/ Kind: function Build the compiled-project driver for registered transaction-bound data transforms. ```go func ProjectMigrations(transforms ...ridumigration.DataTransform) ridumigration.ProjectDriver ``` ## CreatedArtifact Canonical URL: https://riducms.com/reference/sqlite/created-artifact/ Kind: type The stable filesystem identity of a newly committed artifact. ```go type CreatedArtifact struct { Path string `json:"path"` Name string `json:"name"` Checksum string `json:"checksum"` Version uint32 `json:"version"` } ``` ## MigrationStatus Canonical URL: https://riducms.com/reference/sqlite/migration-status/ Kind: type One immutable artifact relative to the SQLite ledger. ```go type MigrationStatus struct { Name string `json:"name"` Checksum string `json:"checksum"` Version uint32 `json:"version"` Applied bool `json:"applied"` Phases []MigrationPhaseStatus `json:"phases"` } ``` ## MigrationPhaseStatus Canonical URL: https://riducms.com/reference/sqlite/migration-phase-status/ Kind: type One atomic transaction phase in an artifact. ```go type MigrationPhaseStatus struct { ID string `json:"id"` Mode ridumigration.PhaseMode `json:"mode"` State string `json:"state"` Steps []MigrationStepStatus `json:"steps"` } ``` ## MigrationStepStatus Canonical URL: https://riducms.com/reference/sqlite/migration-step-status/ Kind: type One SQLite artifact step. ```go type MigrationStepStatus struct { ID string `json:"id"` Kind ridumigration.StepKind `json:"kind"` State string `json:"state"` } ``` ## SafetyError Canonical URL: https://riducms.com/reference/sqlite/safety-error/ Kind: type A valid transition that requires explicit destructive approval. ```go type SafetyError struct { Risks []ridumigration.Risk } ``` ## Store.ApplyArtifacts Canonical URL: https://riducms.com/reference/sqlite/store-apply-artifacts/ Kind: method Validate and atomically apply all pending immutable artifacts. ```go func (backend *Store) ApplyArtifacts(ctx context.Context, directory string, transforms ...ridumigration.DataTransform) error ``` ## Store.ArtifactPlan Canonical URL: https://riducms.com/reference/sqlite/store-artifact-plan/ Kind: method Return manifest-bound pending and applied artifact topology. ```go func (backend *Store) ArtifactPlan(ctx context.Context, directory string, executableManifest schema.Manifest) ([]MigrationStatus, error) ``` ## Store.ArtifactStatus Canonical URL: https://riducms.com/reference/sqlite/store-artifact-status/ Kind: method Report immutable history against the SQLite ledger and executable manifest. ```go func (backend *Store) ArtifactStatus(ctx context.Context, directory string, executableManifest schema.Manifest) ([]MigrationStatus, error) ``` ## Store.DownArtifacts Canonical URL: https://riducms.com/reference/sqlite/store-down-artifacts/ Kind: method Atomically reverse the latest applied artifact. ```go func (backend *Store) DownArtifacts(ctx context.Context, directory string, transforms ...ridumigration.DataTransform) error ``` ## Store.ResetArtifacts Canonical URL: https://riducms.com/reference/sqlite/store-reset-artifacts/ Kind: method Atomically reverse all applied artifacts. ```go func (backend *Store) ResetArtifacts(ctx context.Context, directory string, transforms ...ridumigration.DataTransform) error ``` ## Store.RefreshArtifacts Canonical URL: https://riducms.com/reference/sqlite/store-refresh-artifacts/ Kind: method Atomically reverse and replay committed history. ```go func (backend *Store) RefreshArtifacts(ctx context.Context, directory string, transforms ...ridumigration.DataTransform) error ``` ## Store.FreshArtifacts Canonical URL: https://riducms.com/reference/sqlite/store-fresh-artifacts/ Kind: method Drop non-internal objects and replay committed history atomically. ```go func (backend *Store) FreshArtifacts(ctx context.Context, directory string, transforms ...ridumigration.DataTransform) error ``` ## SafetyError.Error Canonical URL: https://riducms.com/reference/sqlite/safety-error-error-method/ Kind: method Public method SafetyError.Error from github.com/riducms/ridu/adapters/sqlite. ```go func (err *SafetyError) Error() string ``` ## Store.AcquireDocumentLock Canonical URL: https://riducms.com/reference/sqlite/store-acquire-document-lock-method/ Kind: method Public method Store.AcquireDocumentLock from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) AcquireDocumentLock(ctx context.Context, candidate store.DocumentLock, now time.Time, takeover bool) (store.DocumentLock, bool, error) ``` ## Store.AllowAuthAttempt Canonical URL: https://riducms.com/reference/sqlite/store-allow-auth-attempt-method/ Kind: method Public method Store.AllowAuthAttempt from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) AllowAuthAttempt(ctx context.Context, keyHash string, now time.Time, window time.Duration, maximum int) (bool, error) ``` ## Store.CancelTask Canonical URL: https://riducms.com/reference/sqlite/store-cancel-task-method/ Kind: method Public method Store.CancelTask from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) CancelTask(ctx context.Context, id string) error ``` ## Store.ChangePasswordHash Canonical URL: https://riducms.com/reference/sqlite/store-change-password-hash-method/ Kind: method Public method Store.ChangePasswordHash from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) ChangePasswordHash(ctx context.Context, collection schema.Collection, userID string, expectedPasswordHash, hash []byte) error ``` ## Store.ClaimTasks Canonical URL: https://riducms.com/reference/sqlite/store-claim-tasks-method/ Kind: method Public method Store.ClaimTasks from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) ClaimTasks(ctx context.Context, request store.TaskClaim) ([]store.Task, error) ``` ## Store.CompleteTask Canonical URL: https://riducms.com/reference/sqlite/store-complete-task-method/ Kind: method Public method Store.CompleteTask from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) CompleteTask(ctx context.Context, id, leaseToken string, output json.RawMessage) error ``` ## Store.CreateAPIKey Canonical URL: https://riducms.com/reference/sqlite/store-create-api-key-method/ Kind: method Public method Store.CreateAPIKey from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) CreateAPIKey(ctx context.Context, key store.AuthAPIKey, sessionTokenHash string, now time.Time) error ``` ## Store.CreateAuthToken Canonical URL: https://riducms.com/reference/sqlite/store-create-auth-token-method/ Kind: method Public method Store.CreateAuthToken from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) CreateAuthToken(ctx context.Context, token store.AuthToken) error ``` ## Store.CreateSession Canonical URL: https://riducms.com/reference/sqlite/store-create-session-method/ Kind: method Public method Store.CreateSession from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) CreateSession(ctx context.Context, session store.AuthSession, expectedPasswordHash []byte) error ``` ## Store.DeleteAPIKey Canonical URL: https://riducms.com/reference/sqlite/store-delete-api-key-method/ Kind: method Public method Store.DeleteAPIKey from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) DeleteAPIKey(ctx context.Context, collectionID schema.StableID, userID, id string) error ``` ## Store.DeletePreference Canonical URL: https://riducms.com/reference/sqlite/store-delete-preference-method/ Kind: method Public method Store.DeletePreference from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) DeletePreference(ctx context.Context, collectionID schema.StableID, userID, key string) error ``` ## Store.DeletePreferences Canonical URL: https://riducms.com/reference/sqlite/store-delete-preferences-method/ Kind: method Public method Store.DeletePreferences from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) DeletePreferences(ctx context.Context, collectionID schema.StableID, userID string) error ``` ## Store.DeleteSession Canonical URL: https://riducms.com/reference/sqlite/store-delete-session-method/ Kind: method Public method Store.DeleteSession from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) DeleteSession(ctx context.Context, tokenHash string) error ``` ## Store.DeleteUserSession Canonical URL: https://riducms.com/reference/sqlite/store-delete-user-session-method/ Kind: method Public method Store.DeleteUserSession from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) DeleteUserSession(ctx context.Context, collectionID schema.StableID, userID, sessionID string) error ``` ## Store.DeleteUserSessions Canonical URL: https://riducms.com/reference/sqlite/store-delete-user-sessions-method/ Kind: method Public method Store.DeleteUserSessions from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) DeleteUserSessions(ctx context.Context, collectionID schema.StableID, userID string) error ``` ## Store.DismissTaskForTarget Canonical URL: https://riducms.com/reference/sqlite/store-dismiss-task-for-target-method/ Kind: method Public method Store.DismissTaskForTarget from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) DismissTaskForTarget(ctx context.Context, id, slug string, target store.DocumentReference) error ``` ## Store.EnqueueTask Canonical URL: https://riducms.com/reference/sqlite/store-enqueue-task-method/ Kind: method Public method Store.EnqueueTask from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) EnqueueTask(ctx context.Context, task store.Task) (store.Task, error) ``` ## Store.FailTask Canonical URL: https://riducms.com/reference/sqlite/store-fail-task-method/ Kind: method Public method Store.FailTask from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) FailTask(ctx context.Context, failure store.TaskFailure) error ``` ## Store.FindAPIKey Canonical URL: https://riducms.com/reference/sqlite/store-find-api-key-method/ Kind: method Public method Store.FindAPIKey from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) FindAPIKey(ctx context.Context, id string, now time.Time) (store.AuthAPIKey, error) ``` ## Store.FindAuthCredential Canonical URL: https://riducms.com/reference/sqlite/store-find-auth-credential-method/ Kind: method Public method Store.FindAuthCredential from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) FindAuthCredential(ctx context.Context, collection schema.Collection, identity string) (store.AuthCredential, error) ``` ## Store.FindDocumentLock Canonical URL: https://riducms.com/reference/sqlite/store-find-document-lock-method/ Kind: method Public method Store.FindDocumentLock from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) FindDocumentLock(ctx context.Context, collectionID schema.StableID, documentID string, now time.Time) (store.DocumentLock, error) ``` ## Store.FindSession Canonical URL: https://riducms.com/reference/sqlite/store-find-session-method/ Kind: method Public method Store.FindSession from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) FindSession(ctx context.Context, tokenHash string, now time.Time) (store.AuthSession, error) ``` ## Store.FindTask Canonical URL: https://riducms.com/reference/sqlite/store-find-task-method/ Kind: method Public method Store.FindTask from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) FindTask(ctx context.Context, id string) (store.Task, error) ``` ## Store.ForceUnlock Canonical URL: https://riducms.com/reference/sqlite/store-force-unlock-method/ Kind: method Public method Store.ForceUnlock from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) ForceUnlock(ctx context.Context, collectionID schema.StableID, userID string) error ``` ## Store.GetPreference Canonical URL: https://riducms.com/reference/sqlite/store-get-preference-method/ Kind: method Public method Store.GetPreference from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) GetPreference(ctx context.Context, collectionID schema.StableID, userID, key string) (store.Preference, error) ``` ## Store.HeartbeatTask Canonical URL: https://riducms.com/reference/sqlite/store-heartbeat-task-method/ Kind: method Public method Store.HeartbeatTask from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) HeartbeatTask(ctx context.Context, id, leaseToken string, leaseDuration time.Duration) error ``` ## Store.ListAPIKeys Canonical URL: https://riducms.com/reference/sqlite/store-list-api-keys-method/ Kind: method Public method Store.ListAPIKeys from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) ListAPIKeys(ctx context.Context, collectionID schema.StableID, userID string, now time.Time) ([]store.AuthAPIKey, error) ``` ## Store.ListSessions Canonical URL: https://riducms.com/reference/sqlite/store-list-sessions-method/ Kind: method Public method Store.ListSessions from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) ListSessions(ctx context.Context, collectionID schema.StableID, userID string, now time.Time) ([]store.AuthSession, error) ``` ## Store.ListTasks Canonical URL: https://riducms.com/reference/sqlite/store-list-tasks-method/ Kind: method Public method Store.ListTasks from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) ListTasks(ctx context.Context, request store.TaskList) ([]store.Task, error) ``` ## Store.LockUploadObjects Canonical URL: https://riducms.com/reference/sqlite/store-lock-upload-objects-method/ Kind: method LockUploadObjects serializes upload admission and cleanup across every process sharing a file database. SQLite memory databases are private to one Store and use the equivalent in-process gate. ```go func (backend *Store) LockUploadObjects(ctx context.Context, objectKeys []string) (func(), error) ``` ## Store.PruneExpiredAuth Canonical URL: https://riducms.com/reference/sqlite/store-prune-expired-auth-method/ Kind: method PruneExpiredAuth removes at most limit records from each expiring auth family. BEGIN IMMEDIATE serializes candidates across processes so two maintenance workers cannot count or delete the same record. ```go func (backend *Store) PruneExpiredAuth(ctx context.Context, limit int) (store.AuthPruneResult, error) ``` ## Store.PruneTasks Canonical URL: https://riducms.com/reference/sqlite/store-prune-tasks-method/ Kind: method Public method Store.PruneTasks from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) PruneTasks(ctx context.Context, limit int) (int, error) ``` ## Store.RecordFailedLogin Canonical URL: https://riducms.com/reference/sqlite/store-record-failed-login-method/ Kind: method Public method Store.RecordFailedLogin from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) RecordFailedLogin(ctx context.Context, collectionID schema.StableID, userID string, now time.Time, maximum int, lockDuration time.Duration) (store.AuthCredential, error) ``` ## Store.ReleaseDocumentLock Canonical URL: https://riducms.com/reference/sqlite/store-release-document-lock-method/ Kind: method Public method Store.ReleaseDocumentLock from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) ReleaseDocumentLock(ctx context.Context, collectionID schema.StableID, documentID string, ownerCollectionID schema.StableID, ownerID string) error ``` ## Store.ReleaseTask Canonical URL: https://riducms.com/reference/sqlite/store-release-task-method/ Kind: method Public method Store.ReleaseTask from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) ReleaseTask(ctx context.Context, id, leaseToken string, delay time.Duration, code, message string) error ``` ## Store.ResetLoginAttempts Canonical URL: https://riducms.com/reference/sqlite/store-reset-login-attempts-method/ Kind: method Public method Store.ResetLoginAttempts from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) ResetLoginAttempts(ctx context.Context, collectionID schema.StableID, userID string, now time.Time) (bool, error) ``` ## Store.ResetPasswordWithToken Canonical URL: https://riducms.com/reference/sqlite/store-reset-password-with-token-method/ Kind: method Public method Store.ResetPasswordWithToken from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) ResetPasswordWithToken(ctx context.Context, collectionID schema.StableID, tokenHash string, hash []byte, now time.Time) (string, error) ``` ## Store.RotateSession Canonical URL: https://riducms.com/reference/sqlite/store-rotate-session-method/ Kind: method Public method Store.RotateSession from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) RotateSession(ctx context.Context, currentHash string, replacement store.AuthSession, now time.Time) error ``` ## Store.SetPasswordHash Canonical URL: https://riducms.com/reference/sqlite/store-set-password-hash-method/ Kind: method Public method Store.SetPasswordHash from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) SetPasswordHash(ctx context.Context, collection schema.Collection, userID string, hash []byte, initiallyVerified bool) error ``` ## Store.SetPreference Canonical URL: https://riducms.com/reference/sqlite/store-set-preference-method/ Kind: method Public method Store.SetPreference from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) SetPreference(ctx context.Context, preference store.Preference) (store.Preference, error) ``` ## Store.TouchAPIKey Canonical URL: https://riducms.com/reference/sqlite/store-touch-api-key-method/ Kind: method Public method Store.TouchAPIKey from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) TouchAPIKey(ctx context.Context, id string, now time.Time) error ``` ## Store.UpgradePasswordHash Canonical URL: https://riducms.com/reference/sqlite/store-upgrade-password-hash-method/ Kind: method Public method Store.UpgradePasswordHash from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) UpgradePasswordHash(ctx context.Context, collection schema.Collection, userID string, expectedPasswordHash, hash []byte) error ``` ## Store.VerifyEmailWithToken Canonical URL: https://riducms.com/reference/sqlite/store-verify-email-with-token-method/ Kind: method Public method Store.VerifyEmailWithToken from github.com/riducms/ridu/adapters/sqlite. ```go func (backend *Store) VerifyEmailWithToken(ctx context.Context, collectionID schema.StableID, tokenHash string, now time.Time) (string, error) ``` --- # API Reference: mongodb Canonical URL: https://riducms.com/reference/mongodb/ Package: github.com/riducms/ridu/adapters/mongodb The official replica-set MongoDB store, additive development index synchronization, and immutable forward-only migration lifecycle. ## Open Canonical URL: https://riducms.com/reference/mongodb/open/ Kind: function Open a verified-TLS MongoDB replica-set database with bounded defaults. ```go func Open(ctx context.Context, databaseURL string) (*Store, error) ``` The URL must select one database. Open checks for a writable replica-set primary with logical sessions but does not create collections, indexes, or migration state. ```go backend, err := mongodb.Open(ctx, os.Getenv("DATABASE_URL")) if err != nil { return err } defer backend.Close() ``` ## OpenWithConfig Canonical URL: https://riducms.com/reference/mongodb/open-with-config/ Kind: function Open the store with explicit transport, timeout, application-name, and pool bounds. ```go func OpenWithConfig(ctx context.Context, config Config) (*Store, error) ``` ## Config Canonical URL: https://riducms.com/reference/mongodb/config/ Kind: type Runtime-only MongoDB connection behavior. ```go type Config struct { DatabaseURL string // AllowInsecureTransport permits plaintext or certificate verification // bypasses for an explicitly selected local development fixture. AllowInsecureTransport bool ApplicationName string ConnectTimeout time.Duration ServerSelectionTimeout time.Duration MaxConnectionIdleTime time.Duration MaxPoolSize uint64 MinPoolSize uint64 } ``` DatabaseURL never belongs in manifests, artifacts, generated contracts, or diagnostics. Negative durations and invalid pool bounds are rejected. ## Store Canonical URL: https://riducms.com/reference/mongodb/store/ Kind: type A replica-set implementation of Ridu’s document, snapshot, auth, preference, task, lock, upload, readiness, and migration contracts. ```go type Store struct { client *mongo.Client database *mongo.Database now func() time.Time closeMu sync.Mutex closed bool closeErr error indexLifecycleMu sync.Mutex indexesMu sync.RWMutex verifiedIndexes map[schema.StableID]mongoVerifiedIndexPlan verifiedVersionIndexes map[schema.StableID]bool verifiedReferenceIndexes bool verifiedPreferenceIndexes bool verifiedDocumentLockIndexes bool verifiedTaskIndexes bool verifiedAuthIndexes bool verifiedUploadLockIndexes bool uploadLockRetry time.Duration uploadLockWait time.Duration uploadLockLifecycleMu sync.Mutex uploadLockLifecycleCtx context.Context uploadLockLifecycleCancel context.CancelFunc uploadLockOperations sync.WaitGroup } ``` Use the application and Local API for content operations; the adapter exposes no raw BSON filter, database handle, ObjectID contract, or second Mongo-specific content API. Transactions add auth/bootstrap/unlock, versions, distinct, windows, upload-reference lookup, and transaction-level upload locking to store.Transaction. Production support is limited to generated starter and blank applications on Linux x86-64 with MongoDB Community 8.2.9, SCRAM-SHA-256, verified TLS, and a writable three-member replica set. Atlas, DocumentDB, Cosmos DB, standalone or sharded deployments, and other versions, topologies, and platforms are not supported. ## Store.Close Canonical URL: https://riducms.com/reference/mongodb/store-close/ Kind: method Idempotently stop adapter work and release the MongoDB client within an internal bound. ```go func (backend *Store) Close() error ``` ## Store.Ping Canonical URL: https://riducms.com/reference/mongodb/store-ping/ Kind: method Check that the replica set can serve a primary read. ```go func (backend *Store) Ping(ctx context.Context) error ``` ## Store.Ready Canonical URL: https://riducms.com/reference/mongodb/store-ready/ Kind: method Prove manifest-ledger and complete managed-index readiness for compatibility callers. ```go func (backend *Store) Ready(ctx context.Context, manifest schema.Manifest) error ``` This is the legacy manifest-only contract. Production binaries built by ridu build use ReadyWithMigrationHistory. ## Store.ReadyWithMigrationHistory Canonical URL: https://riducms.com/reference/mongodb/store-ready-with-migration-history/ Kind: method Prove exact executable history, manifest, completed step state, and managed-index readiness. ```go func (backend *Store) ReadyWithMigrationHistory(ctx context.Context, manifest schema.Manifest, expectedHistoryDigest string) error ``` It compares every ordered ledger filename and artifact digest with the ridu build fingerprint, verifies indexes without mutation, then rereads the ledger to reject a concurrent change. ## Store.Begin Canonical URL: https://riducms.com/reference/mongodb/store-begin/ Kind: method Begin a majority-committed snapshot-isolated write transaction. ```go func (backend *Store) Begin(ctx context.Context) (store.Transaction, error) ``` ## Store.BeginSnapshot Canonical URL: https://riducms.com/reference/mongodb/store-begin-snapshot/ Kind: method Begin a stable snapshot in read-only adapter mode. ```go func (backend *Store) BeginSnapshot(ctx context.Context) (store.Transaction, error) ``` ## Store.SyncIndexes Canonical URL: https://riducms.com/reference/mongodb/store-sync-indexes/ Kind: method Create only missing managed indexes for explicit development/bootstrap synchronization. ```go func (backend *Store) SyncIndexes(ctx context.Context, manifest schema.Manifest) error ``` SyncIndexes never drops or rewrites an index and does not install migration state. Production changes use reviewed immutable artifacts. ## Store.VerifyIndexes Canonical URL: https://riducms.com/reference/mongodb/store-verify-indexes/ Kind: method Non-mutatingly verify the complete managed index plan and authorize this Store instance. ```go func (backend *Store) VerifyIndexes(ctx context.Context, manifest schema.Manifest) error ``` Open alone does not authorize content operations; authorization is published only after every application and framework index matches. ## CreateArtifact Canonical URL: https://riducms.com/reference/mongodb/create-artifact/ Kind: function Publish an artifact with the frozen legacy MongoDB planner 1.0.0 creator. ```go func CreateArtifact(ctx context.Context, directory, name string, after schema.Manifest, now time.Time) (CreatedArtifact, error) ``` This legacy-v1 entry point remains only for existing direct callers and immutable-history compatibility. New application and CLI-facing migrations use CreateArtifactWithOptions and planner 2.0.0. Planning is offline and never receives a database URL, secret, or live MongoDB state. ## CreateArtifactWithOptions Canonical URL: https://riducms.com/reference/mongodb/create-artifact-with-options/ Kind: function Publish the current MongoDB planner 2.0.0 artifact with reviewed semantic intent. ```go func CreateArtifactWithOptions(ctx context.Context, directory, name string, after schema.Manifest, now time.Time, options ArtifactOptions) (CreatedArtifact, error) ``` This is the creator used by ridu migrate create. It validates the immutable prefix, freezes confirmed renames and transform descriptors, records reviewed retirement/destructive findings, and never opens MongoDB. ## InspectArtifacts Canonical URL: https://riducms.com/reference/mongodb/inspect-artifacts/ Kind: function Inspect exact local history against the live ledger without mutation. ```go func InspectArtifacts(ctx context.Context, config Config, directory string, executableManifest schema.Manifest) ([]MigrationStatus, error) ``` CLI plan/status validates and precompiles the exact in-memory history through the executable manifest before connecting, then uses that retained snapshot for every ledger check. ## VerifyArtifacts Canonical URL: https://riducms.com/reference/mongodb/verify-artifacts/ Kind: function Replay complete immutable history through the adapter runner in an isolated shadow database. ```go func VerifyArtifacts(ctx context.Context, config Config, directory string, transforms ...ridumigration.DataTransform) error ``` The operational credential creates and drops a randomly named shadow database; application collections are not used. Semantic histories use VerifyArtifactsWithOptions with explicit maintenance admission because verification replays the complete history. ## VerifyArtifactsWithOptions Canonical URL: https://riducms.com/reference/mongodb/verify-artifacts-with-options/ Kind: function Verify complete history with explicit maintenance admission and bounded runner controls. ```go func VerifyArtifactsWithOptions(ctx context.Context, config Config, directory string, options RunnerOptions, transforms ...ridumigration.DataTransform) error ``` ## ProjectMigrations Canonical URL: https://riducms.com/reference/mongodb/project-migrations/ Kind: function Build the compiled-project driver for checksum-bound transaction-scoped data transforms. ```go func ProjectMigrations(transforms ...ridumigration.DataTransform) ridumigration.ProjectDriver ``` Callbacks remain compiled into the application; artifacts contain only validated names and checksums. MongoDB owns their transactions, checkpoints, and private connection boundary. ## ArtifactOptions Canonical URL: https://riducms.com/reference/mongodb/artifact-options/ Kind: type Reviewed semantic intent frozen into a planner 2.0.0 artifact. ```go type ArtifactOptions struct { AllowDestructive bool Renames []ridumigration.Rename DataTransforms []ridumigration.DataTransformDescriptor } ``` ## CreatedArtifact Canonical URL: https://riducms.com/reference/mongodb/created-artifact/ Kind: type The stable filesystem identity of one newly published artifact. ```go type CreatedArtifact struct { Path string `json:"path"` Name string `json:"name"` Checksum string `json:"checksum"` Version uint32 `json:"version"` } ``` ## RunnerOptions Canonical URL: https://riducms.com/reference/mongodb/runner-options/ Kind: type Explicit maintenance admission and bounded lease/operation controls. ```go type RunnerOptions struct { AllowMaintenance bool AllowUnbounded bool LeaseWait time.Duration LeaseDuration time.Duration OperationTimeout time.Duration } ``` Zero values select bounded defaults unless AllowUnbounded explicitly admits an unbounded wait or operation; lease expiry remains bounded. ## MigrationStatus Canonical URL: https://riducms.com/reference/mongodb/migration-status/ Kind: type One immutable artifact relative to the MongoDB ledger. ```go type MigrationStatus struct { Name string `json:"name"` Checksum string `json:"checksum"` Version uint32 `json:"version"` Applied bool `json:"applied"` Phases []MigrationPhaseStatus `json:"phases,omitempty"` } ``` ## MigrationPhaseStatus Canonical URL: https://riducms.com/reference/mongodb/migration-phase-status/ Kind: type One immutable transaction, batch, or non-transaction execution boundary. ```go type MigrationPhaseStatus struct { ID string `json:"id"` Mode ridumigration.PhaseMode `json:"mode"` State string `json:"state"` Steps []MigrationStepStatus `json:"steps"` } ``` ## MigrationStepStatus Canonical URL: https://riducms.com/reference/mongodb/migration-step-status/ Kind: type One durable typed MongoDB executor invocation. ```go type MigrationStepStatus struct { ID string `json:"id"` Kind ridumigration.StepKind `json:"kind"` State string `json:"state"` } ``` ## SafetyError Canonical URL: https://riducms.com/reference/mongodb/safety-error/ Kind: type A valid transition that still requires explicit destructive review. ```go type SafetyError struct { Risks []ridumigration.Risk } ``` ## Store.ApplyArtifacts Canonical URL: https://riducms.com/reference/mongodb/store-apply-artifacts/ Kind: method Validate complete immutable history, take the fenced lease, and apply pending work. ```go func (backend *Store) ApplyArtifacts(ctx context.Context, directory string, transforms ...ridumigration.DataTransform) error ``` The lifecycle is forward-only: there are no down, reset, refresh, or fresh methods. Correct forward with another reviewed artifact or restore a matched database-and-upload recovery point. ## Store.ApplyArtifactsWithOptions Canonical URL: https://riducms.com/reference/mongodb/store-apply-artifacts-with-options/ Kind: method Apply pending physical and semantic steps with explicit maintenance and bounded coordination. ```go func (backend *Store) ApplyArtifactsWithOptions(ctx context.Context, directory string, options RunnerOptions, transforms ...ridumigration.DataTransform) error ``` Checksums, lineage, planner reconstruction, transform registry, step ledgers, and source assertions remain mandatory regardless of admissions. ## Store.ArtifactStatus Canonical URL: https://riducms.com/reference/mongodb/store-artifact-status/ Kind: method Validate immutable history and report durable artifact, phase, and step progress. ```go func (backend *Store) ArtifactStatus(ctx context.Context, directory string) ([]MigrationStatus, error) ``` ## Store.ArtifactPlan Canonical URL: https://riducms.com/reference/mongodb/store-artifact-plan/ Kind: method Return the same strict state with deterministic phase and step topology. ```go func (backend *Store) ArtifactPlan(ctx context.Context, directory string) ([]MigrationStatus, error) ``` ## SafetyError.Error Canonical URL: https://riducms.com/reference/mongodb/safety-error-error-method/ Kind: method Public method SafetyError.Error from github.com/riducms/ridu/adapters/mongodb. ```go func (err *SafetyError) Error() string ``` ## Store.AcquireDocumentLock Canonical URL: https://riducms.com/reference/mongodb/store-acquire-document-lock-method/ Kind: method Public method Store.AcquireDocumentLock from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) AcquireDocumentLock(ctx context.Context, candidate store.DocumentLock, now time.Time, takeover bool) (store.DocumentLock, bool, error) ``` ## Store.AllowAuthAttempt Canonical URL: https://riducms.com/reference/mongodb/store-allow-auth-attempt-method/ Kind: method Public method Store.AllowAuthAttempt from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) AllowAuthAttempt(ctx context.Context, keyHash string, now time.Time, window time.Duration, maximum int) (bool, error) ``` ## Store.CancelTask Canonical URL: https://riducms.com/reference/mongodb/store-cancel-task-method/ Kind: method Public method Store.CancelTask from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) CancelTask(ctx context.Context, id string) error ``` ## Store.ChangePasswordHash Canonical URL: https://riducms.com/reference/mongodb/store-change-password-hash-method/ Kind: method Public method Store.ChangePasswordHash from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) ChangePasswordHash(ctx context.Context, collection schema.Collection, userID string, expectedPasswordHash, hash []byte) error ``` ## Store.ClaimTasks Canonical URL: https://riducms.com/reference/mongodb/store-claim-tasks-method/ Kind: method Public method Store.ClaimTasks from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) ClaimTasks(ctx context.Context, request store.TaskClaim) ([]store.Task, error) ``` ## Store.CompleteTask Canonical URL: https://riducms.com/reference/mongodb/store-complete-task-method/ Kind: method Public method Store.CompleteTask from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) CompleteTask(ctx context.Context, id, leaseToken string, output json.RawMessage) error ``` ## Store.CreateAPIKey Canonical URL: https://riducms.com/reference/mongodb/store-create-api-key-method/ Kind: method Public method Store.CreateAPIKey from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) CreateAPIKey(ctx context.Context, key store.AuthAPIKey, sessionTokenHash string, now time.Time) error ``` ## Store.CreateAuthToken Canonical URL: https://riducms.com/reference/mongodb/store-create-auth-token-method/ Kind: method Public method Store.CreateAuthToken from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) CreateAuthToken(ctx context.Context, token store.AuthToken) error ``` ## Store.CreateSession Canonical URL: https://riducms.com/reference/mongodb/store-create-session-method/ Kind: method Public method Store.CreateSession from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) CreateSession(ctx context.Context, session store.AuthSession, expectedPasswordHash []byte) error ``` ## Store.DeleteAPIKey Canonical URL: https://riducms.com/reference/mongodb/store-delete-api-key-method/ Kind: method Public method Store.DeleteAPIKey from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) DeleteAPIKey(ctx context.Context, collectionID schema.StableID, userID, id string) error ``` ## Store.DeletePreference Canonical URL: https://riducms.com/reference/mongodb/store-delete-preference-method/ Kind: method Public method Store.DeletePreference from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) DeletePreference(ctx context.Context, collectionID schema.StableID, userID, key string) error ``` ## Store.DeletePreferences Canonical URL: https://riducms.com/reference/mongodb/store-delete-preferences-method/ Kind: method Public method Store.DeletePreferences from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) DeletePreferences(ctx context.Context, collectionID schema.StableID, userID string) error ``` ## Store.DeleteSession Canonical URL: https://riducms.com/reference/mongodb/store-delete-session-method/ Kind: method Public method Store.DeleteSession from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) DeleteSession(ctx context.Context, tokenHash string) error ``` ## Store.DeleteUserSession Canonical URL: https://riducms.com/reference/mongodb/store-delete-user-session-method/ Kind: method Public method Store.DeleteUserSession from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) DeleteUserSession(ctx context.Context, collectionID schema.StableID, userID, sessionID string) error ``` ## Store.DeleteUserSessions Canonical URL: https://riducms.com/reference/mongodb/store-delete-user-sessions-method/ Kind: method Public method Store.DeleteUserSessions from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) DeleteUserSessions(ctx context.Context, collectionID schema.StableID, userID string) error ``` ## Store.DismissTaskForTarget Canonical URL: https://riducms.com/reference/mongodb/store-dismiss-task-for-target-method/ Kind: method Public method Store.DismissTaskForTarget from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) DismissTaskForTarget(ctx context.Context, id, slug string, target store.DocumentReference) error ``` ## Store.EnqueueTask Canonical URL: https://riducms.com/reference/mongodb/store-enqueue-task-method/ Kind: method Public method Store.EnqueueTask from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) EnqueueTask(ctx context.Context, task store.Task) (store.Task, error) ``` ## Store.FailTask Canonical URL: https://riducms.com/reference/mongodb/store-fail-task-method/ Kind: method Public method Store.FailTask from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) FailTask(ctx context.Context, failure store.TaskFailure) error ``` ## Store.FindAPIKey Canonical URL: https://riducms.com/reference/mongodb/store-find-api-key-method/ Kind: method Public method Store.FindAPIKey from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) FindAPIKey(ctx context.Context, id string, now time.Time) (store.AuthAPIKey, error) ``` ## Store.FindAuthCredential Canonical URL: https://riducms.com/reference/mongodb/store-find-auth-credential-method/ Kind: method Public method Store.FindAuthCredential from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) FindAuthCredential(ctx context.Context, collection schema.Collection, identity string) (store.AuthCredential, error) ``` ## Store.FindDocumentLock Canonical URL: https://riducms.com/reference/mongodb/store-find-document-lock-method/ Kind: method Public method Store.FindDocumentLock from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) FindDocumentLock(ctx context.Context, collectionID schema.StableID, documentID string, now time.Time) (store.DocumentLock, error) ``` ## Store.FindSession Canonical URL: https://riducms.com/reference/mongodb/store-find-session-method/ Kind: method Public method Store.FindSession from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) FindSession(ctx context.Context, tokenHash string, now time.Time) (store.AuthSession, error) ``` ## Store.FindTask Canonical URL: https://riducms.com/reference/mongodb/store-find-task-method/ Kind: method Public method Store.FindTask from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) FindTask(ctx context.Context, id string) (store.Task, error) ``` ## Store.ForceUnlock Canonical URL: https://riducms.com/reference/mongodb/store-force-unlock-method/ Kind: method Public method Store.ForceUnlock from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) ForceUnlock(ctx context.Context, collectionID schema.StableID, userID string) error ``` ## Store.GetPreference Canonical URL: https://riducms.com/reference/mongodb/store-get-preference-method/ Kind: method Public method Store.GetPreference from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) GetPreference(ctx context.Context, collectionID schema.StableID, userID, key string) (store.Preference, error) ``` ## Store.HeartbeatTask Canonical URL: https://riducms.com/reference/mongodb/store-heartbeat-task-method/ Kind: method Public method Store.HeartbeatTask from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) HeartbeatTask(ctx context.Context, id, leaseToken string, leaseDuration time.Duration) error ``` ## Store.ListAPIKeys Canonical URL: https://riducms.com/reference/mongodb/store-list-api-keys-method/ Kind: method Public method Store.ListAPIKeys from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) ListAPIKeys(ctx context.Context, collectionID schema.StableID, userID string, now time.Time) ([]store.AuthAPIKey, error) ``` ## Store.ListSessions Canonical URL: https://riducms.com/reference/mongodb/store-list-sessions-method/ Kind: method Public method Store.ListSessions from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) ListSessions(ctx context.Context, collectionID schema.StableID, userID string, now time.Time) ([]store.AuthSession, error) ``` ## Store.ListTasks Canonical URL: https://riducms.com/reference/mongodb/store-list-tasks-method/ Kind: method Public method Store.ListTasks from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) ListTasks(ctx context.Context, request store.TaskList) ([]store.Task, error) ``` ## Store.LockUploadObjects Canonical URL: https://riducms.com/reference/mongodb/store-lock-upload-objects-method/ Kind: method LockUploadObjects acquires one separately committed exact-owner lock set. Acquisition is all-or-none, and rows remain held until release. Graceful shutdown must drain callers before Store.Close; crash-abandoned rows require explicit operator recovery. ```go func (backend *Store) LockUploadObjects(ctx context.Context, objectKeys []string) (func(), error) ``` ## Store.PruneExpiredAuth Canonical URL: https://riducms.com/reference/mongodb/store-prune-expired-auth-method/ Kind: method Public method Store.PruneExpiredAuth from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) PruneExpiredAuth(ctx context.Context, limit int) (store.AuthPruneResult, error) ``` ## Store.PruneTasks Canonical URL: https://riducms.com/reference/mongodb/store-prune-tasks-method/ Kind: method Public method Store.PruneTasks from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) PruneTasks(ctx context.Context, limit int) (int, error) ``` ## Store.RecordFailedLogin Canonical URL: https://riducms.com/reference/mongodb/store-record-failed-login-method/ Kind: method Public method Store.RecordFailedLogin from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) RecordFailedLogin(ctx context.Context, collectionID schema.StableID, userID string, now time.Time, maximum int, lockDuration time.Duration) (store.AuthCredential, error) ``` ## Store.ReleaseDocumentLock Canonical URL: https://riducms.com/reference/mongodb/store-release-document-lock-method/ Kind: method Public method Store.ReleaseDocumentLock from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) ReleaseDocumentLock( ctx context.Context, collectionID schema.StableID, documentID string, ownerCollectionID schema.StableID, ownerID string, ) error ``` ## Store.ReleaseTask Canonical URL: https://riducms.com/reference/mongodb/store-release-task-method/ Kind: method Public method Store.ReleaseTask from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) ReleaseTask( ctx context.Context, id, leaseToken string, delay time.Duration, code, message string, ) error ``` ## Store.ResetLoginAttempts Canonical URL: https://riducms.com/reference/mongodb/store-reset-login-attempts-method/ Kind: method Public method Store.ResetLoginAttempts from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) ResetLoginAttempts(ctx context.Context, collectionID schema.StableID, userID string, now time.Time) (bool, error) ``` ## Store.ResetPasswordWithToken Canonical URL: https://riducms.com/reference/mongodb/store-reset-password-with-token-method/ Kind: method Public method Store.ResetPasswordWithToken from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) ResetPasswordWithToken(ctx context.Context, collectionID schema.StableID, tokenHash string, hash []byte, now time.Time) (string, error) ``` ## Store.RotateSession Canonical URL: https://riducms.com/reference/mongodb/store-rotate-session-method/ Kind: method Public method Store.RotateSession from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) RotateSession(ctx context.Context, currentHash string, replacement store.AuthSession, now time.Time) error ``` ## Store.SetPasswordHash Canonical URL: https://riducms.com/reference/mongodb/store-set-password-hash-method/ Kind: method Public method Store.SetPasswordHash from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) SetPasswordHash(ctx context.Context, collection schema.Collection, userID string, hash []byte, initiallyVerified bool) error ``` ## Store.SetPreference Canonical URL: https://riducms.com/reference/mongodb/store-set-preference-method/ Kind: method Public method Store.SetPreference from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) SetPreference(ctx context.Context, preference store.Preference) (store.Preference, error) ``` ## Store.TouchAPIKey Canonical URL: https://riducms.com/reference/mongodb/store-touch-api-key-method/ Kind: method Public method Store.TouchAPIKey from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) TouchAPIKey(ctx context.Context, id string, now time.Time) error ``` ## Store.UpgradePasswordHash Canonical URL: https://riducms.com/reference/mongodb/store-upgrade-password-hash-method/ Kind: method Public method Store.UpgradePasswordHash from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) UpgradePasswordHash(ctx context.Context, collection schema.Collection, userID string, expectedPasswordHash, hash []byte) error ``` ## Store.VerifyEmailWithToken Canonical URL: https://riducms.com/reference/mongodb/store-verify-email-with-token-method/ Kind: method Public method Store.VerifyEmailWithToken from github.com/riducms/ridu/adapters/mongodb. ```go func (backend *Store) VerifyEmailWithToken(ctx context.Context, collectionID schema.StableID, tokenHash string, now time.Time) (string, error) ``` --- # API Reference: graphql Canonical URL: https://riducms.com/reference/graphql/ Package: github.com/riducms/ridu/plugins/graphql An optional manifest-generated GraphQL transport over Ridu’s operation engine; importing it is what links the GraphQL runtime. ## Key Canonical URL: https://riducms.com/reference/graphql/key/ Kind: constant The stable compiled plugin key. ```go const Key = "graphql" ``` ## New Canonical URL: https://riducms.com/reference/graphql/new/ Kind: function Register one GraphQL transport with secure defaults. ```go func New(options ...Options) ridu.Plugin ``` Pass zero or one Options value; more than one is invalid. The plugin uses the same access, validation, hooks, transactions, and redaction engine as REST. ```go Plugins: []ridu.Plugin{ graphql.New(graphql.Options{ Path: "/graphql", MaxDepth: 12, AllowIntrospection: false, }), } ``` ## Options Canonical URL: https://riducms.com/reference/graphql/options/ Kind: type Route, request budgets, resource overrides, extensions, and validation rules. ```go type Options struct { Path string MaxBodyBytes int64 MaxVariableBytes int MaxDepth int MaxAliases int MaxComplexity int MaxListLimit int AllowIntrospection bool // Resources optionally renames or suppresses generated surfaces by // collection/global slug. Omitted resources use their manifest labels and // expose both queries and mutations. Resources map[string]ResourceOptions Queries []ExtensionField Mutations []ExtensionField ValidationRules []enginegraphql.ValidationRuleFn } ``` Zero values select bounded secure defaults. Introspection is disabled unless explicitly enabled. Resources keys are collection or global slugs. Overrides change only GraphQL names/surfaces, not manifest slugs or REST routes. ## ResourceOptions Canonical URL: https://riducms.com/reference/graphql/resource-options/ Kind: type GraphQL naming and surface controls for one collection or global. ```go type ResourceOptions struct { SingularName string PluralName string DisableQueries bool DisableMutations bool } ``` ## ExtensionField Canonical URL: https://riducms.com/reference/graphql/extension-field/ Kind: type One trusted compiled root query or mutation field. ```go type ExtensionField struct { Name string Description string Type enginegraphql.Output Args enginegraphql.FieldConfigArgument Cost int Resolve ExtensionResolver } ``` Cost contributes to request complexity. Extensions receive public application APIs, not a raw store adapter. ## ExtensionResolver Canonical URL: https://riducms.com/reference/graphql/extension-resolver/ Kind: type The resolver signature for a compiled extension field. ```go type ExtensionResolver func(ExtensionContext) (interface{}, error) ``` ## ExtensionContext Canonical URL: https://riducms.com/reference/graphql/extension-context/ Kind: type Authenticated execution context and safe public Ridu facades for an extension resolver. ```go type ExtensionContext struct { Context context.Context Args map[string]interface{} Info enginegraphql.ResolveInfo Actor *store.Document ActorCollection riduschema.CollectionSlug Local *ridu.LocalAPI App *ridu.App } ``` Actor is nil for anonymous requests. Use Local for operations so extension behavior retains Ridu authorization and transaction semantics. ## GenerateSDL Canonical URL: https://riducms.com/reference/graphql/generate-sdl/ Kind: function Generate deterministic SDL without starting an application or enabling network introspection. ```go func GenerateSDL(manifest schema.Manifest, options ...Options) (string, error) ``` ```go sdl, err := graphql.GenerateSDL(app.Manifest(), graphql.Options{ AllowIntrospection: false, }) ``` --- # API Reference: mcp Canonical URL: https://riducms.com/reference/mcp/ Package: github.com/riducms/ridu/plugins/mcp An optional authenticated, read-only Model Context Protocol transport over explicitly selected Ridu content. ## Key Canonical URL: https://riducms.com/reference/mcp/key/ Kind: constant The stable compiled plugin key. ```go const Key = "mcp" ``` ## New Canonical URL: https://riducms.com/reference/mcp/new/ Kind: function Register one bounded MCP Streamable HTTP transport. ```go func New(config Config) *Plugin ``` Resource declarations are defensively copied. Zero route and limit values select bounded defaults; unknown resources and normalized tool-name collisions fail startup. ```go Plugins: []ridu.Plugin{ mcp.New(mcp.Config{ Collections: []mcp.Resource{{Slug: "posts"}}, Globals: []mcp.Resource{{Slug: "site-settings"}}, }), } ``` ## Resource Canonical URL: https://riducms.com/reference/mcp/resource/ Kind: type One collection or global explicitly admitted to MCP discovery. ```go type Resource struct { Slug schema.CollectionSlug Description string } ``` Description overrides the manifest presentation text. Selecting a resource does not widen the authenticated actor’s runtime access. ## Config Canonical URL: https://riducms.com/reference/mcp/config/ Kind: type Route, request bounds, result limits, and explicit resource allowlists. ```go type Config struct { Path string MaxBodyBytes int64 DefaultLimit int MaxLimit int Collections []Resource Globals []Resource } ``` The default route is /api/mcp. The current plugin exposes only collection-list and global-read tools; writes and source mutation are not supported. ## Plugin Canonical URL: https://riducms.com/reference/mcp/plugin/ Kind: type The configured compiled MCP plugin. ```go type Plugin struct{ config Config } ``` Plugin implements Ridu’s descriptor and transport provider contracts. Construct it with New so configuration is normalized and copied. ## Plugin.BindTransports Canonical URL: https://riducms.com/reference/mcp/plugin-bind-transports-method/ Kind: method Public method Plugin.BindTransports from github.com/riducms/ridu/plugins/mcp. ```go func (plugin *Plugin) BindTransports(binding ridu.PluginTransportContext) ([]ridu.PluginTransport, error) ``` ## Plugin.Descriptor Canonical URL: https://riducms.com/reference/mcp/plugin-descriptor-method/ Kind: method Public method Plugin.Descriptor from github.com/riducms/ridu/plugins/mcp. ```go func (receiver *Plugin) Descriptor() ridu.PluginDescriptor ``` ## Plugin.Key Canonical URL: https://riducms.com/reference/mcp/plugin-key-method/ Kind: method Public method Plugin.Key from github.com/riducms/ridu/plugins/mcp. ```go func (receiver *Plugin) Key() string ``` --- # API Reference: richtext Canonical URL: https://riducms.com/reference/richtext/ Package: github.com/riducms/ridu/plugins/richtext A paired, versioned Lexical field with authoring for portable content, references, uploads, and blocks. ## Key Canonical URL: https://riducms.com/reference/richtext/key/ Kind: constant The stable backend and plugin-field key. ```go const Key = "richtext" ``` ## DocumentVersion Canonical URL: https://riducms.com/reference/richtext/document-version/ Kind: constant The stored rich-text document format version. ```go const DocumentVersion = 1 ``` ## AdminPluginPairingVersion Canonical URL: https://riducms.com/reference/richtext/admin-plugin-pairing-version/ Kind: constant The required compatibility version between Go and Svelte packages. ```go const AdminPluginPairingVersion = 1 ``` ## New Canonical URL: https://riducms.com/reference/richtext/new/ Kind: function Register the backend half of the paired rich-text plugin. ```go func New() ridu.Plugin ``` The generated admin registry must also resolve @riducms/plugin-richtext with the matching pairing version. ## Field Canonical URL: https://riducms.com/reference/richtext/field/ Kind: function Define rich text with the default feature set. ```go func Field(name string, options ...field.PluginOption) field.Definition ``` ```go richtext.Field("body", field.Required(), field.Localized()) ``` ## DefaultConfig Canonical URL: https://riducms.com/reference/richtext/default-config/ Kind: function Return a defensive copy of the recommended feature configuration. ```go func DefaultConfig() Config ``` Defaults enable links, lists, code, horizontal rules, uploads, and relationships. Blocks are opt-in. ## FieldWithConfig Canonical URL: https://riducms.com/reference/richtext/field-with-config/ Kind: function Define rich text with explicit features. ```go func FieldWithConfig(name string, config Config, options ...field.PluginOption) field.Definition ``` ## Config Canonical URL: https://riducms.com/reference/richtext/config/ Kind: type Enabled features and optional allowlists for relationship and upload nodes. ```go type Config struct { Features []Feature `json:"features"` UploadCollections []string `json:"uploadCollections,omitempty"` RelationshipCollections []string `json:"relationshipCollections,omitempty"` } ``` A nil Features slice inherits defaults; an explicit empty slice disables every optional feature. Empty collection allowlists permit every compatible collection, while non-empty lists restrict node targets. ## Feature Canonical URL: https://riducms.com/reference/richtext/feature/ Kind: type One optional authoring and validation capability. ```go type Feature string ``` ## Feature constants Canonical URL: https://riducms.com/reference/richtext/feature-constants/ Kind: type The supported optional rich-text features. ```go const ( FeatureLinks Feature = "links"; FeatureLists Feature = "lists"; FeatureCode Feature = "code"; FeatureHorizontalRule Feature = "horizontal-rule"; FeatureUploads Feature = "uploads"; FeatureRelationships Feature = "relationships"; FeatureBlocks Feature = "blocks" ) ``` ## Document Canonical URL: https://riducms.com/reference/richtext/document/ Kind: type The exact generated Go value type for a versioned serialized Lexical document. ```go type Document map[string]any ``` Runtime validation requires version 1, a root object, enabled node types, valid references, and bounded complexity (at most 64 levels and 10,000 nodes). Node shapes remain extensible for custom renderer data. ## RenderHTML Canonical URL: https://riducms.com/reference/richtext/render-html/ Kind: function Render portable nodes to escaped HTML, delegating custom node types to caller-owned renderers. ```go func RenderHTML(value store.Value, renderers map[string]func(store.Values) (string, error)) (string, error) ``` Text and attributes are escaped and unsafe link schemes are rejected. Supply renderers for uploads, relationships, blocks, or any custom node presentation; application HTML remains outside storage. ## FeatureBlocks Canonical URL: https://riducms.com/reference/richtext/feature-blocks/ Kind: constant Public constant FeatureBlocks from github.com/riducms/ridu/plugins/richtext. ```go const FeatureBlocks Feature = "blocks" ``` ## FeatureCode Canonical URL: https://riducms.com/reference/richtext/feature-code/ Kind: constant Public constant FeatureCode from github.com/riducms/ridu/plugins/richtext. ```go const FeatureCode Feature = "code" ``` ## FeatureHorizontalRule Canonical URL: https://riducms.com/reference/richtext/feature-horizontal-rule/ Kind: constant Public constant FeatureHorizontalRule from github.com/riducms/ridu/plugins/richtext. ```go const FeatureHorizontalRule Feature = "horizontal-rule" ``` ## FeatureLinks Canonical URL: https://riducms.com/reference/richtext/feature-links/ Kind: constant Public constant FeatureLinks from github.com/riducms/ridu/plugins/richtext. ```go const FeatureLinks Feature = "links" ``` ## FeatureLists Canonical URL: https://riducms.com/reference/richtext/feature-lists/ Kind: constant Public constant FeatureLists from github.com/riducms/ridu/plugins/richtext. ```go const FeatureLists Feature = "lists" ``` ## FeatureRelationships Canonical URL: https://riducms.com/reference/richtext/feature-relationships/ Kind: constant Public constant FeatureRelationships from github.com/riducms/ridu/plugins/richtext. ```go const FeatureRelationships Feature = "relationships" ``` ## FeatureUploads Canonical URL: https://riducms.com/reference/richtext/feature-uploads/ Kind: constant Public constant FeatureUploads from github.com/riducms/ridu/plugins/richtext. ```go const FeatureUploads Feature = "uploads" ``` --- # API Reference: seo Canonical URL: https://riducms.com/reference/seo/ Package: github.com/riducms/ridu/plugins/seo Payload-familiar search metadata fields, authenticated draft-aware generators, and a paired Svelte admin. ## Key Canonical URL: https://riducms.com/reference/seo/key/ Kind: constant The stable backend and admin plugin identity. ```go const Key = "seo" ``` ## AdminPluginPairingVersion Canonical URL: https://riducms.com/reference/seo/admin-plugin-pairing-version/ Kind: constant The required compatibility version between the Go and Svelte packages. ```go const AdminPluginPairingVersion = 1 ``` ## New Canonical URL: https://riducms.com/reference/seo/new/ Kind: function Create one configured SEO plugin instance. ```go func New(config Config) *Plugin ``` Collection and global selectors are copied. Add the returned plugin to executable application config, install the paired admin package, and run ridu generate. ```go seo.New(seo.Config{ Collections: []schema.CollectionSlug{"pages"}, Globals: []schema.CollectionSlug{"site-settings"}, UploadsCollection: "media", TabbedUI: true, }) ``` ## Overview Canonical URL: https://riducms.com/reference/seo/overview/ Kind: function Create the default presentation-only metadata checks. ```go func Overview(options ...field.CommonOption) field.Definition ``` ## OverviewWithConfig Canonical URL: https://riducms.com/reference/seo/overview-with-config/ Kind: function Create overview checks mapped to explicit field paths and guidance ranges. ```go func OverviewWithConfig(selected OverviewConfig, options ...field.CommonOption) field.Definition ``` ## MetaTitle Canonical URL: https://riducms.com/reference/seo/meta-title/ Kind: function Create a localized text field with SEO title guidance and optional generation. ```go func MetaTitle(hasGenerator bool, options ...field.StringOption) field.Definition ``` The 50–60 character range is advisory unless field validation options add an enforced minimum or maximum. ## MetaDescription Canonical URL: https://riducms.com/reference/seo/meta-description/ Kind: function Create a localized textarea with SEO description guidance and optional generation. ```go func MetaDescription(hasGenerator bool, options ...field.StringOption) field.Definition ``` The 100–150 character range is advisory unless field validation options add an enforced minimum or maximum. ## MetaImage Canonical URL: https://riducms.com/reference/seo/meta-image/ Kind: function Create a localized upload reference with SEO image authoring and optional generation. ```go func MetaImage(collection schema.CollectionSlug, hasGenerator bool, options ...field.UploadOption) field.Definition ``` ## MetaImageWithConfig Canonical URL: https://riducms.com/reference/seo/meta-image-with-config/ Kind: function Create a directly placed SEO image field with explicit label and description. ```go func MetaImageWithConfig(selected MetaImageConfig, options ...field.UploadOption) field.Definition ``` ## Preview Canonical URL: https://riducms.com/reference/seo/preview/ Kind: function Create the default presentation-only search-result preview. ```go func Preview(hasGenerator bool, options ...field.CommonOption) field.Definition ``` ## PreviewWithConfig Canonical URL: https://riducms.com/reference/seo/preview-with-config/ Kind: function Create a search preview mapped to explicit title and description paths. ```go func PreviewWithConfig(selected PreviewConfig, options ...field.CommonOption) field.Definition ``` ## GenerateContext Canonical URL: https://riducms.com/reference/seo/generate-context/ Kind: type Trusted runtime input for a title, description, image, or URL generator. ```go type GenerateContext struct { Context ridu.PluginEndpointContext Document map[string]any ID string Locale schema.LocaleCode Collection *ridu.Collection Global *ridu.Global } ``` Exactly one of Collection and Global is non-nil. The endpoint checks authentication and resource capabilities before invoking the callback. ## GenerateText Canonical URL: https://riducms.com/reference/seo/generate-text/ Kind: type A title, description, or preview-URL callback. ```go type GenerateText func(GenerateContext) (string, error) ``` ## GenerateImage Canonical URL: https://riducms.com/reference/seo/generate-image/ Kind: type An image callback that returns a stable upload document ID. ```go type GenerateImage func(GenerateContext) (string, error) ``` ## FieldsOverride Canonical URL: https://riducms.com/reference/seo/fields-override/ Kind: type A callback that replaces the complete ordered contents of the injected meta group. ```go type FieldsOverride func(defaultFields []field.Definition) ([]field.Definition, error) ``` The input and returned slices are detached. Returning no fields fails config resolution. ## Config Canonical URL: https://riducms.com/reference/seo/config/ Kind: type Resource selectors, layout, field overrides, and executable generation callbacks. ```go type Config struct { Collections []schema.CollectionSlug Globals []schema.CollectionSlug UploadsCollection schema.CollectionSlug TabbedUI bool Fields FieldsOverride GenerateTitle GenerateText GenerateDescription GenerateText GenerateImage GenerateImage GenerateURL GenerateText } ``` ## OverviewConfig Canonical URL: https://riducms.com/reference/seo/overview-config/ Kind: type Labels, field paths, and character guidance for a directly placed overview. ```go type OverviewConfig struct { Label string TitlePath string DescriptionPath string ImagePath string TitleMin int TitleMax int DescriptionMin int DescriptionMax int } ``` ## PreviewConfig Canonical URL: https://riducms.com/reference/seo/preview-config/ Kind: type Generator state, label, and field paths for a directly placed preview. ```go type PreviewConfig struct { Generate bool Label string TitlePath string DescriptionPath string } ``` ## MetaImageConfig Canonical URL: https://riducms.com/reference/seo/meta-image-config/ Kind: type Upload collection and authoring presentation for a directly placed image. ```go type MetaImageConfig struct { Collection schema.CollectionSlug Generate bool Label string Description string } ``` ## Plugin Canonical URL: https://riducms.com/reference/seo/plugin/ Kind: type A configured SEO extension implementing config transformation, descriptor, and endpoint capabilities. ```go type Plugin struct { config Config mu sync.RWMutex collections map[schema.CollectionSlug]ridu.Collection globals map[schema.CollectionSlug]ridu.Global } ``` ## Plugin.Descriptor Canonical URL: https://riducms.com/reference/seo/plugin-descriptor-method/ Kind: method Descriptor exposes only deterministic build metadata. Generators remain executable Go values owned by the runtime plugin instance. ```go func (receiver *Plugin) Descriptor() ridu.PluginDescriptor ``` ## Plugin.Endpoints Canonical URL: https://riducms.com/reference/seo/plugin-endpoints-method/ Kind: method Endpoints contributes generation calls below /api/plugins/seo/. All are declared for a stable OpenAPI surface; absent callbacks return an empty value. ```go func (plugin *Plugin) Endpoints() []ridu.PluginEndpoint ``` ## Plugin.Key Canonical URL: https://riducms.com/reference/seo/plugin-key-method/ Kind: method Key implements ridu.Plugin. ```go func (receiver *Plugin) Key() string ``` ## Plugin.TransformConfig Canonical URL: https://riducms.com/reference/seo/plugin-transform-config-method/ Kind: method TransformConfig injects one meta group into each selected resource. ```go func (plugin *Plugin) TransformConfig(config ridu.Config) (ridu.Config, error) ``` --- # API Reference: formbuilder Canonical URL: https://riducms.com/reference/formbuilder/ Package: github.com/riducms/ridu/plugins/formbuilder Payload-familiar dynamic form definitions, server-validated submissions, notifications, uploads, and payment callbacks. ## Key Canonical URL: https://riducms.com/reference/formbuilder/key/ Kind: constant The stable paired plugin identity. ```go const Key = "form-builder" ``` ## AdminPluginPairingVersion Canonical URL: https://riducms.com/reference/formbuilder/admin-plugin-pairing-version/ Kind: constant The backend/admin contract pairing version. ```go const AdminPluginPairingVersion = 1 ``` ## DefaultFormsSlug Canonical URL: https://riducms.com/reference/formbuilder/default-forms-slug/ Kind: constant The default reusable form collection slug. ```go const DefaultFormsSlug schema.CollectionSlug = "forms" ``` ## DefaultSubmissionsSlug Canonical URL: https://riducms.com/reference/formbuilder/default-submissions-slug/ Kind: constant The default captured submission collection slug. ```go const DefaultSubmissionsSlug schema.CollectionSlug = "form-submissions" ``` ## New Canonical URL: https://riducms.com/reference/formbuilder/new/ Kind: function Create one compiled Form Builder plugin from detached configuration. ```go func New(config Config) *Plugin ``` ```go formbuilder.New(formbuilder.Config{ UploadCollections: []schema.CollectionSlug{ "media", }, }) ``` ## GetPaymentTotal Canonical URL: https://riducms.com/reference/formbuilder/get-payment-total/ Kind: function Apply matching arithmetic conditions in order with finite-number checks. ```go func GetPaymentTotal(basePrice float64, conditions []PriceCondition, values map[string]store.Value) (float64, error) ``` ## FieldType Canonical URL: https://riducms.com/reference/formbuilder/field-type/ Kind: type A dynamic input block discriminator. ```go type FieldType string ``` ## Field type constants Canonical URL: https://riducms.com/reference/formbuilder/field-type-constants/ Kind: type The checkbox, country, date, email, message, number, payment, radio, select, state, text, textarea, and upload field kinds. ```go const ( FieldCheckbox FieldType = "checkbox"; FieldCountry FieldType = "country"; FieldDate FieldType = "date"; FieldEmail FieldType = "email"; FieldMessage FieldType = "message"; FieldNumber FieldType = "number"; FieldPayment FieldType = "payment"; FieldRadio FieldType = "radio"; FieldSelect FieldType = "select"; FieldState FieldType = "state"; FieldText FieldType = "text"; FieldTextarea FieldType = "textarea"; FieldUpload FieldType = "upload" ) ``` ## FieldsOverride Canonical URL: https://riducms.com/reference/formbuilder/fields-override/ Kind: type Replace the complete ordered dynamic field-block set. ```go type FieldsOverride func(defaultFields []field.Block) ([]field.Block, error) ``` ## CollectionOverride Canonical URL: https://riducms.com/reference/formbuilder/collection-override/ Kind: type Replace one detached generated Forms or Form Submissions collection. ```go type CollectionOverride func(defaultCollection ridu.Collection) (ridu.Collection, error) ``` ## Config Canonical URL: https://riducms.com/reference/formbuilder/config/ Kind: type Collection names, field selection, overrides, and executable delivery callbacks. ```go type Config struct { FormsSlug schema.CollectionSlug SubmissionsSlug schema.CollectionSlug EnabledFields []FieldType UploadCollections []schema.CollectionSlug RedirectRelationships []schema.CollectionSlug PaymentProcessors []field.Choice Fields FieldsOverride Forms CollectionOverride Submissions CollectionOverride DefaultToEmail string BeforeEmail BeforeEmail SendEmail SendEmail HandlePayment HandlePayment ReportError func(error, string) } ``` ## Plugin Canonical URL: https://riducms.com/reference/formbuilder/plugin/ Kind: type One configured backend plugin implementing descriptor and config transformation contracts. ```go type Plugin struct { config Config } ``` ## PriceCondition Canonical URL: https://riducms.com/reference/formbuilder/price-condition/ Kind: type One conditional arithmetic adjustment to a payment base price. ```go type PriceCondition struct { FieldToUse string Condition string ValueForCondition string Operator string ValueType string ValueForOperator string } ``` ## PaymentContext Canonical URL: https://riducms.com/reference/formbuilder/payment-context/ Kind: type Trusted form, submitted values, field definition, and calculated total supplied before commit. ```go type PaymentContext struct { Context ridu.HookContext Form store.Document Field store.Values SubmissionData map[string]store.Value Total float64 } ``` ## HandlePayment Canonical URL: https://riducms.com/reference/formbuilder/handle-payment/ Kind: type Perform provider work before commit and return the JSON result to persist. ```go type HandlePayment func(PaymentContext) (store.Value, error) ``` ## Email Canonical URL: https://riducms.com/reference/formbuilder/email/ Kind: type One fully formatted outbound email with validated headers. ```go type Email struct { To string CC string BCC string From string ReplyTo string Subject string HTML string } ``` ## EmailContext Canonical URL: https://riducms.com/reference/formbuilder/email-context/ Kind: type The committed submission and selected form supplied to batch transformation. ```go type EmailContext struct { Context ridu.HookContext Form store.Document Submission store.Document } ``` ## BeforeEmail Canonical URL: https://riducms.com/reference/formbuilder/before-email/ Kind: type Transform or filter a detached email batch after commit and before delivery. ```go type BeforeEmail func(EmailContext, []Email) ([]Email, error) ``` ## SendEmail Canonical URL: https://riducms.com/reference/formbuilder/send-email/ Kind: type Deliver one formatted message with application-owned provider credentials. ```go type SendEmail func(stdcontext.Context, Email) error ``` ## FieldCheckbox Canonical URL: https://riducms.com/reference/formbuilder/field-checkbox/ Kind: constant Public constant FieldCheckbox from github.com/riducms/ridu/plugins/formbuilder. ```go const FieldCheckbox FieldType = "checkbox" ``` ## FieldCountry Canonical URL: https://riducms.com/reference/formbuilder/field-country/ Kind: constant Public constant FieldCountry from github.com/riducms/ridu/plugins/formbuilder. ```go const FieldCountry FieldType = "country" ``` ## FieldDate Canonical URL: https://riducms.com/reference/formbuilder/field-date/ Kind: constant Public constant FieldDate from github.com/riducms/ridu/plugins/formbuilder. ```go const FieldDate FieldType = "date" ``` ## FieldEmail Canonical URL: https://riducms.com/reference/formbuilder/field-email/ Kind: constant Public constant FieldEmail from github.com/riducms/ridu/plugins/formbuilder. ```go const FieldEmail FieldType = "email" ``` ## FieldMessage Canonical URL: https://riducms.com/reference/formbuilder/field-message/ Kind: constant Public constant FieldMessage from github.com/riducms/ridu/plugins/formbuilder. ```go const FieldMessage FieldType = "message" ``` ## FieldNumber Canonical URL: https://riducms.com/reference/formbuilder/field-number/ Kind: constant Public constant FieldNumber from github.com/riducms/ridu/plugins/formbuilder. ```go const FieldNumber FieldType = "number" ``` ## FieldPayment Canonical URL: https://riducms.com/reference/formbuilder/field-payment/ Kind: constant Public constant FieldPayment from github.com/riducms/ridu/plugins/formbuilder. ```go const FieldPayment FieldType = "payment" ``` ## FieldRadio Canonical URL: https://riducms.com/reference/formbuilder/field-radio/ Kind: constant Public constant FieldRadio from github.com/riducms/ridu/plugins/formbuilder. ```go const FieldRadio FieldType = "radio" ``` ## FieldSelect Canonical URL: https://riducms.com/reference/formbuilder/field-select/ Kind: constant Public constant FieldSelect from github.com/riducms/ridu/plugins/formbuilder. ```go const FieldSelect FieldType = "select" ``` ## FieldState Canonical URL: https://riducms.com/reference/formbuilder/field-state/ Kind: constant Public constant FieldState from github.com/riducms/ridu/plugins/formbuilder. ```go const FieldState FieldType = "state" ``` ## FieldText Canonical URL: https://riducms.com/reference/formbuilder/field-text/ Kind: constant Public constant FieldText from github.com/riducms/ridu/plugins/formbuilder. ```go const FieldText FieldType = "text" ``` ## FieldTextarea Canonical URL: https://riducms.com/reference/formbuilder/field-textarea/ Kind: constant Public constant FieldTextarea from github.com/riducms/ridu/plugins/formbuilder. ```go const FieldTextarea FieldType = "textarea" ``` ## FieldUpload Canonical URL: https://riducms.com/reference/formbuilder/field-upload/ Kind: constant Public constant FieldUpload from github.com/riducms/ridu/plugins/formbuilder. ```go const FieldUpload FieldType = "upload" ``` ## Plugin.Descriptor Canonical URL: https://riducms.com/reference/formbuilder/plugin-descriptor-method/ Kind: method Descriptor exposes deterministic backend/admin pairing metadata. ```go func (receiver *Plugin) Descriptor() ridu.PluginDescriptor ``` ## Plugin.Key Canonical URL: https://riducms.com/reference/formbuilder/plugin-key-method/ Kind: method Key implements ridu.Plugin. ```go func (receiver *Plugin) Key() string ``` ## Plugin.TransformConfig Canonical URL: https://riducms.com/reference/formbuilder/plugin-transform-config-method/ Kind: method TransformConfig adds the Forms and Form Submissions collections through the same public config surface available to application code. ```go func (plugin *Plugin) TransformConfig(config ridu.Config) (ridu.Config, error) ``` --- # API Reference: storage/local Canonical URL: https://riducms.com/reference/storage-local/ Package: github.com/riducms/ridu/adapters/storage/local Durable filesystem object storage for development and single-host deployments. ## New Canonical URL: https://riducms.com/reference/storage-local/new/ Kind: function Open a local object storage root. ```go func New(root string) (*Backend, error) ``` ```go uploads, err := local.New("./.ridu/uploads") ``` ## Backend Canonical URL: https://riducms.com/reference/storage-local/backend/ Kind: type A filesystem implementation of storage.Backend. ```go type Backend struct { root string filesystem filesystemOperations } ``` ## Backend.Ping Canonical URL: https://riducms.com/reference/storage-local/backend-ping/ Kind: method Verify that the root accepts a durable probe write, then remove the probe. ```go func (backend *Backend) Ping(ctx context.Context) (result error) ``` ## Backend.Put Canonical URL: https://riducms.com/reference/storage-local/backend-put/ Kind: method Atomically and durably write an object with its declared size. ```go func (backend *Backend) Put(ctx context.Context, key string, source io.Reader, size int64, _ string) (result error) ``` The local backend does not persist contentType. It rejects traversal/path-shaped object keys and size mismatches, and preserves an existing object when a replacement fails. ## Backend.Open Canonical URL: https://riducms.com/reference/storage-local/backend-open/ Kind: method Open an object stream and metadata. ```go func (backend *Backend) Open(_ context.Context, key string) (io.ReadCloser, storage.Object, error) ``` ## Backend.Delete Canonical URL: https://riducms.com/reference/storage-local/backend-delete/ Kind: method Delete an object and durably record the directory change. ```go func (backend *Backend) Delete(ctx context.Context, key string) error ``` ## Backend.List Canonical URL: https://riducms.com/reference/storage-local/backend-list/ Kind: method List one bounded page of objects under a prefix in stable key order. ```go func (backend *Backend) List(ctx context.Context, list storage.ListRequest) (storage.ListPage, error) ``` --- # API Reference: storage/s3 Canonical URL: https://riducms.com/reference/storage-s3/ Package: github.com/riducms/ridu/adapters/storage/s3 Dependency-free S3-compatible object storage with SigV4 requests and signed private reads. ## New Canonical URL: https://riducms.com/reference/storage-s3/new/ Kind: function Create an S3-compatible upload backend. ```go func New(config Config) (*Backend, error) ``` New validates the endpoint, credentials, region, bucket, transport security, and spool bounds without contacting the service. ## Config Canonical URL: https://riducms.com/reference/storage-s3/config/ Kind: type Endpoint, credentials, HTTP transport, and bounded upload-spooling settings. ```go type Config struct { Endpoint, Region, Bucket, AccessKey, SecretKey string Client *http.Client // AllowInsecureEndpoint explicitly permits plaintext HTTP for local S3 // emulators such as MinIO. Production credentials must use HTTPS. AllowInsecureEndpoint bool // MaxSpoolBytes bounds temporary disk use when Put receives a reader that // cannot be rewound for signing. Zero selects the Ridu upload limit. MaxSpoolBytes int64 // SpoolDirectory optionally selects the directory for non-seekable Put // payloads. The operating system temporary directory is used by default. SpoolDirectory string } ``` HTTPS is required unless AllowInsecureEndpoint explicitly permits a local emulator such as MinIO. Zero MaxSpoolBytes selects Ridu’s upload limit; non-seekable bodies larger than the limit are rejected before reading. ## Backend Canonical URL: https://riducms.com/reference/storage-s3/backend/ Kind: type An S3 storage and URL-signing backend. ```go type Backend struct { endpoint *url.URL region, bucket, access, secret string client *http.Client maxSpoolBytes int64 spoolDirectory string now func() time.Time } ``` ## Backend.Ping Canonical URL: https://riducms.com/reference/storage-s3/backend-ping/ Kind: method Verify bucket reachability and credentials with HEAD, without listing or mutating objects. ```go func (backend *Backend) Ping(ctx context.Context) error ``` ## Backend.Put Canonical URL: https://riducms.com/reference/storage-s3/backend-put/ Kind: method Upload a size-checked object using a SigV4 payload hash. ```go func (backend *Backend) Put(ctx context.Context, key string, source io.Reader, size int64, contentType string) (result error) ``` Seekable inputs are hashed then rewound. Non-seekable inputs use a bounded temporary spool that is cleaned on success, error, or cancellation. ## Backend.Open Canonical URL: https://riducms.com/reference/storage-s3/backend-open/ Kind: method Open an object stream and response metadata. ```go func (backend *Backend) Open(ctx context.Context, key string) (io.ReadCloser, storage.Object, error) ``` ## Backend.Delete Canonical URL: https://riducms.com/reference/storage-s3/backend-delete/ Kind: method Delete an object. ```go func (backend *Backend) Delete(ctx context.Context, key string) error ``` ## Backend.List Canonical URL: https://riducms.com/reference/storage-s3/backend-list/ Kind: method List one bounded S3 continuation page under a prefix. ```go func (backend *Backend) List(ctx context.Context, list storage.ListRequest) (storage.ListPage, error) ``` ## Backend.SignedURL Canonical URL: https://riducms.com/reference/storage-s3/backend-signed-url/ Kind: method Create a SigV4 GET URL for a private object. ```go func (backend *Backend) SignedURL(ctx context.Context, key string, ttl time.Duration) (string, error) ``` ttl must be between one second and seven days. Object keys are validated before signing. --- # API Reference: conformance Canonical URL: https://riducms.com/reference/store-conformance/ Package: github.com/riducms/ridu/store/conformance Reusable behavioral qualification suites for Ridu store adapters. ## Factory Canonical URL: https://riducms.com/reference/store-conformance/factory/ Kind: type Factory opens a clean store prepared for manifest. Implementations should register cleanup with t and fail the current test when setup cannot finish. ```go type Factory func(t *testing.T, manifest schema.Manifest) store.Store ``` ## Run Canonical URL: https://riducms.com/reference/store-conformance/run/ Kind: function Run executes the shared semantic contract for one adapter. Adapter packages should invoke Run from their own tests so their ordinary integration setup remains responsible for schema creation and external-service availability. ```go func Run(t *testing.T, factory Factory) ``` --- # API Reference: @riducms/sdk Canonical URL: https://riducms.com/reference/sdk/ Package: @riducms/sdk The generated-contract-aware Fetch client for browser and server applications. ## createClient Canonical URL: https://riducms.com/reference/sdk/create-client/ Kind: function Create a typed client from a Ridu base URL and transport options. ```ts function createClient(options: ClientOptions): RiduClient ``` Import the generated client module once to register its config, or pass its config type explicitly when a TypeScript program contains multiple Ridu applications. Methods return ordinary Promise values. Non-2xx responses and malformed success envelopes reject with RiduError. ```ts import "~/generated/ridu.generated"; import { createClient } from "@riducms/sdk"; const cms = createClient({ baseURL: "https://cms.example.com" }); const posts = await cms.list("posts", { limit: 20, sort: ["-publishedAt"], }); ``` ## RiduClient Canonical URL: https://riducms.com/reference/sdk/ridu-client/ Kind: interface The complete typed REST client for schema, auth, access, content, uploads, versions, globals, preview, and preferences. ```ts interface RiduClient { ... } ``` Capability-specific methods only accept generated slugs with the required auth, upload, trash, or version capability. The SDK validates stable envelopes at runtime; generated document shapes remain TypeScript contracts rather than a second client-side schema validator. ## ClientOptions Canonical URL: https://riducms.com/reference/sdk/client-options/ Kind: interface Transport and middleware options for createClient. ```ts interface ClientOptions { ... } ``` baseURL must be absolute. credentials defaults to "include"; client and per-request headers are merged. ## RequestOptions Canonical URL: https://riducms.com/reference/sdk/request-options/ Kind: interface Options shared by every request. ```ts interface RequestOptions { ... } ``` ## LocaleOptions Canonical URL: https://riducms.com/reference/sdk/locale-options/ Kind: interface Localized read and write options. ```ts interface LocaleOptions { ... } ``` locale: "all" returns locale-keyed localized fields. fallbackLocale: false requires an exact locale value. ## MutationLocaleOptions Canonical URL: https://riducms.com/reference/sdk/mutation-locale-options/ Kind: interface Locale and transport options shared by mutations without an optimistic-concurrency contract. ```ts interface MutationLocaleOptions { ... } ``` Mutations target one locale, so locale: "all" is excluded. revision?: never also rejects a revision-bearing options variable instead of only catching fresh object literals. ## MutationOptions Canonical URL: https://riducms.com/reference/sdk/mutation-options/ Kind: interface Localized mutation options with optimistic concurrency. ```ts interface MutationOptions { ... } ``` revision is sent as the If-Match precondition; stale revisions reject with conflict. Publication-state changes use the dedicated publish and unpublish operations so their hooks always run. ## RevisionOptions Canonical URL: https://riducms.com/reference/sdk/revision-options/ Kind: interface Revision and transport options for operations without locale query semantics. ```ts interface RevisionOptions { ... } ``` revision is sent as the If-Match precondition. The never-valued locale keys prevent localized mutation option variables from being passed to operations that do not consume locale query parameters. ## CreateOptions Canonical URL: https://riducms.com/reference/sdk/create-options/ Kind: type Create options, including explicit draft or publish intent for versioned collections. ```ts type CreateOptions = MutationLocaleOptions & DraftCreateOption ``` ## RestoreOptions Canonical URL: https://riducms.com/reference/sdk/restore-options/ Kind: type Version restore options. ```ts type RestoreOptions = MutationOptions & ([Drafts] extends [false] ? { draft?: false } : { draft?: boolean }) ``` ## ListOptions Canonical URL: https://riducms.com/reference/sdk/list-options/ Kind: interface Typed filtering, projection, population, sorting, pagination, locale, and trash options. ```ts interface ListOptions { ... } ``` Prefix a sort field with - for descending order. where, select, and populate are generated per collection. ## FindOptions Canonical URL: https://riducms.com/reference/sdk/find-options/ Kind: interface Projection, population, depth, and locale options for one document or global. ```ts interface FindOptions { ... } ``` ## UploadOptions Canonical URL: https://riducms.com/reference/sdk/upload-options/ Kind: interface Metadata and locale options accompanying an upload. ```ts interface UploadOptions { ... } ``` ## UploadImageInput Canonical URL: https://riducms.com/reference/sdk/upload-image-input/ Kind: interface Focal point and optional crop rectangle for regenerating configured image sizes. ```ts interface UploadImageInput { ... } ``` ## Version Canonical URL: https://riducms.com/reference/sdk/version/ Kind: interface A stored version snapshot; its wire keys intentionally use capital initials. ```ts interface Version { ... } ``` Status follows the generated document _status literal when present and otherwise retains the draft | published compatibility union. ## CollectionContract Canonical URL: https://riducms.com/reference/sdk/collection-contract/ Kind: interface Generated types and capability flags for one collection. ```ts interface CollectionContract { ... } ``` ## GlobalContract Canonical URL: https://riducms.com/reference/sdk/global-contract/ Kind: interface Generated types and capability flags for one global. ```ts interface GlobalContract { ... } ``` ## RiduConfigShape Canonical URL: https://riducms.com/reference/sdk/ridu-config-shape/ Kind: interface The minimum generated contract shape consumed by the SDK. ```ts interface RiduConfigShape { ... } ``` ## GeneratedRiduConfigRegistry Canonical URL: https://riducms.com/reference/sdk/generated-ridu-config-registry/ Kind: interface A type-only registry augmented by generated application packages. ```ts interface GeneratedRiduConfigRegistry { ... } ``` Generated contracts add a manifest-digest-keyed entry through module augmentation. Do not augment it by hand. ## DefaultRiduConfig Canonical URL: https://riducms.com/reference/sdk/default-ridu-config/ Kind: type The sole registered config, or the unbound SDK shape when zero or multiple configs are visible. ```ts type DefaultRiduConfig = [GeneratedRiduConfigKey] extends [never] ? RiduConfigShape : true extends IsUnion ? RiduConfigShape : RegisteredRiduConfig extends RiduConfigShape ? RegisteredRiduConfig : RiduConfigShape ``` ## CollectionSlug Canonical URL: https://riducms.com/reference/sdk/collection-slug/ Kind: type The generated union of collection slugs. ```ts type CollectionSlug = keyof Config["collections"] & string ``` ## GlobalSlug Canonical URL: https://riducms.com/reference/sdk/global-slug/ Kind: type The generated union of global slugs. ```ts type GlobalSlug = keyof NonNullable & string ``` ## GlobalContractFor Canonical URL: https://riducms.com/reference/sdk/global-contract-for/ Kind: type Resolve the generated contract for one global slug. ```ts type GlobalContractFor> = NonNullable[Slug] extends GlobalContract ? NonNullable[Slug] : never ``` ## AuthCollectionSlug Canonical URL: https://riducms.com/reference/sdk/auth-collection-slug/ Kind: type Collection slugs with the generated auth capability. ```ts type AuthCollectionSlug = { [Slug in CollectionSlug]: ContractFor["auth"] extends true ? Slug : never; }[CollectionSlug] ``` ## UploadCollectionSlug Canonical URL: https://riducms.com/reference/sdk/upload-collection-slug/ Kind: type Collection slugs with the generated upload capability. ```ts type UploadCollectionSlug = { [Slug in CollectionSlug]: ContractFor["upload"] extends true ? Slug : never; }[CollectionSlug] ``` ## VersionCollectionSlug Canonical URL: https://riducms.com/reference/sdk/version-collection-slug/ Kind: type Collection slugs with the generated versions capability. ```ts type VersionCollectionSlug = { [Slug in CollectionSlug]: ContractFor["versions"] extends true ? Slug : never; }[CollectionSlug] ``` ## DraftCollectionSlug Canonical URL: https://riducms.com/reference/sdk/draft-collection-slug/ Kind: type Collection slugs with the generated drafts capability. ```ts type DraftCollectionSlug = { [Slug in CollectionSlug]: ContractFor extends { drafts: true } ? Slug : ContractFor extends { drafts: false } ? never : ContractFor["versions"] extends true ? Slug : never; }[CollectionSlug] ``` ## VersionGlobalSlug Canonical URL: https://riducms.com/reference/sdk/version-global-slug/ Kind: type Global slugs with the generated versions capability. ```ts type VersionGlobalSlug = { [Slug in GlobalSlug]: GlobalContractFor["versions"] extends true ? Slug : never; }[GlobalSlug] ``` ## DraftGlobalSlug Canonical URL: https://riducms.com/reference/sdk/draft-global-slug/ Kind: type Global slugs with the generated drafts capability. ```ts type DraftGlobalSlug = { [Slug in GlobalSlug]: GlobalContractFor extends { drafts: true } ? Slug : GlobalContractFor extends { drafts: false } ? never : GlobalContractFor["versions"] extends true ? Slug : never; }[GlobalSlug] ``` ## OutputFor Canonical URL: https://riducms.com/reference/sdk/output-for/ Kind: type Resolve a collection document output type. ```ts type OutputFor> = ContractFor["output"] ``` ## AllLocalesOutputFor Canonical URL: https://riducms.com/reference/sdk/all-locales-output-for/ Kind: type Resolve locale-keyed collection output when generated, otherwise ordinary output. ```ts type AllLocalesOutputFor> = ContractFor extends { allOutput: infer Output } ? Output : OutputFor ``` ## CreateFor Canonical URL: https://riducms.com/reference/sdk/create-for/ Kind: type Resolve a collection create input type. ```ts type CreateFor> = ContractFor["create"] ``` ## UpdateFor Canonical URL: https://riducms.com/reference/sdk/update-for/ Kind: type Resolve a collection update input type. ```ts type UpdateFor> = ContractFor["update"] ``` ## WhereFor Canonical URL: https://riducms.com/reference/sdk/where-for/ Kind: type Resolve a collection filter type. ```ts type WhereFor> = ContractFor["where"] ``` ## SelectFor Canonical URL: https://riducms.com/reference/sdk/select-for/ Kind: type Resolve a collection projection type. ```ts type SelectFor> = ContractFor["select"] ``` ## PopulateFor Canonical URL: https://riducms.com/reference/sdk/populate-for/ Kind: type Resolve a collection population type. ```ts type PopulateFor> = ContractFor["populate"] ``` ## GlobalOutputFor Canonical URL: https://riducms.com/reference/sdk/global-output-for/ Kind: type Resolve a global output type. ```ts type GlobalOutputFor> = GlobalContractFor["output"] ``` ## GlobalAllLocalesOutputFor Canonical URL: https://riducms.com/reference/sdk/global-all-locales-output-for/ Kind: type Resolve locale-keyed global output when generated, otherwise ordinary output. ```ts type GlobalAllLocalesOutputFor> = GlobalContractFor extends { allOutput: infer Output } ? Output : GlobalOutputFor ``` ## GlobalUpdateFor Canonical URL: https://riducms.com/reference/sdk/global-update-for/ Kind: type Resolve a global update input type. ```ts type GlobalUpdateFor> = GlobalContractFor["update"] ``` ## GlobalSelectFor Canonical URL: https://riducms.com/reference/sdk/global-select-for/ Kind: type Resolve a global projection type. ```ts type GlobalSelectFor> = GlobalContractFor["select"] ``` ## GlobalPopulateFor Canonical URL: https://riducms.com/reference/sdk/global-populate-for/ Kind: type Resolve a global population type. ```ts type GlobalPopulateFor> = GlobalContractFor["populate"] ``` ## AuthUser Canonical URL: https://riducms.com/reference/sdk/auth-user/ Kind: type The union of generated output types for auth-enabled collections. ```ts type AuthUser = OutputFor< Config, AuthCollectionSlug > ``` ## LoginCredentials Canonical URL: https://riducms.com/reference/sdk/login-credentials/ Kind: interface Email and password credentials. ```ts interface LoginCredentials { ... } ``` ## JoinMutationInput Canonical URL: https://riducms.com/reference/sdk/join-mutation-input/ Kind: interface IDs to add and remove atomically through a join field. ```ts interface JoinMutationInput { ... } ``` Re-exported from @riducms/protocol for SDK consumers. ## ScheduledPublish Canonical URL: https://riducms.com/reference/sdk/scheduled-publish/ Kind: interface A durable scheduled-publication job returned by publishing methods. ```ts interface ScheduledPublish { ... } ``` Re-exported from @riducms/protocol for SDK consumers. ## CopyLocaleInput Canonical URL: https://riducms.com/reference/sdk/copy-locale-input/ Kind: interface Source and destination locale codes for a copy operation. ```ts interface CopyLocaleInput { ... } ``` ## CollectionSelectionOptions Canonical URL: https://riducms.com/reference/sdk/collection-selection-options/ Kind: interface Typed filter, trash, and locale scope for resolving bulk selection. ```ts interface CollectionSelectionOptions { ... } ``` ## Middleware Canonical URL: https://riducms.com/reference/sdk/middleware/ Kind: type Wrap a Request before it reaches Fetch. ```ts function Middleware(request: Request, next: MiddlewareNext): Promise ``` ```ts const bearer: Middleware = (request, next) => { request.headers.set("Authorization", `Bearer ${token}`); return next(request); }; ``` ## MiddlewareNext Canonical URL: https://riducms.com/reference/sdk/middleware-next/ Kind: type Dispatch to the next middleware or Fetch. ```ts function MiddlewareNext(request: Request): Promise ``` ## RiduError Canonical URL: https://riducms.com/reference/sdk/ridu-error/ Kind: class A structured SDK failure with an error code, HTTP status, request ID, validation issues, and details. ```ts class RiduError { ... } ``` Non-envelope failures receive a stable fallback code. Validation issues retain their paths. ```ts try { await cms.update("posts", id, input, { revision }); } catch (error) { if (error instanceof RiduError && error.code === "conflict") reload(); } ``` ## RiduClient.schema Canonical URL: https://riducms.com/reference/sdk/ridu-client-schema/ Kind: method Read the resolved public schema manifest. ```ts RiduClient.schema(options?: RequestOptions): Promise ``` ## RiduClient.request Canonical URL: https://riducms.com/reference/sdk/ridu-client-request/ Kind: method Dispatch a raw same-origin request to an application-authored custom endpoint. ```ts RiduClient.request(path: string, init?: RequestInit, options?: RequestOptions): Promise ``` Only an absolute path on the configured Ridu origin is accepted; network paths, full URLs, and fragments are rejected before dispatch. The raw Response is returned for every HTTP status. No JSON content type is added implicitly, so the caller retains complete request and response control. The request still uses configured credentials, merged headers, middleware, abort signals, and keepalive behavior. ## RiduClient.requestPlugin Canonical URL: https://riducms.com/reference/sdk/ridu-client-request-plugin/ Kind: method POST to one declared namespaced plugin endpoint through the configured SDK transport. ```ts RiduClient.requestPlugin(plugin: string, path: string, body: unknown, options?: RequestOptions): Promise ``` Plugin keys and every path segment are validated before dispatch; empty, whitespace, traversal, query, fragment, and wildcard paths are rejected. The request retains the client base URL, credentials, merged headers, middleware, abort signal, and structured RiduError behavior. ## RiduClient.preference Canonical URL: https://riducms.com/reference/sdk/ridu-client-preference/ Kind: method Read one preference for the authenticated identity. ```ts RiduClient.preference(key: string, options?: RequestOptions): Promise ``` ## RiduClient.setPreference Canonical URL: https://riducms.com/reference/sdk/ridu-client-set-preference/ Kind: method Create or replace one preference. ```ts RiduClient.setPreference(key: string, value: Value, options?: RequestOptions): Promise ``` ## RiduClient.deletePreference Canonical URL: https://riducms.com/reference/sdk/ridu-client-delete-preference/ Kind: method Delete one preference. ```ts RiduClient.deletePreference(key: string, options?: RequestOptions): Promise ``` ## RiduClient.resetPreferences Canonical URL: https://riducms.com/reference/sdk/ridu-client-reset-preferences/ Kind: method Delete every preference for the authenticated identity. ```ts RiduClient.resetPreferences(options?: RequestOptions): Promise ``` ## RiduClient.login Canonical URL: https://riducms.com/reference/sdk/ridu-client-login/ Kind: method Authenticate against an auth-enabled collection. ```ts RiduClient.login>(collection: Slug, credentials: LoginCredentials, options?: RequestOptions): Promise>> ``` ## RiduClient.session Canonical URL: https://riducms.com/reference/sdk/ridu-client-session/ Kind: method Read and validate the current session. ```ts RiduClient.session(options?: RequestOptions): Promise>> ``` ## RiduClient.refreshSession Canonical URL: https://riducms.com/reference/sdk/ridu-client-refresh-session/ Kind: method Rotate the current session. ```ts RiduClient.refreshSession(options?: RequestOptions): Promise>> ``` ## RiduClient.logout Canonical URL: https://riducms.com/reference/sdk/ridu-client-logout/ Kind: method End the current session. ```ts RiduClient.logout(options?: RequestOptions): Promise ``` ## RiduClient.logoutAll Canonical URL: https://riducms.com/reference/sdk/ridu-client-logout-all/ Kind: method End every session owned by the current user. ```ts RiduClient.logoutAll(options?: RequestOptions): Promise ``` ## RiduClient.sessions Canonical URL: https://riducms.com/reference/sdk/ridu-client-sessions/ Kind: method List the current user’s active sessions. ```ts RiduClient.sessions(options?: RequestOptions): Promise ``` ## RiduClient.revokeSession Canonical URL: https://riducms.com/reference/sdk/ridu-client-revoke-session/ Kind: method Revoke one owned session by ID. ```ts RiduClient.revokeSession(id: string, options?: RequestOptions): Promise ``` ## RiduClient.requestPasswordReset Canonical URL: https://riducms.com/reference/sdk/ridu-client-request-password-reset/ Kind: method Request a password-reset token through the configured delivery hook. ```ts RiduClient.requestPasswordReset>(collection: Slug, email: string, options?: RequestOptions): Promise ``` ## RiduClient.resetPassword Canonical URL: https://riducms.com/reference/sdk/ridu-client-reset-password/ Kind: method Consume a password-reset token. ```ts RiduClient.resetPassword>(collection: Slug, token: string, password: string, options?: RequestOptions): Promise ``` ## RiduClient.authBootstrap Canonical URL: https://riducms.com/reference/sdk/ridu-client-auth-bootstrap/ Kind: method Check whether the configured admin collection still allows one-time first-user setup. ```ts RiduClient.authBootstrap>(collection: Slug, options?: RequestOptions): Promise ``` ## RiduClient.createAuthUser Canonical URL: https://riducms.com/reference/sdk/ridu-client-create-auth-user/ Kind: method Create an auth user and credential together. ```ts RiduClient.createAuthUser>(collection: Slug, data: CreateFor, password: string, options?: MutationLocaleOptions>): Promise> ``` ## RiduClient.requestVerification Canonical URL: https://riducms.com/reference/sdk/ridu-client-request-verification/ Kind: method Request an email-verification token through the configured delivery hook. ```ts RiduClient.requestVerification>(collection: Slug, email: string, options?: RequestOptions): Promise ``` ## RiduClient.verifyEmail Canonical URL: https://riducms.com/reference/sdk/ridu-client-verify-email/ Kind: method Consume an email-verification token. ```ts RiduClient.verifyEmail>(collection: Slug, token: string, options?: RequestOptions): Promise ``` ## RiduClient.changePassword Canonical URL: https://riducms.com/reference/sdk/ridu-client-change-password/ Kind: method Change the current user’s password. ```ts RiduClient.changePassword(currentPassword: string, password: string, options?: RequestOptions): Promise ``` ## RiduClient.createAPIKey Canonical URL: https://riducms.com/reference/sdk/ridu-client-create-a-p-i-key/ Kind: method Create an API key; its secret is returned only once. ```ts RiduClient.createAPIKey(input: CreateAPIKeyInput, options?: RequestOptions): Promise ``` CreateAPIKeyInput is the SDK’s internal name for the inline input shape; it is not a separately importable export. ## RiduClient.apiKeys Canonical URL: https://riducms.com/reference/sdk/ridu-client-api-keys/ Kind: method List API-key metadata without secrets. ```ts RiduClient.apiKeys(options?: RequestOptions): Promise ``` ## RiduClient.revokeAPIKey Canonical URL: https://riducms.com/reference/sdk/ridu-client-revoke-a-p-i-key/ Kind: method Revoke one API key. ```ts RiduClient.revokeAPIKey(id: string, options?: RequestOptions): Promise ``` ## RiduClient.forceUnlock Canonical URL: https://riducms.com/reference/sdk/ridu-client-force-unlock/ Kind: method Clear lockout state for an auth user when authorized. ```ts RiduClient.forceUnlock>(collection: Slug, id: string, options?: RequestOptions): Promise ``` ## RiduClient.collectionAccess Canonical URL: https://riducms.com/reference/sdk/ridu-client-collection-access/ Kind: method Evaluate operation and field capabilities for a prospective collection operation. ```ts RiduClient.collectionAccess>(collection: Slug, options?: CollectionAccessOptions & UpdateFor, LocaleFor>): Promise ``` CollectionAccessOptions is the SDK’s internal name for this inline option shape; it is not a separately importable export. ## RiduClient.resolveFilteredSelection Canonical URL: https://riducms.com/reference/sdk/ridu-client-resolve-filtered-selection/ Kind: method Resolve a filter to authorized IDs and per-document capabilities. ```ts RiduClient.resolveFilteredSelection>(collection: Slug, options?: CollectionSelectionOptions, LocaleFor>): Promise ``` The server applies the access predicate atomically and may reject oversized selections with selection_too_large. ## RiduClient.globalAccess Canonical URL: https://riducms.com/reference/sdk/ridu-client-global-access/ Kind: method Evaluate operation and field capabilities for a global. ```ts RiduClient.globalAccess>(slug: Slug, options?: GlobalAccessOptions, LocaleFor>): Promise ``` GlobalAccessOptions is the SDK’s internal name for this inline option shape; it is not a separately importable export. ## RiduClient.documentLock Canonical URL: https://riducms.com/reference/sdk/ridu-client-document-lock/ Kind: method Read the current document-lock lease. ```ts RiduClient.documentLock>(collection: Slug, id: string, options?: RequestOptions): Promise ``` ## RiduClient.acquireDocumentLock Canonical URL: https://riducms.com/reference/sdk/ridu-client-acquire-document-lock/ Kind: method Acquire or renew a document lock, optionally taking over an eligible lease. ```ts RiduClient.acquireDocumentLock>(collection: Slug, id: string, takeover?: boolean, options?: RequestOptions): Promise ``` ## RiduClient.releaseDocumentLock Canonical URL: https://riducms.com/reference/sdk/ridu-client-release-document-lock/ Kind: method Release a document lock owned by the current user. ```ts RiduClient.releaseDocumentLock>(collection: Slug, id: string, options?: RequestOptions): Promise ``` ## RiduClient.list Canonical URL: https://riducms.com/reference/sdk/ridu-client-list/ Kind: method List authorized collection documents with locale-, projection-, and population-dependent results. ```ts RiduClient.list, const Options extends ListOptions, SelectFor, PopulateFor, LocaleFor> | undefined = undefined>(collection: Slug, options?: Options): Promise>> ``` ## RiduClient.count Canonical URL: https://riducms.com/reference/sdk/ridu-client-count/ Kind: method Count authorized documents matching a typed filter. ```ts RiduClient.count>(collection: Slug, options?: Pick, never, never, LocaleFor>, "where" | "trash" | "locale" | "fallbackLocale" | "signal" | "headers">): Promise ``` ## RiduClient.find Canonical URL: https://riducms.com/reference/sdk/ridu-client-find/ Kind: method Find one authorized document with a locale-, projection-, and population-dependent result. ```ts RiduClient.find, const Options extends FindOptions, PopulateFor, LocaleFor> | undefined = undefined>(collection: Slug, id: string, options?: Options): Promise> ``` ## RiduClient.create Canonical URL: https://riducms.com/reference/sdk/ridu-client-create/ Kind: method Create one collection document with capability-checked draft intent. ```ts RiduClient.create>(collection: Slug, data: CreateFor, options?: CreateOptions, CollectionVersionsFor, CollectionDraftsFor>): Promise> ``` ## RiduClient.duplicate Canonical URL: https://riducms.com/reference/sdk/ridu-client-duplicate/ Kind: method Duplicate a document with optional typed create-field overrides. ```ts RiduClient.duplicate>(collection: Slug, id: string, overrides?: Partial, "id">>, options?: MutationLocaleOptions>): Promise> ``` ## RiduClient.copyLocale Canonical URL: https://riducms.com/reference/sdk/ridu-client-copy-locale/ Kind: method Copy localized values between locales on one document; from and to define the locale scope. ```ts RiduClient.copyLocale>(collection: Slug, id: string, input: CopyLocaleInput>, options?: RevisionOptions): Promise> ``` ## RiduClient.update Canonical URL: https://riducms.com/reference/sdk/ridu-client-update/ Kind: method Update one document, optionally guarded by its revision. ```ts RiduClient.update>(collection: Slug, id: string, data: UpdateFor, options?: MutationOptions>): Promise> ``` ## RiduClient.mutateJoin Canonical URL: https://riducms.com/reference/sdk/ridu-client-mutate-join/ Kind: method Atomically add and remove IDs through a join field. ```ts RiduClient.mutateJoin>(collection: Slug, id: string, field: string, input: JoinMutationInput, options?: MutationLocaleOptions>): Promise>> ``` ## RiduClient.delete Canonical URL: https://riducms.com/reference/sdk/ridu-client-delete/ Kind: method Delete or trash one document according to collection capabilities. ```ts RiduClient.delete>(collection: Slug, id: string, options?: MutationLocaleOptions>): Promise ``` ## RiduClient.bulkUpdate Canonical URL: https://riducms.com/reference/sdk/ridu-client-bulk-update/ Kind: method Update an explicit set of document IDs. ```ts RiduClient.bulkUpdate>(collection: Slug, ids: readonly string[], data: UpdateFor, options?: MutationLocaleOptions>): Promise[]> ``` ## RiduClient.bulkPublish Canonical URL: https://riducms.com/reference/sdk/ridu-client-bulk-publish/ Kind: method Publish an explicit set of versioned documents. ```ts RiduClient.bulkPublish>(collection: Slug, ids: readonly string[], options?: MutationLocaleOptions>): Promise[]> ``` ## RiduClient.bulkUnpublish Canonical URL: https://riducms.com/reference/sdk/ridu-client-bulk-unpublish/ Kind: method Unpublish an explicit set of draft-enabled documents. ```ts RiduClient.bulkUnpublish>(collection: Slug, ids: readonly string[], options?: MutationLocaleOptions>): Promise[]> ``` ## RiduClient.bulkDelete Canonical URL: https://riducms.com/reference/sdk/ridu-client-bulk-delete/ Kind: method Delete or trash an explicit set of document IDs. ```ts RiduClient.bulkDelete>(collection: Slug, ids: readonly string[], options?: MutationLocaleOptions>): Promise[]> ``` ## RiduClient.bulkRestoreDeleted Canonical URL: https://riducms.com/reference/sdk/ridu-client-bulk-restore-deleted/ Kind: method Restore an explicit set of trashed document IDs. ```ts RiduClient.bulkRestoreDeleted>(collection: Slug, ids: readonly string[], options?: MutationLocaleOptions>): Promise[]> ``` TrashCollectionSlug is an internal capability-filtered union of generated collection slugs whose contract enables trash; it is not a separate SDK export. ## RiduClient.bulkDeletePermanent Canonical URL: https://riducms.com/reference/sdk/ridu-client-bulk-delete-permanent/ Kind: method Permanently delete an explicit set of trashed document IDs. ```ts RiduClient.bulkDeletePermanent>(collection: Slug, ids: readonly string[], options?: MutationLocaleOptions>): Promise[]> ``` TrashCollectionSlug is an internal capability-filtered union of generated collection slugs whose contract enables trash; it is not a separate SDK export. ## RiduClient.emptyTrash Canonical URL: https://riducms.com/reference/sdk/ridu-client-empty-trash/ Kind: method Permanently delete every authorized trashed document in a collection. ```ts RiduClient.emptyTrash>(collection: Slug, options?: MutationLocaleOptions>): Promise[]> ``` TrashCollectionSlug is an internal capability-filtered union of generated collection slugs whose contract enables trash; it is not a separate SDK export. ## RiduClient.restoreDeleted Canonical URL: https://riducms.com/reference/sdk/ridu-client-restore-deleted/ Kind: method Restore one trashed document. ```ts RiduClient.restoreDeleted>(collection: Slug, id: string, options?: MutationLocaleOptions>): Promise> ``` TrashCollectionSlug is an internal capability-filtered union of generated collection slugs whose contract enables trash; it is not a separate SDK export. ## RiduClient.deletePermanent Canonical URL: https://riducms.com/reference/sdk/ridu-client-delete-permanent/ Kind: method Permanently delete one trashed document and its retained state. ```ts RiduClient.deletePermanent>(collection: Slug, id: string, options?: MutationLocaleOptions>): Promise ``` TrashCollectionSlug is an internal capability-filtered union of generated collection slugs whose contract enables trash; it is not a separate SDK export. ## RiduClient.upload Canonical URL: https://riducms.com/reference/sdk/ridu-client-upload/ Kind: method Upload a Blob with optional typed metadata. ```ts RiduClient.upload>(collection: Slug, file: Blob, options?: UploadOptions, LocaleFor>): Promise> ``` ## RiduClient.uploadFromURL Canonical URL: https://riducms.com/reference/sdk/ridu-client-upload-from-u-r-l/ Kind: method Ask the server to ingest a remote URL with optional typed metadata. ```ts RiduClient.uploadFromURL>(collection: Slug, url: string, options?: UploadOptions, LocaleFor>): Promise> ``` ## RiduClient.updateUploadImage Canonical URL: https://riducms.com/reference/sdk/ridu-client-update-upload-image/ Kind: method Update non-localized focal/crop metadata and regenerate configured image sizes. ```ts RiduClient.updateUploadImage>(collection: Slug, id: string, input: UploadImageInput, options?: RevisionOptions): Promise> ``` ## RiduClient.versions Canonical URL: https://riducms.com/reference/sdk/ridu-client-versions/ Kind: method List stored versions with locale-dependent snapshot types. ```ts RiduClient.versions, const Options extends LocaleOptions> | undefined = undefined>(collection: Slug, id: string, options?: Options): Promise, AllLocalesOutputFor, Options>>[]> ``` ## RiduClient.version Canonical URL: https://riducms.com/reference/sdk/ridu-client-version/ Kind: method Read one stored revision with a locale-dependent snapshot type. ```ts RiduClient.version, const Options extends LocaleOptions> | undefined = undefined>(collection: Slug, id: string, revision: number, options?: Options): Promise, AllLocalesOutputFor, Options>>> ``` ## RiduClient.schedulePublish Canonical URL: https://riducms.com/reference/sdk/ridu-client-schedule-publish/ Kind: method Schedule a versioned document for publication with an optional revision fence. ```ts RiduClient.schedulePublish>(collection: Slug, id: string, runAt: string | Date, options?: RevisionOptions): Promise ``` ## RiduClient.scheduledPublishes Canonical URL: https://riducms.com/reference/sdk/ridu-client-scheduled-publishes/ Kind: method List scheduled publication jobs for one document. ```ts RiduClient.scheduledPublishes>(collection: Slug, id: string, options?: RequestOptions): Promise ``` ## RiduClient.cancelScheduledPublish Canonical URL: https://riducms.com/reference/sdk/ridu-client-cancel-scheduled-publish/ Kind: method Cancel one scheduled publication job. ```ts RiduClient.cancelScheduledPublish>(collection: Slug, id: string, jobID: string, options?: RequestOptions): Promise ``` ## RiduClient.publish Canonical URL: https://riducms.com/reference/sdk/ridu-client-publish/ Kind: method Publish the current version of a document. ```ts RiduClient.publish>(collection: Slug, id: string, options?: MutationOptions>): Promise> ``` ## RiduClient.publishChanges Canonical URL: https://riducms.com/reference/sdk/ridu-client-publish-changes/ Kind: method Atomically apply edited values and publish through publish access and hooks. ```ts RiduClient.publishChanges>(collection: Slug, id: string, data: UpdateFor, options?: MutationOptions>): Promise> ``` ## RiduClient.unpublish Canonical URL: https://riducms.com/reference/sdk/ridu-client-unpublish/ Kind: method Return a published draft-enabled document to draft. ```ts RiduClient.unpublish>(collection: Slug, id: string, options?: MutationOptions>): Promise> ``` ## RiduClient.restore Canonical URL: https://riducms.com/reference/sdk/ridu-client-restore/ Kind: method Restore a historical revision, optionally as a draft. ```ts RiduClient.restore>(collection: Slug, id: string, revision: number, options?: RestoreOptions, CollectionDraftsFor>): Promise> ``` ## RiduClient.global Canonical URL: https://riducms.com/reference/sdk/ridu-client-global/ Kind: method Read one global with a locale-, projection-, and population-dependent result. ```ts RiduClient.global, const Options extends FindOptions, GlobalPopulateFor, LocaleFor> | undefined = undefined>(slug: Slug, options?: Options): Promise> ``` ## RiduClient.updateGlobal Canonical URL: https://riducms.com/reference/sdk/ridu-client-update-global/ Kind: method Update a global, optionally guarded by its revision. ```ts RiduClient.updateGlobal>(slug: Slug, data: GlobalUpdateFor, options?: MutationOptions>): Promise> ``` ## RiduClient.copyGlobalLocale Canonical URL: https://riducms.com/reference/sdk/ridu-client-copy-global-locale/ Kind: method Copy localized values between locales on a global; from and to define the locale scope. ```ts RiduClient.copyGlobalLocale>(slug: Slug, input: CopyLocaleInput>, options?: RevisionOptions): Promise> ``` ## RiduClient.globalVersions Canonical URL: https://riducms.com/reference/sdk/ridu-client-global-versions/ Kind: method List stored versions for a versioned global with locale-dependent snapshot types. ```ts RiduClient.globalVersions, const Options extends LocaleOptions> | undefined = undefined>(slug: Slug, options?: Options): Promise, GlobalAllLocalesOutputFor, Options>>[]> ``` ## RiduClient.globalVersion Canonical URL: https://riducms.com/reference/sdk/ridu-client-global-version/ Kind: method Read one stored global revision with a locale-dependent snapshot type. ```ts RiduClient.globalVersion, const Options extends LocaleOptions> | undefined = undefined>(slug: Slug, revision: number, options?: Options): Promise, GlobalAllLocalesOutputFor, Options>>> ``` ## RiduClient.publishGlobal Canonical URL: https://riducms.com/reference/sdk/ridu-client-publish-global/ Kind: method Publish a versioned global. ```ts RiduClient.publishGlobal>(slug: Slug, options?: MutationOptions>): Promise> ``` ## RiduClient.publishGlobalChanges Canonical URL: https://riducms.com/reference/sdk/ridu-client-publish-global-changes/ Kind: method Atomically apply edited singleton values and publish through global publish access and hooks. ```ts RiduClient.publishGlobalChanges>(slug: Slug, data: GlobalUpdateFor, options?: MutationOptions>): Promise> ``` ## RiduClient.unpublishGlobal Canonical URL: https://riducms.com/reference/sdk/ridu-client-unpublish-global/ Kind: method Return a draft-enabled global to draft. ```ts RiduClient.unpublishGlobal>(slug: Slug, options?: MutationOptions>): Promise> ``` ## RiduClient.restoreGlobal Canonical URL: https://riducms.com/reference/sdk/ridu-client-restore-global/ Kind: method Restore a historical global revision, optionally as a draft. ```ts RiduClient.restoreGlobal>(slug: Slug, revision: number, options?: RestoreOptions, GlobalDraftsFor>): Promise> ``` ## RiduClient.createPreviewToken Canonical URL: https://riducms.com/reference/sdk/ridu-client-create-preview-token/ Kind: method Create a short-lived preview token for a draft-enabled collection document. ```ts RiduClient.createPreviewToken>(collection: Slug, id: string, options?: RequestOptions): Promise ``` ## RiduClient.revokePreviewToken Canonical URL: https://riducms.com/reference/sdk/ridu-client-revoke-preview-token/ Kind: method Revoke a preview token before it expires. ```ts RiduClient.revokePreviewToken(token: string, options?: RequestOptions): Promise ``` ## RiduClient.preview Canonical URL: https://riducms.com/reference/sdk/ridu-client-preview/ Kind: method Read preview data using a scoped token. ```ts RiduClient.preview>(collection: Slug, id: string, token: string, options?: RequestOptions): Promise> ``` ## RiduClient.createGlobalPreviewToken Canonical URL: https://riducms.com/reference/sdk/ridu-client-create-global-preview-token/ Kind: method Create a short-lived preview token for a draft-enabled global. ```ts RiduClient.createGlobalPreviewToken>(slug: Slug, options?: RequestOptions): Promise ``` ## RiduClient.previewGlobal Canonical URL: https://riducms.com/reference/sdk/ridu-client-preview-global/ Kind: method Read global preview data using a scoped token. ```ts RiduClient.previewGlobal>(slug: Slug, token: string, options?: RequestOptions): Promise> ``` ## connectLivePreview Canonical URL: https://riducms.com/reference/sdk/connect-live-preview/ Kind: function Connect a frontend preview window or iframe to authenticated admin updates. ```ts function connectLivePreview({ adminOrigin, target: expectedTarget, onUpdate, window: injectedWindow, }: { adminOrigin: string; target: LivePreviewTarget; onUpdate: (message: RiduLivePreviewUpdateMessage) => void; window?: object; }): LivePreviewConnection ``` The URL must contain __ridu_preview and run in an iframe or opener. Messages are checked against origin, source window, channel, resource, slug, and ID. Call disconnect on unmount. ## LivePreviewTarget Canonical URL: https://riducms.com/reference/sdk/live-preview-target/ Kind: interface The collection or global identity accepted by a preview route. ```ts interface LivePreviewTarget { ... } ``` ## LivePreviewConnection Canonical URL: https://riducms.com/reference/sdk/live-preview-connection/ Kind: interface A disposable live-preview channel. ```ts interface LivePreviewConnection { ... } ``` ## RiduLivePreviewReadyMessage Canonical URL: https://riducms.com/reference/sdk/ridu-live-preview-ready-message/ Kind: interface The readiness handshake sent to the admin. ```ts interface RiduLivePreviewReadyMessage { ... } ``` ## RiduLivePreviewUpdateMessage Canonical URL: https://riducms.com/reference/sdk/ridu-live-preview-update-message/ Kind: interface One sequenced preview update accepted from the admin. ```ts interface RiduLivePreviewUpdateMessage { ... } ``` ## Live preview constants Canonical URL: https://riducms.com/reference/sdk/live-preview-constants/ Kind: type Stable message and query-parameter constants. ```ts const RIDU_LIVE_PREVIEW_MESSAGE = "ridu-live-preview"; const RIDU_LIVE_PREVIEW_CHANNEL_PARAM = "__ridu_preview"; const RIDU_PREVIEW_TOKEN_PARAM = "__ridu_preview_token" ``` ## ClientOptions.fetch Canonical URL: https://riducms.com/reference/sdk/client-options-fetch-method/ Kind: method Public method ClientOptions.fetch from @riducms/sdk. ```ts ClientOptions.fetch(input: Parameters[0], init?: Parameters[1]): ReturnType ``` ## LivePreviewConnection.disconnect Canonical URL: https://riducms.com/reference/sdk/live-preview-connection-disconnect-method/ Kind: method Public method LivePreviewConnection.disconnect from @riducms/sdk. ```ts LivePreviewConnection.disconnect(): void ``` ## LivePreviewConnection.ready Canonical URL: https://riducms.com/reference/sdk/live-preview-connection-ready-method/ Kind: method Re-announces readiness after an application-side route or renderer reset. ```ts LivePreviewConnection.ready(): void ``` ## RIDU_LIVE_PREVIEW_CHANNEL_PARAM Canonical URL: https://riducms.com/reference/sdk/ridu-live-preview-channel-param/ Kind: constant Public constant RIDU_LIVE_PREVIEW_CHANNEL_PARAM from @riducms/sdk. ```ts const RIDU_LIVE_PREVIEW_CHANNEL_PARAM: "__ridu_preview" ``` ## RIDU_LIVE_PREVIEW_MESSAGE Canonical URL: https://riducms.com/reference/sdk/ridu-live-preview-message/ Kind: constant Public constant RIDU_LIVE_PREVIEW_MESSAGE from @riducms/sdk. ```ts const RIDU_LIVE_PREVIEW_MESSAGE: "ridu-live-preview" ``` ## RIDU_PREVIEW_TOKEN_PARAM Canonical URL: https://riducms.com/reference/sdk/ridu-preview-token-param/ Kind: constant Public constant RIDU_PREVIEW_TOKEN_PARAM from @riducms/sdk. ```ts const RIDU_PREVIEW_TOKEN_PARAM: "__ridu_preview_token" ``` --- # API Reference: @riducms/protocol Canonical URL: https://riducms.com/reference/protocol/ Package: @riducms/protocol Generated wire contracts and runtime guards shared by the SDK and admin. ## PROTOCOL_VERSION Canonical URL: https://riducms.com/reference/protocol/protocol-version/ Kind: constant The generated REST/protocol contract version. ```ts const PROTOCOL_VERSION: 1 ``` ## SCHEMA_MANIFEST_VERSION Canonical URL: https://riducms.com/reference/protocol/schema-manifest-version/ Kind: constant The schema-manifest wire version accepted by this package. ```ts const SCHEMA_MANIFEST_VERSION: 1 ``` ## ADMIN_PLUGIN_API_VERSION Canonical URL: https://riducms.com/reference/protocol/admin-plugin-api-version/ Kind: constant The framework-owned admin-plugin contract version. ```ts const ADMIN_PLUGIN_API_VERSION: 1 ``` ## ErrorCode Canonical URL: https://riducms.com/reference/protocol/error-code/ Kind: type Stable machine-readable failure codes. ```ts type ErrorCode = | "validation" | "access_denied" | "not_found" | "conflict" | "delete_restricted" | "bad_request" | "internal" | "rate_limited" | "email_not_verified" | "auth_feature_disabled" | "invalid_auth_token" | "invalid_preview_token" | "selection_too_large" ``` ## ValidationIssue Canonical URL: https://riducms.com/reference/protocol/validation-issue/ Kind: interface One path-aware validation failure. ```ts interface ValidationIssue { ... } ``` ## ErrorPayload Canonical URL: https://riducms.com/reference/protocol/error-payload/ Kind: interface The structured failure inside an error envelope. ```ts interface ErrorPayload { ... } ``` ## ErrorEnvelope Canonical URL: https://riducms.com/reference/protocol/error-envelope/ Kind: interface The stable REST error envelope. ```ts interface ErrorEnvelope { ... } ``` ## isValidationIssue Canonical URL: https://riducms.com/reference/protocol/is-validation-issue/ Kind: function Guard an unknown value as a validation issue. ```ts function isValidationIssue(value: unknown): value is ValidationIssue ``` ## isErrorEnvelope Canonical URL: https://riducms.com/reference/protocol/is-error-envelope/ Kind: function Guard an unknown value as a complete error envelope. ```ts function isErrorEnvelope(value: unknown): value is ErrorEnvelope ``` The guard checks known error codes, integer status, message, optional request ID, and every validation issue. details remains intentionally open. ## errorPayload Canonical URL: https://riducms.com/reference/protocol/error-payload-function/ Kind: function Return the payload inside a validated error envelope. ```ts function errorPayload(envelope: ErrorEnvelope): ErrorPayload ``` ## Pagination Canonical URL: https://riducms.com/reference/protocol/pagination/ Kind: interface Page metadata included beside list results. ```ts interface Pagination { ... } ``` ## PageEnvelope Canonical URL: https://riducms.com/reference/protocol/page-envelope/ Kind: interface A paginated REST list response. ```ts interface PageEnvelope { ... } ``` ## isPageEnvelope Canonical URL: https://riducms.com/reference/protocol/is-page-envelope/ Kind: function Guard an unknown value as a page envelope. ```ts function isPageEnvelope(value: unknown): value is PageEnvelope ``` The guard validates the envelope and pagination metadata, not each document’s application-specific shape. ## DocumentEnvelope Canonical URL: https://riducms.com/reference/protocol/document-envelope/ Kind: interface A one-document response. ```ts interface DocumentEnvelope { ... } ``` ## CountEnvelope Canonical URL: https://riducms.com/reference/protocol/count-envelope/ Kind: interface A count response. ```ts interface CountEnvelope { ... } ``` ## BulkEnvelope Canonical URL: https://riducms.com/reference/protocol/bulk-envelope/ Kind: interface A bulk-operation response. ```ts interface BulkEnvelope { ... } ``` ## DeleteEnvelope Canonical URL: https://riducms.com/reference/protocol/delete-envelope/ Kind: interface A successful delete response. ```ts interface DeleteEnvelope { ... } ``` ## JoinMutationInput Canonical URL: https://riducms.com/reference/protocol/join-mutation-input/ Kind: interface IDs to add and remove atomically through a join field. ```ts interface JoinMutationInput { ... } ``` ## JoinMutationEnvelope Canonical URL: https://riducms.com/reference/protocol/join-mutation-envelope/ Kind: interface The updated document and actual join mutation counts. ```ts interface JoinMutationEnvelope { ... } ``` ## PreferenceEnvelope Canonical URL: https://riducms.com/reference/protocol/preference-envelope/ Kind: interface A typed preference value. ```ts interface PreferenceEnvelope { ... } ``` ## OperationCapabilities Canonical URL: https://riducms.com/reference/protocol/operation-capabilities/ Kind: interface Authorization results for every admin-visible document operation. ```ts interface OperationCapabilities { ... } ``` ## FieldCapabilities Canonical URL: https://riducms.com/reference/protocol/field-capabilities/ Kind: interface Read/create/update authorization for one field path. ```ts interface FieldCapabilities { ... } ``` ## AccessCapabilitiesEnvelope Canonical URL: https://riducms.com/reference/protocol/access-capabilities-envelope/ Kind: interface Operation and path-keyed field capabilities. ```ts interface AccessCapabilitiesEnvelope { ... } ``` ## CollectionSelectionInput Canonical URL: https://riducms.com/reference/protocol/collection-selection-input/ Kind: interface A filter and trash scope for server-resolved bulk selection. ```ts interface CollectionSelectionInput> { ... } ``` ## CollectionSelectionItem Canonical URL: https://riducms.com/reference/protocol/collection-selection-item/ Kind: interface One selected ID and its evaluated capabilities. ```ts interface CollectionSelectionItem { ... } ``` ## CollectionSelectionEnvelope Canonical URL: https://riducms.com/reference/protocol/collection-selection-envelope/ Kind: interface The authorized result of a server-resolved bulk selection. ```ts interface CollectionSelectionEnvelope { ... } ``` ## DocumentLock Canonical URL: https://riducms.com/reference/protocol/document-lock/ Kind: interface One time-bounded document editing lease. ```ts interface DocumentLock { ... } ``` ## DocumentLockEnvelope Canonical URL: https://riducms.com/reference/protocol/document-lock-envelope/ Kind: interface The current lease and whether this request owns or acquired it. ```ts interface DocumentLockEnvelope { ... } ``` ## AuthSession Canonical URL: https://riducms.com/reference/protocol/auth-session/ Kind: interface An authenticated user session. ```ts interface AuthSession { ... } ``` ## AuthSessionInfo Canonical URL: https://riducms.com/reference/protocol/auth-session-info/ Kind: interface Session metadata safe to expose in account management. ```ts interface AuthSessionInfo { ... } ``` ## SessionEnvelope Canonical URL: https://riducms.com/reference/protocol/session-envelope/ Kind: interface An auth-session response. ```ts interface SessionEnvelope { ... } ``` ## AuthSessionsEnvelope Canonical URL: https://riducms.com/reference/protocol/auth-sessions-envelope/ Kind: interface A list of session metadata. ```ts interface AuthSessionsEnvelope { ... } ``` ## LogoutEnvelope Canonical URL: https://riducms.com/reference/protocol/logout-envelope/ Kind: interface A successful logout response. ```ts interface LogoutEnvelope { ... } ``` ## AuthActionEnvelope Canonical URL: https://riducms.com/reference/protocol/auth-action-envelope/ Kind: interface A successful auth maintenance action. ```ts interface AuthActionEnvelope { ... } ``` ## AuthBootstrapEnvelope Canonical URL: https://riducms.com/reference/protocol/auth-bootstrap-envelope/ Kind: interface Whether the configured admin collection still allows one-time first-user setup. ```ts interface AuthBootstrapEnvelope { ... } ``` ## APIKey Canonical URL: https://riducms.com/reference/protocol/api-key/ Kind: interface A newly created API key including its one-time secret. ```ts interface APIKey { ... } ``` ## APIKeyInfo Canonical URL: https://riducms.com/reference/protocol/api-key-info/ Kind: interface API-key metadata without its secret. ```ts interface APIKeyInfo { ... } ``` ## PreviewToken Canonical URL: https://riducms.com/reference/protocol/preview-token/ Kind: interface A short-lived token scoped to one preview target. ```ts interface PreviewToken { ... } ``` ## ScheduledPublish Canonical URL: https://riducms.com/reference/protocol/scheduled-publish/ Kind: interface A durable scheduled-publication job. ```ts interface ScheduledPublish { ... } ``` ## ScheduledPublishEnvelope Canonical URL: https://riducms.com/reference/protocol/scheduled-publish-envelope/ Kind: interface One scheduled publication response. ```ts interface ScheduledPublishEnvelope { ... } ``` ## ScheduledPublishesEnvelope Canonical URL: https://riducms.com/reference/protocol/scheduled-publishes-envelope/ Kind: interface A list of scheduled publication jobs. ```ts interface ScheduledPublishesEnvelope { ... } ``` ## PreviewTokenEnvelope Canonical URL: https://riducms.com/reference/protocol/preview-token-envelope/ Kind: interface A preview-token response. ```ts interface PreviewTokenEnvelope { ... } ``` ## APIKeyEnvelope Canonical URL: https://riducms.com/reference/protocol/api-key-envelope/ Kind: interface A newly created API key response. ```ts interface APIKeyEnvelope { ... } ``` ## APIKeysEnvelope Canonical URL: https://riducms.com/reference/protocol/api-keys-envelope/ Kind: interface An API-key metadata list response. ```ts interface APIKeysEnvelope { ... } ``` ## SchemaManifest Canonical URL: https://riducms.com/reference/protocol/schema-manifest/ Kind: interface The immutable public schema consumed by generators, the SDK, plugins, and admin. ```ts interface SchemaManifest { ... } ``` The manifest contains declarative public metadata only. Executable access functions, hooks, credentials, and secrets are never serialized into it. ## SchemaApplication Canonical URL: https://riducms.com/reference/protocol/schema-application/ Kind: interface Application identity, translated name, admin settings, and content localization. ```ts interface SchemaApplication { ... } ``` ## SchemaEndpoint Canonical URL: https://riducms.com/reference/protocol/schema-endpoint/ Kind: interface Public method, path, and optional OpenAPI summary for a custom endpoint. ```ts interface SchemaEndpoint { ... } ``` ## SchemaAdminLocalizationSettings Canonical URL: https://riducms.com/reference/protocol/schema-admin-localization-settings/ Kind: interface Configured admin languages, defaults, and editor timezone choices. ```ts interface SchemaAdminLocalizationSettings { ... } ``` ## SchemaAdminLanguage Canonical URL: https://riducms.com/reference/protocol/schema-admin-language/ Kind: interface One available admin interface language. ```ts interface SchemaAdminLanguage { ... } ``` ## SchemaAdminTimeZone Canonical URL: https://riducms.com/reference/protocol/schema-admin-time-zone/ Kind: interface One timezone offered to editors. ```ts interface SchemaAdminTimeZone { ... } ``` ## SchemaAdminSettings Canonical URL: https://riducms.com/reference/protocol/schema-admin-settings/ Kind: interface The auth collection used for framework admin access. ```ts interface SchemaAdminSettings { ... } ``` ## SchemaLocalizationSettings Canonical URL: https://riducms.com/reference/protocol/schema-localization-settings/ Kind: interface Configured locales, default locale, and fallback behavior. ```ts interface SchemaLocalizationSettings { ... } ``` ## SchemaLocale Canonical URL: https://riducms.com/reference/protocol/schema-locale/ Kind: interface One content locale and its ordered fallback chain. ```ts interface SchemaLocale { ... } ``` ## SchemaPlugin Canonical URL: https://riducms.com/reference/protocol/schema-plugin/ Kind: interface A compiled plugin descriptor embedded in the manifest. ```ts interface SchemaPlugin { ... } ``` ## SchemaPluginCompatibility Canonical URL: https://riducms.com/reference/protocol/schema-plugin-compatibility/ Kind: interface The supported Ridu version range declared by a plugin. ```ts interface SchemaPluginCompatibility { ... } ``` ## SchemaPluginAdmin Canonical URL: https://riducms.com/reference/protocol/schema-plugin-admin/ Kind: interface The exact static admin package/export paired with a compiled backend plugin. ```ts interface SchemaPluginAdmin { ... } ``` ## SchemaPluginFieldType Canonical URL: https://riducms.com/reference/protocol/schema-plugin-field-type/ Kind: interface Generated TypeScript/Go type bindings and JSON Schema for a plugin field. ```ts interface SchemaPluginFieldType { ... } ``` ## SchemaPluginDatabaseAdapter Canonical URL: https://riducms.com/reference/protocol/schema-plugin-database-adapter/ Kind: type The database dialect for one private plugin schema bundle. ```ts type SchemaPluginDatabaseAdapter = 'postgres' | 'sqlite' ``` ## SchemaPluginDatabaseContribution Canonical URL: https://riducms.com/reference/protocol/schema-plugin-database-contribution/ Kind: interface One adapter-specific plugin migration history and owned-table list. ```ts interface SchemaPluginDatabaseContribution { ... } ``` ## SchemaPluginMigration Canonical URL: https://riducms.com/reference/protocol/schema-plugin-migration/ Kind: interface One versioned plugin-owned SQL migration. ```ts interface SchemaPluginMigration { ... } ``` ## SchemaPluginEndpoint Canonical URL: https://riducms.com/reference/protocol/schema-plugin-endpoint/ Kind: interface A plugin-owned HTTP endpoint descriptor. ```ts interface SchemaPluginEndpoint { ... } ``` ## SchemaCollection Canonical URL: https://riducms.com/reference/protocol/schema-collection/ Kind: interface One resolved collection or global, including capabilities and field manifest. ```ts interface SchemaCollection { ... } ``` ## SchemaCollectionIndex Canonical URL: https://riducms.com/reference/protocol/schema-collection-index/ Kind: interface An ordered compound index and optional uniqueness constraint. ```ts interface SchemaCollectionIndex { ... } ``` ## SchemaDocumentLockSettings Canonical URL: https://riducms.com/reference/protocol/schema-document-lock-settings/ Kind: interface The configured lease duration for document locking. ```ts interface SchemaDocumentLockSettings { ... } ``` ## SchemaCollectionLabels Canonical URL: https://riducms.com/reference/protocol/schema-collection-labels/ Kind: interface Singular and plural resource labels. ```ts interface SchemaCollectionLabels { ... } ``` ## SchemaGlobal Canonical URL: https://riducms.com/reference/protocol/schema-global/ Kind: type A singleton resource represented with the collection schema shape and global capability. ```ts type SchemaGlobal = SchemaCollection ``` ## SchemaCapabilities Canonical URL: https://riducms.com/reference/protocol/schema-capabilities/ Kind: interface Resolved resource capability flags. ```ts interface SchemaCapabilities { ... } ``` ## SchemaCollectionAdmin Canonical URL: https://riducms.com/reference/protocol/schema-collection-admin/ Kind: interface Admin presentation and live-preview settings for a resource. ```ts interface SchemaCollectionAdmin { ... } ``` ## SchemaLivePreview Canonical URL: https://riducms.com/reference/protocol/schema-live-preview/ Kind: interface The application preview URL template and responsive breakpoints. ```ts interface SchemaLivePreview { ... } ``` ## SchemaPreviewBreakpoint Canonical URL: https://riducms.com/reference/protocol/schema-preview-breakpoint/ Kind: interface One named preview viewport. ```ts interface SchemaPreviewBreakpoint { ... } ``` ## SchemaAuthSettings Canonical URL: https://riducms.com/reference/protocol/schema-auth-settings/ Kind: interface Resolved auth, lockout, reset, verification, and API-key policy. ```ts interface SchemaAuthSettings { ... } ``` ## SchemaUploadSettings Canonical URL: https://riducms.com/reference/protocol/schema-upload-settings/ Kind: interface Upload limits, MIME allowlist, privacy, and generated image sizes. ```ts interface SchemaUploadSettings { ... } ``` ## SchemaImageSize Canonical URL: https://riducms.com/reference/protocol/schema-image-size/ Kind: interface One generated image rendition. ```ts interface SchemaImageSize { ... } ``` ## SchemaVersionSettings Canonical URL: https://riducms.com/reference/protocol/schema-version-settings/ Kind: interface Draft, retention, and autosave settings. ```ts interface SchemaVersionSettings { ... } ``` ## FieldType Canonical URL: https://riducms.com/reference/protocol/field-type/ Kind: type Every built-in and plugin field discriminator understood by the manifest. ```ts type FieldType = | "text" | "code" | "select" | "radio" | "point" | "ui" | "join" | "virtual" | "relationship" | "upload" | "group" | "textarea" | "email" | "date" | "number" | "checkbox" | "json" | "array" | "blocks" | "plugin" ``` ## FieldCategory Canonical URL: https://riducms.com/reference/protocol/field-category/ Kind: type The structural category used by schema-driven consumers. ```ts type FieldCategory = | "scalar" | "nested" | "presentation" | "relationship" | "upload" | "plugin" ``` ## SchemaField Canonical URL: https://riducms.com/reference/protocol/schema-field/ Kind: interface The common field manifest plus the type-specific configuration selected by type. ```ts interface SchemaField { ... } ``` ## SchemaFieldAdmin Canonical URL: https://riducms.com/reference/protocol/schema-field-admin/ Kind: interface Resolved label, layout, condition, and read-only metadata. ```ts interface SchemaFieldAdmin { ... } ``` ## SchemaFieldAdminComponent Canonical URL: https://riducms.com/reference/protocol/schema-field-admin-component/ Kind: interface An exact built-in field renderer owned by a paired static admin plugin. ```ts interface SchemaFieldAdminComponent { ... } ``` ## SchemaFieldRow Canonical URL: https://riducms.com/reference/protocol/schema-field-row/ Kind: interface A stable admin row-layout identity. ```ts interface SchemaFieldRow { ... } ``` ## SchemaFieldCollapsible Canonical URL: https://riducms.com/reference/protocol/schema-field-collapsible/ Kind: interface A stable collapsible field group. ```ts interface SchemaFieldCollapsible { ... } ``` ## SchemaFieldTabGroup Canonical URL: https://riducms.com/reference/protocol/schema-field-tab-group/ Kind: interface A stable tab-group identity. ```ts interface SchemaFieldTabGroup { ... } ``` ## SchemaFieldCondition Canonical URL: https://riducms.com/reference/protocol/schema-field-condition/ Kind: type A manifest-safe recursive expression controlling admin visibility. ```ts type SchemaFieldCondition = | { kind: "all" | "any"; conditions: SchemaFieldCondition[] } | { kind: "not"; conditions: [SchemaFieldCondition] } | { kind: "predicate"; predicate: SchemaFieldConditionPredicate } ``` Conditions are presentation only and never authorization. Sibling paths resolve from the current object or repeating row; document paths resolve from the root. ## SchemaFieldConditionPredicate Canonical URL: https://riducms.com/reference/protocol/schema-field-condition-predicate/ Kind: interface A scoped equals, notEquals, or oneOf scalar comparison. ```ts interface SchemaFieldConditionPredicate { ... } ``` ## SchemaFieldConditionValue Canonical URL: https://riducms.com/reference/protocol/schema-field-condition-value/ Kind: type A canonically encoded typed condition operand. ```ts type SchemaFieldConditionValue = | { type: "string"; value: string } | { type: "number"; value: string } | { type: "boolean"; value: "true" | "false" } ``` ## SchemaTextField Canonical URL: https://riducms.com/reference/protocol/schema-text-field/ Kind: interface Text and textarea length constraints plus optional slug behavior. ```ts interface SchemaTextField { ... } ``` ## SchemaSlugField Canonical URL: https://riducms.com/reference/protocol/schema-slug-field/ Kind: interface First-class slug derivation from one non-repeated string source path. ```ts interface SchemaSlugField { ... } ``` ## SchemaCodeField Canonical URL: https://riducms.com/reference/protocol/schema-code-field/ Kind: interface Code language and length constraints. ```ts interface SchemaCodeField { ... } ``` ## SchemaNumberField Canonical URL: https://riducms.com/reference/protocol/schema-number-field/ Kind: interface Numeric bounds and step. ```ts interface SchemaNumberField { ... } ``` ## SchemaDatePickerAppearance Canonical URL: https://riducms.com/reference/protocol/schema-date-picker-appearance/ Kind: type The admin date/time control mode. ```ts type SchemaDatePickerAppearance = "dayOnly" | "dayAndTime" | "timeOnly" ``` ## SchemaDateField Canonical URL: https://riducms.com/reference/protocol/schema-date-field/ Kind: interface Date field presentation settings. ```ts interface SchemaDateField { ... } ``` ## SchemaPointField Canonical URL: https://riducms.com/reference/protocol/schema-point-field/ Kind: type The point field’s currently empty type-specific manifest. ```ts type SchemaPointField = Record ``` ## SchemaUIField Canonical URL: https://riducms.com/reference/protocol/schema-ui-field/ Kind: type The presentation-only UI field’s currently empty type-specific manifest. ```ts type SchemaUIField = Record ``` ## SchemaJoinField Canonical URL: https://riducms.com/reference/protocol/schema-join-field/ Kind: interface Inverse relationship target, bounds, list defaults, and create affordance. ```ts interface SchemaJoinField { ... } ``` ## SchemaValueType Canonical URL: https://riducms.com/reference/protocol/schema-value-type/ Kind: type The generated value category of a virtual field. ```ts type SchemaValueType = "string" | "number" | "boolean" | "json" ``` ## SchemaVirtualField Canonical URL: https://riducms.com/reference/protocol/schema-virtual-field/ Kind: interface A computed field’s generated value category. ```ts interface SchemaVirtualField { ... } ``` ## SchemaSelectField Canonical URL: https://riducms.com/reference/protocol/schema-select-field/ Kind: interface The resolved choices, cardinality, and ordered multi-select defaults. ```ts interface SchemaSelectField { ... } ``` ## SchemaSelectChoice Canonical URL: https://riducms.com/reference/protocol/schema-select-choice/ Kind: interface One stored select value and author-facing label. ```ts interface SchemaSelectChoice { ... } ``` ## SchemaRelationshipField Canonical URL: https://riducms.com/reference/protocol/schema-relationship-field/ Kind: interface Relationship targets, cardinality, filters, and delete policy. ```ts interface SchemaRelationshipField { ... } ``` ## SchemaReferenceDeleteAction Canonical URL: https://riducms.com/reference/protocol/schema-reference-delete-action/ Kind: type The behavior when a referenced target is permanently deleted. ```ts type SchemaReferenceDeleteAction = "nullify" | "restrict" ``` ## SchemaRelationshipFilter Canonical URL: https://riducms.com/reference/protocol/schema-relationship-filter/ Kind: interface A document-path or typed-literal constraint on reference choices. ```ts interface SchemaRelationshipFilter { ... } ``` ## SchemaRelationshipFilterValue Canonical URL: https://riducms.com/reference/protocol/schema-relationship-filter-value/ Kind: interface One canonically encoded typed literal used by a relationship option filter. ```ts interface SchemaRelationshipFilterValue { ... } ``` ## SchemaRelationshipTarget Canonical URL: https://riducms.com/reference/protocol/schema-relationship-target/ Kind: interface One stable polymorphic relationship target. ```ts interface SchemaRelationshipTarget { ... } ``` ## SchemaUploadField Canonical URL: https://riducms.com/reference/protocol/schema-upload-field/ Kind: interface Upload target, cardinality, option filters, and delete policy. ```ts interface SchemaUploadField { ... } ``` ## SchemaNestedField Canonical URL: https://riducms.com/reference/protocol/schema-nested-field/ Kind: interface Nested fields plus array/block row bounds and presentation. ```ts interface SchemaNestedField { ... } ``` ## SchemaArrayRowLabels Canonical URL: https://riducms.com/reference/protocol/schema-array-row-labels/ Kind: interface Singular and plural repeating-row labels with interface translations. ```ts interface SchemaArrayRowLabels { ... } ``` ## SchemaBlocksField Canonical URL: https://riducms.com/reference/protocol/schema-blocks-field/ Kind: interface The allowed discriminated block types. ```ts interface SchemaBlocksField { ... } ``` ## SchemaBlockType Canonical URL: https://riducms.com/reference/protocol/schema-block-type/ Kind: interface One discriminated block definition. ```ts interface SchemaBlockType { ... } ``` ## SchemaPluginField Canonical URL: https://riducms.com/reference/protocol/schema-plugin-field/ Kind: interface A plugin field key, public config, and reference-bearing config keys. ```ts interface SchemaPluginField { ... } ``` ## SchemaEnvelope Canonical URL: https://riducms.com/reference/protocol/schema-envelope/ Kind: interface The REST wrapper returned by /api/schema. ```ts interface SchemaEnvelope { ... } ``` --- # API Reference: @riducms/plugin Canonical URL: https://riducms.com/reference/plugin/ Package: @riducms/plugin Static Svelte 5 extension contracts for generated admins and plugin packages. ## ADMIN_PLUGIN_API_VERSION Canonical URL: https://riducms.com/reference/plugin/admin-plugin-api-version/ Kind: constant The framework-owned admin extension API version. ```ts const ADMIN_PLUGIN_API_VERSION: 1 ``` ## defineAdminPlugin Canonical URL: https://riducms.com/reference/plugin/define-admin-plugin/ Kind: function Preserve inference while declaring a statically bundled admin plugin. ```ts function defineAdminPlugin(plugin: Plugin): Plugin ``` ```ts export const editorial = defineAdminPlugin({ apiVersion: ADMIN_PLUGIN_API_VERSION, key: "acme.editorial", pairingVersion: 1, fields: [], routes: [ { path: "/editorial", component: EditorialView, navigation: { label: "Editorial" }, }, ], }); ``` ## defineFieldPlugin Canonical URL: https://riducms.com/reference/plugin/define-field-plugin/ Kind: function Preserve inference while declaring a field renderer. ```ts function defineFieldPlugin(plugin: Plugin): Plugin ``` ## defineRowLabelPlugin Canonical URL: https://riducms.com/reference/plugin/define-row-label-plugin/ Kind: function Preserve inference while declaring an array or blocks row-label component. ```ts function defineRowLabelPlugin(plugin: Plugin): Plugin ``` ## defineAdminMessages Canonical URL: https://riducms.com/reference/plugin/define-admin-messages/ Kind: function Define an exact plugin-owned message catalog with build-time key and placeholder checks. ```ts function defineAdminMessages(input: Input & CheckedAdminMessages): DefineAdminMessagesInput ``` ## validateAdminMessages Canonical URL: https://riducms.com/reference/plugin/validate-admin-messages/ Kind: function Validate plugin message keys, translations, plural forms, and placeholders at runtime. ```ts function validateAdminMessages(key: string, messages: PluginMessageCatalog): void ``` ## getAdminI18n Canonical URL: https://riducms.com/reference/plugin/get-admin-i18n/ Kind: variable Read the current admin localization context inside a Svelte plugin component. ```ts function getAdminI18n(): AdminI18n ``` ## setAdminI18n Canonical URL: https://riducms.com/reference/plugin/set-admin-i18n/ Kind: variable Provide the admin localization context to nested plugin components. ```ts function setAdminI18n(context: AdminI18n): AdminI18n ``` ## resolveAdminPluginPairs Canonical URL: https://riducms.com/reference/plugin/resolve-admin-plugin-pairs/ Kind: function Validate compiled backend/admin pairs and return frozen, collision-checked registrations. ```ts function resolveAdminPluginPairs(pairs: readonly AdminPluginPair[]): ResolvedAdminPluginPairs ``` Validation covers unique backend keys, API and pairing versions, matching keys, exact route and asset lists, and plugin-field ownership. Missing packages fail earlier at static import time. ## resolveAdminPluginExtensions Canonical URL: https://riducms.com/reference/plugin/resolve-admin-plugin-extensions/ Kind: function Validate and flatten frontend extension registrations before the admin mounts. ```ts function resolveAdminPluginExtensions(plugins: readonly AdminPlugin[]): ResolvedAdminPluginExtensions ``` Rejects duplicate route and component identities, conflicting replacements, invalid route paths, duplicate exact list-cell targets, and multiple logout-button replacements. ## AdminPlugin Canonical URL: https://riducms.com/reference/plugin/admin-plugin/ Kind: interface The complete statically bundled admin half of a plugin. ```ts interface AdminPlugin { ... } ``` Plugins are compiled into the admin registry; production never downloads or installs executable plugin code dynamically. apiVersion is framework-owned. pairingVersion is plugin-owned and must change when the backend and admin halves stop being mutually compatible. ## BackendAdminPlugin Canonical URL: https://riducms.com/reference/plugin/backend-admin-plugin/ Kind: interface Metadata generated from a compiled Go plugin descriptor. ```ts interface BackendAdminPlugin { ... } ``` ## AdminPluginPair Canonical URL: https://riducms.com/reference/plugin/admin-plugin-pair/ Kind: interface One imported admin export paired with its compiled backend metadata. ```ts interface AdminPluginPair { ... } ``` ## ResolvedAdminPluginPairs Canonical URL: https://riducms.com/reference/plugin/resolved-admin-plugin-pairs/ Kind: interface The immutable flattened registry consumed by the framework admin. ```ts interface ResolvedAdminPluginPairs { ... } ``` ## ResolvedAdminPluginExtensions Canonical URL: https://riducms.com/reference/plugin/resolved-admin-plugin-extensions/ Kind: type The flattened extension registry without the original plugin and field arrays. ```ts type ResolvedAdminPluginExtensions = Omit ``` ## FieldPlugin Canonical URL: https://riducms.com/reference/plugin/field-plugin/ Kind: interface A renderer matched against a manifest field. ```ts interface FieldPlugin { ... } ``` Use type: "plugin" plus key for a paired custom field. For a built-in field renderer, key and componentKey must exactly match field.admin.component; canRender may add a narrower predicate. component is optional so a registration can participate in matching without replacing rendering. ## FieldComponentProps Canonical URL: https://riducms.com/reference/plugin/field-component-props/ Kind: interface The manifest field, form controller, and optional authoring services passed to a Svelte field. ```ts interface FieldComponentProps { ... } ``` ## RowLabelPlugin Canonical URL: https://riducms.com/reference/plugin/row-label-plugin/ Kind: interface One exact plugin-owned component available to array and blocks row headings. ```ts interface RowLabelPlugin { ... } ``` ## RowLabelComponentProps Canonical URL: https://riducms.com/reference/plugin/row-label-component-props/ Kind: interface The field, immutable current row, one-based position, i18n, and deterministic config passed to a custom row label. ```ts interface RowLabelComponentProps { ... } ``` ## RowLabelSnapshot Canonical URL: https://riducms.com/reference/plugin/row-label-snapshot/ Kind: type A detached, recursively frozen snapshot of the current array or blocks row. ```ts type RowLabelSnapshot = Readonly> ``` ## RowLabelValue Canonical URL: https://riducms.com/reference/plugin/row-label-value/ Kind: type A recursively read-only JSON-like value available to row-label components. ```ts type RowLabelValue = | string | number | boolean | null | undefined | readonly RowLabelValue[] | { readonly [key: string]: RowLabelValue } ``` ## FieldForm Canonical URL: https://riducms.com/reference/plugin/field-form/ Kind: interface The manifest-driven form controller exposed to field plugins. ```ts interface FieldForm { ... } ``` Call register when the component mounts and invoke the returned cleanup when it unmounts. Paths are schema paths, including runtime indexes for repeated fields. snapshot returns the current unsaved document when the host supports draft-aware plugin behavior; resource and contentLocale identify its authoring scope. ## FieldFormResource Canonical URL: https://riducms.com/reference/plugin/field-form-resource/ Kind: interface The collection/global identity and optional document ID owned by a field form. ```ts interface FieldFormResource { ... } ``` ## FieldDocument Canonical URL: https://riducms.com/reference/plugin/field-document/ Kind: type The authoring-safe document shape exposed to extension components. ```ts type FieldDocument = Record & { id: string; createdAt?: string; updatedAt?: string; deletedAt?: string; _status?: "draft" | "published"; _revision?: number; _localization?: { sources: Record; }; } ``` ## AdminI18n Canonical URL: https://riducms.com/reference/plugin/admin-i18n/ Kind: interface Current language, direction, translation, and locale-aware formatting available to plugins. ```ts interface AdminI18n { ... } ``` ## DefineAdminMessagesInput Canonical URL: https://riducms.com/reference/plugin/define-admin-messages-input/ Kind: interface Fallback messages and exact per-language plugin translations. ```ts interface DefineAdminMessagesInput>> { ... } ``` ## PluginMessageCatalog Canonical URL: https://riducms.com/reference/plugin/plugin-message-catalog/ Kind: interface A validated plugin-owned fallback catalog and its language catalogs. ```ts interface PluginMessageCatalog { ... } ``` ## PluginTranslationKey Canonical URL: https://riducms.com/reference/plugin/plugin-translation-key/ Kind: type A namespaced plugin message key accepted by AdminI18n.t. ```ts type PluginTranslationKey = `plugin.${string}:${string}` ``` ## FieldAuthoringHost Canonical URL: https://riducms.com/reference/plugin/field-authoring-host/ Kind: interface Optional authoring services for relationship-like field components. ```ts interface FieldAuthoringHost { ... } ``` requestPlugin is owner-scoped by the framework to the component’s paired backend plugin and routes through the configured SDK transport. ## FieldReferenceBrowserProps Canonical URL: https://riducms.com/reference/plugin/field-reference-browser-props/ Kind: interface Props for the framework-owned reference picker. ```ts interface FieldReferenceBrowserProps { ... } ``` ## FieldReferenceFilter Canonical URL: https://riducms.com/reference/plugin/field-reference-filter/ Kind: interface One source-driven filter for reference choices. ```ts interface FieldReferenceFilter { ... } ``` ## AdminPluginRoute Canonical URL: https://riducms.com/reference/plugin/admin-plugin-route/ Kind: interface A plugin route mounted beneath the authenticated admin layout. ```ts interface AdminPluginRoute { ... } ``` path is relative and must exactly match the route declared by the compiled backend descriptor. Omit navigation for link-only routes. ## AdminPluginNavigation Canonical URL: https://riducms.com/reference/plugin/admin-plugin-navigation/ Kind: interface An authenticated-shell navigation entry for a plugin route. ```ts interface AdminPluginNavigation { ... } ``` ## AdminDashboardPanel Canonical URL: https://riducms.com/reference/plugin/admin-dashboard-panel/ Kind: interface A component composed around or replacing the framework dashboard overview. ```ts interface AdminDashboardPanel { ... } ``` ## AdminDashboardPanelProps Canonical URL: https://riducms.com/reference/plugin/admin-dashboard-panel-props/ Kind: interface Manifest and optional current user passed to a dashboard panel. ```ts interface AdminDashboardPanelProps { ... } ``` ## AdminLoginComponent Canonical URL: https://riducms.com/reference/plugin/admin-login-component/ Kind: interface A component composed around or replacing sign-in. ```ts interface AdminLoginComponent { ... } ``` ## AdminLoginComponentProps Canonical URL: https://riducms.com/reference/plugin/admin-login-component-props/ Kind: interface Manifest, current user, default sign-in snippet, and login/notification host. ```ts interface AdminLoginComponentProps { ... } ``` ## AdminLoginExtensionHost Canonical URL: https://riducms.com/reference/plugin/admin-login-extension-host/ Kind: interface Safe sign-in and notification actions. ```ts interface AdminLoginExtensionHost { ... } ``` ## AdminAccountSurface Canonical URL: https://riducms.com/reference/plugin/admin-account-surface/ Kind: type The extensible account screen. ```ts type AdminAccountSurface = "profile" | "security" ``` ## AdminAccountComponent Canonical URL: https://riducms.com/reference/plugin/admin-account-component/ Kind: interface A component composed around or replacing profile or security. ```ts interface AdminAccountComponent { ... } ``` ## AdminAccountComponentProps Canonical URL: https://riducms.com/reference/plugin/admin-account-component-props/ Kind: interface Account surface, default screen, and safe account actions. ```ts interface AdminAccountComponentProps { ... } ``` ## AdminAccountExtensionHost Canonical URL: https://riducms.com/reference/plugin/admin-account-extension-host/ Kind: interface Safe account refresh, logout, and notification actions. ```ts interface AdminAccountExtensionHost { ... } ``` ## AdminNavigationPosition Canonical URL: https://riducms.com/reference/plugin/admin-navigation-position/ Kind: type The composition point around framework navigation. ```ts type AdminNavigationPosition = "before" | "beforeLinks" | "afterLinks" | "after" | "replace" ``` ## AdminNavigationComponent Canonical URL: https://riducms.com/reference/plugin/admin-navigation-component/ Kind: interface A component inserted into or replacing framework navigation. ```ts interface AdminNavigationComponent { ... } ``` ## AdminNavigationComponentProps Canonical URL: https://riducms.com/reference/plugin/admin-navigation-component-props/ Kind: interface Shared extension context plus the complete default navigation snippet. ```ts interface AdminNavigationComponentProps { ... } ``` ## AdminLogoutButton Canonical URL: https://riducms.com/reference/plugin/admin-logout-button/ Kind: interface The single optional replacement for the account-menu sign-out control. ```ts interface AdminLogoutButton { ... } ``` ## AdminLogoutButtonProps Canonical URL: https://riducms.com/reference/plugin/admin-logout-button-props/ Kind: interface Shared extension context and logout host. ```ts interface AdminLogoutButtonProps { ... } ``` ## AdminLogoutExtensionHost Canonical URL: https://riducms.com/reference/plugin/admin-logout-extension-host/ Kind: interface The safe logout action. ```ts interface AdminLogoutExtensionHost { ... } ``` ## AdminCoreViewSurface Canonical URL: https://riducms.com/reference/plugin/admin-core-view-surface/ Kind: type The framework route surface exposed to a core-view extension. ```ts type AdminCoreViewSurface = "collectionList" | "collectionCreate" | "collectionEdit" | "global" | "notFound" ``` ## AdminCoreView Canonical URL: https://riducms.com/reference/plugin/admin-core-view/ Kind: type A replacement or wrapper for collection, global, or not-found routes. ```ts type AdminCoreView = AdminCollectionCoreView | AdminGlobalCoreView | AdminNotFoundCoreView ``` ## AdminCoreViewProps Canonical URL: https://riducms.com/reference/plugin/admin-core-view-props/ Kind: interface Route identity, manifest data, default view, and safe framework actions. ```ts interface AdminCoreViewProps { ... } ``` ## AdminCoreViewHost Canonical URL: https://riducms.com/reference/plugin/admin-core-view-host/ Kind: interface Safe manifest refresh, document invalidation, and notification actions. ```ts interface AdminCoreViewHost { ... } ``` ## AdminBrandSurface Canonical URL: https://riducms.com/reference/plugin/admin-brand-surface/ Kind: type An exact framework branding location. ```ts type AdminBrandSurface = "loginLogo" | "navigationLogo" | "accountAvatar" ``` ## AdminBrandComponent Canonical URL: https://riducms.com/reference/plugin/admin-brand-component/ Kind: interface A replacement graphic at an exact branding surface. ```ts interface AdminBrandComponent { ... } ``` ## AdminBrandComponentProps Canonical URL: https://riducms.com/reference/plugin/admin-brand-component-props/ Kind: interface Shared extension context and branding surface. ```ts interface AdminBrandComponentProps { ... } ``` ## AdminShellPosition Canonical URL: https://riducms.com/reference/plugin/admin-shell-position/ Kind: type An exact global shell insertion point. ```ts type AdminShellPosition = "header" | "actions" | "settingsMenu" ``` ## AdminShellComponent Canonical URL: https://riducms.com/reference/plugin/admin-shell-component/ Kind: interface A component inserted at a global shell position. ```ts interface AdminShellComponent { ... } ``` ## AdminShellComponentProps Canonical URL: https://riducms.com/reference/plugin/admin-shell-component-props/ Kind: interface Shared extension context and shell insertion point. ```ts interface AdminShellComponentProps { ... } ``` ## AdminProvider Canonical URL: https://riducms.com/reference/plugin/admin-provider/ Kind: interface A Svelte context provider wrapping the remaining provider stack and admin. ```ts interface AdminProvider { ... } ``` ## AdminProviderProps Canonical URL: https://riducms.com/reference/plugin/admin-provider-props/ Kind: interface The remaining provider stack and framework admin snippet. ```ts interface AdminProviderProps { ... } ``` ## AdminListCell Canonical URL: https://riducms.com/reference/plugin/admin-list-cell/ Kind: interface A renderer for one exact collection and field pair. ```ts interface AdminListCell { ... } ``` ## AdminListCellProps Canonical URL: https://riducms.com/reference/plugin/admin-list-cell-props/ Kind: interface Manifest context, document, and value for a custom list cell. ```ts interface AdminListCellProps { ... } ``` ## AdminDocumentAction Canonical URL: https://riducms.com/reference/plugin/admin-document-action/ Kind: interface An action rendered beside framework document actions. ```ts interface AdminDocumentAction { ... } ``` Omit collection to target every non-global collection. requires hides the action unless the evaluated document capability is allowed. ## AdminDocumentView Canonical URL: https://riducms.com/reference/plugin/admin-document-view/ Kind: interface A read-only or operational view rendered beside Edit and API. ```ts interface AdminDocumentView { ... } ``` ## AdminDocumentExtensionProps Canonical URL: https://riducms.com/reference/plugin/admin-document-extension-props/ Kind: interface Document context plus safe refresh and notification actions. ```ts interface AdminDocumentExtensionProps { ... } ``` ## AdminExtensionNotificationTone Canonical URL: https://riducms.com/reference/plugin/admin-extension-notification-tone/ Kind: type The notification tones currently exposed to extensions. ```ts type AdminExtensionNotificationTone = "success" | "error" ``` ## AdminDocumentExtensionHost Canonical URL: https://riducms.com/reference/plugin/admin-document-extension-host/ Kind: interface Safe document refresh and notification actions. ```ts interface AdminDocumentExtensionHost { ... } ``` ## AdminExtensionProps Canonical URL: https://riducms.com/reference/plugin/admin-extension-props/ Kind: interface Shared manifest and optional current-user props. ```ts interface AdminExtensionProps { ... } ``` ## AdminAccountComponent.component Canonical URL: https://riducms.com/reference/plugin/admin-account-component-component-method/ Kind: method Public method AdminAccountComponent.component from @riducms/plugin. ```ts AdminAccountComponent.component(this: void, internals: ComponentInternals, props: AdminAccountComponentProps): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial): void; } ``` ## AdminAccountComponentProps.defaultView Canonical URL: https://riducms.com/reference/plugin/admin-account-component-props-default-view-method/ Kind: method The complete framework account screen, available to replacement wrappers. ```ts AdminAccountComponentProps.defaultView(this: void): { "{@render ...} must be called with a Snippet": "import type { Snippet } from 'svelte'"; } & typeof SnippetReturn ``` ## AdminAccountExtensionHost.logout Canonical URL: https://riducms.com/reference/plugin/admin-account-extension-host-logout-method/ Kind: method Ends the current session and returns to sign-in. ```ts AdminAccountExtensionHost.logout(): Promise ``` ## AdminAccountExtensionHost.notify Canonical URL: https://riducms.com/reference/plugin/admin-account-extension-host-notify-method/ Kind: method Public method AdminAccountExtensionHost.notify from @riducms/plugin. ```ts AdminAccountExtensionHost.notify(tone: AdminExtensionNotificationTone, title: string, message?: string): void ``` ## AdminAccountExtensionHost.refreshUser Canonical URL: https://riducms.com/reference/plugin/admin-account-extension-host-refresh-user-method/ Kind: method Reloads the signed-in document and updates the shell identity. ```ts AdminAccountExtensionHost.refreshUser(): Promise ``` ## AdminBrandComponent.component Canonical URL: https://riducms.com/reference/plugin/admin-brand-component-component-method/ Kind: method Public method AdminBrandComponent.component from @riducms/plugin. ```ts AdminBrandComponent.component(this: void, internals: ComponentInternals, props: AdminBrandComponentProps): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial): void; } ``` ## AdminCoreViewHost.documentsChanged Canonical URL: https://riducms.com/reference/plugin/admin-core-view-host-documents-changed-method/ Kind: method Public method AdminCoreViewHost.documentsChanged from @riducms/plugin. ```ts AdminCoreViewHost.documentsChanged(): void ``` ## AdminCoreViewHost.notify Canonical URL: https://riducms.com/reference/plugin/admin-core-view-host-notify-method/ Kind: method Public method AdminCoreViewHost.notify from @riducms/plugin. ```ts AdminCoreViewHost.notify(tone: AdminExtensionNotificationTone, title: string, message?: string): void ``` ## AdminCoreViewHost.refreshManifest Canonical URL: https://riducms.com/reference/plugin/admin-core-view-host-refresh-manifest-method/ Kind: method Public method AdminCoreViewHost.refreshManifest from @riducms/plugin. ```ts AdminCoreViewHost.refreshManifest(): Promise ``` ## AdminCoreViewProps.defaultView Canonical URL: https://riducms.com/reference/plugin/admin-core-view-props-default-view-method/ Kind: method The complete framework route, available to replacement wrappers. ```ts AdminCoreViewProps.defaultView(this: void): { "{@render ...} must be called with a Snippet": "import type { Snippet } from 'svelte'"; } & typeof SnippetReturn ``` ## AdminDashboardPanel.component Canonical URL: https://riducms.com/reference/plugin/admin-dashboard-panel-component-method/ Kind: method Public method AdminDashboardPanel.component from @riducms/plugin. ```ts AdminDashboardPanel.component(this: void, internals: ComponentInternals, props: AdminDashboardPanelProps): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial): void; } ``` ## AdminDocumentAction.component Canonical URL: https://riducms.com/reference/plugin/admin-document-action-component-method/ Kind: method Public method AdminDocumentAction.component from @riducms/plugin. ```ts AdminDocumentAction.component(this: void, internals: ComponentInternals, props: AdminDocumentExtensionProps): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial): void; } ``` ## AdminDocumentExtensionHost.notify Canonical URL: https://riducms.com/reference/plugin/admin-document-extension-host-notify-method/ Kind: method Public method AdminDocumentExtensionHost.notify from @riducms/plugin. ```ts AdminDocumentExtensionHost.notify(tone: AdminExtensionNotificationTone, title: string, message?: string): void ``` ## AdminDocumentExtensionHost.refresh Canonical URL: https://riducms.com/reference/plugin/admin-document-extension-host-refresh-method/ Kind: method Public method AdminDocumentExtensionHost.refresh from @riducms/plugin. ```ts AdminDocumentExtensionHost.refresh(): Promise ``` ## AdminDocumentView.component Canonical URL: https://riducms.com/reference/plugin/admin-document-view-component-method/ Kind: method Public method AdminDocumentView.component from @riducms/plugin. ```ts AdminDocumentView.component(this: void, internals: ComponentInternals, props: AdminDocumentExtensionProps): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial): void; } ``` ## AdminI18n.formatDate Canonical URL: https://riducms.com/reference/plugin/admin-i18n-format-date-method/ Kind: method Public method AdminI18n.formatDate from @riducms/plugin. ```ts AdminI18n.formatDate(value: Date | string | number, options?: Intl.DateTimeFormatOptions): string ``` ## AdminI18n.formatList Canonical URL: https://riducms.com/reference/plugin/admin-i18n-format-list-method/ Kind: method Public method AdminI18n.formatList from @riducms/plugin. ```ts AdminI18n.formatList(values: readonly string[], options?: Intl.ListFormatOptions): string ``` ## AdminI18n.formatNumber Canonical URL: https://riducms.com/reference/plugin/admin-i18n-format-number-method/ Kind: method Public method AdminI18n.formatNumber from @riducms/plugin. ```ts AdminI18n.formatNumber(value: number, options?: Intl.NumberFormatOptions): string ``` ## AdminI18n.formatRelativeTime Canonical URL: https://riducms.com/reference/plugin/admin-i18n-format-relative-time-method/ Kind: method Public method AdminI18n.formatRelativeTime from @riducms/plugin. ```ts AdminI18n.formatRelativeTime(value: number, unit: Intl.RelativeTimeFormatUnit): string ``` ## AdminI18n.t Canonical URL: https://riducms.com/reference/plugin/admin-i18n-t-method/ Kind: method Public method AdminI18n.t from @riducms/plugin. ```ts AdminI18n.t(key: AdminTranslationKey, variables?: TranslationVariables): string ``` ## AdminI18n.text Canonical URL: https://riducms.com/reference/plugin/admin-i18n-text-method/ Kind: method Public method AdminI18n.text from @riducms/plugin. ```ts AdminI18n.text(canonical: string, translations?: Readonly>): string ``` ## AdminListCell.component Canonical URL: https://riducms.com/reference/plugin/admin-list-cell-component-method/ Kind: method Public method AdminListCell.component from @riducms/plugin. ```ts AdminListCell.component(this: void, internals: ComponentInternals, props: AdminListCellProps): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial): void; } ``` ## AdminLoginComponent.component Canonical URL: https://riducms.com/reference/plugin/admin-login-component-component-method/ Kind: method Public method AdminLoginComponent.component from @riducms/plugin. ```ts AdminLoginComponent.component(this: void, internals: ComponentInternals, props: AdminLoginComponentProps): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial): void; } ``` ## AdminLoginComponentProps.defaultView Canonical URL: https://riducms.com/reference/plugin/admin-login-component-props-default-view-method/ Kind: method The complete framework sign-in screen, available to replacement wrappers. ```ts AdminLoginComponentProps.defaultView(this: void): { "{@render ...} must be called with a Snippet": "import type { Snippet } from 'svelte'"; } & typeof SnippetReturn ``` ## AdminLoginExtensionHost.login Canonical URL: https://riducms.com/reference/plugin/admin-login-extension-host-login-method/ Kind: method Authenticates, evaluates admin access, and enters the authenticated shell. ```ts AdminLoginExtensionHost.login(credentials: { email: string; password: string; }): Promise ``` ## AdminLoginExtensionHost.notify Canonical URL: https://riducms.com/reference/plugin/admin-login-extension-host-notify-method/ Kind: method Public method AdminLoginExtensionHost.notify from @riducms/plugin. ```ts AdminLoginExtensionHost.notify(tone: AdminExtensionNotificationTone, title: string, message?: string): void ``` ## AdminLogoutButton.component Canonical URL: https://riducms.com/reference/plugin/admin-logout-button-component-method/ Kind: method Public method AdminLogoutButton.component from @riducms/plugin. ```ts AdminLogoutButton.component(this: void, internals: ComponentInternals, props: AdminLogoutButtonProps): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial): void; } ``` ## AdminLogoutExtensionHost.logout Canonical URL: https://riducms.com/reference/plugin/admin-logout-extension-host-logout-method/ Kind: method Public method AdminLogoutExtensionHost.logout from @riducms/plugin. ```ts AdminLogoutExtensionHost.logout(): Promise ``` ## AdminNavigationComponent.component Canonical URL: https://riducms.com/reference/plugin/admin-navigation-component-component-method/ Kind: method Public method AdminNavigationComponent.component from @riducms/plugin. ```ts AdminNavigationComponent.component(this: void, internals: ComponentInternals, props: AdminNavigationComponentProps): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial): void; } ``` ## AdminNavigationComponentProps.defaultView Canonical URL: https://riducms.com/reference/plugin/admin-navigation-component-props-default-view-method/ Kind: method The complete framework navigation, available to replacement wrappers. ```ts AdminNavigationComponentProps.defaultView(this: void): { "{@render ...} must be called with a Snippet": "import type { Snippet } from 'svelte'"; } & typeof SnippetReturn ``` ## AdminPluginRoute.component Canonical URL: https://riducms.com/reference/plugin/admin-plugin-route-component-method/ Kind: method Svelte route component rendered by the framework router. ```ts AdminPluginRoute.component(this: void, internals: ComponentInternals, props: {}): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial<{}>): void; } ``` ## AdminProvider.component Canonical URL: https://riducms.com/reference/plugin/admin-provider-component-method/ Kind: method Public method AdminProvider.component from @riducms/plugin. ```ts AdminProvider.component(this: void, internals: ComponentInternals, props: AdminProviderProps): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial): void; } ``` ## AdminProviderProps.defaultView Canonical URL: https://riducms.com/reference/plugin/admin-provider-props-default-view-method/ Kind: method The remaining provider stack and framework admin application. ```ts AdminProviderProps.defaultView(this: void): { "{@render ...} must be called with a Snippet": "import type { Snippet } from 'svelte'"; } & typeof SnippetReturn ``` ## AdminShellComponent.component Canonical URL: https://riducms.com/reference/plugin/admin-shell-component-component-method/ Kind: method Public method AdminShellComponent.component from @riducms/plugin. ```ts AdminShellComponent.component(this: void, internals: ComponentInternals, props: AdminShellComponentProps): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial): void; } ``` ## FieldAuthoringHost.findDocument Canonical URL: https://riducms.com/reference/plugin/field-authoring-host-find-document-method/ Kind: method Public method FieldAuthoringHost.findDocument from @riducms/plugin. ```ts FieldAuthoringHost.findDocument(collection: string, id: string, signal?: AbortSignal): Promise ``` ## FieldAuthoringHost.referenceBrowser Canonical URL: https://riducms.com/reference/plugin/field-authoring-host-reference-browser-method/ Kind: method Public method FieldAuthoringHost.referenceBrowser from @riducms/plugin. ```ts FieldAuthoringHost.referenceBrowser(this: void, internals: ComponentInternals, props: FieldReferenceBrowserProps): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial): void; } ``` ## FieldAuthoringHost.requestPlugin Canonical URL: https://riducms.com/reference/plugin/field-authoring-host-request-plugin-method/ Kind: method Public method FieldAuthoringHost.requestPlugin from @riducms/plugin. ```ts FieldAuthoringHost.requestPlugin(path: string, body: unknown, signal?: AbortSignal): Promise ``` ## FieldForm.get Canonical URL: https://riducms.com/reference/plugin/field-form-get-method/ Kind: method Public method FieldForm.get from @riducms/plugin. ```ts FieldForm.get(path: string): unknown ``` ## FieldForm.issuesFor Canonical URL: https://riducms.com/reference/plugin/field-form-issues-for-method/ Kind: method Public method FieldForm.issuesFor from @riducms/plugin. ```ts FieldForm.issuesFor(path: string): readonly ValidationIssue[] ``` ## FieldForm.register Canonical URL: https://riducms.com/reference/plugin/field-form-register-method/ Kind: method Public method FieldForm.register from @riducms/plugin. ```ts FieldForm.register(path: string): () => void ``` ## FieldForm.set Canonical URL: https://riducms.com/reference/plugin/field-form-set-method/ Kind: method Public method FieldForm.set from @riducms/plugin. ```ts FieldForm.set(path: string, value: unknown): void ``` ## FieldForm.snapshot Canonical URL: https://riducms.com/reference/plugin/field-form-snapshot-method/ Kind: method Public method FieldForm.snapshot from @riducms/plugin. ```ts FieldForm.snapshot(): Record ``` ## FieldPlugin.canRender Canonical URL: https://riducms.com/reference/plugin/field-plugin-can-render-method/ Kind: method Public method FieldPlugin.canRender from @riducms/plugin. ```ts FieldPlugin.canRender(field: SchemaField): boolean ``` ## FieldPlugin.component Canonical URL: https://riducms.com/reference/plugin/field-plugin-component-method/ Kind: method Public method FieldPlugin.component from @riducms/plugin. ```ts FieldPlugin.component(this: void, internals: ComponentInternals, props: FieldComponentProps): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial): void; } ``` ## FieldReferenceBrowserProps.onClose Canonical URL: https://riducms.com/reference/plugin/field-reference-browser-props-on-close-method/ Kind: method Public method FieldReferenceBrowserProps.onClose from @riducms/plugin. ```ts FieldReferenceBrowserProps.onClose(): void ``` ## FieldReferenceBrowserProps.onCommit Canonical URL: https://riducms.com/reference/plugin/field-reference-browser-props-on-commit-method/ Kind: method Public method FieldReferenceBrowserProps.onCommit from @riducms/plugin. ```ts FieldReferenceBrowserProps.onCommit(ids: string[]): void | boolean | Promise ``` ## RowLabelPlugin.component Canonical URL: https://riducms.com/reference/plugin/row-label-plugin-component-method/ Kind: method Public method RowLabelPlugin.component from @riducms/plugin. ```ts RowLabelPlugin.component(this: void, internals: ComponentInternals, props: RowLabelComponentProps): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial): void; } ``` --- # API Reference: @riducms/build Canonical URL: https://riducms.com/reference/build/ Package: @riducms/build Build-time Vite, Svelte 5, and UnoCSS conventions for generated admins and plugin libraries. ## createAdminApplicationConfig Canonical URL: https://riducms.com/reference/build/create-admin-application-config/ Kind: function Create the Vite config for a routed Ridu admin application. ```ts function createAdminApplicationConfig(options: AdminApplicationConfigOptions): UserConfigFnObject ``` Sets the canonical /admin/ base by default, Svelte runes, content-derived CSS hashes, UnoCSS, icons, collision-free application and framework source aliases, Svelte/Bits UI deduplication, schema-reload handling, and optional /api proxying. ```ts export default createAdminApplicationConfig({ outDir: "../internal/adminassets/dist", schemaReloadSignal: "../.ridu/admin-schema.reload", proxyTarget: process.env.RIDU_DEV_API, }); ``` ## AdminApplicationConfigOptions Canonical URL: https://riducms.com/reference/build/admin-application-config-options/ Kind: interface Required output/reload paths plus focused Vite and Svelte overrides. ```ts interface AdminApplicationConfigOptions { ... } ``` ## createAdminLibraryConfig Canonical URL: https://riducms.com/reference/build/create-admin-library-config/ Kind: function Create an ES-only Vite library config for a Svelte admin plugin package. ```ts function createAdminLibraryConfig(options?: AdminLibraryConfigOptions): UserConfig ``` Externalizes bare dependencies, keeps Uno virtual CSS inside the bundle, enables runes and stable CSS hashes, and injects uno.css unless uno is false. ## AdminLibraryConfigOptions Canonical URL: https://riducms.com/reference/build/admin-library-config-options/ Kind: interface Entry, dedupe, pre-Svelte plugin, compiler, and UnoCSS options for a plugin library. ```ts interface AdminLibraryConfigOptions { ... } ``` ## createAdminUnoConfig Canonical URL: https://riducms.com/reference/build/create-admin-uno-config/ Kind: function Create the shared semantic Ridu UnoCSS configuration. ```ts function createAdminUnoConfig(options?: AdminUnoConfigOptions): UserConfig ``` The default filesystem scan includes Bits UI. Add plugin-specific files through filesystem rather than copying Ridu’s presets. ## presetRiduUtilities Canonical URL: https://riducms.com/reference/build/preset-ridu-utilities/ Kind: function Return Ridu's shared UnoCSS utility shortcuts and variants. ```ts function presetRiduUtilities(): Preset ``` ## AdminUnoConfigOptions Canonical URL: https://riducms.com/reference/build/admin-uno-config-options/ Kind: interface Additional filesystem content globs. ```ts interface AdminUnoConfigOptions { ... } ``` ## riduSchemaReloadPlugin Canonical URL: https://riducms.com/reference/build/ridu-schema-reload-plugin/ Kind: function Watch the generated schema signal and issue full or custom Vite reload events. ```ts function riduSchemaReloadPlugin(signalPath: string): Plugin ``` Generated ridu.generated.ts and ridu.plugins.generated.ts updates are suppressed from ordinary module HMR because the signal coordinates the correct reload boundary. ## packageSourceAliasPlugin Canonical URL: https://riducms.com/reference/build/package-source-alias-plugin/ Kind: function Resolve the application @/ alias and each framework-owned source alias to its unambiguous src directory. ```ts function packageSourceAliasPlugin(): Plugin ``` Exported from @riducms/build/vite. Generated applications own @/, while @admin/, @ui/, @plugin-richtext/, and @plugin-seo/ resolve from the importing framework package. The same distinct aliases are emitted in the generated TypeScript configuration. --- # API Reference: @riducms/ui Canonical URL: https://riducms.com/reference/ui/ Package: @riducms/ui Shared Svelte 5 interaction primitives and class composition for the admin and static plugins. ## Button Canonical URL: https://riducms.com/reference/ui/button/ Kind: component A Ridu-themed button or anchor with optional integrated tooltip. ```ts component Button(props: ButtonProps) ``` Variants are default, outline, secondary, ghost, destructive, and link. Sizes are default, xs, sm, lg, icon, icon-xs, icon-sm, and icon-lg. href selects anchor rendering; disabled anchors remove href and become unfocusable. ```ts ``` ## ButtonProps Canonical URL: https://riducms.com/reference/ui/button-props/ Kind: type Merged button/anchor attributes and Ridu variant controls. ```ts type ButtonProps = any ``` ## buttonVariants Canonical URL: https://riducms.com/reference/ui/button-variants/ Kind: type The shared tailwind-variants recipe used by Button. ```ts type buttonVariants = any ``` ## ButtonVariant Canonical URL: https://riducms.com/reference/ui/button-variant/ Kind: type The Button visual variant union. ```ts type ButtonVariant = any ``` ## ButtonSize Canonical URL: https://riducms.com/reference/ui/button-size/ Kind: type The Button size and icon-only size union. ```ts type ButtonSize = any ``` ## ConfirmationDialog Canonical URL: https://riducms.com/reference/ui/confirmation-dialog/ Kind: component An accessible, cancel-first confirmation dialog for admin and static-plugin actions. ```ts component ConfirmationDialog(props: $$ComponentProps) ``` The dialog focuses Cancel when opened, prevents dismissal while an asynchronous confirmation is pending, and closes only after onconfirm succeeds. Consumers own localized copy. ## FieldFrame Canonical URL: https://riducms.com/reference/ui/field-frame/ Kind: component Accessible label, required/read-only state, help text, errors, and control slot for a form field. ```ts component FieldFrame(props: $$ComponentProps) ``` ## Input Canonical URL: https://riducms.com/reference/ui/input/ Kind: component A bindable themed input supporting ordinary values and file FileList binding. ```ts component Input(props: Props) ``` ## Textarea Canonical URL: https://riducms.com/reference/ui/textarea/ Kind: component A bindable themed textarea. ```ts component Textarea(props: WithoutChildren>) ``` ## CommandRoot Canonical URL: https://riducms.com/reference/ui/command-root/ Kind: component The state and context root for a command menu. ```ts component CommandRoot(props: Command.RootProps) ``` Import every compound part through @riducms/ui. Mixing wrappers from separate Bits UI installations can split Svelte context identity. ## CommandInput Canonical URL: https://riducms.com/reference/ui/command-input/ Kind: component The searchable command-menu input. ```ts component CommandInput(props: Command.InputProps) ``` ## CommandList Canonical URL: https://riducms.com/reference/ui/command-list/ Kind: component The scrollable command result list. ```ts component CommandList(props: Command.ListProps) ``` ## CommandViewport Canonical URL: https://riducms.com/reference/ui/command-viewport/ Kind: component The command list viewport. ```ts component CommandViewport(props: Command.ViewportProps) ``` ## CommandGroup Canonical URL: https://riducms.com/reference/ui/command-group/ Kind: component A labelled command result group. ```ts component CommandGroup(props: Command.GroupProps) ``` ## CommandGroupHeading Canonical URL: https://riducms.com/reference/ui/command-group-heading/ Kind: component A command group heading. ```ts component CommandGroupHeading(props: Command.GroupHeadingProps) ``` ## CommandGroupItems Canonical URL: https://riducms.com/reference/ui/command-group-items/ Kind: component The item container inside a command group. ```ts component CommandGroupItems(props: Command.GroupItemsProps) ``` ## CommandItem Canonical URL: https://riducms.com/reference/ui/command-item/ Kind: component One keyboard-navigable command choice. ```ts component CommandItem(props: Command.ItemProps) ``` ## CommandEmpty Canonical URL: https://riducms.com/reference/ui/command-empty/ Kind: component Empty search-result content. ```ts component CommandEmpty(props: Command.EmptyProps) ``` ## CommandSeparator Canonical URL: https://riducms.com/reference/ui/command-separator/ Kind: component A visual and semantic separator between command groups. ```ts component CommandSeparator(props: Command.SeparatorProps) ``` ## PopoverRoot Canonical URL: https://riducms.com/reference/ui/popover-root/ Kind: component The state and context root for a popover. ```ts component PopoverRoot(props: Popover.RootProps) ``` ## PopoverTrigger Canonical URL: https://riducms.com/reference/ui/popover-trigger/ Kind: component The popover trigger boundary. ```ts component PopoverTrigger(props: Popover.TriggerProps) ``` ## PopoverContent Canonical URL: https://riducms.com/reference/ui/popover-content/ Kind: component The themed positioned popover content. ```ts component PopoverContent(props: $$ComponentProps) ``` ## TooltipProvider Canonical URL: https://riducms.com/reference/ui/tooltip-provider/ Kind: component Shared tooltip delay and context provider. ```ts component TooltipProvider(props: TooltipPrimitive.ProviderProps) ``` ## TooltipRoot Canonical URL: https://riducms.com/reference/ui/tooltip-root/ Kind: component The state and context root for one tooltip. ```ts component TooltipRoot(props: TooltipPrimitive.RootProps) ``` ## TooltipTrigger Canonical URL: https://riducms.com/reference/ui/tooltip-trigger/ Kind: component The tooltip trigger boundary. ```ts component TooltipTrigger(props: TooltipPrimitive.TriggerProps) ``` ## TooltipContent Canonical URL: https://riducms.com/reference/ui/tooltip-content/ Kind: component The themed positioned tooltip content. ```ts component TooltipContent(props: TooltipPrimitive.ContentProps) ``` ## ToolbarRoot Canonical URL: https://riducms.com/reference/ui/toolbar-root/ Kind: component The accessible toolbar root. ```ts component ToolbarRoot(props: Toolbar.RootProps) ``` ## ToolbarButton Canonical URL: https://riducms.com/reference/ui/toolbar-button/ Kind: component A toolbar button with optional active state. ```ts component ToolbarButton(props: $$ComponentProps) ``` ## cn Canonical URL: https://riducms.com/reference/ui/cn/ Kind: constant Compose class values using the package-owned tailwind-variants runtime. ```ts function cn(...classnames: T): CnReturn ``` ## tv Canonical URL: https://riducms.com/reference/ui/tv/ Kind: constant Create shared variant recipes using the package-owned tailwind-variants runtime. ```ts function tv, CV extends TVCompoundVariants, DV extends TVDefaultVariants, B extends ClassNameValue = undefined, S extends TVSlots = undefined, E extends TVReturnTypeLike = TVReturnTypeLike, EV extends TVVariants = E["variants"], ES extends TVSlots = E["slots"] extends TVSlots ? E["slots"] : undefined>(options: { extend?: E; base?: B; slots?: S; variants?: V; compoundVariants?: CV; compoundSlots?: TVCompoundSlots; defaultVariants?: DV; }, config?: TVConfig): TVReturnType ``` ## WithoutChild Canonical URL: https://riducms.com/reference/ui/without-child/ Kind: type Remove a child snippet property when present. ```ts type WithoutChild = T extends { child?: any } ? Omit : T ``` ## WithoutChildren Canonical URL: https://riducms.com/reference/ui/without-children/ Kind: type Remove a children snippet property when present. ```ts type WithoutChildren = T extends { children?: any } ? Omit : T ``` ## WithoutChildrenOrChild Canonical URL: https://riducms.com/reference/ui/without-children-or-child/ Kind: type Remove both child and children snippet properties. ```ts type WithoutChildrenOrChild = WithoutChildren> ``` ## WithElementRef Canonical URL: https://riducms.com/reference/ui/with-element-ref/ Kind: type Add an optional bindable element ref to component props. ```ts type WithElementRef = T & { ref?: U | null; } ``` ## ClassValue Canonical URL: https://riducms.com/reference/ui/class-value/ Kind: type Class input accepted by cn and variant recipes. ```ts type ClassValue = ClassNameArray | string | null | undefined | 0 | 0n | false ``` ## VariantProps Canonical URL: https://riducms.com/reference/ui/variant-props/ Kind: type Infer variant props from a tailwind-variants recipe. ```ts type VariantProps any> = Omit[0]>, "class" | "className"> ``` --- # API Reference: @riducms/plugin-richtext Canonical URL: https://riducms.com/reference/plugin-richtext/ Package: @riducms/plugin-richtext The statically bundled Svelte/Lexical half of the rich-text plugin. ## richTextAdminPlugin Canonical URL: https://riducms.com/reference/plugin-richtext/rich-text-admin-plugin/ Kind: constant The paired admin export named by the Go plugin descriptor. ```ts const richTextAdminPlugin: ReturnType ``` Uses admin-plugin API 1, key richtext, and pairing version 1. Install it through ridu plugin add so the generated registry verifies and imports the exact export. ## richTextFieldPlugin Canonical URL: https://riducms.com/reference/plugin-richtext/rich-text-field-plugin/ Kind: constant The plugin-field renderer registration used by richTextAdminPlugin. ```ts const richTextFieldPlugin: { readonly type: "plugin"; readonly key: "richtext"; readonly component: LegacyComponentType; readonly canRender: (field: SchemaField) => boolean; } ``` ## richTextMessages Canonical URL: https://riducms.com/reference/plugin-richtext/rich-text-messages/ Kind: constant Exact namespaced English, French, and Arabic messages used by the rich-text admin plugin. ```ts const richTextMessages: ReturnType ``` ## RichTextDocument Canonical URL: https://riducms.com/reference/plugin-richtext/rich-text-document/ Kind: interface The generated TypeScript input/output contract for stored version-1 content. ```ts interface RichTextDocument { ... } ``` ## RichTextFeature Canonical URL: https://riducms.com/reference/plugin-richtext/rich-text-feature/ Kind: type A rich-text authoring capability supported by the current editor. ```ts type RichTextFeature = "links" | "lists" | "code" | "horizontal-rule" | "uploads" | "relationships" | "blocks" ``` ## RichTextConfig Canonical URL: https://riducms.com/reference/plugin-richtext/rich-text-config/ Kind: interface The manifest configuration consumed by the editor. ```ts interface RichTextConfig { ... } ``` ## SerializedUploadNode Canonical URL: https://riducms.com/reference/plugin-richtext/serialized-upload-node/ Kind: type The public serialized Lexical shape for an embedded upload reference. ```ts type SerializedUploadNode = Spread< { caption?: string; format: ElementFormatType; id: string; relationTo: string; }, SerializedLexicalNode > ``` --- # API Reference: @riducms/plugin-seo Canonical URL: https://riducms.com/reference/plugin-seo/ Package: @riducms/plugin-seo The statically bundled Svelte authoring half of the official SEO plugin. ## lengthState Canonical URL: https://riducms.com/reference/plugin-seo/length-state/ Kind: function Classify a title or description against inclusive advisory bounds. ```ts function lengthState(text: string, minLength: number, maxLength: number): LengthState ``` ## generationSnapshotToken Canonical URL: https://riducms.com/reference/plugin-seo/generation-snapshot-token/ Kind: function Create the deterministic draft token used to reject stale generation responses. ```ts function generationSnapshotToken(document: Readonly>): string ``` ## generationScopeToken Canonical URL: https://riducms.com/reference/plugin-seo/generation-scope-token/ Kind: function Create the resource, ID, global, and locale token used to reject cross-context responses. ```ts function generationScopeToken(resource: FieldFormResource | undefined, locale: string | undefined): string ``` ## seoAdminPlugin Canonical URL: https://riducms.com/reference/plugin-seo/seo-admin-plugin/ Kind: constant The paired admin export named by the Go plugin descriptor. ```ts const seoAdminPlugin: ReturnType ``` Uses admin-plugin API 1, key seo, and pairing version 1. The generated registry verifies the exact pairing before mounting any renderer. ## seoFieldPlugins Canonical URL: https://riducms.com/reference/plugin-seo/seo-field-plugins/ Kind: constant Exact overview, title, description, image, and preview renderer registrations. ```ts const seoFieldPlugins: readonly [{ readonly type: "ui"; readonly key: "seo"; readonly componentKey: "overview"; readonly component: LegacyComponentType; readonly canRender: (field: SchemaField) => boolean; }, { ...; }, { ...; }, { ...; }, { ...; }] ``` Each registration matches the manifest plugin and component identity while retaining the built-in field’s storage semantics. ## seoMessages Canonical URL: https://riducms.com/reference/plugin-seo/seo-messages/ Kind: constant Exact namespaced English, French, and Arabic messages used by the SEO admin. ```ts const seoMessages: ReturnType ``` ## LengthStatus Canonical URL: https://riducms.com/reference/plugin-seo/length-status/ Kind: type One advisory SEO length classification. ```ts type LengthStatus = "missing" | "tooShort" | "almostThere" | "good" | "tooLong" ``` ## LengthState Canonical URL: https://riducms.com/reference/plugin-seo/length-state-interface/ Kind: interface Length classification, progress, and remaining character count. ```ts interface LengthState { ... } ``` --- # API Reference: @riducms/plugin-form-builder Canonical URL: https://riducms.com/reference/plugin-form-builder/ Package: @riducms/plugin-form-builder Framework-neutral public form helpers plus a separately exported static admin pairing. ## buildSubmissionInput Canonical URL: https://riducms.com/reference/plugin-form-builder/build-submission-input/ Kind: function Split public values into scalar and upload submission rows. ```ts function buildSubmissionInput(form: FormDefinition, values: FormValues): FormSubmissionInput ``` ## validateFormValues Canonical URL: https://riducms.com/reference/plugin-form-builder/validate-form-values/ Kind: function Provide immediate required, email, number, choice, and upload feedback. ```ts function validateFormValues(form: FormDefinition, values: FormValues): FormValidationIssue[] ``` Server validation remains authoritative. ## confirmationFor Canonical URL: https://riducms.com/reference/plugin-form-builder/confirmation-for/ Kind: function Normalize the configured message or redirect after a successful create. ```ts function confirmationFor(form: FormDefinition): Confirmation ``` ## getPaymentTotal Canonical URL: https://riducms.com/reference/plugin-form-builder/get-payment-total/ Kind: function Calculate the display total with the same finite arithmetic model as Go. ```ts function getPaymentTotal(basePrice: number, conditions: readonly PriceCondition[], values: FormValues): number ``` The trusted Go callback recalculates the authoritative total before commit. ## formBuilderAdminPlugin Canonical URL: https://riducms.com/reference/plugin-form-builder/form-builder-admin-plugin/ Kind: constant The static admin export declared by the Go descriptor. ```ts const formBuilderAdminPlugin: ReturnType ``` Import from @riducms/plugin-form-builder/admin. It uses admin-plugin API 1, key form-builder, and pairing version 1. ## formBuilderMessages Canonical URL: https://riducms.com/reference/plugin-form-builder/form-builder-messages/ Kind: constant Namespaced fallback English plugin messages exported from the admin entrypoint. ```ts const formBuilderMessages: DefineAdminMessagesInput<{ readonly forms: "Forms"; readonly submissions: "Form submissions"; }> ``` ## FormFieldBase Canonical URL: https://riducms.com/reference/plugin-form-builder/form-field-base/ Kind: interface Shared identity, label, required, and width values for input blocks. ```ts interface FormFieldBase { ... } ``` ## TextFormField Canonical URL: https://riducms.com/reference/plugin-form-builder/text-form-field/ Kind: interface A text or textarea input definition. ```ts interface TextFormField { ... } ``` ## EmailFormField Canonical URL: https://riducms.com/reference/plugin-form-builder/email-form-field/ Kind: interface An email input definition. ```ts interface EmailFormField { ... } ``` ## NumberFormField Canonical URL: https://riducms.com/reference/plugin-form-builder/number-form-field/ Kind: interface A numeric input definition. ```ts interface NumberFormField { ... } ``` ## CheckboxFormField Canonical URL: https://riducms.com/reference/plugin-form-builder/checkbox-form-field/ Kind: interface A checkbox input definition. ```ts interface CheckboxFormField { ... } ``` ## DateFormField Canonical URL: https://riducms.com/reference/plugin-form-builder/date-form-field/ Kind: interface A date input definition. ```ts interface DateFormField { ... } ``` ## ChoiceOption Canonical URL: https://riducms.com/reference/plugin-form-builder/choice-option/ Kind: interface One author-configured select or radio option. ```ts interface ChoiceOption { ... } ``` ## ChoiceFormField Canonical URL: https://riducms.com/reference/plugin-form-builder/choice-form-field/ Kind: interface A select or radio input definition. ```ts interface ChoiceFormField { ... } ``` ## CountryFormField Canonical URL: https://riducms.com/reference/plugin-form-builder/country-form-field/ Kind: interface A country or state input definition. ```ts interface CountryFormField { ... } ``` ## MessageFormField Canonical URL: https://riducms.com/reference/plugin-form-builder/message-form-field/ Kind: interface Presentation content inside a form. ```ts interface MessageFormField { ... } ``` ## UploadFormField Canonical URL: https://riducms.com/reference/plugin-form-builder/upload-form-field/ Kind: interface An upload reference input and its constraints. ```ts interface UploadFormField { ... } ``` ## PriceCondition Canonical URL: https://riducms.com/reference/plugin-form-builder/price-condition/ Kind: type One conditional price operation. ```ts type PriceCondition = { _key?: string; fieldToUse: string; condition: "equals" | "hasValue" | "notEquals"; operator: "add" | "divide" | "multiply" | "subtract"; valueForCondition?: string; valueForOperator: string; valueType: "static" | "valueOfField"; } ``` ## PaymentFormField Canonical URL: https://riducms.com/reference/plugin-form-builder/payment-form-field/ Kind: interface A payment total and provider selection definition. ```ts interface PaymentFormField { ... } ``` ## FormField Canonical URL: https://riducms.com/reference/plugin-form-builder/form-field/ Kind: type The discriminated union a public renderer switches over. ```ts type FormField = | CheckboxFormField | ChoiceFormField | CountryFormField | DateFormField | EmailFormField | MessageFormField | NumberFormField | PaymentFormField | TextFormField | UploadFormField ``` ## CustomFormField Canonical URL: https://riducms.com/reference/plugin-form-builder/custom-form-field/ Kind: interface A project-owned input block whose renderer and type-specific validation remain application-owned. ```ts interface CustomFormField { ... } ``` ## FormFieldDefinition Canonical URL: https://riducms.com/reference/plugin-form-builder/form-field-definition/ Kind: type The built-in or project-owned field definition accepted by generic helpers. ```ts type FormFieldDefinition = FormField | CustomFormField ``` ## FormEmail Canonical URL: https://riducms.com/reference/plugin-form-builder/form-email/ Kind: interface A protected saved notification template. ```ts interface FormEmail { ... } ``` ## FormRedirect Canonical URL: https://riducms.com/reference/plugin-form-builder/form-redirect/ Kind: interface A custom or relationship-backed success redirect. ```ts interface FormRedirect { ... } ``` ## FormDefinition Canonical URL: https://riducms.com/reference/plugin-form-builder/form-definition/ Kind: interface The reusable form shape consumed by application renderers. ```ts interface FormDefinition { ... } ``` ## SubmissionValue Canonical URL: https://riducms.com/reference/plugin-form-builder/submission-value/ Kind: interface One scalar submission row. ```ts interface SubmissionValue { ... } ``` ## UploadReference Canonical URL: https://riducms.com/reference/plugin-form-builder/upload-reference/ Kind: type A single-target document ID or canonical Ridu polymorphic upload reference. ```ts type UploadReference = string | PolymorphicUploadReference ``` ## PolymorphicUploadReference Canonical URL: https://riducms.com/reference/plugin-form-builder/polymorphic-upload-reference/ Kind: interface One canonical Ridu polymorphic upload document reference. ```ts interface PolymorphicUploadReference { ... } ``` ## SubmissionUpload Canonical URL: https://riducms.com/reference/plugin-form-builder/submission-upload/ Kind: interface One named upload submission row. ```ts interface SubmissionUpload { ... } ``` ## FormSubmissionInput Canonical URL: https://riducms.com/reference/plugin-form-builder/form-submission-input/ Kind: interface The normalized public create payload. ```ts interface FormSubmissionInput { ... } ``` ## FormValidationIssue Canonical URL: https://riducms.com/reference/plugin-form-builder/form-validation-issue/ Kind: interface One immediate client validation message. ```ts interface FormValidationIssue { ... } ``` ## FormValue Canonical URL: https://riducms.com/reference/plugin-form-builder/form-value/ Kind: type One public form control value. ```ts type FormValue = | boolean | number | string | readonly UploadReference[] | Readonly> | null | undefined ``` ## FormValues Canonical URL: https://riducms.com/reference/plugin-form-builder/form-values/ Kind: type Values keyed by editor-authored form field name. ```ts type FormValues = Readonly> ``` ## Confirmation Canonical URL: https://riducms.com/reference/plugin-form-builder/confirmation/ Kind: type The normalized post-submit action. ```ts type Confirmation = { type: "message"; message: string } | { type: "redirect"; redirect: FormRedirect } ``` --- # API Reference: @riducms/admin Canonical URL: https://riducms.com/reference/admin/ Package: @riducms/admin The framework-owned Svelte admin mount contract and public admin client surface. ## AdminClient Canonical URL: https://riducms.com/reference/admin/admin-client/ Kind: type Public type AdminClient from @riducms/admin. ```ts type AdminClient = RiduClient ``` ## mountAdmin Canonical URL: https://riducms.com/reference/admin/mount-admin/ Kind: function Public function mountAdmin from @riducms/admin. ```ts function mountAdmin(options: MountAdminOptions): ReturnType ``` ## MountAdminOptions Canonical URL: https://riducms.com/reference/admin/mount-admin-options/ Kind: interface Public interface MountAdminOptions from @riducms/admin. ```ts interface MountAdminOptions { ... } ``` ## MountAdminOptions.clientFactory Canonical URL: https://riducms.com/reference/admin/mount-admin-options-client-factory-method/ Kind: method Creates the generated, application-specific Fetch client. ```ts MountAdminOptions.clientFactory(): RiduClient ``` --- # API Reference: @riducms/translations Canonical URL: https://riducms.com/reference/translations/ Package: @riducms/translations Typed admin translations, language negotiation, plurals, and Intl formatting. ## AdminI18n Canonical URL: https://riducms.com/reference/translations/admin-i18n/ Kind: interface Public interface AdminI18n from @riducms/translations. ```ts interface AdminI18n { ... } ``` ## AdminI18n.formatDate Canonical URL: https://riducms.com/reference/translations/admin-i18n-format-date-method/ Kind: method Public method AdminI18n.formatDate from @riducms/translations. ```ts AdminI18n.formatDate(value: Date | string | number, options?: Intl.DateTimeFormatOptions): string ``` ## AdminI18n.formatList Canonical URL: https://riducms.com/reference/translations/admin-i18n-format-list-method/ Kind: method Public method AdminI18n.formatList from @riducms/translations. ```ts AdminI18n.formatList(values: readonly string[], options?: Intl.ListFormatOptions): string ``` ## AdminI18n.formatNumber Canonical URL: https://riducms.com/reference/translations/admin-i18n-format-number-method/ Kind: method Public method AdminI18n.formatNumber from @riducms/translations. ```ts AdminI18n.formatNumber(value: number, options?: Intl.NumberFormatOptions): string ``` ## AdminI18n.formatRelativeTime Canonical URL: https://riducms.com/reference/translations/admin-i18n-format-relative-time-method/ Kind: method Public method AdminI18n.formatRelativeTime from @riducms/translations. ```ts AdminI18n.formatRelativeTime(value: number, unit: Intl.RelativeTimeFormatUnit): string ``` ## AdminI18n.t Canonical URL: https://riducms.com/reference/translations/admin-i18n-t-method/ Kind: method Public method AdminI18n.t from @riducms/translations. ```ts AdminI18n.t(key: AdminTranslationKey, variables?: TranslationVariables): string ``` ## AdminI18n.text Canonical URL: https://riducms.com/reference/translations/admin-i18n-text-method/ Kind: method Public method AdminI18n.text from @riducms/translations. ```ts AdminI18n.text(canonical: string, translations?: Readonly>): string ``` ## AdminTranslationKey Canonical URL: https://riducms.com/reference/translations/admin-translation-key/ Kind: type Public type AdminTranslationKey from @riducms/translations. ```ts type AdminTranslationKey = CoreTranslationKey | PluginTranslationKey ``` ## ar Canonical URL: https://riducms.com/reference/translations/ar/ Kind: constant Public constant ar from @riducms/translations. ```ts const ar: TranslationLanguage ``` ## arMessages Canonical URL: https://riducms.com/reference/translations/ar-messages/ Kind: constant Public constant arMessages from @riducms/translations. ```ts const arMessages: CoreTranslationCatalog ``` ## CoreTranslationCatalog Canonical URL: https://riducms.com/reference/translations/core-translation-catalog/ Kind: type Public type CoreTranslationCatalog from @riducms/translations. ```ts type CoreTranslationCatalog = Readonly> ``` ## CoreTranslationKey Canonical URL: https://riducms.com/reference/translations/core-translation-key/ Kind: type Public type CoreTranslationKey from @riducms/translations. ```ts type CoreTranslationKey = keyof typeof enMessages ``` ## createAdminI18n Canonical URL: https://riducms.com/reference/translations/create-admin-i18n/ Kind: function Public function createAdminI18n from @riducms/translations. ```ts function createAdminI18n(options?: CreateAdminI18nOptions): AdminI18n ``` ## CreateAdminI18nOptions Canonical URL: https://riducms.com/reference/translations/create-admin-i18n-options/ Kind: interface Public interface CreateAdminI18nOptions from @riducms/translations. ```ts interface CreateAdminI18nOptions { ... } ``` ## defineTranslationLanguage Canonical URL: https://riducms.com/reference/translations/define-translation-language/ Kind: function Defines and validates a complete statically bundled admin language. ```ts function defineTranslationLanguage(language: Language): Language ``` ## en Canonical URL: https://riducms.com/reference/translations/en/ Kind: constant Public constant en from @riducms/translations. ```ts const en: { readonly code: "en"; readonly label: "English"; readonly rtl: false; readonly messages: typeof enMessages } ``` ## enMessages Canonical URL: https://riducms.com/reference/translations/en-messages/ Kind: constant Public constant enMessages from @riducms/translations. ```ts const enMessages: Record ``` ## extendTranslationLanguage Canonical URL: https://riducms.com/reference/translations/extend-translation-language/ Kind: function Creates a complete catalog from a built-in language and typed project overrides. ```ts function extendTranslationLanguage(base: TranslationLanguage, options: { code?: string; label?: string; rtl?: boolean; messages: Readonly>>; }): TranslationLanguage ``` ## fr Canonical URL: https://riducms.com/reference/translations/fr/ Kind: constant Public constant fr from @riducms/translations. ```ts const fr: { readonly code: "fr"; readonly label: "Français"; readonly rtl: false; readonly messages: typeof frMessages } ``` ## frMessages Canonical URL: https://riducms.com/reference/translations/fr-messages/ Kind: constant Public constant frMessages from @riducms/translations. ```ts const frMessages: CoreTranslationCatalog ``` ## parseAcceptLanguage Canonical URL: https://riducms.com/reference/translations/parse-accept-language/ Kind: function Public function parseAcceptLanguage from @riducms/translations. ```ts function parseAcceptLanguage(header: string): string[] ``` ## PluginMessageCatalog Canonical URL: https://riducms.com/reference/translations/plugin-message-catalog/ Kind: interface Public interface PluginMessageCatalog from @riducms/translations. ```ts interface PluginMessageCatalog { ... } ``` ## PluginTranslationKey Canonical URL: https://riducms.com/reference/translations/plugin-translation-key/ Kind: type Public type PluginTranslationKey from @riducms/translations. ```ts type PluginTranslationKey = `plugin.${string}:${string}` ``` ## PluralCategory Canonical URL: https://riducms.com/reference/translations/plural-category/ Kind: type Public type PluralCategory from @riducms/translations. ```ts type PluralCategory = Intl.LDMLPluralRule ``` ## PluralMessage Canonical URL: https://riducms.com/reference/translations/plural-message/ Kind: type Public type PluralMessage from @riducms/translations. ```ts type PluralMessage = Readonly> & { other: string }> ``` ## resolvePreferredLanguage Canonical URL: https://riducms.com/reference/translations/resolve-preferred-language/ Kind: function Public function resolvePreferredLanguage from @riducms/translations. ```ts function resolvePreferredLanguage(preferences: readonly string[], supported: readonly string[], fallback: string): string ``` ## TranslationLanguage Canonical URL: https://riducms.com/reference/translations/translation-language/ Kind: interface Public interface TranslationLanguage from @riducms/translations. ```ts interface TranslationLanguage { ... } ``` ## TranslationMessage Canonical URL: https://riducms.com/reference/translations/translation-message/ Kind: type Public type TranslationMessage from @riducms/translations. ```ts type TranslationMessage = string | PluralMessage ``` ## TranslationVariables Canonical URL: https://riducms.com/reference/translations/translation-variables/ Kind: type Public type TranslationVariables from @riducms/translations. ```ts type TranslationVariables = Readonly> ``` ## validateLanguageCatalogs Canonical URL: https://riducms.com/reference/translations/validate-language-catalogs/ Kind: function Public function validateLanguageCatalogs from @riducms/translations. ```ts function validateLanguageCatalogs(languages: readonly TranslationLanguage[]): void ``` ## validatePluginMessageCatalog Canonical URL: https://riducms.com/reference/translations/validate-plugin-message-catalog/ Kind: function Public function validatePluginMessageCatalog from @riducms/translations. ```ts function validatePluginMessageCatalog(pluginKey: string, catalog: PluginMessageCatalog): void ``` --- # API Reference: @riducms/cli/run Canonical URL: https://riducms.com/reference/cli-launcher/ Package: @riducms/cli/run Programmatic Node launcher for invoking the platform-specific Ridu CLI binary. ## runRidu Canonical URL: https://riducms.com/reference/cli-launcher/run-ridu/ Kind: function Download or reuse the matching native Ridu binary, run it with inherited stdio, and resolve its exit code. ```ts function runRidu(arguments_: any): Promise ``` The launcher forwards SIGINT and SIGTERM while the child is running and inherits the parent process standard streams. ```ts import { runRidu } from '@riducms/cli/run'; process.exitCode = await runRidu(['doctor']); ``` --- # API Reference: ridu CLI Canonical URL: https://riducms.com/reference/cli/ Package: ridu The implemented project lifecycle: scaffolding, generation, migrations, development, checks, builds, diagnostics, and static plugin management. ## ridu new Canonical URL: https://riducms.com/reference/cli/new/ Kind: command Scaffold a thin Ridu application, resolve Go dependencies, and generate its first contracts. ```shell ridu new [--template starter|blank] [--database postgres|sqlite|mongodb] [--package-manager npm|bun|pnpm|yarn] [--agent codex|claude|cursor|all|none] [--no-agent] [--module ] [--scope ] [directory] ``` The scaffold is kept if dependency setup or initial generation fails, and the CLI prints recovery commands. --release-version is a framework-development override for exercising an alternate dependency release; ordinary application authors should not use it. ```shell ridu new --package-manager npm \ --module github.com/acme/content \ --scope @acme \ content cd content npm install npm run dev ``` ## ridu agent install Canonical URL: https://riducms.com/reference/cli/agent-install/ Kind: command Install a release-matched local agent layout into an existing Ridu project. ```shell ridu agent install [--agent codex|claude|cursor|all] ``` Installs both ridu-project and payload-to-ridu with their offline references. Existing AGENTS.md or CLAUDE.md instructions are preserved, and unmanaged skill files are never replaced. .ridu-agent-docs.json records only framework-owned files, digests, selected layouts, and the framework release. ```shell ridu agent install --agent claude ``` ## ridu agent sync Canonical URL: https://riducms.com/reference/cli/agent-sync/ Kind: command Synchronize installed framework-owned skill references with the current CLI release. ```shell ridu agent sync ``` Sync validates every recorded digest before writing and stops if a managed file contains local edits. Root project instructions are never synchronized. ## ridu doctor Canonical URL: https://riducms.com/reference/cli/doctor/ Kind: command Diagnose Go, Bun, project discovery, frontend dependencies, and local database prerequisites. ```shell ridu doctor ``` Docker or OrbStack is optional when DATABASE_URL is already set for PostgreSQL or MongoDB, and is not required for SQLite projects. doctor validates RIDU_SQLITE_PATH when configured and reports whether frontend dependencies are installed or will be installed by dev/build. ## ridu dev Canonical URL: https://riducms.com/reference/cli/dev/ Kind: command Run the selected database adapter, generation, safe schema sync, API, admin watch mode, and Go-config watching together. ```shell ridu dev [--database-url | --database-path ] [--address ] [--admin-port ] [--no-docker] [--no-install] [--no-sync] ``` Automatic sync pauses instead of guessing when a possible rename needs review. Create and apply a migration, then restart dev. Development injects local-only insecure cookie/database admissions into the child server; those are not production defaults. ```shell ridu dev --database-url "$DATABASE_URL" --no-docker ridu dev --database-path .ridu/development.sqlite ``` ## ridu generate Canonical URL: https://riducms.com/reference/cli/generate/ Kind: command Resolve executable Go config and atomically write every configured generated contract. ```shell ridu generate [--check] ``` Generation executes the application’s versioned private manifest command; it never parses Go source and never connects to the database. Configured outputs include the canonical schema manifest, Go and TypeScript contracts/client module, OpenAPI, and static admin plugin registry. ```shell ridu generate git diff -- generated/ ridu generate --check ``` ## ridu check Canonical URL: https://riducms.com/reference/cli/check/ Kind: command Run the generated-contract, migration-history, Go, TypeScript, and Svelte project checks. ```shell ridu check ``` The command checks generation drift, current migration history, gofmt, go vet, go test ./..., then the project Bun check script when an admin is configured. It does not silently regenerate stale contracts. ## ridu build Canonical URL: https://riducms.com/reference/cli/build/ Kind: command Regenerate contracts, build the admin, and atomically install one production Go binary. ```shell ridu build [--output ] ``` Missing frontend dependencies are installed first. The admin assets are compiled before go build -trimpath; the final binary is renamed into place only after a successful build. ```shell ridu build --output ./bin/content ``` ## ridu migrate create Canonical URL: https://riducms.com/reference/cli/migrate-create/ Kind: command Plan and write one reviewable immutable migration artifact without connecting to a database. ```shell ridu migrate create --name [--accept-renames | --transform ] [--allow-destructive] ``` PostgreSQL and MongoDB rename candidates require confirmation or --accept-renames. SQLite rejects --accept-renames and uses --transform instead for stored canonical JSON rewrites. MongoDB transforms run through the compiled project migration driver. Destructive approval does not bypass semantic transitions Ridu cannot safely automate. ```shell ridu migrate create --name rename-post-title git diff -- migrations/ ``` ## ridu migrate plan Canonical URL: https://riducms.com/reference/cli/migrate-plan/ Kind: command Inspect pending immutable execution topology without applying it. ```shell ridu migrate plan [--database-url | --database-path ] [--allow-insecure-database (PostgreSQL or MongoDB)] [--json] ``` PostgreSQL and MongoDB use --database-url or DATABASE_URL and accept --allow-insecure-database only for local development; SQLite uses --database-path or RIDU_SQLITE_PATH. Current executable config must match the latest artifact target before database inspection proceeds. JSON output exposes adapter-owned phase, step, checksum, and state details. ## ridu migrate status Canonical URL: https://riducms.com/reference/cli/migrate-status/ Kind: command Compare immutable artifact history with the database ledger. ```shell ridu migrate status [--database-url | --database-path ] [--allow-insecure-database (PostgreSQL or MongoDB)] [--json] ``` PostgreSQL and MongoDB use --database-url or DATABASE_URL; SQLite uses --database-path or RIDU_SQLITE_PATH. Status is read-only and does not accept maintenance, timeout, or stop-boundary flags. MongoDB status validates immutable lineage, checksum-bound durable progress, and exact physical state. ## ridu migrate verify Canonical URL: https://riducms.com/reference/cli/migrate-verify/ Kind: command Replay complete history in an isolated adapter-owned database and validate every intermediate state. ```shell ridu migrate verify [--database-url ] [adapter runner options] ``` PostgreSQL verification uses a temporary shadow schema and accepts runner timeout controls but not stop boundaries. SQLite needs no deployment path and replays history, including registered compiled transforms, in a temporary database. MongoDB uses a command-scoped credential to create, replay, verify, and drop a random shadow database; use separate scoped credentials for the running application, verification, and backups. ## ridu migrate up Canonical URL: https://riducms.com/reference/cli/migrate-up/ Kind: command Validate complete history and apply pending artifacts under adapter-owned coordination. ```shell ridu migrate up [--database-url | --database-path ] [adapter runner options] ``` PostgreSQL requires secure transport unless explicitly admitted, holds a session advisory lock, and resumes durable phased checkpoints. SQLite applies every pending artifact atomically under one BEGIN IMMEDIATE writer reservation. MongoDB requires verified TLS unless explicitly admitted for local development, holds a fenced expiring lease, and resumes checksum-bound durable steps. ```shell DATABASE_URL="$MONGODB_MIGRATION_URL" ridu migrate plan --json # Drain every old application process, worker, and other writer. DATABASE_URL="$MONGODB_OPERATIONAL_URL" ridu migrate verify # Capture the matched database/upload snapshot. DATABASE_URL="$MONGODB_MIGRATION_URL" ridu migrate up DATABASE_URL="$MONGODB_MIGRATION_URL" ridu migrate status # Start only the new digest; require /readyz before admitting traffic. DATABASE_URL="$MONGODB_APP_URL" ./dist/content ``` ## ridu migrate down Canonical URL: https://riducms.com/reference/cli/migrate-down/ Kind: command Reverse the latest applied SQLite artifact while retaining its immutable file. ```shell ridu migrate down [--database-path ] --allow-destructive ``` SQLite only. The path may instead come from RIDU_SQLITE_PATH. Status reports the reversed artifact as pending so migrate up can replay it. ## ridu migrate reset Canonical URL: https://riducms.com/reference/cli/migrate-reset/ Kind: command Reverse every applied SQLite artifact in exact reverse order. ```shell ridu migrate reset [--database-path ] --allow-destructive ``` SQLite only. The path may instead come from RIDU_SQLITE_PATH. Artifact files and checksums remain committed; schema, callbacks, and ledger changes roll back atomically. ## ridu migrate refresh Canonical URL: https://riducms.com/reference/cli/migrate-refresh/ Kind: command Reverse and replay complete committed SQLite history atomically. ```shell ridu migrate refresh [--database-path ] --allow-destructive ``` SQLite only. The path may instead come from RIDU_SQLITE_PATH. Registered compiled down and up callbacks run with their checksum-bound artifacts in the same transaction. ## ridu migrate fresh Canonical URL: https://riducms.com/reference/cli/migrate-fresh/ Kind: command Drop non-internal SQLite objects and replay committed history atomically. ```shell ridu migrate fresh [--database-path ] --allow-destructive ``` SQLite only. The path may instead come from RIDU_SQLITE_PATH. Use this explicit destructive workflow for a reviewed local rebuild, not as production startup synchronization. ## PostgreSQL migration runner options Canonical URL: https://riducms.com/reference/cli/migration-runner-options/ Kind: command PostgreSQL operational admissions and bounds accepted by migrate up and, except stop boundaries, verify. ```shell --database-url --allow-insecure-database --allow-maintenance --allow-unbounded --advisory-lock-wait --lock-timeout --statement-timeout --batch-timeout --concurrent-index-timeout --idle-in-transaction-timeout --stop-after-phase --stop-after-step ``` --allow-maintenance requires every application process and worker to remain stopped through completion and retries. Zero durations select bounded defaults unless --allow-unbounded is explicit. --stop-after-phase and --stop-after-step are accepted only by PostgreSQL migrate up; verify always runs to completion. ## MongoDB migration runner options Canonical URL: https://riducms.com/reference/cli/mongodb-migration-runner-options/ Kind: command MongoDB operational admissions and bounds accepted by migrate up and verify. ```shell --database-url --allow-insecure-database --allow-maintenance --allow-unbounded --advisory-lock-wait --concurrent-index-timeout ``` --allow-maintenance requires every application process and worker to remain stopped through completion and retries. --advisory-lock-wait bounds acquisition of the fenced migration lease; --concurrent-index-timeout bounds the complete MongoDB migration operation. Zero selects bounded defaults unless --allow-unbounded is explicit, and lease expiry remains bounded. MongoDB rejects the PostgreSQL-only --lock-timeout, --statement-timeout, --batch-timeout, --idle-in-transaction-timeout, --stop-after-phase, and --stop-after-step controls. Interrupted work resumes from the checksum-bound durable step ledger. ## ridu plugin new Canonical URL: https://riducms.com/reference/cli/plugin-new/ Kind: command Scaffold paired Go and Svelte plugin packages with conformance tests. ```shell ridu plugin new --key --module --admin-package ``` The key must be stable and lowercase. Publish the Go and admin packages with matching plugin pairing versions after both conformance suites pass. ```shell ridu plugin new ./ridu-color \ --key color \ --module example.com/acme/ridu-color \ --admin-package @acme/ridu-color-admin ``` ## ridu plugin add Canonical URL: https://riducms.com/reference/cli/plugin-add/ Kind: command Install and register a compiled backend plugin and optional paired admin package. ```shell ridu plugin add --go-package [--go-version ] [--constructor ] [--admin-package ] [--admin-version ] [--no-install] ``` ridu add is an exact alias. The command updates dependencies and registration, regenerates contracts, checks compatibility, and rolls back its files on failure. Review the descriptor and create a migration afterward. ## ridu plugin remove Canonical URL: https://riducms.com/reference/cli/plugin-remove/ Kind: command Remove static plugin registration and dependencies, then regenerate contracts. ```shell ridu plugin remove [--no-install] ``` Without --no-install the command removes the Bun dependency and runs go mod tidy. It rolls back on generation failure. Create a migration to review any plugin down steps. ## ridu version Canonical URL: https://riducms.com/reference/cli/version/ Kind: command Print the compiled CLI version. ```shell ridu version | ridu --version | ridu -v ``` ## ridu help Canonical URL: https://riducms.com/reference/cli/help/ Kind: command Show commands and the compiled project-protocol and schema-manifest versions. ```shell ridu help | ridu --help | ridu -h ```