Skip to content

feat: implement organization-scoped custom templates#403

Merged
bradtaylorsf merged 4 commits into
stagingfrom
fix/template-organization-scoping-and-security
Jul 19, 2025
Merged

feat: implement organization-scoped custom templates#403
bradtaylorsf merged 4 commits into
stagingfrom
fix/template-organization-scoping-and-security

Conversation

@diecoscai
Copy link
Copy Markdown

Overview

This comprehensive update addresses GitHub issue #391 and Jira ticket AAI-487 by implementing multi-tenant template
management with proper organization scoping and critical security fixes.

🆕 New Features

Multi-Tenant Template System

  • Organization Scoping: Templates now belong to specific organizations
  • Template Sharing: Option to share templates within organization
  • Template Lineage: Track parent-child relationships and template origins
  • Answer Agent Framework: Added support for Answer Agent framework detection

Enhanced UI Experience

  • Organization Templates Tab: New tab showing organization-shared templates
  • Template Segregation: Answer Agent templates filtered from Example Templates
  • Share Toggle: UI option to share templates with organization members
  • Improved Template Export: Better framework detection and metadata handling

🔧 Database Schema Updates

New Migrations

  • AddOrganizationToCustomTemplate: Adds organization and user scoping
  • AddParentIdToCustomTemplate: Enables template lineage tracking
  • AddTemplateIdToChatFlow: Links chatflows to their template origins

Enhanced Entities

  • CustomTemplate: Added userId, organizationId, shareWithOrg, parentId fields
  • ChatFlow: Added templateId field for template tracking
  • Soft Delete: Implemented for data integrity and audit trails

🛡️ Critical Security Fixes

Authentication & Authorization

  • Mandatory Authentication: All marketplace endpoints now require authentication
  • Ownership Validation: Proper user/organization ownership checks
  • Permission System: Role-based access control for templates

Chatflow Deletion Security

  • Authorization Logic: Fixed flawed permission checking in deleteChatflow
  • Route Security: Removed vulnerable DELETE pattern allowing deletion without ID
  • Transaction Safety: Wrapped deletion operations in database transactions

Migration Resilience

  • No-Organization Handling: Migration handles environments without organizations
  • System Templates: Orphaned templates become system-wide instead of failing

🎯 API Improvements

New Endpoints

  • GET /marketplaces/organization: Retrieve organization-shared templates
  • Enhanced marketplace endpoints with proper authentication middleware

Enhanced Services

  • Template Service: Improved filtering, validation, and framework detection
  • Chatflow Service: Better authorization and cleanup procedures
  • Error Handling: Consistent error responses and proper status codes

📊 Frontend Enhancements

Template Management

  • Filtered Views: Answer Agent templates excluded from Example Templates
  • Organization Tab: Dedicated view for organization-shared templates
  • Enhanced Metadata: Better template information display and searching

User Experience

  • Template Sharing: Easy organization sharing toggle
  • Framework Detection: Automatic framework classification
  • Improved Navigation: Better template organization and discovery

🔍 Technical Details

Framework Detection

  • Automatic detection of Answer Agent templates based on MCP Tools usage
  • Enhanced framework categorization (Langchain, LlamaIndex, Answer Agent)
  • Better template metadata extraction and processing

Data Integrity

  • Soft delete implementation across all related entities
  • Proper cleanup of chatflow dependencies (messages, feedback, history)
  • Transaction-safe operations with rollback capabilities

Performance Optimizations

  • Efficient query patterns with proper indexing
  • Optimized filtering and search operations
  • Reduced database roundtrips through better query design

🚀 New MCP Sidekick Templates

  • Answer Agent MCP Sidekick
  • BraveSearch MCP Sidekick
  • Confluence MCP Sidekick
  • Contentful MCP Sidekick
  • Jira MCP Sidekick
  • PostgreSQL MCP Sidekick
  • Salesforce MCP Sidekick
  • Slack MCP Sidekick
  • YouTube MCP Sidekick

Fixes: #391
Jira: AAI-487

…rovements

This comprehensive update addresses GitHub issue #391 and Jira ticket AAI-487 by implementing multi-tenant template management with proper organization scoping and critical security fixes.

## 🆕 New Features

### Multi-Tenant Template System
- **Organization Scoping**: Templates now belong to specific organizations
- **Template Sharing**: Option to share templates within organization
- **Template Lineage**: Track parent-child relationships and template origins
- **Answer Agent Framework**: Added support for Answer Agent framework detection

### Enhanced UI Experience
- **Organization Templates Tab**: New tab showing organization-shared templates
- **Template Segregation**: Answer Agent templates filtered from Example Templates
- **Share Toggle**: UI option to share templates with organization members
- **Improved Template Export**: Better framework detection and metadata handling

## 🔧 Database Schema Updates

### New Migrations
- `AddOrganizationToCustomTemplate`: Adds organization and user scoping
- `AddParentIdToCustomTemplate`: Enables template lineage tracking
- `AddTemplateIdToChatFlow`: Links chatflows to their template origins

### Enhanced Entities
- **CustomTemplate**: Added userId, organizationId, shareWithOrg, parentId fields
- **ChatFlow**: Added templateId field for template tracking
- **Soft Delete**: Implemented for data integrity and audit trails

## 🛡️ Critical Security Fixes

### Authentication & Authorization
- **Mandatory Authentication**: All marketplace endpoints now require authentication
- **Ownership Validation**: Proper user/organization ownership checks
- **Permission System**: Role-based access control for templates

### Chatflow Deletion Security
- **Authorization Logic**: Fixed flawed permission checking in deleteChatflow
- **Route Security**: Removed vulnerable DELETE pattern allowing deletion without ID
- **Transaction Safety**: Wrapped deletion operations in database transactions

### Migration Resilience
- **No-Organization Handling**: Migration handles environments without organizations
- **System Templates**: Orphaned templates become system-wide instead of failing

## 🎯 API Improvements

### New Endpoints
- `GET /marketplaces/organization`: Retrieve organization-shared templates
- Enhanced marketplace endpoints with proper authentication middleware

### Enhanced Services
- **Template Service**: Improved filtering, validation, and framework detection
- **Chatflow Service**: Better authorization and cleanup procedures
- **Error Handling**: Consistent error responses and proper status codes

## 📊 Frontend Enhancements

### Template Management
- **Filtered Views**: Answer Agent templates excluded from Example Templates
- **Organization Tab**: Dedicated view for organization-shared templates
- **Enhanced Metadata**: Better template information display and searching

### User Experience
- **Template Sharing**: Easy organization sharing toggle
- **Framework Detection**: Automatic framework classification
- **Improved Navigation**: Better template organization and discovery

## 🔍 Technical Details

### Framework Detection
- Automatic detection of Answer Agent templates based on MCP Tools usage
- Enhanced framework categorization (Langchain, LlamaIndex, Answer Agent)
- Better template metadata extraction and processing

### Data Integrity
- Soft delete implementation across all related entities
- Proper cleanup of chatflow dependencies (messages, feedback, history)
- Transaction-safe operations with rollback capabilities

### Performance Optimizations
- Efficient query patterns with proper indexing
- Optimized filtering and search operations
- Reduced database roundtrips through better query design

## 🚀 New MCP Sidekick Templates
- Answer Agent MCP Sidekick
- BraveSearch MCP Sidekick
- Confluence MCP Sidekick
- Contentful MCP Sidekick
- Jira MCP Sidekick
- PostgreSQL MCP Sidekick
- Salesforce MCP Sidekick
- Slack MCP Sidekick
- YouTube MCP Sidekick

Fixes: #391
Jira: AAI-487
@vercel
Copy link
Copy Markdown

vercel Bot commented Jul 18, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
answerai-docs ✅ Ready (Inspect) Visit Preview Jul 18, 2025 1:51pm
the-answerai ✅ Ready (Inspect) Visit Preview Jul 18, 2025 1:51pm

@diecoscai diecoscai self-assigned this Jul 18, 2025

// DELETE
router.delete(['/', '/:id'], enforceAbility('ChatFlow'), chatflowsController.deleteChatflow)
router.delete('/:id', enforceAbility('ChatFlow'), chatflowsController.deleteChatflow)

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs authorization, but is not rate-limited.

Copilot Autofix

AI 11 months ago

The best way to fix this issue is to integrate a rate-limiting middleware into the Express application. Using a library like express-rate-limit allows us to limit the number of requests a user can make to the DELETE endpoint within a specified time window. This protects the server from potential DoS attacks while maintaining normal functionality for legitimate users.

To implement this:

  1. Install the express-rate-limit package if not already installed.
  2. Define a rate limiter configuration with an appropriate maximum request limit and time window.
  3. Apply this rate limiter to the DELETE route (router.delete('/:id')).
  4. Ensure the change does not disrupt existing functionality.
Suggested changeset 1
packages/server/src/routes/chatflows/index.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/server/src/routes/chatflows/index.ts b/packages/server/src/routes/chatflows/index.ts
--- a/packages/server/src/routes/chatflows/index.ts
+++ b/packages/server/src/routes/chatflows/index.ts
@@ -1,8 +1,16 @@
 import express from 'express'
 import chatflowsController from '../../controllers/chatflows'
 import enforceAbility from '../../middlewares/authentication/enforceAbility'
+import rateLimit from 'express-rate-limit' // Import express-rate-limit
 const router = express.Router()
 
+// Rate limiter for DELETE requests
+const deleteRateLimiter = rateLimit({
+    windowMs: 15 * 60 * 1000, // 15 minutes
+    max: 100, // Limit each IP to 100 requests per windowMs
+    message: 'Too many delete requests from this IP, please try again later.',
+})
+
 // CREATE
 router.post('/', enforceAbility('ChatFlow'), chatflowsController.saveChatflow)
 router.post('/importchatflows', enforceAbility('ChatFlow'), chatflowsController.importChatflows)
@@ -16,6 +22,6 @@
 router.put(['/', '/:id'], enforceAbility('ChatFlow'), chatflowsController.updateChatflow)
 
 // DELETE
-router.delete('/:id', enforceAbility('ChatFlow'), chatflowsController.deleteChatflow)
+router.delete('/:id', deleteRateLimiter, enforceAbility('ChatFlow'), chatflowsController.deleteChatflow)
 
 export default router
EOF
@@ -1,8 +1,16 @@
import express from 'express'
import chatflowsController from '../../controllers/chatflows'
import enforceAbility from '../../middlewares/authentication/enforceAbility'
import rateLimit from 'express-rate-limit' // Import express-rate-limit
const router = express.Router()

// Rate limiter for DELETE requests
const deleteRateLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limit each IP to 100 requests per windowMs
message: 'Too many delete requests from this IP, please try again later.',
})

// CREATE
router.post('/', enforceAbility('ChatFlow'), chatflowsController.saveChatflow)
router.post('/importchatflows', enforceAbility('ChatFlow'), chatflowsController.importChatflows)
@@ -16,6 +22,6 @@
router.put(['/', '/:id'], enforceAbility('ChatFlow'), chatflowsController.updateChatflow)

// DELETE
router.delete('/:id', enforceAbility('ChatFlow'), chatflowsController.deleteChatflow)
router.delete('/:id', deleteRateLimiter, enforceAbility('ChatFlow'), chatflowsController.deleteChatflow)

export default router
Copilot is powered by AI and may make mistakes. Always verify output.

router.post('/custom', enforceAbility('CustomTemplate'), marketplacesController.saveCustomTemplate)
// READ - Custom templates (req authentication)
router.get('/custom', enforceAbility('Marketplace'), marketplacesController.getAllCustomTemplates)

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs authorization, but is not rate-limited.

Copilot Autofix

AI 11 months ago

To address the issue, we will integrate a rate-limiting middleware using the express-rate-limit package. This will restrict the number of requests that can be made to the /custom endpoint within a specified time window.

Steps to fix:

  1. Install the express-rate-limit package if it is not already part of the project dependencies.
  2. Create a rate limiter configuration with appropriate limits, such as a maximum of 100 requests per 15 minutes.
  3. Apply the rate limiter middleware specifically to the /custom route to prevent abuse.

Suggested changeset 1
packages/server/src/routes/marketplaces/index.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/server/src/routes/marketplaces/index.ts b/packages/server/src/routes/marketplaces/index.ts
--- a/packages/server/src/routes/marketplaces/index.ts
+++ b/packages/server/src/routes/marketplaces/index.ts
@@ -8,8 +8,16 @@
 router.get('/templates/:id', marketplacesController.getMarketplaceTemplate)
 
 // READ - Custom templates (req authentication)
-router.get('/custom', enforceAbility('Marketplace'), marketplacesController.getAllCustomTemplates)
+import rateLimit from 'express-rate-limit'
 
+// Rate limiter: Maximum 100 requests per 15 minutes
+const customTemplatesRateLimiter = rateLimit({
+  windowMs: 15 * 60 * 1000, // 15 minutes
+  max: 100, // Limit each IP to 100 requests per windowMs
+});
+
+router.get('/custom', customTemplatesRateLimiter, enforceAbility('Marketplace'), marketplacesController.getAllCustomTemplates)
+
 // 🆕 Add - Organization templates
 router.get('/organization', enforceAbility('Marketplace'), marketplacesController.getOrganizationTemplates)
 // CREATE - Create custom template
EOF
@@ -8,8 +8,16 @@
router.get('/templates/:id', marketplacesController.getMarketplaceTemplate)

// READ - Custom templates (req authentication)
router.get('/custom', enforceAbility('Marketplace'), marketplacesController.getAllCustomTemplates)
import rateLimit from 'express-rate-limit'

// Rate limiter: Maximum 100 requests per 15 minutes
const customTemplatesRateLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limit each IP to 100 requests per windowMs
});

router.get('/custom', customTemplatesRateLimiter, enforceAbility('Marketplace'), marketplacesController.getAllCustomTemplates)

// 🆕 Add - Organization templates
router.get('/organization', enforceAbility('Marketplace'), marketplacesController.getOrganizationTemplates)
// CREATE - Create custom template
Copilot is powered by AI and may make mistakes. Always verify output.
// READ
router.get('/custom', marketplacesController.getAllCustomTemplates)
// 🆕 Add - Organization templates
router.get('/organization', enforceAbility('Marketplace'), marketplacesController.getOrganizationTemplates)

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs authorization, but is not rate-limited.

Copilot Autofix

AI 11 months ago

To fix the issue, we will add a rate-limiting middleware to the /organization route. The express-rate-limit package is a suitable choice for this purpose. This middleware will limit the number of requests that can be made to the route within a specified time window. We will:

  1. Import the express-rate-limit package at the top of the file.
  2. Define a rate limiter with appropriate settings, such as allowing a maximum of 100 requests per 15-minute window.
  3. Apply this rate limiter specifically to the /organization route.

This change will ensure that the route is protected from abuse while maintaining its functionality.


Suggested changeset 1
packages/server/src/routes/marketplaces/index.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/server/src/routes/marketplaces/index.ts b/packages/server/src/routes/marketplaces/index.ts
--- a/packages/server/src/routes/marketplaces/index.ts
+++ b/packages/server/src/routes/marketplaces/index.ts
@@ -1,6 +1,7 @@
 import express from 'express'
 import marketplacesController from '../../controllers/marketplaces'
 import enforceAbility from '../../middlewares/authentication/enforceAbility'
+import rateLimit from 'express-rate-limit'
 const router = express.Router()
 
 // READ - Templates del marketplace (public)
@@ -11,7 +12,11 @@
 router.get('/custom', enforceAbility('Marketplace'), marketplacesController.getAllCustomTemplates)
 
 // 🆕 Add - Organization templates
-router.get('/organization', enforceAbility('Marketplace'), marketplacesController.getOrganizationTemplates)
+const organizationRateLimiter = rateLimit({
+    windowMs: 15 * 60 * 1000, // 15 minutes
+    max: 100, // limit each IP to 100 requests per windowMs
+})
+router.get('/organization', organizationRateLimiter, enforceAbility('Marketplace'), marketplacesController.getOrganizationTemplates)
 // CREATE - Create custom template
 router.post('/custom', enforceAbility('Marketplace'), marketplacesController.saveCustomTemplate)
 
EOF
@@ -1,6 +1,7 @@
import express from 'express'
import marketplacesController from '../../controllers/marketplaces'
import enforceAbility from '../../middlewares/authentication/enforceAbility'
import rateLimit from 'express-rate-limit'
const router = express.Router()

// READ - Templates del marketplace (public)
@@ -11,7 +12,11 @@
router.get('/custom', enforceAbility('Marketplace'), marketplacesController.getAllCustomTemplates)

// 🆕 Add - Organization templates
router.get('/organization', enforceAbility('Marketplace'), marketplacesController.getOrganizationTemplates)
const organizationRateLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
})
router.get('/organization', organizationRateLimiter, enforceAbility('Marketplace'), marketplacesController.getOrganizationTemplates)
// CREATE - Create custom template
router.post('/custom', enforceAbility('Marketplace'), marketplacesController.saveCustomTemplate)

Copilot is powered by AI and may make mistakes. Always verify output.
// 🆕 Add - Organization templates
router.get('/organization', enforceAbility('Marketplace'), marketplacesController.getOrganizationTemplates)
// CREATE - Create custom template
router.post('/custom', enforceAbility('Marketplace'), marketplacesController.saveCustomTemplate)

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs authorization, but is not rate-limited.

Copilot Autofix

AI 11 months ago

To address the missing rate limiting, we should add a rate-limiting middleware to the router, specifically to the POST /custom endpoint (line 16). The best practice is to use the well-known express-rate-limit package. This involves:

  • Adding an import for express-rate-limit.
  • Creating a rate limiter instance with sensible defaults (e.g., limit to 100 requests per 15 minutes per IP).
  • Applying the rate limiter as middleware to the sensitive route, before authorization and controller logic.
  • All changes will be made within the shown code in packages/server/src/routes/marketplaces/index.ts.

Suggested changeset 1
packages/server/src/routes/marketplaces/index.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/server/src/routes/marketplaces/index.ts b/packages/server/src/routes/marketplaces/index.ts
--- a/packages/server/src/routes/marketplaces/index.ts
+++ b/packages/server/src/routes/marketplaces/index.ts
@@ -1,8 +1,16 @@
 import express from 'express'
 import marketplacesController from '../../controllers/marketplaces'
 import enforceAbility from '../../middlewares/authentication/enforceAbility'
+import rateLimit from 'express-rate-limit'
 const router = express.Router()
 
+// Rate limiter for sensitive routes
+const createCustomTemplateLimiter = rateLimit({
+  windowMs: 15 * 60 * 1000, // 15 minutes
+  max: 100, // limit each IP to 100 requests per windowMs
+  standardHeaders: true,
+  legacyHeaders: false,
+})
 // READ - Templates del marketplace (public)
 router.get('/templates', marketplacesController.getAllTemplates)
 router.get('/templates/:id', marketplacesController.getMarketplaceTemplate)
@@ -13,7 +19,7 @@
 // 🆕 Add - Organization templates
 router.get('/organization', enforceAbility('Marketplace'), marketplacesController.getOrganizationTemplates)
 // CREATE - Create custom template
-router.post('/custom', enforceAbility('Marketplace'), marketplacesController.saveCustomTemplate)
+router.post('/custom', createCustomTemplateLimiter, enforceAbility('Marketplace'), marketplacesController.saveCustomTemplate)
 
 // DELETE - Delete custom template
 router.delete('/custom/:id', enforceAbility('Marketplace'), marketplacesController.deleteCustomTemplate)
EOF
@@ -1,8 +1,16 @@
import express from 'express'
import marketplacesController from '../../controllers/marketplaces'
import enforceAbility from '../../middlewares/authentication/enforceAbility'
import rateLimit from 'express-rate-limit'
const router = express.Router()

// Rate limiter for sensitive routes
const createCustomTemplateLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
standardHeaders: true,
legacyHeaders: false,
})
// READ - Templates del marketplace (public)
router.get('/templates', marketplacesController.getAllTemplates)
router.get('/templates/:id', marketplacesController.getMarketplaceTemplate)
@@ -13,7 +19,7 @@
// 🆕 Add - Organization templates
router.get('/organization', enforceAbility('Marketplace'), marketplacesController.getOrganizationTemplates)
// CREATE - Create custom template
router.post('/custom', enforceAbility('Marketplace'), marketplacesController.saveCustomTemplate)
router.post('/custom', createCustomTemplateLimiter, enforceAbility('Marketplace'), marketplacesController.saveCustomTemplate)

// DELETE - Delete custom template
router.delete('/custom/:id', enforceAbility('Marketplace'), marketplacesController.deleteCustomTemplate)
Copilot is powered by AI and may make mistakes. Always verify output.
// DELETE
router.delete(['/', '/custom/:id'], marketplacesController.deleteCustomTemplate)
// DELETE - Delete custom template
router.delete('/custom/:id', enforceAbility('Marketplace'), marketplacesController.deleteCustomTemplate)

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs authorization, but is not rate-limited.

Copilot Autofix

AI 11 months ago

To address the issue, we will integrate rate limiting into the route handler for DELETE /custom/:id. This can be achieved using the express-rate-limit middleware. We will:

  1. Import the express-rate-limit package.
  2. Define a rate limiter configuration with a reasonable rate limit (e.g., 100 requests per 15 minutes).
  3. Apply this rate limiter specifically to the flagged route handler (DELETE /custom/:id).

This approach ensures that the route is protected from abuse without affecting other routes unnecessarily.


Suggested changeset 1
packages/server/src/routes/marketplaces/index.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/server/src/routes/marketplaces/index.ts b/packages/server/src/routes/marketplaces/index.ts
--- a/packages/server/src/routes/marketplaces/index.ts
+++ b/packages/server/src/routes/marketplaces/index.ts
@@ -1,8 +1,16 @@
 import express from 'express'
 import marketplacesController from '../../controllers/marketplaces'
 import enforceAbility from '../../middlewares/authentication/enforceAbility'
+import rateLimit from 'express-rate-limit'
 const router = express.Router()
 
+// Define rate limiter: maximum of 100 requests per 15 minutes
+const limiter = rateLimit({
+  windowMs: 15 * 60 * 1000, // 15 minutes
+  max: 100, // Limit each IP to 100 requests per windowMs
+  message: 'Too many requests, please try again later.',
+})
+
 // READ - Templates del marketplace (public)
 router.get('/templates', marketplacesController.getAllTemplates)
 router.get('/templates/:id', marketplacesController.getMarketplaceTemplate)
@@ -16,6 +22,6 @@
 router.post('/custom', enforceAbility('Marketplace'), marketplacesController.saveCustomTemplate)
 
 // DELETE - Delete custom template
-router.delete('/custom/:id', enforceAbility('Marketplace'), marketplacesController.deleteCustomTemplate)
+router.delete('/custom/:id', limiter, enforceAbility('Marketplace'), marketplacesController.deleteCustomTemplate)
 
 export default router
EOF
@@ -1,8 +1,16 @@
import express from 'express'
import marketplacesController from '../../controllers/marketplaces'
import enforceAbility from '../../middlewares/authentication/enforceAbility'
import rateLimit from 'express-rate-limit'
const router = express.Router()

// Define rate limiter: maximum of 100 requests per 15 minutes
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limit each IP to 100 requests per windowMs
message: 'Too many requests, please try again later.',
})

// READ - Templates del marketplace (public)
router.get('/templates', marketplacesController.getAllTemplates)
router.get('/templates/:id', marketplacesController.getMarketplaceTemplate)
@@ -16,6 +22,6 @@
router.post('/custom', enforceAbility('Marketplace'), marketplacesController.saveCustomTemplate)

// DELETE - Delete custom template
router.delete('/custom/:id', enforceAbility('Marketplace'), marketplacesController.deleteCustomTemplate)
router.delete('/custom/:id', limiter, enforceAbility('Marketplace'), marketplacesController.deleteCustomTemplate)

export default router
Copilot is powered by AI and may make mistakes. Always verify output.
- Fixed orphaned object literals after commented console.log statements
- Properly commented out object properties in MarketplaceCanvas.jsx
- Properly commented out object properties in MarketplaceLanding.jsx
- Properly commented out object properties in canvas/index.jsx
- Resolves build errors while preserving debug information for future use
@bradtaylorsf bradtaylorsf merged commit a65dc4e into staging Jul 19, 2025
2 of 6 checks passed
@bradtaylorsf bradtaylorsf deleted the fix/template-organization-scoping-and-security branch July 19, 2025 18:59
@bradtaylorsf bradtaylorsf mentioned this pull request Jul 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants