Workspace Templates & Cloning — Chat Prompts
If your B2B SaaS lets users create projects, workspaces, documents, dashboards, or any structured collection — eventually a customer will say "I want to start a new one that looks like the last one." Then: "I want to share a template with my team." Then: "I want to publish a template to your community for others." Templates are how users avoid recreating structure from scratch — and how power-users + agencies + consultants spread best practices.
The naive shape: "Duplicate" button on a project. Works for v1. Doesn't survive once templates need to be shared across users, contain references that should be reset (dates, assignees, statuses), have public/private modes, support placeholders ({{client_name}}), or distinguish between the structure (fields, sections) vs. the content (sample values).
A real template system handles: cloning vs templating (different operations), template metadata + categorization, sharing modes (private / workspace / public), placeholder substitution, reference handling (reset assignees, dates), nested resource preservation, version control, attribution, and a marketplace if scaled. Linear's template gallery, Notion's template directory, ClickUp templates, Airtable Universe — every modern collaborative SaaS ships this; it's table stakes for sticky workflows.
This chat walks through implementing a real template + cloning system: data model, cloning semantics, template metadata, sharing + permissions, placeholder substitution, marketplace patterns, and operational realities.
What you're building
- Cloning of resources (project, workspace, document, dashboard, etc.)
- Template definitions distinct from clones (templates are first-class objects)
- Template metadata (name, description, preview, category, author)
- Sharing modes (private / workspace / public)
- Placeholder substitution ({{client_name}}, etc.)
- Reference handling (reset / preserve / remap)
- Template gallery / browse UI
- "Use this template" creation flow
- Marketplace patterns (if public)
- Operational concerns (versioning, abuse, attribution)
1. Decide cloning vs templating
First decision: clone or template? They look similar but are different.
CLONING (instance copy)
- Take resource X; produce X' that's an independent copy
- All fields copied; reference IDs new
- One-time operation
- No ongoing relationship between X and X'
- Use case: "duplicate this project for next quarter"
TEMPLATING (reusable pattern)
- Take resource X; mark/save it as a "template"
- Template is a first-class object (separate from regular resources)
- Many users can spawn copies from the template
- Optional: template can be updated; existing instances NOT affected
- Use case: "save this as a template; let my team start projects from it"
Both are valuable. Most products ship cloning first; add templating when users ask "can I share this?"
Three increasingly-deep shapes:
LEVEL 1: CLONE ONLY (the simplest start)
- "Duplicate" button on a resource
- One-shot copy; no template object
- Pros: ships in 1-2 weeks
- Cons: no sharing; no metadata; no marketplace
LEVEL 2: WORKSPACE-PRIVATE TEMPLATES
- Save as template (creates a separate template object)
- Template stays in workspace; team members can use
- Template metadata (name, description, preview)
- Pros: 4-6 weeks; high-leverage for teams
- Cons: no public templates yet
LEVEL 3: PUBLIC TEMPLATE GALLERY
- Templates can be published to public gallery
- Categorized; searchable; rated
- Author attribution; usage analytics
- Pros: marketing channel; viral
- Cons: 12-24 weeks; abuse / quality moderation; ongoing curation
LEVEL 4: TEMPLATE MARKETPLACE
- Level 3 + paid templates / monetization
- Author payouts; revenue share
- Curation team
- Pros: ecosystem play
- Cons: massive ongoing engineering; rare in B2B SaaS
DEFAULT FOR MOST B2B SaaS:
- Year 1: Level 1 (clone only)
- Year 2: Level 2 (workspace templates)
- Year 3+: Level 3 (public gallery) IF community pull justifies
- Don't pre-build Level 4 without specific buyer
Output: scope decision; explicit boundary.
Output: scope statement; what's in v1 and what's not.
2. Design the data model
Schema for templates:
If just cloning (Level 1): no new schema needed. The "duplicate" function reads the source resource + creates new rows.
For Level 2+ (templating):
templates (
id uuid pk
workspace_id uuid -- nullable for global / public templates
resource_type text -- 'project', 'workspace', 'document', 'dashboard'
name text not null
description text
preview_image_url text
category text -- 'engineering', 'marketing', 'sales', etc.
tags text[]
visibility text -- 'private' | 'workspace' | 'public'
status text -- 'draft' | 'published' | 'archived'
source_resource_id uuid -- the resource this template was created from (snapshot)
template_data jsonb -- full structured snapshot of the resource
schema_version int -- for migrations as resource shape evolves
author_user_id uuid
workspace_owner uuid -- which workspace owns this template
created_at timestamptz
updated_at timestamptz
published_at timestamptz
use_count bigint default 0 -- denormalized counter
star_count int default 0
)
UNIQUE INDEX (workspace_id, name) WHERE visibility = 'workspace'
INDEX (visibility, category) WHERE status = 'published'
template_uses (
id uuid pk
template_id uuid not null
used_by uuid not null -- user
workspace_id uuid not null
created_resource_id uuid -- the new resource created from template
used_at timestamptz
)
template_stars (
user_id uuid
template_id uuid
starred_at timestamptz
PRIMARY KEY (user_id, template_id)
)
Why store template_data as snapshot JSONB (rather than reference source):
- Templates need to be stable; source can change/delete
- Use is read-only; performance better with snapshot
- Template versioning easier
- Can re-export later if needed
template_data shape (varies by resource_type):
For a project template:
{
"schema_version": 1,
"resource_type": "project",
"fields": {
"name": "Project name placeholder", // PLACEHOLDER text
"description": "Default description",
"color": "blue",
"starts_at": null, // RESET ON USE
},
"sections": [
{ "id": "section1", "name": "To Do", "order": 0 },
{ "id": "section2", "name": "In Progress", "order": 1 },
{ "id": "section3", "name": "Done", "order": 2 }
],
"tasks": [
{
"id": "task1",
"title": "Kickoff meeting",
"section": "section1",
"assignee": null, // RESET ON USE
"due_date": null, // RESET (or relative-to-creation)
"priority": "high",
"tags": ["meeting"]
},
// ... more
],
"settings": { ... },
"placeholders": [
{ "key": "client_name", "label": "Client Name", "default": "Acme Corp" },
{ "key": "start_date", "label": "Start Date", "type": "date" }
]
}
Placeholder substitution:
- Template-creator marks fields as {{placeholder_name}}
- On use: prompt user for values; substitute throughout
- Preserves cloning ergonomics
Implement:
1. Migration for templates + uses + stars tables
2. JSONB validation per resource_type
3. RLS / multi-tenancy
4. Indexes for browse + search
5. Snapshot vs reference design decision documented
Output: schema that supports the operations.
3. Implement clone (Level 1)
Cloning is the simpler operation. Get this right first.
Clone semantics — the hard decisions:
1. New IDs everywhere (don't reuse source IDs)
2. References within the cloned resource: REMAP to new IDs
3. References OUTSIDE the cloned resource: PRESERVE (link to original) or RESET (don't link)
4. Owner / creator: CHANGE to user doing the clone
5. Created/updated timestamps: NEW (clone time, not source time)
6. State that should reset:
- Status (e.g., done → not done)
- Assignees (often reset)
- Comments (often NOT cloned)
- Activity log (NOT cloned)
- View counts / metrics (NOT cloned)
7. State that should preserve:
- Title (often + " (copy)")
- Description
- Structure / configuration
- Custom fields (cloned with empty values, OR with default values, OR with source values)
Implementation pattern:
async function cloneProject(sourceId: string, userId: string, workspaceId: string): Promise<Project> {
const source = await db.projects.findById(sourceId)
if (!await canRead(userId, source)) throw new PermissionError()
// Create new project
const newProject = await db.projects.create({
workspace_id: workspaceId,
name: source.name + ' (copy)',
description: source.description,
color: source.color,
created_by: userId,
status: 'active', // RESET; don't inherit source status
})
// Build ID remap table for references within
const idMap = new Map<string, string>()
// Clone sections (preserving order; new IDs)
const sourceSections = await db.sections.findByProjectId(sourceId)
for (const s of sourceSections) {
const newSection = await db.sections.create({
project_id: newProject.id,
name: s.name,
order: s.order,
})
idMap.set(s.id, newSection.id)
}
// Clone tasks
const sourceTasks = await db.tasks.findByProjectId(sourceId)
for (const t of sourceTasks) {
await db.tasks.create({
project_id: newProject.id,
section_id: idMap.get(t.section_id), // REMAP
title: t.title,
description: t.description,
priority: t.priority,
// NULLED fields
assignee_id: null, // RESET
status: 'todo', // RESET
due_date: null, // RESET
// ... handle custom fields, attachments, etc.
})
}
// Skip: comments, activity, attachments (with caveats), references, etc.
return newProject
}
Handle nested resources:
- Each nested type has its own clone logic
- Use a clone-strategy pattern (each resource type defines what to copy / reset)
Handle large projects (1000s of tasks):
- Background job for clones > 100 items
- Show progress to user
- Use bulk INSERT for performance
Handle permissions:
- Source resource: read access required to clone
- Target workspace: create access required
- Don't clone if user can't access EVERYTHING in source (e.g., private sections)
Handle attachments / files:
- Decision: clone the underlying file (storage cost) OR reference (cheaper but breaks if source deleted)
- Default: copy files for full independence (most reliable)
Implement:
1. Per-resource clone strategies
2. ID remapping
3. Nullification of state-fields
4. Background job for large clones
5. Permission checks
6. UI: "Duplicate" button + progress feedback
Output: cloning that works for the common case.
4. Implement template creation (Level 2)
Templates are NOT just snapshots. They have placeholders, metadata, and reusability.
Template-creation flow:
1. User opens a project
2. Clicks "Save as Template"
3. Modal:
- Template name (default: "[Project name] Template")
- Description (encourage: "When to use this template")
- Visibility (Private / Workspace / Public if eligible)
- Category (dropdown)
- Tags
- Preview (auto-generated; user can replace)
4. Optional: configure placeholders
- Tap on a field → "Make this a placeholder"
- Define placeholder key + label
- Set default value
5. Confirm + save
What gets stored:
- Snapshot of structure (sections, tasks, fields)
- All TEXT fields scanned for placeholder syntax
- Placeholders extracted to a separate list
- Metadata (name, description, etc.)
Placeholder syntax (recommend Mustache / Handlebars-style):
"{{client_name}} Q1 2026 Project Plan"
In template_data:
{
"fields": {
"name": "{{client_name}} Q1 2026 Project Plan",
},
"placeholders": [
{ "key": "client_name", "label": "Client Name", "default": "Acme" }
]
}
When a user uses the template:
1. User clicks "Use this template"
2. Modal asks for placeholder values
3. Server substitutes placeholders throughout template_data
4. Server creates new resource with substituted data (similar to clone)
5. User lands on new resource
Reset rules (similar to clone):
- Assignees: reset to null OR map to {{template_creator}} = user doing the use
- Dates: reset OR offset relative to creation date
- Statuses: reset to default
- Custom fields: include OR exclude based on template-creator choice
Updating templates:
- Templates can be updated (new version)
- Existing resources created from template are NOT auto-updated
- New uses get the latest version
- Optional: version history; users can pin to specific version
Implement:
1. "Save as template" UI
2. Placeholder definition UX (mark fields; define key + label)
3. Template snapshot creation
4. "Use this template" flow with placeholder prompts
5. Substitution logic (Handlebars or simple regex)
6. Reset rules per resource type
7. Template update / versioning
Output: a template system users can create, share, and use.
5. Build the gallery UI
For Level 2+ (templates), build a gallery so users can browse + use.
Gallery routes:
- /templates — main browse page
- /templates/[id] — template detail page
- /templates/categories/[category] — filtered
Browse page:
Layout:
- Filter sidebar: Category, Tags, Sort by (popular / new / starred)
- Search bar
- Grid of template cards:
- Preview image
- Name
- Description (truncated)
- Author name + avatar
- Use count + star count
- "Use template" button
- Pagination
Detail page:
- Full preview (rendered template structure)
- Author bio
- Description (long form)
- Tags + category
- Use count + stars
- Reviews / comments (if enabled)
- "Use template" CTA
- "Star" button
- Share button (copy link)
For workspace-private templates:
- Workspace-only browse view (under /settings/templates or /templates/workspace)
- Separate from public
For public templates (Level 3):
- Available at /community/templates or /gallery
- Indexed for SEO
- Shareable via link
Permissions:
- Anyone can VIEW public templates
- Only authenticated users can USE
- Only template author + admins can EDIT
- Workspace admins can curate workspace template list
Implement:
1. Browse page with filters + search
2. Detail page
3. Card components
4. Permissions enforcement
5. SEO (for public gallery)
6. Sharing (copy link; per-template URL)
Output: discovery UX that drives template adoption.
6. Operational + abuse handling
Public templates require moderation.
Abuse vectors:
- Spam templates (low-quality; misleading)
- Malicious placeholder values (XSS; injection)
- Copyright violations
- Inappropriate content
- Misleading claims ("get 100K customers in 30 days")
Moderation:
Pre-publication (for public visibility):
- Author flag: "Submit for review"
- Manual review queue (for v1; automate when scale demands)
- Auto-checks: text screening, image moderation
- Approval before publication
Post-publication:
- Report button on every public template
- Reports trigger review
- Quick-remove for clear violations
- Audit log of moderation actions
Author reputation:
- New authors: review-required
- Trusted authors: auto-publish
- Reputation: built from non-flagged templates + community engagement
- Sanctions: reduce reputation on flags; ban on egregious violations
Quality signals:
- Star count
- Use count
- Conversion (use → keep using)
- Review average
- Bounce rate (used and immediately deleted)
Curation:
- Featured templates
- Category leaderboards
- Editor's picks
- Seasonal collections
Attribution + IP:
- Author retains attribution; doesn't forfeit IP
- Workspace customers' DATA isn't in templates (templates are STRUCTURE only)
- Clear ToS that templates are for reuse / sharing
Implement:
1. Reporting + moderation queue
2. Author reputation system
3. Manual moderation UI
4. Auto-checks (XSS, profanity, image)
5. Featured / curated templates
6. Attribution display
7. ToS / publishing agreement
Output: a public gallery that doesn't become a spam wasteland.
7. Edge cases + operational realities
Walk me through:
1. Template references workspace-specific data (e.g., specific user, custom field, integration)
- Template uses placeholder for user (substitute on use)
- Custom fields: prompt user to map source fields to target workspace fields
- Integrations: don't include in template; user must reconnect after use
2. Source resource deleted; templates derived from it
- Templates are independent (snapshot); not affected
- Continue to use templates
3. Template uses a feature that's removed from product
- Mark template as "deprecated"
- Users get warning when trying to use
- Migration path: tell author to update
4. Schema evolves; old templates don't match
- Templates store schema_version
- Migration on use: transform old → new schema
- Or: deprecate old templates beyond N versions
5. Public template later contains private/sensitive info (oversight by author)
- Author can edit + republish
- Old uses NOT affected
- Important: private workspace data should NEVER be in templates (workspace customer data isn't shipped in templates)
6. Use template across workspaces (e.g., agency uses same template for multiple clients)
- "Use template" creates fresh resource in chosen workspace
- Each use gets new IDs; independent
7. Template massive (10,000 tasks); use takes minutes
- Background job for use; show progress
- Email when done
8. Workspace deleted; templates owned by workspace
- Cascade-delete templates (or transfer to admin user)
- Public templates: special handling (often retain or transfer ownership)
9. User publishes template; later wants to remove
- Allow removal
- Existing uses are NOT affected (snapshots)
- Template archived (not deleted; for moderation history)
10. Template marketplace: paid templates
- Stripe integration
- Author revenue share (typical: 70-80% to author; 20-30% to platform)
- Refund policy
- Tax handling
11. Organization has many similar templates
- Template "folders" or categories within workspace
- Search within workspace
- Bulk template operations
12. SEO-driven public gallery
- Per-template URL with metadata
- Sitemap
- Schema markup (e.g., schema.org/SoftwareApplication or HowTo)
For each: code change + UX impact + ops consideration.
Output: operational maturity.
8. Recap
What you've built:
- Cloning of resources (Level 1)
- Workspace-private templates (Level 2)
- Public template gallery (Level 3; if applicable)
- Placeholder substitution
- Reset rules for state fields
- Browse + search + detail UI
- Permissions + visibility
- Moderation + reporting
- Author attribution + reputation
- Versioning + schema migration
- Edge cases handled
What you're explicitly NOT shipping in v1:
- Paid template marketplace (Level 4; defer)
- Cross-workspace template sharing (private to author / workspace only)
- Template forking / collaborative editing (defer)
- Template AI generation (e.g. "generate a template for X") (defer; could be cool)
- Template-as-API (programmatic use) (defer)
Ship Level 1 in 2 weeks; Level 2 in 4-6 weeks; Level 3 in 12-24 weeks if community demand justifies.
The biggest mistake teams make: shipping public template gallery without moderation infrastructure. Spam templates damage product trust quickly.
The second mistake: not handling references properly. Templates with broken references (missing users, deleted custom fields) frustrate users.
The third mistake: not using placeholders. Templates without placeholders are basically clones; users have to manually edit each instance. Placeholders are the high-value pattern.
See Also
- Custom Fields & Schema Extensibility — pairs (templates may include custom-field definitions)
- Bulk Operations — adjacent (template use is a bulk-create)
- CSV Import — adjacent import pattern
- Workspace Branding & Custom Domains — pairs for white-label templates
- Roles & Permissions — pairs for template visibility
- Multi-Tenancy — pairs for workspace-scoped templates
- Public Share Links & Permissioned Sharing — adjacent share pattern
- Tags & Labels System — adjacent (categorize templates)
- Search — pairs for template search
- Database Migrations — depended-upon
- Schema Validation Zod — depended-upon
- Background Jobs & Queue Management — pairs for large clone / use jobs
- Programmatic SEO — adjacent (public gallery is SEO surface)
- SEO Setup — adjacent
- Activity Feed & Timeline — adjacent (template uses are events)
- Audit Logs — pairs for template + clone audits
- Account Deletion & Data Export — adjacent (template ownership on workspace delete)