Skip to main content

🎯 Workflow Studio: N8N Killer Architecture - Complete Vision

Mission: Transform Workflow Studio into the most powerful, intuitive workflow automation platform on Earth by implementing advanced content picking, data mapping, and real-time validation systems.


πŸ—οΈ Architectural Foundation​

Existing Infrastructure (Already Built)​

  1. ThorAPI Code Generation System

    • OpenAPI spec β†’ Spring Boot + TypeScript clients + JPA models
    • Generated models: ExecModule, IntegrationAccount, Workflow, Task, WorkflowState, OasOpenAPISpec
    • All CRUD operations + QBE filtering + pagination
  2. ExecModule System

    • 20+ modules (Email, REST, Stripe, AWS, Social, etc.)
    • IntegrationAccount relationship: Each ExecModule can have associated IntegrationAccount for auth
    • Module config stored as JSON in moduleData field
    • Metadata: className, moduleType, moduleOrder, status
  3. WorkflowState

    • Key-value store for workflow runtime data
    • Stored per workflow: List<WorkflowState>
    • Usage: Pass data between tasks/modules
    • Example: WorkflowState(name="imageUrl", stateValue="https://...")
  4. OpenAPI Spec System

    • OasOpenAPISpec model with structured data
    • Paths, operations, schemas, components
    • Used by ThorAPIController for code generation
    • Fail-safe backup spec available

🎨 New Architecture: The Big Picture​

Core Concept: Workflow as API Contract + Data Flow Graph​

Every workflow should:

  1. Define its API surface (what data sources/endpoints it uses)
  2. Track IntegrationAccounts (credentials for each service)
  3. Enable content/URL picking (select from previous module outputs)
  4. Support field-level data mapping (GraphQL-style field selection with Gridheim transforms)
  5. Provide real-time validation (sanity check after every action)

πŸ“¦ Component Architecture​

1. Content Picker System​

Purpose: Select content from:

  • Workflow-defined data sources (from OpenAPI spec)
  • Previous ExecModule outputs
  • IntegrationAccount-scoped resources (templates, lists, etc.)

Architecture:

// New Component: ContentPicker
interface ContentPickerProps {
/** Workflow context for filtering available sources */
workflow: Workflow;

/** Type of content to pick (template, list, url, file, etc.) */
contentType: ContentType;

/** Optional filter by integration account type */
accountType?: string; // "mailchimp", "stripe", "aws-s3", etc.

/** Callback when content selected */
onSelect: (content: PickedContent) => void;

/** Enable multi-select */
multiSelect?: boolean;
}

interface PickedContent {
/** Source type */
source: "workflow-api" | "module-output" | "integration-resource";

/** Reference path for runtime resolution */
path: string; // e.g., "{{ImageGen.output.url}}" or "spec://BlogPostApi/posts"

/** Metadata for display */
label: string;
description?: string;
preview?: string | object;
}

// ContentPicker renders:
// 1. "From Previous Modules" tab β†’ shows upstream module outputs (existing VariablePicker)
// 2. "From API Sources" tab β†’ lists workflow's OpenAPI spec endpoints
// 3. "From Integration" tab β†’ resources from specific IntegrationAccount

Integration with Existing System:

  • Extends VariablePicker component (already built)
  • Uses workflow.specs (OpenAPI spec reference) for API sources
  • Queries IntegrationAccountService for integration resources

2. URL Picker System​

Purpose: Select URLs from:

  • Previous module outputs (e.g., {{ImageGen.url}})
  • Workflow API endpoints (e.g., GET /api/templates/{id}/download)
  • Static URLs with validation

Architecture:

// New Component: URLPicker
interface URLPickerProps {
/** Current field value */
value: string;

/** Available upstream modules */
availableModules: ExecModule[];

/** Workflow API spec for endpoint selection */
workflowSpec?: OasOpenAPISpec;

/** Callback on URL selected */
onChange: (url: string) => void;
}

// URLPicker renders:
// 1. Variable picker button (🎯) β†’ opens VariablePicker for module outputs
// 2. API endpoint picker (πŸ”—) β†’ opens ContentPicker filtered to URL-returning endpoints
// 3. Manual input with real-time validation

Smart Detection:

  • Detect URL fields in ExecModule config automatically
  • Show picker button next to any field containing "url", "uri", "endpoint", "webhook"
  • Validate URL format and reachability (optional ping check)

3. IntegrationAccount Scoping​

Current State:

  • ExecModule has integrationAccount property (ManyToOne relationship)
  • IntegrationAccount has execModule (inverse relationship)
  • Can query: findIntegrationAccountByExecModule(execModule)

Enhancement:

// New: Workflow-level IntegrationAccount registry
interface WorkflowIntegrationRegistry {
workflow: Workflow;
integrationAccounts: IntegrationAccount[];

/** Get accounts filtered by type */
getAccountsByType(type: string): IntegrationAccount[];

/** Get all accounts used by workflow tasks */
getAllUsedAccounts(): IntegrationAccount[];
}

// Service method (Java backend)
@Service
public class WorkflowIntegrationRegistryService {
/**
* Get all IntegrationAccounts referenced by workflow's ExecModules
*/
public List<IntegrationAccount> getWorkflowIntegrationAccounts(UUID workflowId) {
Workflow workflow = workflowRepo.findById(workflowId).orElseThrow();
Set<IntegrationAccount> accounts = new HashSet<>();

for (Task task : workflow.getTasks()) {
for (ExecModule module : task.getModules()) {
if (module.getIntegrationAccount() != null) {
accounts.add(module.getIntegrationAccount());
}
}
}

return new ArrayList<>(accounts);
}

/**
* Get all API/data sources defined in workflow's OpenAPI spec
*/
public List<ApiSource> getWorkflowApiSources(UUID workflowId) {
Workflow workflow = workflowRepo.findById(workflowId).orElseThrow();
if (workflow.getSpecs() == null || workflow.getSpecs().isEmpty()) {
return Collections.emptyList();
}

// Parse first spec (main API definition)
OasOpenAPISpec spec = workflow.getSpecs().get(0);
List<ApiSource> sources = new ArrayList<>();

for (OasPath path : spec.getPaths()) {
sources.add(new ApiSource(
path.getPath(),
path.getSummary(),
path.getOperations()
));
}

return sources;
}
}

UI Integration:

  • New toolbar button: "πŸ“‹ Accounts & APIs" β†’ shows WorkflowIntegrationRegistry modal
  • Lists all IntegrationAccounts used by workflow
  • Lists all API endpoints defined in workflow.specs
  • Quick actions: "Add Account", "Edit Account", "Test Connection"

4. Data Mapper Component​

Purpose: Visual field-to-field mapping between ExecModules with Gridheim transformations

Architecture:

// New Component: DataMapper
interface DataMapperProps {
/** Source module (left side) */
sourceModule: ExecModule;

/** Target module (right side) */
targetModule: ExecModule;

/** Current mapping configuration */
mapping: FieldMapping[];

/** Callback when mapping changes */
onChange: (mapping: FieldMapping[]) => void;
}

interface FieldMapping {
/** Source field path (e.g., "response.data.items[0].title") */
sourcePath: string;

/** Target field path (e.g., "config.emailSubject") */
targetPath: string;

/** Optional transformation (Gridheim Rune calc) */
transform?: GridheimRuneCalc;
}

interface GridheimRuneCalc {
/** Rune expression (e.g., "UPPER(A1)", "CONCAT(A1, ' - ', A2)") */
expression: string;

/** Preview of transformed value */
preview?: string;
}

// DataMapper UI Layout:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ SOURCE MODULE β”‚ TRANSFORM β”‚ TARGET MODULE β”‚
β”‚ (REST API Response) β”‚ β”‚ (Email Module) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ response.data.title β”‚ β†’ UPPER() β†’ β”‚ config.emailSubject β”‚
β”‚ response.data.body β”‚ β†’ (none) β†’ β”‚ config.emailBody β”‚
β”‚ response.status β”‚ β†’ =IF() β†’ β”‚ config.priority β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Features:

  1. Drag-and-drop field connections (left source β†’ right target)
  2. Middle column shows transformation formula (Gridheim Rune calc)
  3. Live preview of transformed values (using sample data)
  4. Type validation (warn if string mapped to number field)
  5. Auto-suggestions for common transforms:
    • UPPER(), LOWER(), TRIM()
    • CONCAT(), SPLIT(), REPLACE()
    • IF(), SWITCH(), VLOOKUP()
    • Date/time formatting: DATEFORMAT(), NOW()

Integration with Gridheim:

  • Reuse Gridheim's Rune calc engine for transformations
  • Expose common Excel-like functions
  • Support cell references: A1 = source field, B1 = transformed value

5. Real-Time Validation System​

Purpose: Sanity check workflow after every action (like compilation)

Architecture:

// New Service: WorkflowValidationService
interface WorkflowValidationResult {
valid: boolean;
errors: ValidationError[];
warnings: ValidationWarning[];
suggestions: ValidationSuggestion[];
}

interface ValidationError {
severity: "error" | "warning" | "info";
taskId?: UUID;
moduleId?: UUID;
field?: string;
message: string;
quickFix?: QuickFix;
}

interface QuickFix {
label: string;
action: () => void;
}

// Validation Rules (Backend):
@Service
public class WorkflowValidationService {
/**
* Validate workflow and return actionable errors
*/
public WorkflowValidationResult validate(Workflow workflow) {
List<ValidationError> errors = new ArrayList<>();

// Rule 1: Missing IntegrationAccount
for (Task task : workflow.getTasks()) {
for (ExecModule module : task.getModules()) {
if (requiresIntegrationAccount(module) && module.getIntegrationAccount() == null) {
errors.add(new ValidationError(
"error",
task.getId(),
module.getId(),
"integrationAccount",
"Module '" + module.getName() + "' requires an IntegrationAccount",
createQuickFix("Select account", () -> showAccountPicker(module))
));
}
}
}

// Rule 2: Invalid variable references
for (Task task : workflow.getTasks()) {
for (ExecModule module : task.getModules()) {
String moduleData = module.getModuleData();
List<String> refs = extractVariableReferences(moduleData);

for (String ref : refs) {
if (!isValidReference(ref, workflow)) {
errors.add(new ValidationError(
"error",
task.getId(),
module.getId(),
"moduleData",
"Invalid variable reference: " + ref,
createQuickFix("Pick variable", () -> openVariablePicker(module))
));
}
}
}
}

// Rule 3: Missing required fields
// Rule 4: Type mismatches
// Rule 5: Unreachable tasks
// Rule 6: Circular dependencies
// Rule 7: Missing API endpoints in spec

return new WorkflowValidationResult(
errors.isEmpty(),
errors.stream().filter(e -> e.severity == "error").toList(),
errors.stream().filter(e -> e.severity == "warning").toList(),
generateSuggestions(workflow)
);
}
}

UI Integration:

  • Validation panel at bottom of Workflow Studio (like VS Code Problems panel)
  • Auto-runs after every workflow change (debounced 500ms)
  • Shows errors, warnings, and suggestions
  • Click error β†’ jumps to offending task/module + highlights field
  • Quick Fix button β†’ applies auto-fix

Visual Indicators:

  • ❌ Red badge on task with errors
  • ⚠️ Yellow badge on task with warnings
  • βœ… Green checkmark on valid task
  • Status bar: "βœ… No errors" or "❌ 3 errors, 2 warnings"

πŸ”„ Data Flow Architecture​

Runtime Execution Flow​

1. Workflow starts
↓
2. Load WorkflowState (initial data)
↓
3. For each Task:
a. Resolve variable references ({{moduleName.output.field}})
b. Apply Gridheim transformations (DataMapper rules)
c. Execute ExecModule with resolved config
d. Store output in WorkflowState
↓
4. Pass data to next Task/Module
↓
5. Repeat until all Tasks complete

Key Components:

  1. Variable Resolution Engine (Backend)

    @Service
    public class WorkflowVariableResolver {
    /**
    * Resolve {{variable}} references in moduleData
    */
    public String resolveVariables(String moduleData, Map<String, Object> workflowState) {
    // Pattern: {{moduleName.outputField}}
    Pattern pattern = Pattern.compile("\\{\\{([^}]+)\\}\\}");
    Matcher matcher = pattern.matcher(moduleData);

    StringBuffer result = new StringBuffer();
    while (matcher.find()) {
    String varPath = matcher.group(1);
    Object value = resolveVariablePath(varPath, workflowState);
    matcher.appendReplacement(result, String.valueOf(value));
    }
    matcher.appendTail(result);

    return result.toString();
    }
    }
  2. Data Transform Engine (Gridheim Integration)

    @Service
    public class WorkflowTransformService {
    @Autowired
    private GridheimRuneCalcEngine runeEngine;

    /**
    * Apply Gridheim Rune calc transformations
    */
    public Object transform(Object sourceValue, String runeExpression) {
    // Create temporary cell with source value
    Cell cell = new Cell();
    cell.setValue(sourceValue);

    // Execute Rune calc
    RuneResult result = runeEngine.evaluate(runeExpression, cell);

    return result.getValue();
    }
    }
  3. WorkflowState Manager (State Persistence)

    @Service
    public class WorkflowStateManager {
    /**
    * Store module output in WorkflowState
    */
    public void storeModuleOutput(Workflow workflow, ExecModule module, Map<String, Object> output) {
    String moduleName = module.getName() != null ? module.getName() : module.getClassName();

    // Flatten output object into WorkflowState entries
    for (Map.Entry<String, Object> entry : output.entrySet()) {
    String stateName = moduleName + "." + entry.getKey();
    String stateValue = JSON.stringify(entry.getValue());

    WorkflowState state = new WorkflowState()
    .name(stateName)
    .stateValue(stateValue)
    .workflowId(workflow.getId());

    workflowStateRepo.save(state);
    }
    }
    }

🎯 Implementation Roadmap​

Phase 1: Foundation (Week 1)​

1.1 Backend Services​

Create core services:

// WorkflowIntegrationRegistryService.java
@Service
public class WorkflowIntegrationRegistryService {
public List<IntegrationAccount> getWorkflowIntegrationAccounts(UUID workflowId) { }
public List<ApiSource> getWorkflowApiSources(UUID workflowId) { }
public IntegrationAccount selectIntegrationAccount(UUID moduleId, UUID accountId) { }
}

// WorkflowValidationService.java
@Service
public class WorkflowValidationService {
public WorkflowValidationResult validate(Workflow workflow) { }
public List<ValidationError> validateModule(ExecModule module) { }
public List<String> extractVariableReferences(String json) { }
public boolean isValidReference(String ref, Workflow workflow) { }
}

// WorkflowVariableResolver.java
@Service
public class WorkflowVariableResolver {
public String resolveVariables(String moduleData, Map<String, Object> state) { }
public Object resolveVariablePath(String path, Map<String, Object> state) { }
}

// WorkflowStateManager.java
@Service
public class WorkflowStateManager {
public void storeModuleOutput(Workflow workflow, ExecModule module, Map<String, Object> output) { }
public Map<String, Object> getWorkflowState(UUID workflowId) { }
}

1.2 REST API Endpoints​

Add validation and registry endpoints:

@RestController
@RequestMapping("/v1/workflow")
public class WorkflowStudioController {

@PostMapping("/{id}/validate")
public ResponseEntity<WorkflowValidationResult> validateWorkflow(@PathVariable UUID id) {
Workflow workflow = workflowService.findById(id).orElseThrow();
WorkflowValidationResult result = validationService.validate(workflow);
return ResponseEntity.ok(result);
}

@GetMapping("/{id}/integrations")
public ResponseEntity<List<IntegrationAccount>> getWorkflowIntegrations(@PathVariable UUID id) {
List<IntegrationAccount> accounts = registryService.getWorkflowIntegrationAccounts(id);
return ResponseEntity.ok(accounts);
}

@GetMapping("/{id}/api-sources")
public ResponseEntity<List<ApiSource>> getWorkflowApiSources(@PathVariable UUID id) {
List<ApiSource> sources = registryService.getWorkflowApiSources(id);
return ResponseEntity.ok(sources);
}
}

Phase 2: Content Picker System (Week 2)​

2.1 ContentPicker Component​

Extend VariablePicker with API/Integration tabs:

// ContentPicker.tsx
export const ContentPicker: React.FC<ContentPickerProps> = ({
workflow,
contentType,
accountType,
onSelect,
multiSelect = false,
}) => {
const [activeTab, setActiveTab] = useState<
"modules" | "apis" | "integrations"
>("modules");

// Fetch data sources
const { data: moduleOutputs } = useGetModuleOutputsQuery(workflow.id);
const { data: apiSources } = useGetWorkflowApiSourcesQuery(workflow.id);
const { data: integrationAccounts } = useGetWorkflowIntegrationsQuery(
workflow.id
);

return (
<Modal show={show} onClose={onCancel}>
<Tabs activeTab={activeTab} onChange={setActiveTab}>
<Tab name="modules" label="πŸ“¦ From Modules">
<VariablePicker
availableModules={moduleOutputs}
onSelect={onSelect}
/>
</Tab>

<Tab name="apis" label="πŸ”— From APIs">
<ApiSourceList
sources={apiSources}
contentType={contentType}
onSelect={onSelect}
/>
</Tab>

<Tab name="integrations" label="πŸ” From Integrations">
<IntegrationResourceList
accounts={integrationAccounts}
accountType={accountType}
contentType={contentType}
onSelect={onSelect}
/>
</Tab>
</Tabs>
</Modal>
);
};

2.2 URL Picker Integration​

Add URL picker to FormFieldRenderer:

// Update FormFieldRenderer.tsx
const renderURLField = (fieldName: string, value: string) => {
return (
<div style={{ display: "flex", gap: "8px" }}>
<input
type="url"
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder="https://example.com/resource"
/>

{/* Variable picker button */}
<button onClick={() => openVariablePicker()}>🎯</button>

{/* API endpoint picker button */}
<button onClick={() => openContentPicker("url")}>πŸ”—</button>

{/* URL validator */}
<ValidationBadge url={value} />
</div>
);
};

Phase 3: Data Mapper (Week 3)​

3.1 DataMapper Component​

Build visual field mapper:

// DataMapper.tsx
export const DataMapper: React.FC<DataMapperProps> = ({
sourceModule,
targetModule,
mapping,
onChange,
}) => {
const [connections, setConnections] = useState<Connection[]>([]);

// Detect source fields from module output schema
const sourceFields = useMemo(
() => extractFieldsFromSchema(sourceModule.outputSchema),
[sourceModule]
);

// Detect target fields from module config schema
const targetFields = useMemo(
() => extractFieldsFromSchema(targetModule.configSchema),
[targetModule]
);

return (
<div className="data-mapper">
<div className="mapper-grid">
{/* Left: Source fields */}
<div className="source-panel">
<h3>{sourceModule.name || "Source"}</h3>
{sourceFields.map((field) => (
<FieldNode
key={field.path}
field={field}
onDragStart={() => handleDragStart(field)}
/>
))}
</div>

{/* Middle: Transformations */}
<div className="transform-panel">
{mapping.map((map, idx) => (
<TransformEditor
key={idx}
mapping={map}
onUpdate={(newMap) => updateMapping(idx, newMap)}
/>
))}
</div>

{/* Right: Target fields */}
<div className="target-panel">
<h3>{targetModule.name || "Target"}</h3>
{targetFields.map((field) => (
<FieldNode
key={field.path}
field={field}
onDrop={(sourceField) => createMapping(sourceField, field)}
/>
))}
</div>
</div>

{/* Visual connections (SVG lines) */}
<ConnectionLines connections={connections} />
</div>
);
};

3.2 Gridheim Rune Calc Integration​

Add transformation formula editor:

// TransformEditor.tsx
const TransformEditor: React.FC<{ mapping: FieldMapping }> = ({ mapping }) => {
const [formula, setFormula] = useState(mapping.transform?.expression || "");
const [preview, setPreview] = useState<string>("");

// Live preview of transformation
useEffect(() => {
if (formula && mapping.sourceValue) {
const result = evaluateGridheimFormula(formula, mapping.sourceValue);
setPreview(result);
}
}, [formula, mapping.sourceValue]);

return (
<div className="transform-editor">
<input
value={formula}
onChange={(e) => setFormula(e.target.value)}
placeholder="=UPPER(A1)"
/>
<div className="preview">
Preview: <code>{preview}</code>
</div>
<FunctionPicker onSelect={(fn) => setFormula(fn)} />
</div>
);
};

Phase 4: Real-Time Validation (Week 4)​

4.1 Validation Panel Component​

Build VS Code-style problems panel:

// ValidationPanel.tsx
export const ValidationPanel: React.FC<{ workflow: Workflow }> = ({
workflow,
}) => {
const [validationResult, setValidationResult] =
useState<WorkflowValidationResult | null>(null);

// Auto-validate on workflow changes (debounced)
useEffect(() => {
const timer = setTimeout(() => {
validateWorkflow(workflow.id).then(setValidationResult);
}, 500);

return () => clearTimeout(timer);
}, [workflow]);

if (!validationResult) {
return <div>Validating...</div>;
}

return (
<div className="validation-panel">
<div className="panel-header">
{validationResult.valid ? (
<span>βœ… No errors</span>
) : (
<span>
❌ {validationResult.errors.length} errors, ⚠️{" "}
{validationResult.warnings.length} warnings
</span>
)}
</div>

<div className="error-list">
{validationResult.errors.map((error, idx) => (
<ErrorItem
key={idx}
error={error}
onJumpTo={() => jumpToError(error)}
onQuickFix={() => error.quickFix?.action()}
/>
))}
</div>
</div>
);
};

4.2 Visual Error Indicators​

Add badges to TaskNode:

// Update WorkflowCanvas.tsx TaskNode rendering
const TaskNode = ({ data }) => {
const { errors, warnings } = useTaskValidation(data.task.id);

return (
<div className="task-node">
<div className="task-header">
{data.task.name}

{/* Validation badges */}
{errors > 0 && <span className="badge error">❌ {errors}</span>}
{warnings > 0 && <span className="badge warning">⚠️ {warnings}</span>}
{errors === 0 && warnings === 0 && (
<span className="badge success">βœ…</span>
)}
</div>

{/* Rest of task rendering... */}
</div>
);
};

πŸ“Š Data Model Extensions​

New Models (Add to OpenAPI Spec)​

# api-source.yaml
ApiSource:
type: object
properties:
path:
type: string
description: API endpoint path (e.g., "/api/templates")
method:
type: string
enum: [GET, POST, PUT, DELETE, PATCH]
summary:
type: string
responseType:
type: string
description: Response content type
outputSchema:
type: object
description: JSON schema of response

# field-mapping.yaml
FieldMapping:
type: object
properties:
sourceModule:
$ref: "#/components/schemas/ExecModule"
targetModule:
$ref: "#/components/schemas/ExecModule"
sourcePath:
type: string
example: "response.data.title"
targetPath:
type: string
example: "config.emailSubject"
transform:
$ref: "#/components/schemas/GridheimRuneCalc"

# gridheim-rune-calc.yaml
GridheimRuneCalc:
type: object
properties:
expression:
type: string
description: Rune formula (e.g., "=UPPER(A1)")
preview:
type: string
description: Preview of transformed value

# workflow-validation-result.yaml
WorkflowValidationResult:
type: object
properties:
valid:
type: boolean
errors:
type: array
items:
$ref: "#/components/schemas/ValidationError"
warnings:
type: array
items:
$ref: "#/components/schemas/ValidationError"
suggestions:
type: array
items:
$ref: "#/components/schemas/ValidationSuggestion"

ValidationError:
type: object
properties:
severity:
type: string
enum: [error, warning, info]
taskId:
type: string
format: uuid
moduleId:
type: string
format: uuid
field:
type: string
message:
type: string
quickFix:
$ref: "#/components/schemas/QuickFix"

🎨 UI/UX Enhancements​

Workflow Studio Toolbar​

Add new buttons:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ πŸ’Ύ Save ▢️ Run ⏸️ Pause πŸ”„ Refresh πŸ“‹ Accounts & APIs β”‚
β”‚ β”‚
β”‚ 🎯 Variables πŸ”— URLs πŸ“Š Data Mapper βœ… Validate β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Task Context Menu​

Right-click on task:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ βš™οΈ Configure β”‚
β”‚ 🧩 Add Module β”‚
β”‚ 🎯 Pick Variables β”‚
β”‚ πŸ“Š Map Data β”‚
β”‚ πŸ”— Select URLs β”‚
β”‚ πŸ” Set Integration Account β”‚
β”‚ βœ… Validate Task β”‚
β”‚ πŸ—‘οΈ Delete Task β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”₯ Success Criteria​

  1. βœ… Content Picker

    • Can select from module outputs, API endpoints, integration resources
    • Multi-source support (modules, APIs, integrations)
    • Type filtering (templates, lists, URLs, files)
  2. βœ… URL Picker

    • Smart detection of URL fields
    • Variable picker integration (🎯)
    • API endpoint picker integration (πŸ”—)
    • Real-time URL validation
  3. βœ… IntegrationAccount Management

    • Workflow-level account registry
    • Auto-detect accounts used by modules
    • Quick account selection/switching
    • Type-based filtering (QBE)
  4. βœ… Data Mapper

    • Visual field-to-field connections (drag-and-drop)
    • Gridheim Rune calc transformations
    • Live preview of transformed values
    • Auto-suggestions for common transforms
  5. βœ… Real-Time Validation

    • Auto-validate after every workflow change
    • Problems panel (errors, warnings, suggestions)
    • Visual error indicators on canvas
    • Quick Fix actions
  6. βœ… OpenAPI Spec Integration

    • Workflow.specs defines available data sources
    • API endpoint picker uses spec metadata
    • Schema-based field detection

πŸ“ Documentation Requirements​

  1. Architecture Decision Record (ADR)

    • Why content picker vs manual entry
    • Why Gridheim for transformations
    • Why real-time validation vs on-save
  2. Developer Guide

    • How to add new ContentPicker sources
    • How to create custom validation rules
    • How to extend DataMapper transforms
  3. User Guide

    • How to use Content Picker
    • How to map data between modules
    • How to fix validation errors

πŸš€ Next Steps​

Phase 1 (Backend Foundation):

  1. Create WorkflowIntegrationRegistryService
  2. Create WorkflowValidationService
  3. Create WorkflowVariableResolver
  4. Add REST API endpoints

Phase 2 (Content Picker):

  1. Create ContentPicker component
  2. Extend VariablePicker with tabs
  3. Build ApiSourceList component
  4. Build IntegrationResourceList component

Phase 3 (Data Mapper):

  1. Create DataMapper component
  2. Build FieldNode component
  3. Build TransformEditor component
  4. Integrate Gridheim Rune calc engine

Phase 4 (Validation):

  1. Create ValidationPanel component
  2. Add visual error badges to TaskNode
  3. Implement auto-validation system
  4. Add Quick Fix actions

This architecture transforms ValkyrAI into the most powerful workflow automation platform on Earth - a true N8N killer! 🎯πŸ”₯