Workflow Planner
The Workflow Planner is a management view that shows when your scheduled workflows run, how long they actually take, and where they compete for the same external services. It is designed to answer operational questions such as:
- What is running on Monday at 8 AM?
- Are two workflows hitting the same SMTP server at the same time?
- Where do I have free slots to schedule a new heavy job?
- How saturated is each day of the week?
Unlike the Workflows view (which is operational, “run/edit”), the Planner is strategic: it helps you organize the execution time of the entire system.
How to access
Section titled “How to access”From the side menu: Planner.
The route is /workflow-planner. It appears automatically for any authenticated user of the client.
Where the data comes from
Section titled “Where the data comes from”The planner combines two real sources of information from the system:
- Workflows with active cron for the current client (
workflows.workflow_json.schedulewithactive_schedule = true). - Execution history from the
workflowstatestable, aggregated per node over a configurable window (7, 14, 30, 60 or 90 days) — used to compute the average duration of each node and draw the segments proportionally.
It does not use mock data. If your client has no workflows with active cron, the planner shows an explicit empty state. Manual workflows and webhook-triggered workflows are not shown in this version (planned for a second phase as “hot-spot analysis from history”).
The two views
Section titled “The two views”Macro view (Week / Month)
Section titled “Macro view (Week / Month)”A heatmap by day: each day is a cell showing how many total execution hours are planned. The darker, the higher the load.
- Week mode shows the 7 days (Monday to Sunday).
- Month mode shows 30 days (useful to detect monthly patterns).
- Red warning icons mark days with detected service collisions.
- Use it for a quick overview of weekly distribution and to spot overloaded or empty days.
24h Detail view
Section titled “24h Detail view”A Gantt-style diagram for the selected day:
- Fixed left column with workflow name + schedule + actions menu button.
- Hour axis from 00h to 23h (with horizontal scroll if the screen is narrow; the left column stays sticky).
- One row per workflow, with a colored block representing its execution.
- Per-node segments inside the block, sized proportionally to the node’s average duration in the history. Colors are stable per module type (always the same color for
mail_send, etc.). - “Free slots” row with green stripes marking periods with no workflow.
- Blocks with a red border indicate that workflow has a detected collision with another.
Why a 1-hour minimum visible duration
Section titled “Why a 1-hour minimum visible duration”Most real workflows last seconds. If we drew their exact duration on a 24h scale, blocks would be invisible (1 pixel). That’s why the planner enforces a 1-hour minimum visible duration per block. This:
- Guarantees you can see the per-node segments.
- Makes nearby-time collisions detectable (e.g. two crons at 08:00 and 08:30).
- Does not affect the real history or average durations: only the graphical representation.
The collision concept
Section titled “The collision concept”This is the most important part to understand. We do not consider it a collision just because two workflows overlap in time. The exact definition is:
A collision occurs when two distinct workflows execute a node of the same
moduleName(same service type) in overlapping time windows.
Why this criterion
Section titled “Why this criterion”A workflow is just an orchestrator. What actually competes for resources are its nodes, and specifically the external service each node calls:
- If two workflows run at the same time but one talks to
mail_sendand the other todataStore, they don’t bother each other: they use different resources. - If both run
mail_sendat the exact same second, they do bother each other: both fight for the same SMTP provider, may hit rate limits, deliver emails out of order, etc.
“Service collision” tells you what real operational problem you will have, not just that two crons cross.
How it is calculated (step-by-step algorithm)
Section titled “How it is calculated (step-by-step algorithm)”For each block in the day (workflow x occurrence):
-
The block is broken into per-node sub-intervals, proportional to each node’s average duration.
Example:
Sync CRM(08:00-09:00, 60min visible total, 3 nodes):Node % Interval webhook 8% 08:00-08:04 transformation 60% 08:04-08:48 mail_send 32% 08:48-09:00 -
All pairs of sub-intervals between distinct blocks of the same day are compared. For each pair
(intervalA, intervalB):- Same day?
- Different workflows?
- Same
moduleName(root type)? - Time overlap? (
max(startA, startB) < min(endA, endB))
All four conditions must hold for it to count as a collision.
-
If they all hold, the collision is recorded with the exact overlap time range.
Analysis cases
Section titled “Analysis cases”Case 1 — Real collision on the same service
Section titled “Case 1 — Real collision on the same service”Setup:
Sync CRM, cron0 8 * * 1(Monday 08:00). Nodes:webhook->transformation->mail_send.Backup DB, cron30 8 * * 1(Monday 08:30). Nodes:dataStore->mail_send.
Analysis:
Both workflows touch mail_send near the end of their execution. With the 1h minimum visible duration:
Sync CRMoccupies 08:00-09:00;mail_sendfalls roughly at 08:48-09:00.Backup DBoccupies 08:30-09:30;mail_sendfalls roughly at 09:18-09:30.
If the proportions overlap in time, the collisions table will show an entry like:
| Day | Schedule | Service | Workflow A | Workflow B |
|---|---|---|---|---|
| Monday | 08:48-09:00 | mail_send | Sync CRM | Backup DB |
What to do: change Backup DB cron to 09:00, or configure a different SMTP credential per flow.
Case 2 — Time overlap without collision
Section titled “Case 2 — Time overlap without collision”Setup:
Invoice Cron, cron0 6 * * 1(Monday 06:00). Nodes:billing->pdf_generator->mail_send.Stock Update, cron15 6 * * 1(Monday 06:15). Nodes:webhook->transformation->dataStore.
Analysis:
Visually the blocks overlap in the 06:15-07:00 range. But the service sets are disjoint: {billing, pdf_generator, mail_send} ∩ {webhook, transformation, dataStore} = empty.
The algorithm correctly does not count this as a collision. The “Detected service collisions” table will show 0 entries related to this pair.
Conclusion: visual overlap does not imply operational conflict. Even though the planner draws them on top of each other, both can run in parallel without competing for resources.
Case 3 — Three workflows, chained collisions
Section titled “Case 3 — Three workflows, chained collisions”Setup:
Email Reports A, cron0 14 * * 5. Nodes:dataframe->mail_send.Email Reports B, cron5 14 * * 5. Nodes:dataframe->mail_send.Email Reports C, cron10 14 * * 5. Nodes:dataframe->mail_send.
Analysis:
All three run within a 15-minute window. With the 1h minimum visible duration, their blocks are 14:00-15:00, 14:05-15:05 and 14:10-15:10. All end with mail_send.
The table will show three collisions (one per pair combination):
| Day | Schedule | Service | Workflow A | Workflow B |
|---|---|---|---|---|
| Friday | 14:48-15:00 | mail_send | Reports A | Reports B |
| Friday | 14:53-15:00 | mail_send | Reports A | Reports C |
| Friday | 14:53-15:05 | mail_send | Reports B | Reports C |
What to do: merge them into a single parallelizable workflow, or space the crons apart by at least the total estimated duration.
Case 4 — Workflow without history
Section titled “Case 4 — Workflow without history”Setup: a freshly created workflow with active cron but no executions recorded in workflowstates within the window.
Analysis:
The backend returns the workflow with nodes: [] and totalDurationMs: 0. The planner draws it as a block of the minimum visible size (1h) with a single gray segment labeled “(no history)”.
It does not generate collisions because its dummy moduleName will never match a real service.
What to do: run the workflow at least once (manually or by waiting for the cron) so that real durations appear on the next planner load.
Per-workflow actions
Section titled “Per-workflow actions”Each row has a context menu (three-dot icon in the left column) with six options:
| Option | What it does |
|---|---|
| View summary | Navigates to the workflow summary (/workflows/summary/:id) |
| Go to Editor | Opens the visual editor of the workflow |
| Run | Manually launches the workflow (does not affect planning) |
| Schedule | Opens a dialog to edit the cron and toggle the schedule |
| View incidents | Shows a dialog with open and resolved incidents |
| View comments | Opens the comments box of the workflow |
About “Schedule”
Section titled “About “Schedule””The dialog uses the CronExpressionField component (the same one used in the workflow editor). On save:
- It calls
PUT /api/workflows/:id/scheduleto update the cron and theactive_scheduleflag. - It automatically reloads the entire planning data.
- It recomputes blocks, occurrences and collisions — because changing a cron may create or resolve a collision in another day/hour.
This makes the planner an interactive tool: you can move schedules around and see the effect immediately on the chart.
Export to PDF
Section titled “Export to PDF”The Export Report button generates a horizontal A4 PDF with:
- Header: title, generation date and current view (Macro/Detail).
- Clean snapshot of the current chart (rendered with
html2canvas, scale 2x for sharpness). - Detected collisions table redrawn with
jsPDF(selectable text, not an image) with columns: Day, Schedule, Service, Workflow A, Workflow B. Auto-paginates if there are many rows.
The report is useful for internal reviews, planning audits, or to document cron changes before/after.
History window configuration
Section titled “History window configuration”The “History” selector (top right) controls how many days back are averaged to compute per-node durations:
| Window | When to use it |
|---|---|
| 7 days | Diagnosing a recent issue |
| 14 days | Short-term trend view |
| 30 days | Default — recommended for regular planning |
| 60 days | Workflows with low frequency (weekly/biweekly) |
| 90 days | Monthly workflows or long-term view |
Changing the window triggers an automatic reload of the endpoint.
Backend endpoint
Section titled “Backend endpoint”GET /api/workflow/planner-schedules?days=30
Requires authentication (Bearer token). Returns:
{ "success": true, "data": [ { "workflowId": 102, "workflowName": "Sync CRM", "cron": "0 8 * * 1", "isplay": 1, "occurrences": [ { "dayOfWeek": 0, "startHour": 8.0 } ], "totalDurationMs": 4500, "executions": 28, "nodes": [ { "nodeId": "1", "nodeName": "webhook_1", "moduleName": "webhook", "avgDurationMs": 200, "executions": 28, "proportion": 0.044 } ] } ], "windowDays": 30}Notes:
dayOfWeek: 0 = Monday, 6 = Sunday (ISO format).startHour: decimal hour (e.g., 8.5 = 08:30).nodeNameis the instance (e.g.,webhook_1);moduleNameis the root type (e.g.,webhook) used for collision detection.proportion: percentage of the workflow’s total time taken by that node (0..1).isplay: workflow status in the DB (1 = running, other values = paused/draft).
The endpoint omits workflows without active cron and workflows with isplay = 0 (deleted).
Known limitations
Section titled “Known limitations”- No credential-level collision detection: two
mail_sendnodes with different SMTP accounts are still counted as a collision. Planned for phase 2 (requires reading each node’s configuration). - No manual or webhook workflows: only workflows with active cron are shown. Phase 2 will analyze the history to display “hot spots” of manual/webhook executions.
- 1-hour minimum visible: very fast workflows (seconds) may look bigger than they are. This is a deliberate decision so collisions remain visible.
- Cron must be standard: the endpoint uses
cron-parser. Unsupported expressions (years, exact seconds, custom aliases) are silently skipped.
Recommended use cases
Section titled “Recommended use cases”- Before scheduling a new workflow: open the planner, find a free green slot in the desired day and time range, and configure the cron to land there.
- After a schedule change: reopen the planner and verify you didn’t create a collision when moving a workflow.
- Weekly audit: export a PDF every Monday and archive it. It provides traceability of how the client’s planning evolves.
- Diagnosing send failures: if you have intermittent errors in
mail_send, check the planner for several workflows triggering emails simultaneously. The cause is often a rate-limit collision.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause | Fix |
|---|---|---|
| No workflow shows up | The client has no workflows with active_schedule = true | Schedule at least one workflow from the editor or the Schedule menu |
| Blocks appear empty as “(no history)“ | The workflow has never executed in the history window | Run it manually once or widen the history window |
| Visual overlap but 0 collisions | Workflows use different services (correct case) | No action needed — it is not a real collision |
| The cron shows the wrong hour | The workflow’s JSON schedule field was not updated | Edit the cron from the planner’s Schedule menu |
| PDF text gets cut off | Too many collisions for one page | jsPDF auto-paginates, the full content is present |
See also
Section titled “See also”- Traces, history and performance — source of the historical data
- Edit flow — where to initially configure a workflow’s cron
- Good practices — workflow design recommendations