package main
import (
"context"
"log"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
"github.com/oarkflow/mq/workflow"
)
// SMS Demo server with comprehensive workflow pipeline
func main() {
// Initialize workflow engine
config := &workflow.Config{
MaxWorkers: 10,
ExecutionTimeout: 30 * time.Minute,
EnableMetrics: true,
EnableAudit: true,
EnableTracing: true,
}
engine := workflow.NewWorkflowEngine(config)
ctx := context.Background()
engine.Start(ctx)
defer engine.Stop(ctx)
// Initialize user manager and middleware
userManager := workflow.NewUserManager()
middlewareManager := workflow.NewMiddlewareManager()
// Create demo users
createDemoUsers(userManager)
// Setup middleware
setupMiddleware(middlewareManager)
// Register SMS workflow pipeline
registerSMSWorkflows(engine)
// Start HTTP server
app := fiber.New(fiber.Config{
AppName: "Advanced SMS Workflow Engine",
})
// Add fiber middleware
app.Use(cors.New())
app.Use(logger.New())
app.Use(recover.New())
// Setup routes
setupRoutes(app, engine, userManager, middlewareManager)
log.Println("🚀 Advanced SMS Workflow Engine started on http://localhost:3000")
log.Println("📱 SMS Pipeline Demo: http://localhost:3000/sms")
log.Println("👤 User Auth Demo: http://localhost:3000/auth")
log.Println("📊 Admin Dashboard: http://localhost:3000/admin")
log.Println("📝 API Documentation: http://localhost:3000/docs")
log.Fatal(app.Listen(":3000"))
}
func createDemoUsers(userManager *workflow.UserManager) {
users := []*workflow.User{
{
ID: "admin",
Username: "admin",
Email: "admin@company.com",
Role: workflow.UserRoleAdmin,
Permissions: []string{"admin"},
},
{
ID: "manager",
Username: "manager",
Email: "manager@company.com",
Role: workflow.UserRoleManager,
Permissions: []string{"read", "write", "execute"},
},
{
ID: "operator",
Username: "operator",
Email: "operator@company.com",
Role: workflow.UserRoleOperator,
Permissions: []string{"read", "execute"},
},
}
for _, user := range users {
if err := userManager.CreateUser(user); err != nil {
log.Printf("Error creating user %s: %v", user.Username, err)
}
}
log.Println("✅ Demo users created: admin/password, manager/password, operator/password")
}
func setupMiddleware(middlewareManager *workflow.MiddlewareManager) {
// Add logging middleware
loggingMiddleware := workflow.Middleware{
ID: "logging",
Name: "Request Logging",
Type: workflow.MiddlewareLogging,
Priority: 1,
Enabled: true,
Config: map[string]interface{}{},
}
middlewareManager.AddMiddleware(loggingMiddleware)
// Add rate limiting middleware
rateLimitMiddleware := workflow.Middleware{
ID: "rate_limit",
Name: "Rate Limiting",
Type: workflow.MiddlewareRateLimit,
Priority: 2,
Enabled: true,
Config: map[string]interface{}{
"requests_per_minute": 100,
},
}
middlewareManager.AddMiddleware(rateLimitMiddleware)
// Add auth middleware
authMiddleware := workflow.Middleware{
ID: "auth",
Name: "Authentication",
Type: workflow.MiddlewareAuth,
Priority: 3,
Enabled: true,
Config: map[string]interface{}{},
}
middlewareManager.AddMiddleware(authMiddleware)
log.Println("✅ Middleware configured: logging, rate limiting, authentication")
}
func registerSMSWorkflows(engine *workflow.WorkflowEngine) {
ctx := context.Background()
// 1. User Authentication Sub-DAG
authWorkflow := createAuthSubDAG()
if err := engine.RegisterWorkflow(ctx, authWorkflow); err != nil {
log.Printf("Error registering auth workflow: %v", err)
}
// 2. Main SMS Pipeline Workflow
smsWorkflow := createSMSPipelineWorkflow()
if err := engine.RegisterWorkflow(ctx, smsWorkflow); err != nil {
log.Printf("Error registering SMS workflow: %v", err)
}
// 3. Webhook Handler Workflow
webhookWorkflow := createWebhookHandlerWorkflow()
if err := engine.RegisterWorkflow(ctx, webhookWorkflow); err != nil {
log.Printf("Error registering webhook workflow: %v", err)
}
log.Println("✅ SMS workflow pipeline registered successfully")
}
func createAuthSubDAG() *workflow.WorkflowDefinition {
return &workflow.WorkflowDefinition{
ID: "user-auth-subdag",
Name: "User Authentication Sub-DAG",
Description: "Handles user login and token validation",
Version: "1.0.0",
Status: workflow.WorkflowStatusActive,
Nodes: []workflow.WorkflowNode{
{
ID: "validate-credentials",
Name: "Validate User Credentials",
Type: workflow.NodeTypeAuth,
Description: "Authenticate user with credentials",
Config: workflow.NodeConfig{
AuthType: "login",
Credentials: map[string]string{
"admin": "password",
"manager": "password",
"operator": "password",
},
TokenExpiry: 24 * time.Hour,
},
},
{
ID: "check-permissions",
Name: "Check SMS Permissions",
Type: workflow.NodeTypeValidator,
Description: "Validate user has SMS sending permissions",
Config: workflow.NodeConfig{
ValidationType: "strict",
ValidationRules: []workflow.ValidationRule{
{
Field: "permissions",
Type: "required",
Message: "User permissions required",
},
{
Field: "role",
Type: "required",
Message: "User role required",
},
},
},
},
},
Edges: []workflow.WorkflowEdge{
{
ID: "auth-to-permissions",
FromNode: "validate-credentials",
ToNode: "check-permissions",
},
},
}
}
func createSMSPipelineWorkflow() *workflow.WorkflowDefinition {
return &workflow.WorkflowDefinition{
ID: "sms-pipeline",
Name: "Comprehensive SMS Pipeline",
Description: "Complete SMS workflow with authentication, validation, routing, and reporting",
Version: "1.0.0",
Status: workflow.WorkflowStatusActive,
Nodes: []workflow.WorkflowNode{
// Step 1: User Authentication (Sub-DAG)
{
ID: "user-authentication",
Name: "User Authentication",
Type: workflow.NodeTypeSubDAG,
Description: "Authenticate user and validate permissions",
Config: workflow.NodeConfig{
SubWorkflowID: "user-auth-subdag",
InputMapping: map[string]string{
"username": "username",
"password": "password",
},
OutputMapping: map[string]string{
"auth_token": "token",
"user_info": "user",
},
},
},
// Step 2: SMS HTML Page Generation
{
ID: "generate-sms-page",
Name: "Generate SMS HTML Page",
Type: workflow.NodeTypeHTML,
Description: "Create dynamic HTML page for SMS composition",
Config: workflow.NodeConfig{
Template: `
SMS Composer
Welcome, {{.user.username}}!
Role: {{.user.role}} | Permissions: {{.user.permissions}}
SMS Composer
`,
TemplateData: map[string]string{
"timestamp": "{{.timestamp}}",
},
OutputPath: "/tmp/sms-composer.html",
},
},
// Step 3: SMS Validation
{
ID: "validate-sms-data",
Name: "Validate SMS Data",
Type: workflow.NodeTypeValidator,
Description: "Validate phone numbers and message content",
Config: workflow.NodeConfig{
ValidationType: "strict",
ValidationRules: []workflow.ValidationRule{
{
Field: "recipients",
Type: "required",
Message: "Recipients are required",
},
{
Field: "message",
Type: "required",
Message: "Message content is required",
},
{
Field: "message",
Type: "length",
Value: map[string]interface{}{
"min": 1,
"max": 160,
},
Message: "Message must be 1-160 characters",
},
},
},
},
// Step 4: Provider Selection & Routing
{
ID: "route-sms-provider",
Name: "Route SMS Provider",
Type: workflow.NodeTypeRouter,
Description: "Select SMS provider based on routing rules",
Config: workflow.NodeConfig{
RoutingRules: []workflow.RoutingRule{
{
Condition: "recipient_count > 100",
Destination: "bulk_provider",
Priority: 1,
Weight: 100,
},
{
Condition: "country == 'US'",
Destination: "twilio",
Priority: 2,
Weight: 80,
},
{
Condition: "country == 'UK'",
Destination: "nexmo",
Priority: 2,
Weight: 80,
},
},
DefaultRoute: "standard_provider",
},
},
// Step 5: Phone & Message Validation
{
ID: "validate-phones-spam",
Name: "Phone & Spam Validation",
Type: workflow.NodeTypeValidator,
Description: "Validate phone numbers and check for spam",
Config: workflow.NodeConfig{
ValidationType: "strict",
ValidationRules: []workflow.ValidationRule{
{
Field: "recipients",
Type: "pattern",
Value: `^\+?[1-9]\d{1,14}$`,
Message: "Invalid phone number format",
},
},
},
},
// Step 6: SMS Dispatch
{
ID: "dispatch-sms",
Name: "Dispatch SMS",
Type: workflow.NodeTypeSMS,
Description: "Send SMS through selected provider",
Config: workflow.NodeConfig{
Provider: "auto", // Will be set by router
From: "+1234567890",
MessageType: "transactional",
},
},
// Step 7: Send User Notification
{
ID: "notify-user",
Name: "Send User Notification",
Type: workflow.NodeTypeNotify,
Description: "Notify user about SMS status",
Config: workflow.NodeConfig{
NotifyType: "email",
Channel: "smtp",
},
},
// Step 8: Store SMS Report
{
ID: "store-sms-report",
Name: "Store SMS Report",
Type: workflow.NodeTypeStorage,
Description: "Store SMS delivery report",
Config: workflow.NodeConfig{
StorageType: "database",
StoragePath: "sms_reports",
StorageConfig: map[string]string{
"table": "sms_reports",
"connection": "main_db",
},
},
},
// Step 9: Webhook Receiver for Provider Callbacks
{
ID: "webhook-receiver",
Name: "SMS Provider Webhook",
Type: workflow.NodeTypeWebhookRx,
Description: "Receive delivery status from SMS provider",
Config: workflow.NodeConfig{
ListenPath: "/webhook/sms/status",
Secret: "webhook_secret_key",
Timeout: 30 * time.Second,
},
},
},
Edges: []workflow.WorkflowEdge{
{
ID: "auth-to-html",
FromNode: "user-authentication",
ToNode: "generate-sms-page",
},
{
ID: "html-to-validate",
FromNode: "generate-sms-page",
ToNode: "validate-sms-data",
},
{
ID: "validate-to-route",
FromNode: "validate-sms-data",
ToNode: "route-sms-provider",
},
{
ID: "route-to-phone-validate",
FromNode: "route-sms-provider",
ToNode: "validate-phones-spam",
},
{
ID: "phone-validate-to-dispatch",
FromNode: "validate-phones-spam",
ToNode: "dispatch-sms",
},
{
ID: "dispatch-to-notify",
FromNode: "dispatch-sms",
ToNode: "notify-user",
},
{
ID: "notify-to-store",
FromNode: "notify-user",
ToNode: "store-sms-report",
},
{
ID: "store-to-webhook",
FromNode: "store-sms-report",
ToNode: "webhook-receiver",
},
},
Variables: map[string]workflow.Variable{
"username": {
Name: "username",
Type: "string",
Required: true,
Description: "User username for authentication",
},
"password": {
Name: "password",
Type: "string",
Required: true,
Description: "User password for authentication",
},
"recipients": {
Name: "recipients",
Type: "array",
Required: true,
Description: "List of SMS recipients",
},
"message": {
Name: "message",
Type: "string",
Required: true,
Description: "SMS message content",
},
},
}
}
func createWebhookHandlerWorkflow() *workflow.WorkflowDefinition {
return &workflow.WorkflowDefinition{
ID: "sms-webhook-handler",
Name: "SMS Webhook Handler",
Description: "Processes SMS delivery status webhooks from providers",
Version: "1.0.0",
Status: workflow.WorkflowStatusActive,
Nodes: []workflow.WorkflowNode{
{
ID: "parse-webhook",
Name: "Parse Webhook Data",
Type: workflow.NodeTypeTransform,
Description: "Parse incoming webhook payload",
Config: workflow.NodeConfig{
TransformType: "json_parse",
Expression: "$.webhook_data",
},
},
{
ID: "validate-webhook",
Name: "Validate Webhook",
Type: workflow.NodeTypeValidator,
Description: "Validate webhook signature and data",
Config: workflow.NodeConfig{
ValidationType: "strict",
ValidationRules: []workflow.ValidationRule{
{
Field: "message_id",
Type: "required",
Message: "Message ID required",
},
{
Field: "status",
Type: "required",
Message: "Delivery status required",
},
},
},
},
{
ID: "update-report",
Name: "Update SMS Report",
Type: workflow.NodeTypeStorage,
Description: "Update SMS report with delivery status",
Config: workflow.NodeConfig{
StorageType: "database",
StoragePath: "sms_reports",
StorageConfig: map[string]string{
"operation": "update",
"table": "sms_reports",
},
},
},
{
ID: "send-final-notification",
Name: "Send Final Notification",
Type: workflow.NodeTypeNotify,
Description: "Send final delivery notification to user",
Config: workflow.NodeConfig{
NotifyType: "email",
Channel: "smtp",
},
},
},
Edges: []workflow.WorkflowEdge{
{
ID: "parse-to-validate",
FromNode: "parse-webhook",
ToNode: "validate-webhook",
},
{
ID: "validate-to-update",
FromNode: "validate-webhook",
ToNode: "update-report",
},
{
ID: "update-to-notify",
FromNode: "update-report",
ToNode: "send-final-notification",
},
},
}
}
func setupRoutes(app *fiber.App, engine *workflow.WorkflowEngine, userManager *workflow.UserManager, middlewareManager *workflow.MiddlewareManager) {
// Main page
app.Get("/", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{
"message": "🚀 Advanced SMS Workflow Engine",
"version": "2.0.0",
"features": []string{
"Sub-DAG Support",
"HTML Page Generation",
"SMS Pipeline with Provider Routing",
"User Authentication & Authorization",
"Middleware System",
"Webhook Receivers",
"Real-time Reporting",
},
"endpoints": map[string]string{
"sms": "/sms - SMS Pipeline Demo",
"auth": "/auth - Authentication Demo",
"admin": "/admin - Admin Dashboard",
"docs": "/docs - API Documentation",
"webhook": "/webhook/sms/status - SMS Status Webhook",
},
})
})
// SMS Pipeline routes
app.Post("/sms/send", func(c *fiber.Ctx) error {
var request map[string]interface{}
if err := c.BodyParser(&request); err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid request body"})
}
// Execute middleware chain
result := middlewareManager.Execute(c.Context(), request)
if !result.Continue {
return c.Status(401).JSON(fiber.Map{"error": result.Error.Error()})
}
// Execute SMS workflow
execution, err := engine.ExecuteWorkflow(c.Context(), "sms-pipeline", request, &workflow.ExecutionOptions{
Priority: workflow.PriorityHigh,
Owner: "sms-api",
})
if err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{
"success": true,
"execution_id": execution.ID,
"status": execution.Status,
"message": "SMS workflow started successfully",
})
})
// Authentication routes
app.Post("/auth/login", func(c *fiber.Ctx) error {
var credentials struct {
Username string `json:"username"`
Password string `json:"password"`
}
if err := c.BodyParser(&credentials); err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid credentials format"})
}
authContext, err := userManager.AuthenticateUser(credentials.Username, credentials.Password)
if err != nil {
return c.Status(401).JSON(fiber.Map{"error": "Invalid credentials"})
}
return c.JSON(fiber.Map{
"success": true,
"token": authContext.Token,
"user": authContext.User,
"expires_at": time.Now().Add(24 * time.Hour),
})
})
app.Post("/auth/validate", func(c *fiber.Ctx) error {
token := c.Get("Authorization")
if token == "" {
return c.Status(400).JSON(fiber.Map{"error": "Authorization header required"})
}
authContext, err := userManager.ValidateSession(token)
if err != nil {
return c.Status(401).JSON(fiber.Map{"error": "Invalid token"})
}
return c.JSON(fiber.Map{
"valid": true,
"user": authContext.User,
})
})
// Admin routes
app.Get("/admin/workflows", func(c *fiber.Ctx) error {
workflows, err := engine.ListWorkflows(c.Context(), &workflow.WorkflowFilter{})
if err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{
"workflows": workflows,
"total": len(workflows),
})
})
app.Get("/admin/executions", func(c *fiber.Ctx) error {
executions, err := engine.ListExecutions(c.Context(), &workflow.ExecutionFilter{})
if err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{
"executions": executions,
"total": len(executions),
})
})
// SMS status webhook endpoint
app.Post("/webhook/sms/status", func(c *fiber.Ctx) error {
var webhookData map[string]interface{}
if err := c.BodyParser(&webhookData); err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid webhook data"})
}
// Execute webhook handler workflow
execution, err := engine.ExecuteWorkflow(c.Context(), "sms-webhook-handler", webhookData, &workflow.ExecutionOptions{
Priority: workflow.PriorityHigh,
Owner: "webhook-handler",
})
if err != nil {
log.Printf("Webhook handler error: %v", err)
return c.Status(500).JSON(fiber.Map{"error": "Webhook processing failed"})
}
log.Printf("SMS webhook processed: execution_id=%s", execution.ID)
return c.JSON(fiber.Map{"status": "processed", "execution_id": execution.ID})
})
// Demo pages with proper authentication flow
app.Get("/login", func(c *fiber.Ctx) error {
html := `
SMS Workflow - Login
🔐 SMS Workflow Login
Demo Users:
admin / password (Full access)
manager / password (Write access)
operator / password (Read access)
Username:
Password:
Login
`
return c.Type("html").Send([]byte(html))
})
app.Get("/sms", func(c *fiber.Ctx) error {
// For /sms page, we'll check authentication on the client side
// since we store the token in sessionStorage
// The server will serve the page and let JavaScript handle auth check
html := `
SMS Workflow Pipeline
Recipients (comma-separated phone numbers):
Message:
Hello! This is a test SMS from the advanced workflow engine.
Next: Choose Provider
🤖 Auto-Select (Recommended)
Let the system choose the best provider based on cost and delivery rates
📱 Twilio
Premium provider with high delivery rates - $0.0075/SMS
🌍 Vonage (Nexmo)
Global coverage with competitive pricing - $0.0065/SMS
☁️ AWS SNS
Reliable cloud-based SMS service - $0.0055/SMS
Previous
Next: Send SMS
Previous
🚀 Send SMS
Sending SMS...
Please wait while we process your SMS through the workflow pipeline
`
return c.Type("html").Send([]byte(html))
})
// API Documentation
app.Get("/docs", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{
"title": "Advanced SMS Workflow Engine API",
"version": "2.0.0",
"endpoints": map[string]interface{}{
"POST /auth/login": map[string]interface{}{
"description": "Authenticate user and get token",
"body": map[string]string{
"username": "string",
"password": "string",
},
},
"POST /sms/send": map[string]interface{}{
"description": "Send SMS through workflow pipeline",
"headers": map[string]string{
"Authorization": "Bearer token",
},
"body": map[string]interface{}{
"recipients": []string{"+1234567890"},
"message": "string",
"provider": "auto|twilio|nexmo",
},
},
"POST /webhook/sms/status": map[string]interface{}{
"description": "Receive SMS delivery status webhook",
"body": map[string]interface{}{
"message_id": "string",
"status": "delivered|failed|pending",
"timestamp": "ISO 8601 string",
},
},
},
"workflows": []string{
"user-auth-subdag - User authentication sub-workflow",
"sms-pipeline - Complete SMS sending pipeline",
"sms-webhook-handler - SMS delivery status handler",
},
})
})
log.Println("✅ All routes configured successfully")
}