Convex Database Layer
Relevant source files
The following files were used as context for generating this wiki page:
The Convex Database Layer serves as the primary persistence and server-side logic tier for the Nordcom Commerce platform. It encompasses the database schema, table definitions, and server functions (queries and mutations) that manage multi-tenant data, including shops, users, and a native Content Management System (CMS).
This layer is designed for strict multi-tenancy, where a single deployment serves multiple shops. Data isolation is achieved by indexing tenant-scoped tables with a shop key (e.g., by_shop). All data interactions occur through Convex server functions, which are accessed via a typed service seam in @nordcom/commerce-db.
Sources: packages/convex/README.md:1-12, README.md:14-25, packages/convex/README.md:38-38
Architecture and Trust Tiers
The Convex layer implements a "Trust Tier" system to manage access control and identity validation for all public functions. These tiers are implemented via specific function constructors that enforce security requirements before executing business logic.
| Trust Tier | Constructor | Identity Requirement | Use Case |
|---|---|---|---|
| Tenant | tenantQuery / tenantMutation | Validated RS256 JWT | End-user actions within a specific shop. |
| Authed | authedQuery / authedMutation | Validated Identity | Customer profile management (shop-independent). |
| Server | serverQuery / serverMutation | CONVEX_SERVER_SECRET | Middleware lookups and Auth.js adapter operations. |
| System | systemQuery / systemMutation | Internal only | Crons and system reconciliation jobs. |
Sources: packages/convex/README.md:23-34
Data Access Flow
The following diagram illustrates how an application request reaches the Convex database through the service seam:
The application interacts with @nordcom/commerce-db services, which act as a proxy to Convex, providing lazy clients and identity management.
Sources: packages/db/README.md:1-10, packages/db/README.md:54-65
Data Model and Schema
The platform data model is organized into table groups, with a focus on multi-tenancy. Every document includes a public id (often a legacy ID), createdAt, and updatedAt timestamps.
Core Entities
| Table | Purpose | Key Indexes |
|---|---|---|
shops | Primary tenant record containing domain, i18n, and provider config. | by_domain, by_legacy_id |
users | Platform-wide user accounts with auth identities. | by_email, by_clerk_user_id |
shopCollaborators | Maps users to shops with specific permissions (admin, editor, etc.). | by_shop, by_shop_user |
cmsDocuments | Core CMS storage for pages, articles, and globals. | by_shop_collection |
cmsVersions | Snapshot history for CMS documents supporting draft/publish states. | by_document |
Sources: packages/convex/convex/_generated/dataModel.d.ts:21-700, packages/db/README.md:73-82
Multi-Tenant Indexing Strategy
To ensure performance and isolation, tenant-scoped tables follow a strict indexing convention:
- Primary Index: The shop key (
shopIdorshop) is always the first field in the index. - Compound Indexes: Common patterns include
[shopId, collection]for CMS data or[shopId, createdAt]for sorted lists.
Sources: packages/convex/README.md:38-38, packages/convex/convex/_generated/dataModel.d.ts:85-88
CMS Database Integration
The CMS within Convex is a specialized subsystem for managing structured content. It utilizes a versioning system that separates "Working Drafts" from "Published Snapshots."
Document Versioning State Machine
CMS content is read through cms/read functions which handle locale resolution by collapsing "locale buckets" (e.g., { 'en-US': 'Hello', 'de-DE': 'Hallo' }) into single values based on the request locale.
Sources: packages/convex/convex/cms/read.test.ts:316-360, packages/cms/README.md:46-51
Localization and Shredding
For large content fields (like rich-text body), the system uses "shredding." Instead of storing all translations in the main document, they are moved to a specialized cms_i18n table and reassembled during the read operation.
| Table | Field | Description |
|---|---|---|
cmsDocuments | data | Stores small localized buckets and non-localized data. |
cms_i18n | value | Stores large localized field values (e.g., Prosemirror docs). |
Sources: packages/convex/convex/_generated/dataModel.d.ts:44-65, packages/convex/convex/cms/read.test.ts:444-455
Media and File Storage
The database layer handles media through a combination of Convex file storage and metadata tracking in the cmsMedia and cmsMediaDerivatives tables.
- Upload: Files are stored in Convex storage, generating a
storageId. - Finalization:
cms/media:finalizeUploadrecords file metadata (MIME, size, dimensions). - Derivatives: A server-side action (using
sharp) generates frozen sizes (thumbnail,card,feature,hero).
Sources: apps/admin/src/lib/pages-editor-gate.test.tsx:431-450, packages/convex/convex/_generated/dataModel.d.ts:107-154
Summary
The Convex Database Layer provides a robust, multi-tenant foundation for Nordcom Commerce. By utilizing strict trust tiers, tenant-first indexing, and a sophisticated CMS versioning system, it ensures data isolation and high performance across many shops. The layer effectively bridges the gap between raw storage and application services through the @nordcom/commerce-db seam, maintaining type safety and security throughout the data lifecycle.
Sources: packages/convex/README.md:1-12, packages/db/README.md:54-65