From 1dd9929ff8ee5b60fe868dc59ceda26340f24164 Mon Sep 17 00:00:00 2001 From: Konstantinos Kopanidis Date: Mon, 22 Jun 2026 10:48:44 +0300 Subject: [PATCH 1/4] docs(web): expand database module page with schemas, query ops, and GitOps Problem-first rewrite covering custom endpoint comparison operators (including CONTAIN), introspection as Admin API-only, and state export resources. --- apps/web/content/docs/modules/database.mdx | 160 ++++++++++++++++++--- 1 file changed, 137 insertions(+), 23 deletions(-) diff --git a/apps/web/content/docs/modules/database.mdx b/apps/web/content/docs/modules/database.mdx index 4a1c5f40..bee41ffc 100644 --- a/apps/web/content/docs/modules/database.mdx +++ b/apps/web/content/docs/modules/database.mdx @@ -1,10 +1,12 @@ --- title: Database -description: Schemas, CRUD, custom endpoints, indexes, and query trees. -agent_summary: "Client: /database/{Schema}, /database/function/{name}; provision schemas via MCP; no client-side filtering — custom endpoints for filtered queries." +description: Schemas, CRUD, custom endpoints, indexes, query trees, and GitOps export. +agent_summary: "Client: /database/{Schema}, /database/function/{name}; provision schemas and custom endpoints via MCP; never filter collections client-side; introspection is Admin API only (not MCP)." --- -The **database** module is the data layer. Apps never connect to MongoDB or PostgreSQL directly — schemas define document shapes, CMS options expose CRUD routes, and custom endpoints serve filtered queries. +Your app needs structured data, but connecting to MongoDB or PostgreSQL directly bypasses Conduit auth, authorization, and routing. The **database** module is the data layer: you define **schemas**, enable **CMS CRUD** routes for simple access, and provision **custom endpoints** for every filtered query. + +The most common mistake is calling `GET /database/{Schema}` and filtering in application code. That route runs `findMany({}, …)` — **there is no filter parameter**. Any WHERE clause, ownership scope, date range, or text search belongs in a provisioned custom endpoint at `/database/function/{name}`. ## Use cases @@ -16,15 +18,19 @@ The **database** module is the data layer. Apps never connect to MongoDB or Post }, { title: "Filtered lists", - outcome: "Custom endpoints for WHERE clauses, search, and pagination", + outcome: "Custom endpoints with query trees for WHERE, search, and pagination", }, { title: "Multi-tenant records", outcome: "Authorization-enabled schemas with scope on create", }, { - title: "Extend auth User", - outcome: "Schema extensions add fields to module-owned schemas", + title: "Brownfield databases", + outcome: "Introspect existing collections via Admin API, finalize as CMS schemas", + }, + { + title: "Config-as-code", + outcome: "Export schemas, extensions, and custom endpoints in GitOps state snapshots", }, ]} /> @@ -33,14 +39,16 @@ The **database** module is the data layer. Apps never connect to MongoDB or Post @@ -72,43 +80,140 @@ The **database** module is the data layer. Apps never connect to MongoDB or Post ## How it works +### Schemas + +A schema declares field types, indexes, and `conduitOptions` that control runtime behavior: + +| `conduitOptions` key | Effect | +|---------------------|--------| +| `cms.enabled` | Register CMS routes for this schema | +| `cms.crudOperations.*.enabled` | Per-operation route exposure (create, read, update, delete) | +| `cms.crudOperations.*.authenticated` | Require bearer token on that operation | +| `authorization.enabled` | ReBAC ownership tuples on documents — pass `scope` on creates | +| `permissions.*` | Admin-panel schema permissions (separate from document ReBAC) | + +**Schema extensions** add fields to module-owned schemas (e.g. extend the auth `User` schema). Extensions are database-owned and included in GitOps export alongside base schemas. + +Provision schemas at dev/deploy time via MCP `post_database_schemas` or `patch_database_schemas_id`. Module-owned schemas cannot be overwritten by import. + ### CMS CRUD -When `conduitOptions.cms.enabled` and per-operation flags are set, the Client API exposes: +When `conduitOptions.cms` flags are set, the Client API exposes: | Intent | HTTP | Path | |--------|------|------| | List (unfiltered) | GET | `/database/{Schema}?skip&limit&sort&populate&scope` | | Get by id | GET | `/database/{Schema}/{id}` | -| Create | POST | `/database/{Schema}` | +| Create | POST | `/database/{Schema}?scope` | | Update | PATCH | `/database/{Schema}/{id}` | | Delete | DELETE | `/database/{Schema}/{id}` | -`GET /database/{Schema}` runs `findMany({}, …)` — **no filter parameter exists**. - -### The iron rule +List queries accept `skip`, `limit`, `sort`, and `populate` (GraphQL-style relation joins on REST). On authorization-enabled schemas, pass `scope` (e.g. `Team:abc`) on **creates** so ownership tuples attach to the right resource. -Any query needing WHERE clauses, `$in`, date ranges, text search, or ownership scoping must use a **provisioned custom endpoint** at `/database/function/{name}`. Never fetch a collection and `.filter()` in application code. +`GET /database/{Schema}` always queries with an empty filter `{}`. Use it only when a full collection scan (with pagination) is intentional. ### Custom endpoints -Provision via MCP `post_database_customendpoints`. Operations map to HTTP methods (GET, POST, PUT, PATCH, DELETE). Query trees declare inputs, filters, populate, pagination (`paginated: true` requires `skip` + `limit`), and optional `like: true` text search. +Custom endpoints map to Client API routes at `/database/function/{name}`. Provision via MCP `post_database_customendpoints`. + +| Field | Purpose | +|-------|---------| +| `operation` | HTTP verb: `0` GET, `1` POST, `2` PUT, `3` DELETE, `4` PATCH | +| `selectedSchema` / `selectedSchemaName` | Target schema | +| `inputs` | Parameters (`location`: `0` body, `1` query, `2` URL) | +| `query` | Query tree for read/update/delete filters | +| `assignments` | Field writes for POST/PUT/PATCH | +| `authentication` | Require bearer token (mandatory on authorization-enabled schemas) | +| `paginated` | Require `skip` + `limit` inputs | +| `sorted` | Enable sort parameter | + +**Query trees** nest `AND` / `OR` arrays of leaf nodes. Each leaf has `schemaField`, `operation`, and `comparisonField`: + +```json +{ + "AND": [ + { + "schemaField": "authorId", + "operation": 0, + "comparisonField": { "type": "Input", "value": "authorId" } + } + ] +} +``` + +`comparisonField.type` is `Input` (from endpoint params), `Schema` (literal schema field), `Custom` (fixed value), or `Context` (request context path). + +Set `comparisonField.like: true` for case-insensitive text search (`$ilike`); `caseSensitiveLike: true` uses `$like`. Text `like` is not supported on PostgreSQL/Sequelize. + +#### Comparison operations -On authorization-enabled schemas, custom endpoints **must** have `authentication: true` and accept optional `scope`. +| Op | Name | BSON / behavior | +|----|------|-----------------| +| `0` | Equal | `{ field: value }` | +| `1` | Not equal | `{ field: { $ne: value } }` | +| `2` | Greater than | `{ field: { $gt: value } }` | +| `3` | Greater or equal | `{ field: { $gte: value } }` | +| `4` | Less than | `{ field: { $lt: value } }` | +| `5` | Less or equal | `{ field: { $lte: value } }` | +| `6` | In set | `{ field: { $in: value } }` — value must be an array | +| `7` | Not in set | `{ field: { $nin: value } }` | +| `8` | Contains | `{ field: value }` — for array fields, matches documents where the array contains the value | + +#### Assignment actions (write endpoints) + +For POST/PUT/PATCH endpoints, `assignments` map inputs to schema fields: + +| Action | Name | Effect | +|--------|------|--------| +| `0` | Set | Assign field value | +| `1` | Increment | `$inc` positive | +| `2` | Decrement | `$inc` negative | +| `3` | Append | `$push` (array fields only; PUT only) | +| `4` | Remove | `$pull` (array fields only; PUT only) | + +### Database introspection + +When you already have collections or tables outside Conduit, **introspection** discovers them and registers **pending schemas** for review. Finalize pending schemas to convert them into CMS schemas (CRUD disabled by default on imported schemas). + +Introspection is an **operator workflow** on the Admin API (`GET`/`POST /database/introspection`, pending schema routes). These routes are marked `mcp: false` — **no MCP tools exist for introspection**. Use the Admin Panel or direct Admin API calls with admin credentials. + +Large MongoDB collections can slow introspection; PostgreSQL introspection improved in recent releases. + +### GitOps export + +The database module participates in platform state export/import. Exportable resource types: + +| Type | Priority | Contents | +|------|----------|----------| +| `schemas` | 10 | CMS schema definitions | +| `extensions` | 11 | Database-owned schema extensions | +| `customEndpoints` | 20 | Custom endpoint definitions | + +Use `GET /state/export` and `POST /state/import` on the Admin API, or module-scoped `GET /database/schemas/export` and `GET /database/customEndpoints/export`. See [GitOps state export](/docs/guides/gitops-state-export). + +`POST /database/schemas/import` is also excluded from MCP (`mcp: false`) — prefer `/state/import` or Admin API directly in CI pipelines. ## Configure -Provision at dev/deploy time via MCP with `?modules=database`: +Enable the database module in deployment, then provision via MCP with `?modules=database`: ```text post_database_schemas patch_database_schemas_id post_database_customendpoints +patch_database_customendpoints_id post_database_schemas_id_indexes +patch_config_database ``` -Key `conduitOptions` keys: `cms.enabled`, `cms.crudOperations.*.enabled`, `cms.crudOperations.*.authenticated`, `authorization.enabled`. +| Config key | Meaning | +|------------|---------| +| `readPreference` | MongoDB replica read preference (`primary`, `secondaryPreferred`, …) | +| `writeConcern` | MongoDB write concern (`1`, `majority`) | +| `readConcern` | MongoDB read concern (`local`, `majority`, …) | + +Sequelize/PostgreSQL caveats: index creation via Admin API is limited, `like` filters do not work, and partial-row updates only change provided columns. ## Client API @@ -120,16 +225,25 @@ Key `conduitOptions` keys: `cms.enabled`, `cms.crudOperations.*.enabled`, `cms.c ## MCP +Enable with `?modules=database` in your MCP server URL. + | Tool | Purpose | |------|---------| -| `post_database_schemas` | Create schema | | `get_database_schemas` | List schemas | -| `post_database_customendpoints` | Create filtered query endpoint | -| `post_database_schemas_id_indexes` | Add DB index | +| `post_database_schemas` | Create schema | +| `patch_database_schemas_id` | Update schema | +| `get_database_customendpoints` | List custom endpoints | +| `post_database_customendpoints` | Create custom endpoint | +| `patch_database_customendpoints_id` | Update custom endpoint | +| `post_database_schemas_id_indexes` | Add index | +| `patch_config_database` | Replica set / DB engine settings | + +**Not exposed via MCP:** introspection routes (`/database/introspection/*`), `POST /database/schemas/import`. Use Admin API or Admin Panel for those operator workflows. From d6529684e6e7cae2eaffcfffe257be3010e6e830 Mon Sep 17 00:00:00 2001 From: Konstantinos Kopanidis Date: Mon, 22 Jun 2026 12:45:33 +0300 Subject: [PATCH 2/4] docs(database): fix PostgreSQL ilike and CONTAIN op 8 wording Document $ilike support on PostgreSQL and clarify that operation 8 currently falls through to equality, not array-contains. --- apps/web/content/docs/modules/database.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/content/docs/modules/database.mdx b/apps/web/content/docs/modules/database.mdx index bee41ffc..fd017202 100644 --- a/apps/web/content/docs/modules/database.mdx +++ b/apps/web/content/docs/modules/database.mdx @@ -143,7 +143,7 @@ Custom endpoints map to Client API routes at `/database/function/{name}`. Provis `comparisonField.type` is `Input` (from endpoint params), `Schema` (literal schema field), `Custom` (fixed value), or `Context` (request context path). -Set `comparisonField.like: true` for case-insensitive text search (`$ilike`); `caseSensitiveLike: true` uses `$like`. Text `like` is not supported on PostgreSQL/Sequelize. +Set `comparisonField.like: true` for case-insensitive text search (`$ilike`); `caseSensitiveLike: true` uses `$like`. On **PostgreSQL**, `$ilike` maps to `ILIKE` via the Sequelize adapter. On **MongoDB**, both operators are supported natively. Avoid `like: true` on non-text field types. #### Comparison operations @@ -157,7 +157,7 @@ Set `comparisonField.like: true` for case-insensitive text search (`$ilike`); `c | `5` | Less or equal | `{ field: { $lte: value } }` | | `6` | In set | `{ field: { $in: value } }` — value must be an array | | `7` | Not in set | `{ field: { $nin: value } }` | -| `8` | Contains | `{ field: value }` — for array fields, matches documents where the array contains the value | +| `8` | Contains (reserved) | Currently translates to `{ field: value }` — same as **Equal** (`0`). Array-contains semantics are not implemented yet; use MongoDB `$in` / element-match patterns via custom logic until this operator is completed. | #### Assignment actions (write endpoints) @@ -213,7 +213,7 @@ patch_config_database | `writeConcern` | MongoDB write concern (`1`, `majority`) | | `readConcern` | MongoDB read concern (`local`, `majority`, …) | -Sequelize/PostgreSQL caveats: index creation via Admin API is limited, `like` filters do not work, and partial-row updates only change provided columns. +Sequelize/PostgreSQL caveats: index creation via Admin API is limited, case-sensitive `$like` behavior differs by dialect, and partial-row updates only change provided columns. ## Client API From d095ba4b8cfb232b8139695655b4dac7deadf44b Mon Sep 17 00:00:00 2001 From: Konstantinos Kopanidis Date: Mon, 22 Jun 2026 13:31:51 +0300 Subject: [PATCH 3/4] fix(docs): render ModuleDeepDive tables via imported MDX fragment --- apps/web/content/docs/modules/database.mdx | 115 +----------------- .../src/components/docs/module-deep-dive.tsx | 4 +- .../src/mdx/deep-dives/database-deep-dive.mdx | 112 +++++++++++++++++ 3 files changed, 118 insertions(+), 113 deletions(-) create mode 100644 apps/web/src/mdx/deep-dives/database-deep-dive.mdx diff --git a/apps/web/content/docs/modules/database.mdx b/apps/web/content/docs/modules/database.mdx index fd017202..8f904497 100644 --- a/apps/web/content/docs/modules/database.mdx +++ b/apps/web/content/docs/modules/database.mdx @@ -4,6 +4,8 @@ description: Schemas, CRUD, custom endpoints, indexes, query trees, and GitOps e agent_summary: "Client: /database/{Schema}, /database/function/{name}; provision schemas and custom endpoints via MCP; never filter collections client-side; introspection is Admin API only (not MCP)." --- +import DatabaseDeepDive from "@/mdx/deep-dives/database-deep-dive.mdx"; + Your app needs structured data, but connecting to MongoDB or PostgreSQL directly bypasses Conduit auth, authorization, and routing. The **database** module is the data layer: you define **schemas**, enable **CMS CRUD** routes for simple access, and provision **custom endpoints** for every filtered query. The most common mistake is calling `GET /database/{Schema}` and filtering in application code. That route runs `findMany({}, …)` — **there is no filter parameter**. Any WHERE clause, ownership scope, date range, or text search belongs in a provisioned custom endpoint at `/database/function/{name}`. @@ -80,118 +82,7 @@ The most common mistake is calling `GET /database/{Schema}` and filtering in app ## How it works -### Schemas - -A schema declares field types, indexes, and `conduitOptions` that control runtime behavior: - -| `conduitOptions` key | Effect | -|---------------------|--------| -| `cms.enabled` | Register CMS routes for this schema | -| `cms.crudOperations.*.enabled` | Per-operation route exposure (create, read, update, delete) | -| `cms.crudOperations.*.authenticated` | Require bearer token on that operation | -| `authorization.enabled` | ReBAC ownership tuples on documents — pass `scope` on creates | -| `permissions.*` | Admin-panel schema permissions (separate from document ReBAC) | - -**Schema extensions** add fields to module-owned schemas (e.g. extend the auth `User` schema). Extensions are database-owned and included in GitOps export alongside base schemas. - -Provision schemas at dev/deploy time via MCP `post_database_schemas` or `patch_database_schemas_id`. Module-owned schemas cannot be overwritten by import. - -### CMS CRUD - -When `conduitOptions.cms` flags are set, the Client API exposes: - -| Intent | HTTP | Path | -|--------|------|------| -| List (unfiltered) | GET | `/database/{Schema}?skip&limit&sort&populate&scope` | -| Get by id | GET | `/database/{Schema}/{id}` | -| Create | POST | `/database/{Schema}?scope` | -| Update | PATCH | `/database/{Schema}/{id}` | -| Delete | DELETE | `/database/{Schema}/{id}` | - -List queries accept `skip`, `limit`, `sort`, and `populate` (GraphQL-style relation joins on REST). On authorization-enabled schemas, pass `scope` (e.g. `Team:abc`) on **creates** so ownership tuples attach to the right resource. - -`GET /database/{Schema}` always queries with an empty filter `{}`. Use it only when a full collection scan (with pagination) is intentional. - -### Custom endpoints - -Custom endpoints map to Client API routes at `/database/function/{name}`. Provision via MCP `post_database_customendpoints`. - -| Field | Purpose | -|-------|---------| -| `operation` | HTTP verb: `0` GET, `1` POST, `2` PUT, `3` DELETE, `4` PATCH | -| `selectedSchema` / `selectedSchemaName` | Target schema | -| `inputs` | Parameters (`location`: `0` body, `1` query, `2` URL) | -| `query` | Query tree for read/update/delete filters | -| `assignments` | Field writes for POST/PUT/PATCH | -| `authentication` | Require bearer token (mandatory on authorization-enabled schemas) | -| `paginated` | Require `skip` + `limit` inputs | -| `sorted` | Enable sort parameter | - -**Query trees** nest `AND` / `OR` arrays of leaf nodes. Each leaf has `schemaField`, `operation`, and `comparisonField`: - -```json -{ - "AND": [ - { - "schemaField": "authorId", - "operation": 0, - "comparisonField": { "type": "Input", "value": "authorId" } - } - ] -} -``` - -`comparisonField.type` is `Input` (from endpoint params), `Schema` (literal schema field), `Custom` (fixed value), or `Context` (request context path). - -Set `comparisonField.like: true` for case-insensitive text search (`$ilike`); `caseSensitiveLike: true` uses `$like`. On **PostgreSQL**, `$ilike` maps to `ILIKE` via the Sequelize adapter. On **MongoDB**, both operators are supported natively. Avoid `like: true` on non-text field types. - -#### Comparison operations - -| Op | Name | BSON / behavior | -|----|------|-----------------| -| `0` | Equal | `{ field: value }` | -| `1` | Not equal | `{ field: { $ne: value } }` | -| `2` | Greater than | `{ field: { $gt: value } }` | -| `3` | Greater or equal | `{ field: { $gte: value } }` | -| `4` | Less than | `{ field: { $lt: value } }` | -| `5` | Less or equal | `{ field: { $lte: value } }` | -| `6` | In set | `{ field: { $in: value } }` — value must be an array | -| `7` | Not in set | `{ field: { $nin: value } }` | -| `8` | Contains (reserved) | Currently translates to `{ field: value }` — same as **Equal** (`0`). Array-contains semantics are not implemented yet; use MongoDB `$in` / element-match patterns via custom logic until this operator is completed. | - -#### Assignment actions (write endpoints) - -For POST/PUT/PATCH endpoints, `assignments` map inputs to schema fields: - -| Action | Name | Effect | -|--------|------|--------| -| `0` | Set | Assign field value | -| `1` | Increment | `$inc` positive | -| `2` | Decrement | `$inc` negative | -| `3` | Append | `$push` (array fields only; PUT only) | -| `4` | Remove | `$pull` (array fields only; PUT only) | - -### Database introspection - -When you already have collections or tables outside Conduit, **introspection** discovers them and registers **pending schemas** for review. Finalize pending schemas to convert them into CMS schemas (CRUD disabled by default on imported schemas). - -Introspection is an **operator workflow** on the Admin API (`GET`/`POST /database/introspection`, pending schema routes). These routes are marked `mcp: false` — **no MCP tools exist for introspection**. Use the Admin Panel or direct Admin API calls with admin credentials. - -Large MongoDB collections can slow introspection; PostgreSQL introspection improved in recent releases. - -### GitOps export - -The database module participates in platform state export/import. Exportable resource types: - -| Type | Priority | Contents | -|------|----------|----------| -| `schemas` | 10 | CMS schema definitions | -| `extensions` | 11 | Database-owned schema extensions | -| `customEndpoints` | 20 | Custom endpoint definitions | - -Use `GET /state/export` and `POST /state/import` on the Admin API, or module-scoped `GET /database/schemas/export` and `GET /database/customEndpoints/export`. See [GitOps state export](/docs/guides/gitops-state-export). - -`POST /database/schemas/import` is also excluded from MCP (`mcp: false`) — prefer `/state/import` or Admin API directly in CI pipelines. + ## Configure diff --git a/apps/web/src/components/docs/module-deep-dive.tsx b/apps/web/src/components/docs/module-deep-dive.tsx index c3b17ddb..573ae2c5 100644 --- a/apps/web/src/components/docs/module-deep-dive.tsx +++ b/apps/web/src/components/docs/module-deep-dive.tsx @@ -8,7 +8,9 @@ type ModuleDeepDiveProps = { export function ModuleDeepDive({ children }: ModuleDeepDiveProps) { return (
-
{children}
+
+ {children} +
); } diff --git a/apps/web/src/mdx/deep-dives/database-deep-dive.mdx b/apps/web/src/mdx/deep-dives/database-deep-dive.mdx new file mode 100644 index 00000000..a11cfb90 --- /dev/null +++ b/apps/web/src/mdx/deep-dives/database-deep-dive.mdx @@ -0,0 +1,112 @@ +### Schemas + +A schema declares field types, indexes, and `conduitOptions` that control runtime behavior: + +| `conduitOptions` key | Effect | +|---------------------|--------| +| `cms.enabled` | Register CMS routes for this schema | +| `cms.crudOperations.*.enabled` | Per-operation route exposure (create, read, update, delete) | +| `cms.crudOperations.*.authenticated` | Require bearer token on that operation | +| `authorization.enabled` | ReBAC ownership tuples on documents — pass `scope` on creates | +| `permissions.*` | Admin-panel schema permissions (separate from document ReBAC) | + +**Schema extensions** add fields to module-owned schemas (e.g. extend the auth `User` schema). Extensions are database-owned and included in GitOps export alongside base schemas. + +Provision schemas at dev/deploy time via MCP `post_database_schemas` or `patch_database_schemas_id`. Module-owned schemas cannot be overwritten by import. + +### CMS CRUD + +When `conduitOptions.cms` flags are set, the Client API exposes: + +| Intent | HTTP | Path | +|--------|------|------| +| List (unfiltered) | GET | `/database/{Schema}?skip&limit&sort&populate&scope` | +| Get by id | GET | `/database/{Schema}/{id}` | +| Create | POST | `/database/{Schema}?scope` | +| Update | PATCH | `/database/{Schema}/{id}` | +| Delete | DELETE | `/database/{Schema}/{id}` | + +List queries accept `skip`, `limit`, `sort`, and `populate` (GraphQL-style relation joins on REST). On authorization-enabled schemas, pass `scope` (e.g. `Team:abc`) on **creates** so ownership tuples attach to the right resource. + +`GET /database/{Schema}` always queries with an empty filter `{}`. Use it only when a full collection scan (with pagination) is intentional. + +### Custom endpoints + +Custom endpoints map to Client API routes at `/database/function/{name}`. Provision via MCP `post_database_customendpoints`. + +| Field | Purpose | +|-------|---------| +| `operation` | HTTP verb: `0` GET, `1` POST, `2` PUT, `3` DELETE, `4` PATCH | +| `selectedSchema` / `selectedSchemaName` | Target schema | +| `inputs` | Parameters (`location`: `0` body, `1` query, `2` URL) | +| `query` | Query tree for read/update/delete filters | +| `assignments` | Field writes for POST/PUT/PATCH | +| `authentication` | Require bearer token (mandatory on authorization-enabled schemas) | +| `paginated` | Require `skip` + `limit` inputs | +| `sorted` | Enable sort parameter | + +**Query trees** nest `AND` / `OR` arrays of leaf nodes. Each leaf has `schemaField`, `operation`, and `comparisonField`: + +```json +{ + "AND": [ + { + "schemaField": "authorId", + "operation": 0, + "comparisonField": { "type": "Input", "value": "authorId" } + } + ] +} +``` + +`comparisonField.type` is `Input` (from endpoint params), `Schema` (literal schema field), `Custom` (fixed value), or `Context` (request context path). + +Set `comparisonField.like: true` for case-insensitive text search (`$ilike`); `caseSensitiveLike: true` uses `$like`. On **PostgreSQL**, `$ilike` maps to `ILIKE` via the Sequelize adapter. On **MongoDB**, both operators are supported natively. Avoid `like: true` on non-text field types. + +#### Comparison operations + +| Op | Name | BSON / behavior | +|----|------|-----------------| +| `0` | Equal | `{ field: value }` | +| `1` | Not equal | `{ field: { $ne: value } }` | +| `2` | Greater than | `{ field: { $gt: value } }` | +| `3` | Greater or equal | `{ field: { $gte: value } }` | +| `4` | Less than | `{ field: { $lt: value } }` | +| `5` | Less or equal | `{ field: { $lte: value } }` | +| `6` | In set | `{ field: { $in: value } }` — value must be an array | +| `7` | Not in set | `{ field: { $nin: value } }` | +| `8` | Contains (reserved) | Currently translates to `{ field: value }` — same as **Equal** (`0`). Array-contains semantics are not implemented yet; use MongoDB `$in` / element-match patterns via custom logic until this operator is completed. | + +#### Assignment actions (write endpoints) + +For POST/PUT/PATCH endpoints, `assignments` map inputs to schema fields: + +| Action | Name | Effect | +|--------|------|--------| +| `0` | Set | Assign field value | +| `1` | Increment | `$inc` positive | +| `2` | Decrement | `$inc` negative | +| `3` | Append | `$push` (array fields only; PUT only) | +| `4` | Remove | `$pull` (array fields only; PUT only) | + +### Database introspection + +When you already have collections or tables outside Conduit, **introspection** discovers them and registers **pending schemas** for review. Finalize pending schemas to convert them into CMS schemas (CRUD disabled by default on imported schemas). + +Introspection is an **operator workflow** on the Admin API (`GET`/`POST /database/introspection`, pending schema routes). These routes are marked `mcp: false` — **no MCP tools exist for introspection**. Use the Admin Panel or direct Admin API calls with admin credentials. + +Large MongoDB collections can slow introspection; PostgreSQL introspection improved in recent releases. + +### GitOps export + +The database module participates in platform state export/import. Exportable resource types: + +| Type | Priority | Contents | +|------|----------|----------| +| `schemas` | 10 | CMS schema definitions | +| `extensions` | 11 | Database-owned schema extensions | +| `customEndpoints` | 20 | Custom endpoint definitions | + +Use `GET /state/export` and `POST /state/import` on the Admin API, or module-scoped `GET /database/schemas/export` and `GET /database/customEndpoints/export`. See [GitOps state export](/docs/guides/gitops-state-export). + +`POST /database/schemas/import` is also excluded from MCP (`mcp: false`) — prefer `/state/import` or Admin API directly in CI pipelines. From 266d110290d0d42f656c58ba2af751e10a92bc76 Mon Sep 17 00:00:00 2001 From: Konstantinos Kopanidis Date: Mon, 22 Jun 2026 14:22:11 +0300 Subject: [PATCH 4/4] fix(docs): polish ModuleDeepDive styling to match page prose Use full prose instead of prose-sm, restore td align-top, improve blockquote and heading rhythm, and fix layout in deep-dive fragments. --- apps/web/src/components/docs/module-deep-dive.tsx | 15 +++++++++++++-- .../web/src/mdx/deep-dives/database-deep-dive.mdx | 6 ++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/docs/module-deep-dive.tsx b/apps/web/src/components/docs/module-deep-dive.tsx index 573ae2c5..b0e3dc81 100644 --- a/apps/web/src/components/docs/module-deep-dive.tsx +++ b/apps/web/src/components/docs/module-deep-dive.tsx @@ -7,8 +7,19 @@ type ModuleDeepDiveProps = { /** Visual container for expert content — use a markdown ## heading above for TOC. */ export function ModuleDeepDive({ children }: ModuleDeepDiveProps) { return ( -
-
+
+
{children}
diff --git a/apps/web/src/mdx/deep-dives/database-deep-dive.mdx b/apps/web/src/mdx/deep-dives/database-deep-dive.mdx index a11cfb90..baad6e51 100644 --- a/apps/web/src/mdx/deep-dives/database-deep-dive.mdx +++ b/apps/web/src/mdx/deep-dives/database-deep-dive.mdx @@ -59,7 +59,7 @@ Custom endpoints map to Client API routes at `/database/function/{name}`. Provis } ``` -`comparisonField.type` is `Input` (from endpoint params), `Schema` (literal schema field), `Custom` (fixed value), or `Context` (request context path). +`comparisonField.type` is `Input` (from endpoint params), `Schema` (field value from the matched document), `Custom` (fixed value), or `Context` (request context path). Set `comparisonField.like: true` for case-insensitive text search (`$ilike`); `caseSensitiveLike: true` uses `$like`. On **PostgreSQL**, `$ilike` maps to `ILIKE` via the Sequelize adapter. On **MongoDB**, both operators are supported natively. Avoid `like: true` on non-text field types. @@ -75,7 +75,9 @@ Set `comparisonField.like: true` for case-insensitive text search (`$ilike`); `c | `5` | Less or equal | `{ field: { $lte: value } }` | | `6` | In set | `{ field: { $in: value } }` — value must be an array | | `7` | Not in set | `{ field: { $nin: value } }` | -| `8` | Contains (reserved) | Currently translates to `{ field: value }` — same as **Equal** (`0`). Array-contains semantics are not implemented yet; use MongoDB `$in` / element-match patterns via custom logic until this operator is completed. | +| `8` | Contains (reserved) | Same as **Equal** (`0`) — `{ field: value }` | + +Op `8` does not implement array-contains yet. Use MongoDB `$in` / element-match patterns via custom logic until this operator is completed. #### Assignment actions (write endpoints)