Template System
Technical documentation for the module template and reset system
This document covers the technical implementation of module templates, installation, customization detection, and the reset mechanism.
Core Concepts
VendorManaged Flag
Every field, view, and reference has a VendorManaged boolean flag that indicates whether it came from a template or was created by the user.
| VendorManaged | Meaning | Reset Behavior |
|---|---|---|
true | Created by template installation | Reset will restore to template default |
false | Created by user | Never modified by reset |
This separation allows reset to restore template items without touching user customizations.
Template vs. Installed Schema
When a template is installed, Coherence stores:
- Template definition - The original schema in the template catalog
- Installed schema - The current state in the workspace
Reset compares these to identify what changed.
Customization Detection
How hasCustomizations Works
The marketplace shows "Reset to default" only when hasCustomizations: true. This is computed by comparing:
Template Definition:
{
fields: ["first_name", "last_name", "email", "phone"],
views: ["list", "detail"],
references: ["account_id"]
}Installed Schema (VendorManaged only):
{
fields: ["first_name", "last_name", "email"], // phone removed
views: ["list"], // detail removed
references: ["account_id"]
}If any difference exists, hasCustomizations = true.
Query Logic
Only vendor-managed items are compared:
-- Get installed vendor-managed fields
SELECT DISTINCT "ModuleId", "Slug"
FROM "ModuleField"
WHERE "ModuleId" = ? AND "VendorManaged" = true;
-- Get installed vendor-managed views
SELECT DISTINCT "ModuleId", "Slug"
FROM "ModuleView"
WHERE "ModuleId" = ? AND "VendorManaged" = true;
-- Get installed vendor-managed references
SELECT DISTINCT "SourceModuleId" as "ModuleId", "Slug"
FROM "ModuleReference"
WHERE "SourceModuleId" = ? AND "VendorManaged" = true;User-created items (VendorManaged = false) are ignored in the comparison because they're intentional additions, not deviations from the template.
Reset Process
Overview
Reset performs three operations:
- Delete - Remove vendor-managed items not in template
- Update - Restore vendor-managed items to template config
- Insert - Add template items that were deleted
User-created items are never touched.
Config Merging
Field configurations contain both static settings (type, label, options) and runtime state (auto-number sequences, formula caches). Reset uses a merge strategy:
// Template provides defaults
const templateConfig = { prefix: "PER-", padLength: 4 };
// Existing config has runtime state
const existingConfig = { prefix: "PER-", padLength: 4, nextValue: 157 };
// Merge: template defaults + existing overrides
const mergedConfig = { ...templateConfig, ...existingConfig };
// Result: { prefix: "PER-", padLength: 4, nextValue: 157 }This preserves:
- Auto-number
nextValuesequences - Formula calculation caches
- Any runtime state in the Config column
Reset Response
The reset endpoint returns a summary:
interface ResetResult {
fieldsRemoved: number; // User modifications to template fields
fieldsAdded: number; // Template fields that were deleted
viewsAdded: number; // Template views that were deleted
referencesAdded: number; // Template references that were deleted
}Database Schema
Module Table
CREATE TABLE "Module" (
"ModuleId" UUID PRIMARY KEY,
"AccountId" UUID NOT NULL,
"Slug" VARCHAR(255) NOT NULL,
"VendorManaged" BOOLEAN DEFAULT false,
"TemplateSlug" VARCHAR(255), -- Source template identifier
"TemplateVersion" VARCHAR(50), -- Installed template version
...
);ModuleField Table
CREATE TABLE "ModuleField" (
"ModuleFieldId" UUID PRIMARY KEY,
"ModuleId" UUID NOT NULL,
"Slug" VARCHAR(255) NOT NULL,
"Type" VARCHAR(50) NOT NULL,
"Config" JSONB, -- Type-specific configuration
"VendorManaged" BOOLEAN DEFAULT false,
...
);ModuleView Table
CREATE TABLE "ModuleView" (
"ModuleViewId" UUID PRIMARY KEY,
"ModuleId" UUID NOT NULL,
"Slug" VARCHAR(255) NOT NULL,
"Type" VARCHAR(50) NOT NULL,
"Config" JSONB,
"VendorManaged" BOOLEAN DEFAULT false,
...
);ModuleReference Table
CREATE TABLE "ModuleReference" (
"ModuleReferenceId" UUID PRIMARY KEY,
"SourceModuleId" UUID NOT NULL,
"TargetModuleId" UUID NOT NULL,
"Slug" VARCHAR(255) NOT NULL,
"VendorManaged" BOOLEAN DEFAULT false,
...
);API Endpoints
List Template Catalog
GET /api/templates/catalog
Returns available templates with installation status:
{
"templates": [
{
"templateSlug": "people",
"name": "People",
"description": "Track individuals...",
"templateVersion": "1.0.0",
"installed": true,
"installedModuleId": "mod_abc123",
"hasCustomizations": true
}
]
}Reset to Template
POST /api/modules/:moduleId/reset-to-template
Resets the module schema to match the template definition.
Response:
{
"success": true,
"fieldsRemoved": 2,
"fieldsAdded": 1,
"viewsAdded": 1,
"referencesAdded": 0
}Auto-Number Fields
Sequence Preservation
Auto-number fields store their sequence counter in the Config column:
{
"prefix": "PER-",
"padLength": 4,
"nextValue": 157
}Reset preserves nextValue through config merging, so existing records keep their numbers and new records continue the sequence.
Backfill Feature
To regenerate numbers for existing records:
PATCH /api/modules/:moduleId/fields/:fieldId
{
"backfillExisting": true
}This assigns sequential numbers to all records missing a value, starting from nextValue.
Implementation Files
| File | Purpose |
|---|---|
services/module-config/src/services/template-catalog-service.ts | Catalog listing and hasCustomizations |
services/module-config/src/services/workspace-bootstrap-service.ts | Reset and installation logic |
packages/sdk/src/types.ts | TypeScript types for templates |
apps/web/src/pages/AddonsMarketplacePage.tsx | Marketplace UI |
Related: API Overview | Module Templates