feat: implement organization-scoped custom templates#403
Conversation
…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
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
|
||
| // DELETE | ||
| router.delete(['/', '/:id'], enforceAbility('ChatFlow'), chatflowsController.deleteChatflow) | ||
| router.delete('/:id', enforceAbility('ChatFlow'), chatflowsController.deleteChatflow) |
Check failure
Code scanning / CodeQL
Missing rate limiting High
Show autofix suggestion
Hide autofix suggestion
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:
- Install the
express-rate-limitpackage if not already installed. - Define a rate limiter configuration with an appropriate maximum request limit and time window.
- Apply this rate limiter to the DELETE route (
router.delete('/:id')). - Ensure the change does not disrupt existing functionality.
| @@ -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 |
|
|
||
| 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
Show autofix suggestion
Hide autofix suggestion
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:
- Install the
express-rate-limitpackage if it is not already part of the project dependencies. - Create a rate limiter configuration with appropriate limits, such as a maximum of 100 requests per 15 minutes.
- Apply the rate limiter middleware specifically to the
/customroute to prevent abuse.
| @@ -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 |
| // 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
Show autofix suggestion
Hide autofix suggestion
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:
- Import the
express-rate-limitpackage at the top of the file. - Define a rate limiter with appropriate settings, such as allowing a maximum of 100 requests per 15-minute window.
- Apply this rate limiter specifically to the
/organizationroute.
This change will ensure that the route is protected from abuse while maintaining its functionality.
| @@ -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) | ||
|
|
| // 🆕 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
Show autofix suggestion
Hide autofix suggestion
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.
| @@ -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) |
| // 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
Show autofix suggestion
Hide autofix suggestion
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:
- Import the
express-rate-limitpackage. - Define a rate limiter configuration with a reasonable rate limit (e.g., 100 requests per 15 minutes).
- 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.
| @@ -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 |
- 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
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
Enhanced UI Experience
🔧 Database Schema Updates
New Migrations
AddOrganizationToCustomTemplate: Adds organization and user scopingAddParentIdToCustomTemplate: Enables template lineage trackingAddTemplateIdToChatFlow: Links chatflows to their template originsEnhanced Entities
🛡️ Critical Security Fixes
Authentication & Authorization
Chatflow Deletion Security
Migration Resilience
🎯 API Improvements
New Endpoints
GET /marketplaces/organization: Retrieve organization-shared templatesEnhanced Services
📊 Frontend Enhancements
Template Management
User Experience
🔍 Technical Details
Framework Detection
Data Integrity
Performance Optimizations
🚀 New MCP Sidekick Templates
Fixes: #391
Jira: AAI-487