Skip to main content

Blocks Controller

Path: internal/api/v1/funnels/controllers/blocks.controller.js
Service: funnelBlockService
Module: Funnels


Overview

The Blocks controller manages reusable UI components (blocks) for the funnel builder. Blocks are pre-designed sections (headers, footers, hero sections, forms, etc.) that users can save and reuse across multiple funnels and steps.

Key Capabilities

  • User Blocks: Save and manage account-specific blocks
  • Global Blocks: Manage system-wide template blocks (admin)
  • Block Library: Browse available blocks with filtering
  • Cursor Pagination: Efficient browsing of large block collections
  • Type Filtering: Filter blocks by type (header, footer, hero, etc.)

Methods

saveBlocks()

Saves a reusable block to the user's account library.

Route: POST /v1/funnels/blocks
Auth: Required (account-scoped)

Request Body

{
"blockData": {
"name": "Hero Section - Modern",
"type": "hero",
"thumbnail": "https://cdn.example.com/thumbnails/hero-modern.jpg",
"components": {
"version": "1.0",
"elements": [
{
"id": "hero-container",
"type": "container",
"settings": {
"background": "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
"padding": "80px 20px",
"textAlign": "center"
},
"children": [
{
"id": "hero-heading",
"type": "heading",
"tag": "h1",
"content": "Build Amazing Landing Pages",
"settings": {
"fontSize": "48px",
"fontWeight": "bold",
"color": "#ffffff"
}
},
{
"id": "hero-subheading",
"type": "paragraph",
"content": "Create high-converting funnels in minutes",
"settings": {
"fontSize": "20px",
"color": "#f0f0f0"
}
},
{
"id": "hero-cta",
"type": "button",
"content": "Get Started Free",
"settings": {
"backgroundColor": "#ff6b6b",
"color": "#ffffff",
"padding": "15px 40px",
"borderRadius": "5px"
}
}
]
}
]
},
"html": "<div class='hero-section'>...</div>",
"css": ".hero-section { /* styles */ }",
"tags": ["hero", "gradient", "modern"],
"category": "hero-sections"
}
}

Response

{
"success": true,
"message": "SUCCESS",
"data": {
"_id": "60d5ec49f1b2c72e8c8e4b32",
"account_id": "60d5ec49f1b2c72e8c8e4b19",
"name": "Hero Section - Modern",
"type": "hero",
"thumbnail": "https://cdn.example.com/thumbnails/hero-modern.jpg",
"components": {
/* component data */
},
"html": "<div class='hero-section'>...</div>",
"css": ".hero-section { /* styles */ }",
"tags": ["hero", "gradient", "modern"],
"category": "hero-sections",
"created_at": "2024-01-22T15:00:00Z",
"updated_at": "2024-01-22T15:00:00Z"
}
}

MongoDB Collections

CollectionOperationPurpose
funnel_blocksinsertOneCreate new user block

getBlocks()

Retrieves user's saved blocks with cursor pagination and filtering.

Route: GET /v1/funnels/blocks
Auth: Required (account-scoped)

Request Query Parameters

{
limit?: number; // Results per page (default: 20)
cursor?: string; // Cursor for pagination (ObjectId)
type?: string; // Filter by block type
}

Response

{
"success": true,
"message": "SUCCESS",
"data": {
"blocks": [
{
"_id": "60d5ec49f1b2c72e8c8e4b32",
"account_id": "60d5ec49f1b2c72e8c8e4b19",
"name": "Hero Section - Modern",
"type": "hero",
"thumbnail": "https://cdn.example.com/thumbnails/hero-modern.jpg",
"components": {
/* component data */
},
"html": "<div class='hero-section'>...</div>",
"css": ".hero-section { /* styles */ }",
"tags": ["hero", "gradient", "modern"],
"category": "hero-sections",
"created_at": "2024-01-22T15:00:00Z"
},
{
"_id": "60d5ec49f1b2c72e8c8e4b33",
"account_id": "60d5ec49f1b2c72e8c8e4b19",
"name": "Contact Form - Simple",
"type": "form",
"thumbnail": "https://cdn.example.com/thumbnails/form-simple.jpg",
"components": {
/* component data */
},
"html": "<form class='contact-form'>...</form>",
"css": ".contact-form { /* styles */ }",
"tags": ["form", "contact", "simple"],
"category": "forms",
"created_at": "2024-01-20T12:30:00Z"
}
],
"next_cursor": "60d5ec49f1b2c72e8c8e4b34",
"has_more": true,
"total": 45
}
}

MongoDB Collections

CollectionOperationPurpose
funnel_blocksfind with cursorQuery user blocks with pagination

Cursor Pagination

  • First Request: Omit cursor parameter to get first page
  • Subsequent Requests: Use next_cursor from previous response
  • Cursor Format: MongoDB ObjectId as string
  • Sorting: Blocks sorted by created_at descending (newest first)

deleteBlocks()

Deletes a user's saved block.

Route: DELETE /v1/funnels/blocks/:id
Auth: Required (account-scoped)

Request Parameters

{
id: string; // Block ID to delete
}

Response

{
"success": true,
"message": "SUCCESS"
}

MongoDB Collections

CollectionOperationPurpose
funnel_blocksdeleteOneRemove user block

saveGlobalBlocks()

Saves a block to the global template library (admin only).

Route: POST /v1/funnels/blocks/global
Auth: Required (admin permissions)

Request Body

{
"blockData": {
"name": "Premium Hero - Gradient",
"type": "hero",
"thumbnail": "https://cdn.example.com/thumbnails/premium-hero.jpg",
"components": {
/* component data */
},
"html": "<div class='premium-hero'>...</div>",
"css": ".premium-hero { /* styles */ }",
"tags": ["hero", "premium", "gradient"],
"category": "hero-sections",
"featured": true,
"premium": false
}
}

Response

{
"success": true,
"message": "SUCCESS",
"data": {
"_id": "60d5ec49f1b2c72e8c8e4b34",
"is_global": true,
"name": "Premium Hero - Gradient",
"type": "hero",
"thumbnail": "https://cdn.example.com/thumbnails/premium-hero.jpg",
"components": {
/* component data */
},
"html": "<div class='premium-hero'>...</div>",
"css": ".premium-hero { /* styles */ }",
"tags": ["hero", "premium", "gradient"],
"category": "hero-sections",
"featured": true,
"premium": false,
"created_at": "2024-01-22T16:00:00Z"
}
}

MongoDB Collections

CollectionOperationPurpose
funnel_global_blocksinsertOneCreate global block

Authorization

  • Requires admin permissions (verified in service layer)
  • Standard users cannot access this endpoint

getGlobalBlocks()

Retrieves global template blocks available to all users.

Route: GET /v1/funnels/blocks/global
Auth: Required

Request Query Parameters

{
limit?: number; // Results per page (default: 20)
page?: number; // Page number (1-indexed)
cursor?: string; // Cursor for pagination (alternative to page)
type?: string; // Filter by block type
}

Response

{
"success": true,
"message": "SUCCESS",
"data": {
"blocks": [
{
"_id": "60d5ec49f1b2c72e8c8e4b34",
"is_global": true,
"name": "Premium Hero - Gradient",
"type": "hero",
"thumbnail": "https://cdn.example.com/thumbnails/premium-hero.jpg",
"components": {
/* component data */
},
"html": "<div class='premium-hero'>...</div>",
"css": ".premium-hero { /* styles */ }",
"tags": ["hero", "premium", "gradient"],
"category": "hero-sections",
"featured": true,
"premium": false,
"created_at": "2024-01-22T16:00:00Z"
},
{
"_id": "60d5ec49f1b2c72e8c8e4b35",
"is_global": true,
"name": "Testimonial Carousel",
"type": "testimonial",
"thumbnail": "https://cdn.example.com/thumbnails/testimonial-carousel.jpg",
"components": {
/* component data */
},
"html": "<div class='testimonial-carousel'>...</div>",
"css": ".testimonial-carousel { /* styles */ }",
"tags": ["testimonial", "carousel", "social-proof"],
"category": "testimonials",
"featured": false,
"premium": true,
"created_at": "2024-01-21T10:00:00Z"
}
],
"next_cursor": "60d5ec49f1b2c72e8c8e4b36",
"has_more": true,
"total": 158
}
}

MongoDB Collections

CollectionOperationPurpose
funnel_global_blocksfind with cursorQuery global blocks

Filtering

  • Featured blocks: Prioritized in results (sorted first)
  • Premium blocks: Flagged for paid accounts
  • Type filtering: Exact match on type field
  • Search: Can be extended to support name/tag search

deleteGlobalBlocks()

Deletes a global template block (admin only).

Route: DELETE /v1/funnels/blocks/global/:id
Auth: Required (admin permissions)

Request Parameters

{
id: string; // Global block ID to delete
}

Response

{
"success": true,
"message": "SUCCESS"
}

MongoDB Collections

CollectionOperationPurpose
funnel_global_blocksdeleteOneRemove global block

Authorization

  • Requires admin permissions (verified in service layer)
  • Standard users cannot delete global blocks

Data Models

User Block Document

{
_id: ObjectId;
account_id: ObjectId; // Owner account
name: string; // Block display name
type: string; // Block type (hero, form, footer, etc.)
thumbnail?: string; // Preview image URL

// Component structure
components: {
version: string;
elements: Array<{
id: string;
type: string;
tag?: string;
content?: string;
settings: Record<string, any>;
children?: Array<any>;
}>;
};

// Rendered output
html?: string; // Compiled HTML
css?: string; // Compiled CSS

// Metadata
tags?: string[]; // Searchable tags
category?: string; // Organization category
description?: string; // Block description

// Usage tracking
use_count?: number; // Times block used
last_used_at?: Date; // Last usage timestamp

created_at: Date;
updated_at: Date;
}

Global Block Document

{
_id: ObjectId;
is_global: true; // Flag for global blocks
name: string; // Block display name
type: string; // Block type
thumbnail?: string; // Preview image URL

// Component structure (same as user blocks)
components: {
version: string;
elements: Array<any>;
};

html?: string; // Compiled HTML
css?: string; // Compiled CSS

// Metadata
tags?: string[]; // Searchable tags
category?: string; // Organization category
description?: string; // Block description

// Template flags
featured: boolean; // Show in featured section
premium: boolean; // Requires premium account

// Usage analytics
total_uses?: number; // Total times used across all accounts
popularity_score?: number; // Calculated popularity metric

created_at: Date;
updated_at: Date;
created_by?: ObjectId; // Admin user who created
}

Block Types

Common Block Types

TypeDescriptionCommon Use Cases
heroHero sectionsLanding page headers, above-the-fold content
formForm sectionsLead capture, contact forms, checkout
testimonialTestimonial displaysSocial proof, customer reviews
pricingPricing tablesProduct pricing, plan comparison
featuresFeature showcasesProduct features, benefits
ctaCall-to-action sectionsConversion-focused sections
footerPage footersNavigation, legal links, contact info
headerPage headersNavigation bars, top sections
galleryImage galleriesProduct images, portfolio
videoVideo embedsYouTube, Vimeo, custom video
faqFAQ sectionsQ&A, accordion content
teamTeam member displaysAbout page, team showcase
contactContact sectionsContact info, maps, forms
countdownCountdown timersLimited offers, event countdowns

Business Logic & Workflows

Block Save Flow

sequenceDiagram
participant User
participant Controller
participant Service
participant Database

User->>Controller: POST /blocks (saveBlocks)
Controller->>Service: saveBlocks()
Service->>Database: Check duplicate name

alt Name Available
Service->>Service: Process component structure
Service->>Service: Generate HTML/CSS
Service->>Database: Insert block document
Database-->>Service: Block created
Service-->>Controller: Block data
Controller-->>User: 200 OK + block
else Name Exists
Service-->>Controller: Duplicate name error
Controller-->>User: 400 Bad Request
end

Block Usage Flow

sequenceDiagram
participant Builder
participant Blocks
participant Funnel
participant Database

Builder->>Blocks: GET /blocks (user + global)
Blocks->>Database: Query user blocks
Blocks->>Database: Query global blocks
Database-->>Blocks: Block collections
Blocks-->>Builder: Combined block list

Builder->>Builder: User selects block
Builder->>Funnel: Add block to step
Funnel->>Database: Save step with block components
Funnel->>Blocks: Increment block use_count
Database-->>Funnel: Step saved
Funnel-->>Builder: Success

Performance Considerations

Cursor Pagination

  • More efficient than offset pagination for large datasets
  • Uses _id field as cursor (always indexed)
  • Prevents page drift as data changes
  • No expensive COUNT queries required

Query Optimization

  • Indexed fields: account_id, type, created_at, is_global
  • Compound indexes: (account_id, type), (is_global, featured, type)
  • Thumbnail URLs: Served via CDN for fast loading

Caching Strategy

  • Global blocks: Cached for 1 hour (rarely change)
  • User blocks: No caching (frequently modified)
  • Thumbnail images: CDN cached with long TTL

Integration Points

Funnel Builder

  • Purpose: Drag-and-drop block insertion into funnel steps
  • Integration: Blocks provide component JSON for builder
  • Workflow: User selects block → Components copied to step

CDN/Asset Storage

  • Purpose: Store and serve block thumbnails
  • Integration: Thumbnail URLs point to CDN
  • Upload: Admin uploads thumbnails to CDN, stores URL

Template Marketplace

  • Purpose: Browse and purchase premium blocks
  • Integration: Global blocks with premium: true flag
  • Monetization: Premium blocks require subscription

Security

Multi-Tenant Isolation

  • User blocks: Always filtered by account_id
  • Global blocks: Accessible to all authenticated users
  • Delete operations: Verify account ownership

Authorization

  • User blocks: Any authenticated user
  • Global blocks (read): Any authenticated user
  • Global blocks (write/delete): Admin only

Input Validation

  • Component structure validation (prevent XSS)
  • HTML sanitization for user-provided content
  • CSS validation (prevent malicious styles)

Error Handling

Common Errors

// Block not found
{
"success": false,
"message": "Block not found",
"statusCode": 404
}

// Duplicate block name
{
"success": false,
"message": "Block with this name already exists",
"statusCode": 409
}

// Invalid block type
{
"success": false,
"message": "Invalid block type",
"statusCode": 400
}

// Unauthorized (global block operations)
{
"success": false,
"message": "Admin permissions required",
"statusCode": 403
}

Best Practices

When to Use This Controller

  • ✅ Building drag-and-drop page builders
  • ✅ Creating template marketplaces
  • ✅ Implementing reusable component libraries
  • ✅ Providing pre-designed sections

Common Patterns

  1. Combine user + global blocks: Merge both collections for complete library
  2. Type-based filtering: Allow users to filter by block type
  3. Preview images: Always include thumbnails for visual selection
  4. Version components: Use component version for backward compatibility

Edge Cases

  • Large block libraries: Use cursor pagination for performance
  • Deleted blocks in use: Blocks used in funnels remain even if deleted from library
  • Premium blocks: Check account subscription before allowing usage
  • Duplicate names: Allow duplicates between user blocks and global blocks

  • Funnels Controller: Using blocks in funnel steps
  • Global Templates Controller: Template management
  • Builder Components: Component structure specification
  • Asset Management: Thumbnail upload and CDN integration

Last Updated: January 2025
API Version: v1
Maintained By: DashClicks Engineering

💬

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:31 AM