mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 22:04:56 +00:00
## Phase 1: Monolithic File Refactoring ✅ - Refactored 8 large files (300-500 LOC) into 40+ modular components/hooks - All files now <150 LOC per file (max 125 LOC) - CanvasSettings: 343 → 7 components - SecuritySettings: 273 → 6 components - NotificationSettings: 239 → 6 components - Editor/Toolbar: 258 → 7 components - InfiniteCanvas: 239 → 10 modules - WorkflowCard: 320 → 5 components + custom hook - useProjectCanvas: 322 → 8 hooks - projectSlice: 335 → 4 Redux slices ## Phase 2: Business Logic Extraction ✅ - Extracted logic from 5 components into 8 custom hooks - register/page.tsx: 235 → 167 LOC (-29%) - login/page.tsx: 137 → 100 LOC (-27%) - MainLayout.tsx: 216 → 185 LOC (-14%) - ProjectSidebar.tsx: 200 → 200 LOC (refactored) - page.tsx (Dashboard): 197 → 171 LOC (-13%) - New hooks: useAuthForm, usePasswordValidation, useLoginLogic, useRegisterLogic, useHeaderLogic, useResponsiveSidebar, useProjectSidebarLogic, useDashboardLogic ## Phase 3: Dead Code Analysis & Implementation ✅ - Identified and documented 3 unused hooks (244 LOC) - Removed useRealtimeService from exports - Cleaned 8 commented lines in useProject.ts - Documented useExecution stub methods - Removed 3 commented dispatch calls in useCanvasKeyboard - Fixed 3 'as any' type assertions ## Phase 4: Stub Code Implementation ✅ - Fully implemented useExecution methods: execute(), stop(), getDetails(), getStats(), getHistory() - Integrated useCanvasKeyboard into InfiniteCanvas with Redux dispatch - Verified useCanvasVirtualization for 100+ items - Enhanced useRealtimeService documentation for Phase 4 WebSocket integration ## Backend Updates - Added SQLAlchemy models: Workspace, Project, ProjectCanvasItem - Added Flask API endpoints for CRUD operations - Configured multi-tenant filtering for all queries - Added database migrations for new entities ## Build Verification ✅ - TypeScript strict mode: 0 errors - Production build: ✅ Successful (161 kB First Load JS) - No breaking changes - 100% backward compatibility maintained ## Documentation Generated - 6 comprehensive guides (70+ KB total) - Test templates for all new implementations - Quick reference for all 42 hooks - Implementation checklist and deployment guide Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
389 lines
8.8 KiB
JSON
389 lines
8.8 KiB
JSON
{
|
|
"name": "Dispatch Notification",
|
|
"active": false,
|
|
"nodes": [
|
|
{
|
|
"id": "validate_context",
|
|
"name": "Validate Context",
|
|
"type": "metabuilder.validate",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
100,
|
|
100
|
|
],
|
|
"parameters": {
|
|
"input": "{{ $context.tenantId }}",
|
|
"operation": "validate",
|
|
"validator": "required"
|
|
}
|
|
},
|
|
{
|
|
"id": "validate_input",
|
|
"name": "Validate Input",
|
|
"type": "metabuilder.validate",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
400,
|
|
100
|
|
],
|
|
"parameters": {
|
|
"input": "{{ $json }}",
|
|
"operation": "validate",
|
|
"rules": {
|
|
"userId": "required|string",
|
|
"type": "required|string",
|
|
"title": "required|string|maxLength:200",
|
|
"message": "required|string|maxLength:1000",
|
|
"channels": "required|array"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"id": "fetch_user_preferences",
|
|
"name": "Fetch User Preferences",
|
|
"type": "metabuilder.database",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
700,
|
|
100
|
|
],
|
|
"parameters": {
|
|
"filter": {
|
|
"userId": "{{ $json.userId }}",
|
|
"tenantId": "{{ $context.tenantId }}"
|
|
},
|
|
"operation": "database_read",
|
|
"entity": "NotificationPreference"
|
|
}
|
|
},
|
|
{
|
|
"id": "create_notification_record",
|
|
"name": "Create Notification Record",
|
|
"type": "metabuilder.database",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
100,
|
|
300
|
|
],
|
|
"parameters": {
|
|
"data": {
|
|
"tenantId": "{{ $context.tenantId }}",
|
|
"userId": "{{ $json.userId }}",
|
|
"type": "{{ $json.type }}",
|
|
"title": "{{ $json.title }}",
|
|
"message": "{{ $json.message }}",
|
|
"isRead": false,
|
|
"metadata": "{{ $json.metadata || {} }}",
|
|
"createdAt": "{{ new Date().toISOString() }}",
|
|
"expiresAt": "{{ new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString() }}"
|
|
},
|
|
"operation": "database_create",
|
|
"entity": "Notification"
|
|
}
|
|
},
|
|
{
|
|
"id": "dispatch_in_app",
|
|
"name": "Dispatch In App",
|
|
"type": "metabuilder.condition",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
400,
|
|
300
|
|
],
|
|
"parameters": {
|
|
"condition": "{{ $json.channels.includes('in_app') && $steps.fetch_user_preferences.output.enableInApp !== false }}",
|
|
"operation": "condition"
|
|
}
|
|
},
|
|
{
|
|
"id": "emit_in_app_notification",
|
|
"name": "Emit In App Notification",
|
|
"type": "metabuilder.action",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
700,
|
|
300
|
|
],
|
|
"parameters": {
|
|
"data": {
|
|
"notificationId": "{{ $steps.create_notification_record.output.id }}",
|
|
"title": "{{ $json.title }}",
|
|
"message": "{{ $json.message }}",
|
|
"type": "{{ $json.type }}"
|
|
},
|
|
"action": "emit_event",
|
|
"event": "notification_received",
|
|
"channel": "{{ 'user:' + $json.userId }}"
|
|
}
|
|
},
|
|
{
|
|
"id": "check_email_rate_limit",
|
|
"name": "Check Email Rate Limit",
|
|
"type": "metabuilder.condition",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
100,
|
|
500
|
|
],
|
|
"parameters": {
|
|
"condition": "{{ $json.channels.includes('email') && $steps.fetch_user_preferences.output.enableEmail !== false }}",
|
|
"operation": "condition"
|
|
}
|
|
},
|
|
{
|
|
"id": "apply_email_rate_limit",
|
|
"name": "Apply Email Rate Limit",
|
|
"type": "metabuilder.rateLimit",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
400,
|
|
500
|
|
],
|
|
"parameters": {
|
|
"operation": "rate_limit",
|
|
"key": "{{ 'email:' + $json.userId }}",
|
|
"limit": 10,
|
|
"window": 3600000
|
|
}
|
|
},
|
|
{
|
|
"id": "fetch_user_email",
|
|
"name": "Fetch User Email",
|
|
"type": "metabuilder.database",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
700,
|
|
500
|
|
],
|
|
"parameters": {
|
|
"filter": {
|
|
"id": "{{ $json.userId }}",
|
|
"tenantId": "{{ $context.tenantId }}"
|
|
},
|
|
"operation": "database_read",
|
|
"entity": "User"
|
|
}
|
|
},
|
|
{
|
|
"id": "send_email",
|
|
"name": "Send Email via SMTP Relay",
|
|
"type": "smtp-relay-send",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
100,
|
|
700
|
|
],
|
|
"parameters": {
|
|
"to": "{{ $steps.fetch_user_email.output.email }}",
|
|
"subject": "{{ $json.title }}",
|
|
"body": "{{ $json.message }}",
|
|
"template": "{{ $json.emailTemplate }}",
|
|
"from": "{{ $env.SMTP_FROM_ADDRESS || 'noreply@metabuilder.local' }}",
|
|
"retryAttempts": 3
|
|
}
|
|
},
|
|
{
|
|
"id": "dispatch_push",
|
|
"name": "Dispatch Push",
|
|
"type": "metabuilder.condition",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
400,
|
|
700
|
|
],
|
|
"parameters": {
|
|
"condition": "{{ $json.channels.includes('push') && $steps.fetch_user_preferences.output.enablePush !== false }}",
|
|
"operation": "condition"
|
|
}
|
|
},
|
|
{
|
|
"id": "send_push_notification",
|
|
"name": "Send Push Notification",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
700,
|
|
700
|
|
],
|
|
"parameters": {
|
|
"operation": "http_request",
|
|
"url": "https://fcm.googleapis.com/fcm/send",
|
|
"method": "POST",
|
|
"headers": {
|
|
"Authorization": "{{ 'Bearer ' + $env.FCM_KEY }}"
|
|
},
|
|
"body": {
|
|
"to": "{{ $steps.fetch_user_email.output.fcmToken }}",
|
|
"notification": {
|
|
"title": "{{ $json.title }}",
|
|
"body": "{{ $json.message }}"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"id": "return_success",
|
|
"name": "Return Success",
|
|
"type": "metabuilder.action",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
100,
|
|
900
|
|
],
|
|
"parameters": {
|
|
"action": "http_response",
|
|
"status": 202,
|
|
"body": {
|
|
"notificationId": "{{ $steps.create_notification_record.output.id }}",
|
|
"message": "Notification dispatched successfully"
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"connections": {
|
|
"validate_context": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "validate_input",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"validate_input": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "fetch_user_preferences",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"fetch_user_preferences": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "create_notification_record",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"create_notification_record": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "dispatch_in_app",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"dispatch_in_app": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "emit_in_app_notification",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"emit_in_app_notification": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "check_email_rate_limit",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"check_email_rate_limit": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "apply_email_rate_limit",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"apply_email_rate_limit": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "fetch_user_email",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"fetch_user_email": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "send_email",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"send_email": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "dispatch_push",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"dispatch_push": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "send_push_notification",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"send_push_notification": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "return_success",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
}
|
|
},
|
|
"staticData": {},
|
|
"meta": {},
|
|
"settings": {
|
|
"timezone": "UTC",
|
|
"executionTimeout": 3600,
|
|
"saveExecutionProgress": true,
|
|
"saveDataErrorExecution": "all",
|
|
"saveDataSuccessExecution": "all"
|
|
},
|
|
"id": "workflow_dispatch",
|
|
"version": "3.0.0",
|
|
"tenantId": "${TENANT_ID}"
|
|
} |