docs(10): create phase plan for workflow modularization

Phase 10: Workflow Modularization
- 4 plan(s) in 3 wave(s)
- Wave 1: Orphan cleanup (1 plan)
- Wave 2: Sub-workflow extraction (2 plans parallel)
- Wave 3: Integration verification (1 plan)
- Ready for execution

Plans:
- 10-01: Remove 8 orphan nodes
- 10-02: Extract container-update sub-workflow (DEBT-03)
- 10-03: Extract container-actions sub-workflow
- 10-04: Integration verification with user checkpoint

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Lucas Berger
2026-02-04 11:39:54 -05:00
parent a8e947ec95
commit c122803fad
6 changed files with 1157 additions and 4 deletions
+7 -4
View File
@@ -20,10 +20,13 @@ Modularize the workflow for maintainability, add "update all" functionality, fix
**Requirements:** MOD-01, MOD-02, DEBT-03 **Requirements:** MOD-01, MOD-02, DEBT-03
**Plans:** 0 plans **Plans:** 4 plans
Plans: Plans:
- [ ] TBD (run /gsd:plan-phase 10 to break down) - [ ] 10-01-PLAN.md — Orphan node cleanup (remove 8 orphan nodes before modularization)
- [ ] 10-02-PLAN.md — Extract container update sub-workflow (consolidates DEBT-03)
- [ ] 10-03-PLAN.md — Extract container actions sub-workflow (start/stop/restart)
- [ ] 10-04-PLAN.md — Integration verification and user checkpoint
**Success Criteria:** **Success Criteria:**
1. Workflow split into logical sub-workflows (command routing, container operations, keyboard generation, etc.) 1. Workflow split into logical sub-workflows (command routing, container operations, keyboard generation, etc.)
@@ -104,7 +107,7 @@ Plans:
| 7 | Socket Security | v1.1 | Complete | | 7 | Socket Security | v1.1 | Complete |
| 8 | Inline Keyboard Infrastructure | v1.1 | Complete | | 8 | Inline Keyboard Infrastructure | v1.1 | Complete |
| 9 | Batch Operations | v1.1 | Complete | | 9 | Batch Operations | v1.1 | Complete |
| 10 | Workflow Modularization | v1.2 | Pending | | 10 | Workflow Modularization | v1.2 | Planned |
| 11 | Update All & Callback Limits | v1.2 | Pending | | 11 | Update All & Callback Limits | v1.2 | Pending |
| 12 | Polish & Audit | v1.2 | Pending | | 12 | Polish & Audit | v1.2 | Pending |
| 13 | Documentation Overhaul | v1.2 | Pending | | 13 | Documentation Overhaul | v1.2 | Pending |
@@ -112,4 +115,4 @@ Plans:
**v1.2 Coverage:** 12 requirements mapped across 4 phases **v1.2 Coverage:** 12 requirements mapped across 4 phases
--- ---
*Updated: 2026-02-04 after v1.1 milestone* *Updated: 2026-02-04 after Phase 10 planning*
@@ -0,0 +1,134 @@
---
phase: 10-workflow-modularization
plan: 01
type: execute
wave: 1
depends_on: []
files_modified: [n8n-workflow.json]
autonomous: true
must_haves:
truths:
- "Workflow has no orphan nodes visible in n8n canvas"
- "All existing functionality still works after cleanup"
- "Workflow node count reduced by 8"
artifacts:
- path: "n8n-workflow.json"
provides: "Cleaned workflow without orphan nodes"
contains: "Telegram Trigger"
key_links:
- from: "Telegram Trigger"
to: "All action paths"
via: "No broken connections"
pattern: "connections.*main"
---
<objective>
Remove 8 orphan nodes from the n8n workflow before modularization work begins.
Purpose: Clean up vestigial nodes from workflow evolution to establish a clean baseline for modularization. Orphan nodes clutter the canvas and may cause confusion during sub-workflow extraction.
Output: Workflow JSON with orphan nodes removed, deployed and verified working.
</objective>
<execution_context>
@/home/luc/.claude/get-shit-done/workflows/execute-plan.md
@/home/luc/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/10-workflow-modularization/10-RESEARCH.md
@n8n-workflow.json
</context>
<tasks>
<task type="auto">
<name>Task 1: Identify and document orphan nodes</name>
<files>n8n-workflow.json</files>
<action>
Analyze the workflow to identify all orphan nodes - nodes with no incoming connections that are not triggers, and nodes with no outgoing connections that are not legitimate terminal nodes (like Telegram send messages).
Programmatic analysis has found at minimum:
- "Answer Batch Exec" (position [1340, 900]) - httpRequest with no incoming connection
- "Batch Loop" (position [3100, -500]) - splitInBatches with no connections
The user reports 8 total orphan nodes. Examine the workflow carefully to identify all 8:
1. Search for nodes with no incoming connections that aren't triggers
2. Search for nodes with no outgoing connections that aren't terminal nodes (Send/Edit messages)
3. Check positions far from main flow (negative Y positions, isolated X positions)
4. Look for vestigial nodes from prior development phases
Document each orphan with:
- Node name
- Node type
- Position
- Why it's orphaned (no connections, leftover from development, etc.)
</action>
<verify>Create a list of all 8 orphan nodes with their positions and types</verify>
<done>All 8 orphan nodes identified and documented</done>
</task>
<task type="auto">
<name>Task 2: Remove orphan nodes and deploy</name>
<files>n8n-workflow.json</files>
<action>
Remove all identified orphan nodes from n8n-workflow.json:
1. For each orphan node:
- Remove the node object from the "nodes" array
- Remove any connection entries referencing the node from "connections" object
- Note: Use the node "name" field to find connections, not "id"
2. Verify JSON validity after removal:
- Parse the JSON to confirm it's valid
- Check that no connections reference removed nodes
3. Deploy updated workflow to n8n:
- Use n8n API to update the workflow
- Verify workflow activates without errors
4. Test core functionality still works:
- Test /status command
- Test container submenu navigation
- Test at least one action (start/stop/restart)
Do NOT remove any nodes that:
- Are triggers (Telegram Trigger)
- Are legitimate terminal nodes (Send/Edit message nodes)
- Have both incoming AND outgoing connections
- Are part of the batch execution flow (even if appears orphaned, verify first)
</action>
<verify>
- `python3 -c "import json; json.load(open('n8n-workflow.json'))"` succeeds
- Workflow deploys via n8n API without errors
- /status command returns container list
- At least one container action works
</verify>
<done>8 orphan nodes removed, workflow deployed, core functionality verified working</done>
</task>
</tasks>
<verification>
1. Workflow JSON is valid and parses without errors
2. n8n workflow is deployed and active
3. /status command shows container list inline keyboard
4. Container actions (start/stop/restart) work
5. Batch operations still function
6. Text commands (status, update <name>) still work
</verification>
<success_criteria>
- 8 orphan nodes removed from workflow
- Node count reduced from 248 to ~240
- All existing bot functionality works
- Workflow ready for modularization
</success_criteria>
<output>
After completion, create `.planning/phases/10-workflow-modularization/10-01-SUMMARY.md`
</output>
@@ -0,0 +1,222 @@
---
phase: 10-workflow-modularization
plan: 02
type: execute
wave: 2
depends_on: [10-01]
files_modified: [n8n-workflow.json, n8n-container-update.json]
autonomous: true
must_haves:
truths:
- "Single container update via text command works"
- "Single container update via inline keyboard works"
- "Batch update operations work"
- "Update flow exists in one place only (sub-workflow)"
artifacts:
- path: "n8n-container-update.json"
provides: "Container update sub-workflow"
contains: "executeWorkflowTrigger"
- path: "n8n-workflow.json"
provides: "Main workflow calling update sub-workflow"
contains: "executeWorkflow"
key_links:
- from: "n8n-workflow.json"
to: "n8n-container-update.json"
via: "Execute Sub-workflow node"
pattern: "executeWorkflow.*container-update"
---
<objective>
Extract the container update flow into a dedicated sub-workflow to consolidate duplicated code (DEBT-03).
Purpose: The update logic is currently duplicated between the text command path (~lines 1656-2400) and the callback/inline keyboard path (~lines 3628-4010). Extracting to a sub-workflow creates a single source of truth, reduces main workflow complexity, and makes the update logic independently testable.
Output: New container-update sub-workflow JSON file and updated main workflow that calls it from both text and callback paths.
</objective>
<execution_context>
@/home/luc/.claude/get-shit-done/workflows/execute-plan.md
@/home/luc/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/10-workflow-modularization/10-RESEARCH.md
@.planning/phases/10-workflow-modularization/10-01-SUMMARY.md
@n8n-workflow.json
</context>
<tasks>
<task type="auto">
<name>Task 1: Create container-update sub-workflow</name>
<files>n8n-container-update.json</files>
<action>
Create a new sub-workflow file `n8n-container-update.json` that encapsulates the entire container update flow.
**Input contract (Execute Sub-workflow Trigger with defined fields):**
```json
{
"containerId": "string - Docker container ID",
"containerName": "string - Container name for messages",
"chatId": "number - Telegram chat ID",
"messageId": "number - Message ID for inline edits (0 for text mode)",
"responseMode": "string - 'text' or 'inline'"
}
```
**Flow to extract (from research):**
1. Inspect container configuration (get current image, config, host config)
2. Pull latest image (with :latest tag protection)
3. Inspect new image and compare digests
4. If update needed:
- Stop container
- Remove old container
- Create new container with same config
- Start new container
5. Clean up old image
6. Return result
**Output contract:**
```json
{
"success": "boolean",
"message": "string - Result message for user",
"updated": "boolean - Whether update was performed",
"oldDigest": "string (optional)",
"newDigest": "string (optional)"
}
```
**Implementation notes:**
- Use "Define using fields" schema type for input contract (per research best practice)
- Include progress message editing for inline mode (messageId > 0)
- Include new message sending for text mode (messageId == 0)
- Handle both "update needed" and "already up to date" cases
- Preserve :latest tag protection (default to :latest if no tag)
- Preserve image cleanup after successful update
</action>
<verify>
- JSON file is valid: `python3 -c "import json; json.load(open('n8n-container-update.json'))"`
- Contains "executeWorkflowTrigger" node
- Has proper input schema with all 5 fields
</verify>
<done>Container update sub-workflow created with proper input/output contracts</done>
</task>
<task type="auto">
<name>Task 2: Wire main workflow to use sub-workflow</name>
<files>n8n-workflow.json</files>
<action>
Modify the main workflow to call the container-update sub-workflow instead of having inline update logic.
**Changes needed:**
1. **Text command path:**
- Find the text update flow (around the "Update Container" text command routing)
- Replace inline update nodes with:
a. Code node to prepare sub-workflow input (containerId, containerName, chatId, messageId=0, responseMode='text')
b. Execute Sub-workflow node pointing to container-update workflow
- Remove the duplicate update logic nodes from text path
2. **Callback/inline path:**
- Find the callback update flow (around "Handle Update Action" or similar)
- Replace inline update nodes with:
a. Code node to prepare sub-workflow input (containerId, containerName, chatId, messageId from callback, responseMode='inline')
b. Execute Sub-workflow node pointing to container-update workflow
- Remove the duplicate update logic nodes from callback path
3. **Batch update path:**
- Find where batch update calls individual container updates
- Ensure it also uses the sub-workflow (may already be structured to call the same code)
**Execute Sub-workflow node configuration:**
```json
{
"parameters": {
"source": "database",
"workflowId": "<will be set after import>",
"mode": "once",
"options": {
"waitForSubWorkflow": true
}
},
"type": "n8n-nodes-base.executeWorkflow"
}
```
**Important:** After extraction, the main workflow should be significantly shorter (estimate ~750 fewer lines per research).
</action>
<verify>
- Main workflow JSON is valid
- Contains "executeWorkflow" node(s) for update paths
- Old inline update nodes are removed (workflow is shorter)
</verify>
<done>Main workflow updated to call container-update sub-workflow from all update paths</done>
</task>
<task type="auto">
<name>Task 3: Deploy and verify update functionality</name>
<files>n8n-workflow.json, n8n-container-update.json</files>
<action>
Deploy both workflows to n8n and verify all update paths work.
**Deployment steps:**
1. Import container-update sub-workflow to n8n via API (create new workflow)
2. Note the workflow ID assigned by n8n
3. Update main workflow's Execute Sub-workflow node(s) with correct workflow ID
4. Deploy main workflow update to n8n via API
**Verification tests:**
1. **Text command update:**
- Send "update <container-name>" to bot
- Should show update confirmation prompt
- Confirm and verify update completes (or shows "already up to date")
2. **Inline keyboard update:**
- Use /status to get container list
- Select a container
- Tap "Update" button
- Should show confirmation dialog
- Confirm and verify update completes with progress messages
3. **Batch update (if time permits):**
- Initiate a batch update for 2 containers
- Verify both update correctly
</action>
<verify>
- Sub-workflow imported and has valid ID in n8n
- Main workflow deployed with correct sub-workflow reference
- Text "update <name>" command works
- Inline keyboard update flow works
- Progress messages display correctly
</verify>
<done>Update sub-workflow deployed and all update paths verified working</done>
</task>
</tasks>
<verification>
1. n8n-container-update.json exists and is valid JSON
2. Sub-workflow has proper Execute Sub-workflow Trigger with input schema
3. Main workflow contains Execute Sub-workflow nodes calling update workflow
4. Main workflow line count reduced by ~500+ lines
5. Text command "update <container>" works end-to-end
6. Inline keyboard update with confirmation works end-to-end
7. "Already up to date" case handled correctly
8. Old image cleanup still occurs after successful update
</verification>
<success_criteria>
- Container update logic exists in ONE place (sub-workflow)
- Both text and inline update paths use the sub-workflow
- DEBT-03 (duplicated update flow) resolved
- All update functionality works as before
</success_criteria>
<output>
After completion, create `.planning/phases/10-workflow-modularization/10-02-SUMMARY.md`
</output>
@@ -0,0 +1,224 @@
---
phase: 10-workflow-modularization
plan: 03
type: execute
wave: 2
depends_on: [10-01]
files_modified: [n8n-workflow.json, n8n-container-actions.json]
autonomous: true
must_haves:
truths:
- "Container start via text and inline works"
- "Container stop via text and inline works"
- "Container restart via text and inline works"
- "Simple actions exist in one place (sub-workflow)"
artifacts:
- path: "n8n-container-actions.json"
provides: "Container actions sub-workflow (start/stop/restart)"
contains: "executeWorkflowTrigger"
- path: "n8n-workflow.json"
provides: "Main workflow calling actions sub-workflow"
contains: "executeWorkflow"
key_links:
- from: "n8n-workflow.json"
to: "n8n-container-actions.json"
via: "Execute Sub-workflow node"
pattern: "executeWorkflow.*container-actions"
---
<objective>
Extract container simple actions (start/stop/restart) into a dedicated sub-workflow.
Purpose: Like the update flow, start/stop/restart actions are handled in both text command and callback paths. Extracting to a sub-workflow creates a single source of truth for container state changes and supports MOD-01/MOD-02 requirements.
Output: New container-actions sub-workflow JSON file and updated main workflow that calls it from both text and callback paths.
</objective>
<execution_context>
@/home/luc/.claude/get-shit-done/workflows/execute-plan.md
@/home/luc/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/10-workflow-modularization/10-RESEARCH.md
@.planning/phases/10-workflow-modularization/10-01-SUMMARY.md
@n8n-workflow.json
</context>
<tasks>
<task type="auto">
<name>Task 1: Create container-actions sub-workflow</name>
<files>n8n-container-actions.json</files>
<action>
Create a new sub-workflow file `n8n-container-actions.json` that encapsulates container start/stop/restart operations.
**Input contract (Execute Sub-workflow Trigger with defined fields):**
```json
{
"containerId": "string - Docker container ID",
"containerName": "string - Container name for messages",
"action": "string - 'start' | 'stop' | 'restart'",
"chatId": "number - Telegram chat ID",
"messageId": "number - Message ID for inline edits (0 for text mode)",
"responseMode": "string - 'text' or 'inline'"
}
```
**Flow to implement:**
1. Route based on action type (Switch node)
2. For each action:
- Call Docker API endpoint (/containers/{id}/start, /stop, /restart)
- Handle success response
- Handle error response
3. Format result message
4. Return result (or send message directly if simpler)
**Output contract:**
```json
{
"success": "boolean",
"message": "string - Result message for user",
"action": "string - Which action was performed",
"containerName": "string"
}
```
**Implementation notes:**
- Use "Define using fields" schema type for input contract
- Stop and restart require confirmation in the caller (main workflow handles confirmation dialogs)
- This sub-workflow executes the action AFTER confirmation is received
- Include proper error handling for API failures
- Message formatting should match existing bot style (emoji + container name + result)
</action>
<verify>
- JSON file is valid: `python3 -c "import json; json.load(open('n8n-container-actions.json'))"`
- Contains "executeWorkflowTrigger" node
- Has proper input schema with all 6 fields
- Has Switch node routing to start/stop/restart paths
</verify>
<done>Container actions sub-workflow created with proper input/output contracts</done>
</task>
<task type="auto">
<name>Task 2: Wire main workflow to use actions sub-workflow</name>
<files>n8n-workflow.json</files>
<action>
Modify the main workflow to call the container-actions sub-workflow for start/stop/restart operations.
**Changes needed:**
1. **Text command path (immediate actions - start/restart):**
- Find where text commands route to start/restart handlers
- Replace inline action execution with:
a. Code node to prepare sub-workflow input
b. Execute Sub-workflow node pointing to container-actions workflow
- Keep confirmation handling in main workflow (stop still needs confirmation)
2. **Text command path (stop with confirmation):**
- Keep confirmation dialog handling in main workflow
- After confirmation received, call sub-workflow with action='stop'
3. **Callback/inline path (immediate actions):**
- Find where callback routes to start/restart handlers
- Replace inline execution with Execute Sub-workflow call
4. **Callback/inline path (stop with confirmation):**
- Keep confirmation keyboard generation in main workflow
- After confirmation callback received, call sub-workflow with action='stop'
5. **Batch action path:**
- Find where batch operations execute individual actions
- Route through the sub-workflow for consistency
**Key principle:** Confirmation dialogs stay in main workflow. Only the actual Docker API call moves to sub-workflow.
**Execute Sub-workflow node configuration:**
```json
{
"parameters": {
"source": "database",
"workflowId": "<will be set after import>",
"mode": "once",
"options": {
"waitForSubWorkflow": true
}
},
"type": "n8n-nodes-base.executeWorkflow"
}
```
</action>
<verify>
- Main workflow JSON is valid
- Contains "executeWorkflow" node(s) for action paths
- Confirmation dialogs still work (handled in main workflow)
</verify>
<done>Main workflow updated to call container-actions sub-workflow</done>
</task>
<task type="auto">
<name>Task 3: Deploy and verify action functionality</name>
<files>n8n-workflow.json, n8n-container-actions.json</files>
<action>
Deploy the actions sub-workflow and updated main workflow, then verify all action paths work.
**Deployment steps:**
1. Import container-actions sub-workflow to n8n via API
2. Note the workflow ID assigned by n8n
3. Update main workflow's Execute Sub-workflow node(s) with correct workflow ID
4. Deploy main workflow update to n8n via API
**Verification tests:**
1. **Text command actions:**
- "start <container>" - Should start and confirm
- "stop <container>" - Should prompt for confirmation, then stop
- "restart <container>" - Should restart and confirm
2. **Inline keyboard actions:**
- Use /status and select a container
- Test Start button (on stopped container)
- Test Stop button (should show confirmation)
- Test Restart button
3. **Batch actions:**
- Select 2 containers for batch stop
- Verify confirmation and execution work
</action>
<verify>
- Sub-workflow imported and has valid ID in n8n
- Main workflow deployed with correct sub-workflow reference
- Text commands work: start, stop (with confirmation), restart
- Inline buttons work: Start, Stop (with confirmation), Restart
- Batch operations work for start/stop/restart
</verify>
<done>Actions sub-workflow deployed and all action paths verified working</done>
</task>
</tasks>
<verification>
1. n8n-container-actions.json exists and is valid JSON
2. Sub-workflow has proper Execute Sub-workflow Trigger with input schema
3. Main workflow contains Execute Sub-workflow nodes for actions
4. Text command "start <container>" works
5. Text command "stop <container>" with confirmation works
6. Text command "restart <container>" works
7. Inline keyboard Start/Stop/Restart buttons work
8. Stop confirmation dialog works in both text and inline modes
9. Batch start/stop/restart operations work
</verification>
<success_criteria>
- Container actions (start/stop/restart) exist in ONE place (sub-workflow)
- Both text and inline action paths use the sub-workflow
- Confirmation dialogs still function correctly
- All action functionality works as before
</success_criteria>
<output>
After completion, create `.planning/phases/10-workflow-modularization/10-03-SUMMARY.md`
</output>
@@ -0,0 +1,216 @@
---
phase: 10-workflow-modularization
plan: 04
type: execute
wave: 3
depends_on: [10-02, 10-03]
files_modified: [n8n-workflow.json]
autonomous: false
must_haves:
truths:
- "All text commands work after modularization"
- "All inline keyboard flows work after modularization"
- "All batch operations work after modularization"
- "Main workflow is significantly smaller than before"
artifacts:
- path: "n8n-workflow.json"
provides: "Modularized main workflow"
min_lines: 4000
- path: "n8n-container-update.json"
provides: "Update sub-workflow"
contains: "executeWorkflowTrigger"
- path: "n8n-container-actions.json"
provides: "Actions sub-workflow"
contains: "executeWorkflowTrigger"
key_links:
- from: "n8n-workflow.json"
to: "n8n-container-update.json"
via: "Execute Sub-workflow"
pattern: "executeWorkflow"
- from: "n8n-workflow.json"
to: "n8n-container-actions.json"
via: "Execute Sub-workflow"
pattern: "executeWorkflow"
---
<objective>
Perform full integration verification of modularized workflow and checkpoint with user.
Purpose: After extracting update and actions to sub-workflows, verify the entire bot still works correctly. This includes edge cases and flows that may not have been explicitly tested in prior plans.
Output: Verified working modularized workflow, user confirmation, and updated ROADMAP showing phase complete.
</objective>
<execution_context>
@/home/luc/.claude/get-shit-done/workflows/execute-plan.md
@/home/luc/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/10-workflow-modularization/10-RESEARCH.md
@.planning/phases/10-workflow-modularization/10-01-SUMMARY.md
@.planning/phases/10-workflow-modularization/10-02-SUMMARY.md
@.planning/phases/10-workflow-modularization/10-03-SUMMARY.md
@n8n-workflow.json
@n8n-container-update.json
@n8n-container-actions.json
</context>
<tasks>
<task type="auto">
<name>Task 1: Comprehensive functionality audit</name>
<files>n8n-workflow.json, n8n-container-update.json, n8n-container-actions.json</files>
<action>
Run through all bot functionality systematically to verify nothing was broken by modularization.
**Text command tests:**
1. `/start` or `/status` - Should show help or status
2. `status` - Should list all containers with inline keyboard
3. `status <container>` - Should show specific container status
4. `start <container>` - Should start and confirm
5. `stop <container>` - Should prompt confirmation, then stop
6. `restart <container>` - Should restart and confirm
7. `update <container>` - Should prompt confirmation, show progress, complete
8. `logs <container>` - Should show logs
9. `logs <container> 100` - Should show 100 lines of logs
10. `batch start <names>` - Should batch start
11. `batch stop <names>` - Should batch stop with confirmation
12. `batch update <names>` - Should batch update with confirmation
**Inline keyboard tests:**
1. Container list navigation (pagination if >10 containers)
2. Container submenu display
3. Start button (on stopped container)
4. Stop button with confirmation dialog
5. Restart button
6. Update button with confirmation dialog
7. Update progress messages
8. Logs button with refresh
9. Back navigation
10. Batch selection mode
11. Batch execution with progress
**Edge cases:**
1. Container not found (fuzzy match suggestions)
2. Ambiguous container name (disambiguation)
3. Update when already up to date
4. Action on already running/stopped container
5. Confirmation timeout (30 seconds)
Document any issues found.
</action>
<verify>
- All text commands execute without errors
- All inline keyboard flows work
- Batch operations complete successfully
- Edge cases handled gracefully
</verify>
<done>Full functionality audit completed, issues documented</done>
</task>
<task type="auto">
<name>Task 2: Measure modularization impact</name>
<files>n8n-workflow.json, n8n-container-update.json, n8n-container-actions.json</files>
<action>
Quantify the improvements from modularization:
1. **Line count comparison:**
- Original main workflow: ~8,485 lines
- New main workflow: Count lines
- Update sub-workflow: Count lines
- Actions sub-workflow: Count lines
- Calculate total and reduction percentage
2. **Node count comparison:**
- Original: ~248 nodes (after orphan cleanup: ~240)
- New main workflow: Count nodes
- Update sub-workflow: Count nodes
- Actions sub-workflow: Count nodes
3. **Code duplication analysis:**
- Before: Update flow duplicated (text + callback paths)
- After: Single update flow in sub-workflow
- Document specific duplication eliminated
4. **Document the modular structure:**
```
Main Workflow (n8n-workflow.json)
├── Telegram Trigger
├── Authentication
├── Command Routing
├── Confirmation Dialogs
└── Sub-workflow Calls
├── container-update (for all update operations)
└── container-actions (for start/stop/restart)
```
Create a summary table of before/after metrics.
</action>
<verify>
- Line counts documented for all workflow files
- Node counts documented
- Reduction percentage calculated
- Modular structure documented
</verify>
<done>Modularization impact measured and documented</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<what-built>
Modularized n8n workflow with:
- Main workflow calling sub-workflows for container operations
- Container Update sub-workflow (handles all update paths)
- Container Actions sub-workflow (handles start/stop/restart)
- Orphan nodes cleaned up
- Duplicated update code consolidated (DEBT-03)
</what-built>
<how-to-verify>
Please test the following in Telegram:
1. **Basic commands:**
- Send `status` - Should show container list keyboard
- Send `update <container>` - Should prompt confirmation, then update
2. **Inline keyboard flow:**
- Tap a container from the list
- Try Start/Stop/Restart buttons
- Try Update button (with confirmation)
- Try Logs button
3. **Batch operation:**
- Start batch mode and select 2 containers
- Execute a batch action
Report any issues or confirm all functionality works as expected.
</how-to-verify>
<resume-signal>Type "approved" to complete Phase 10, or describe any issues found</resume-signal>
</task>
</tasks>
<verification>
1. All text commands work correctly
2. All inline keyboard flows work correctly
3. All batch operations work correctly
4. Edge cases handled (not found, disambiguation, timeouts)
5. Main workflow line count reduced significantly
6. Update flow exists in single location (sub-workflow)
7. Actions flow exists in single location (sub-workflow)
8. User has verified bot works from their phone
</verification>
<success_criteria>
- MOD-01: Main workflow broken into logical sub-workflows (update, actions)
- MOD-02: Sub-workflows callable from main without duplication
- DEBT-03: Update flow consolidated (no longer duplicated)
- All v1.1 functionality preserved
- User verification passed
</success_criteria>
<output>
After completion, create `.planning/phases/10-workflow-modularization/10-04-SUMMARY.md`
</output>
@@ -0,0 +1,354 @@
# Phase 10: Workflow Modularization - Research
**Researched:** 2026-02-04
**Domain:** n8n workflow modularization
**Confidence:** HIGH (verified against official n8n documentation)
## Summary
The current n8n workflow (`n8n-workflow.json`) is 8,485 lines with approximately 150+ nodes handling all functionality in a single monolithic workflow. This phase will break it into modular sub-workflows using n8n's built-in sub-workflow infrastructure.
n8n provides first-class support for workflow modularization through the **Execute Sub-workflow** node and **Execute Sub-workflow Trigger** node. Sub-workflows enable:
- Breaking large workflows into focused components (recommended: 5-10 nodes per sub-workflow)
- Reusing logic across multiple entry points (e.g., update flow used by text commands AND callbacks)
- Memory isolation - sub-workflow memory is released after completion
- Independent testing and debugging
- Clear data contracts between components
**Primary recommendation:** Use n8n's Execute Sub-workflow node to extract logical modules, starting with the duplicated update flow (DEBT-03) as the first extraction target since it's called from two places.
## Standard Stack
### Core n8n Nodes for Modularization
| Node | Purpose | Why Standard |
|------|---------|--------------|
| Execute Sub-workflow Trigger | Entry point for sub-workflows | Built-in n8n node, defines input contract |
| Execute Sub-workflow | Calls sub-workflows from parent | Built-in n8n node, handles data passing |
| Code Node | Data transformation between modules | Prepare inputs, format outputs |
| Switch Node | Route to different sub-workflows | Handle multiple action types |
### Input Data Modes
| Mode | When to Use |
|------|-------------|
| Define using fields | Best for typed, validated inputs (recommended) |
| Define using JSON example | When input structure is complex/nested |
| Accept all data | Legacy/migration - avoid for new sub-workflows |
**Recommendation:** Use "Define using fields" for all new sub-workflows - provides clear data contracts and automatic field population in the Execute Sub-workflow node.
## Architecture Patterns
### Recommended Module Structure
Based on workflow analysis, these logical sub-workflows are recommended:
```
Main Orchestrator (n8n-workflow.json - reduced)
├── Authentication check (inline - too small to extract)
├── Command routing (inline - just a switch node)
├── Sub-workflows:
│ ├── container-operations/
│ │ ├── container-action.json # start/stop/restart a container
│ │ ├── container-update.json # full update flow (DEBT-03 consolidation)
│ │ └── container-logs.json # fetch and format logs
│ │
│ ├── keyboard-generation/
│ │ ├── container-list.json # paginated container list keyboard
│ │ ├── container-submenu.json # single container action menu
│ │ └── confirmation-dialog.json # stop/update confirmation keyboards
│ │
│ └── batch-operations/
│ ├── batch-loop.json # execute action on multiple containers
│ └── batch-selection.json # selection keyboard management
```
### Pattern 1: Container Update Sub-workflow (Priority - addresses DEBT-03)
**What:** Extract the entire container update sequence into a single sub-workflow
**Why:** This logic is currently duplicated between:
1. Text command path (lines ~1656-2400)
2. Callback/inline keyboard path (lines ~3628-4010)
**Input contract (Execute Sub-workflow Trigger):**
```json
{
"containerId": "string",
"containerName": "string",
"chatId": "number",
"messageId": "number (optional - for inline updates)",
"responseMode": "string ('text' | 'inline')"
}
```
**Output contract (returned to parent):**
```json
{
"success": "boolean",
"message": "string",
"oldDigest": "string (optional)",
"newDigest": "string (optional)"
}
```
**Flow extracted:**
1. Inspect container configuration
2. Pull latest image
3. Compare digests
4. If update needed: stop -> remove -> create -> start
5. Clean up old image
6. Return result
### Pattern 2: Keyboard Generation Sub-workflow
**What:** Extract keyboard building logic
**Why:** Keyboard generation is scattered throughout and could be centralized
**Example input:**
```json
{
"type": "submenu",
"containerName": "string",
"containerState": "running|exited|paused",
"options": {
"showBack": true,
"backTarget": "list:0"
}
}
```
### Pattern 3: Data Contract Design
**Principle:** Every sub-workflow should have clearly defined inputs and outputs.
```
[Parent Workflow]
▼ Input: { containerId, containerName, chatId, messageId }
[Execute Sub-workflow Node]
▼ Processes via Execute Sub-workflow Trigger
[Sub-workflow: container-update]
▼ Output: { success, message, details }
[Parent continues with result]
```
### Anti-Patterns to Avoid
- **Shared state via workflow static data:** Use explicit input/output instead
- **Over-modularization:** Don't extract nodes that are only used once
- **Deep nesting:** Keep sub-workflow call depth to 2 maximum (parent -> child)
- **Accept all data mode:** Always define explicit inputs for maintainability
## Don't Hand-Roll
| Problem | Don't Build | Use Instead | Why |
|---------|-------------|-------------|-----|
| Workflow-to-workflow communication | Custom webhooks | Execute Sub-workflow node | Built-in, handles data passing, memory isolation |
| Reusable logic extraction | Copy-paste nodes | Sub-workflow with trigger | Single source of truth, DRY |
| Complex routing | Deeply nested If nodes | Switch + sub-workflows | Cleaner, testable |
| Input validation | Manual checks in Code node | Define input fields in trigger | Type safety, documentation |
**Key insight:** n8n's sub-workflow infrastructure handles all the complexity of data passing, execution context, and memory management. Using Execute Sub-workflow node instead of custom solutions provides memory isolation that prevents heap exhaustion on large operations.
## Common Pitfalls
### Pitfall 1: Circular Sub-workflow Calls
**What goes wrong:** Sub-workflow A calls B which calls A, causing infinite loop
**Why it happens:** Accidental dependency cycles during refactoring
**How to avoid:** Document call hierarchy, keep sub-workflows single-purpose
**Warning signs:** Workflow hangs indefinitely, memory usage spikes
### Pitfall 2: Lost Context in Multi-step Flows
**What goes wrong:** Data from early nodes not available in sub-workflow
**Why it happens:** Sub-workflow only receives explicit inputs, not parent context
**How to avoid:** Design complete input contracts - if sub-workflow needs data, it must be in input
**Warning signs:** "Cannot read property of undefined" errors in sub-workflow
### Pitfall 3: Credential Scope Issues
**What goes wrong:** Sub-workflow can't access credentials defined in parent
**Why it happens:** Credentials are workflow-scoped, not globally shared
**How to avoid:** Configure same credentials in both parent and sub-workflows
**Warning signs:** Authentication failures only when running as sub-workflow
### Pitfall 4: Breaking Existing Callback Data
**What goes wrong:** Inline keyboard callbacks stop working after modularization
**Why it happens:** Callback data parsing expects specific node structure/names
**How to avoid:** Preserve callback data format, update routing to call sub-workflows
**Warning signs:** "Callback query expired" or routing errors after deployment
### Pitfall 5: Over-extraction
**What goes wrong:** Simple operations become 5+ sub-workflow calls, adding latency
**Why it happens:** Applying microservice patterns too aggressively
**How to avoid:** Only extract logic that is: (a) reused, OR (b) large/complex, OR (c) needs isolation
**Warning signs:** Simple operations now take seconds instead of milliseconds
## Code Examples
### Example 1: Sub-workflow Trigger Setup
```json
{
"name": "Container Update",
"nodes": [
{
"parameters": {
"inputSource": "passthrough",
"schema": {
"schemaType": "fromFields",
"fields": [
{ "fieldName": "containerId", "fieldType": "string" },
{ "fieldName": "containerName", "fieldType": "string" },
{ "fieldName": "chatId", "fieldType": "number" },
{ "fieldName": "messageId", "fieldType": "number" },
{ "fieldName": "responseMode", "fieldType": "string" }
]
}
},
"name": "When executed by another workflow",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1.1
}
]
}
```
### Example 2: Calling Sub-workflow from Parent
```json
{
"parameters": {
"source": "database",
"workflowId": "container-update-workflow-id",
"mode": "once",
"options": {
"waitForSubWorkflow": true
}
},
"name": "Execute Update",
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.2
}
```
### Example 3: Preparing Sub-workflow Input (Code Node)
```javascript
// In parent workflow, prepare input for sub-workflow
const containerData = $('Match Container').item.json;
const triggerData = $('Telegram Trigger').item.json;
return {
json: {
containerId: containerData.matches[0].Id,
containerName: containerData.matches[0].Name,
chatId: triggerData.message.chat.id,
messageId: triggerData.message.message_id,
responseMode: 'text'
}
};
```
### Example 4: Converting Callback Path to Use Sub-workflow
```javascript
// Instead of duplicated update logic, call sub-workflow
const callbackData = $('Parse Callback Data').item.json;
return {
json: {
containerId: callbackData.containerId,
containerName: callbackData.containerName,
chatId: callbackData.chatId,
messageId: callbackData.messageId,
responseMode: 'inline' // Sub-workflow handles response format
}
};
```
## State of the Art
| Old Approach | Current Approach | When Changed | Impact |
|--------------|------------------|--------------|--------|
| Monolithic workflows | Modular sub-workflows | n8n 1.0+ | Better maintainability, memory efficiency |
| Copy-paste nodes | Execute Sub-workflow node | Core feature | DRY, single source of truth |
| Accept all data | Define using fields | 2025 best practice | Type safety, documentation |
| Manual webhook calls | Native sub-workflow execution | Core feature | Built-in context, error handling |
**Current n8n sub-workflow features (2026):**
- Execute Sub-workflow Trigger node with schema definition
- Sub-workflow conversion from canvas context menu (select nodes -> right-click -> Create sub-workflow)
- Memory isolation for sub-workflows
- Sub-workflow executions don't count toward n8n Cloud quotas
- Wait for completion toggle for async patterns
## Open Questions
### 1. Sub-workflow File Organization
**What we know:** n8n stores workflows as individual entities in its database
**What's unclear:** Whether to export sub-workflows as separate JSON files in git or keep them n8n-internal
**Recommendation:** Export as separate files for version control, document workflow IDs in main workflow
### 2. Testing Sub-workflows
**What we know:** Can use Manual Trigger + test data for isolated testing
**What's unclear:** Best practice for automated testing
**Recommendation:** Create test input nodes in each sub-workflow, manually validate before deployment
### 3. Migration Strategy
**What we know:** Can convert existing nodes to sub-workflow via context menu
**What's unclear:** Whether to do incremental migration or big-bang refactor
**Recommendation:** Incremental - extract one sub-workflow at a time, test, then proceed
## Specific Extraction Plan
Based on workflow analysis, recommended extraction order:
### Priority 1: Container Update (addresses DEBT-03)
- **Why first:** Addresses explicit tech debt requirement, duplicated in two places
- **Lines affected:** ~1656-2400 (text path) + ~3628-4010 (callback path)
- **Expected reduction:** ~750 lines from main workflow
- **Risk:** Medium - update flow is critical, needs thorough testing
### Priority 2: Container Simple Actions (start/stop/restart)
- **Why second:** Simpler than update, similar pattern of text+callback duplication
- **Expected reduction:** ~200 lines
- **Risk:** Low - simple operations
### Priority 3: Keyboard Generation
- **Why third:** Scattered throughout, centralizing improves consistency
- **Expected reduction:** ~300 lines
- **Risk:** Low - UI only, easy to test
### Priority 4: Batch Loop (if time permits)
- **Why last:** Complex state management, higher risk
- **Expected reduction:** ~400 lines
- **Risk:** Medium-High - batch operations have edge cases
## Sources
### Primary (HIGH confidence)
- [n8n Sub-workflows Documentation](https://docs.n8n.io/flow-logic/subworkflows/) - Official docs on sub-workflow concepts
- [Execute Sub-workflow Node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.executeworkflow/) - Official node documentation
- [Execute Sub-workflow Trigger](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.executeworkflowtrigger/) - Official trigger documentation
### Secondary (MEDIUM confidence)
- [n8n Best Practices 2026](https://michaelitoback.com/n8n-workflow-best-practices/) - Community best practices guide
- [When to Use Sub-workflows](https://community.n8n.io/t/how-to-use-sub-workflows-in-n8-when-to-use-examples/257577) - n8n Community guidance
- [n8n Expert Best Practices](https://n8n.expert/it-automation/best-practices-designing-n8n-workflows/) - Expert recommendations
### Tertiary (LOW confidence)
- [Modularizing n8n Workflows](https://optimizesmart.com/blog/modularizing-n8n-workflows-build-smarter-workflows/) - Blog post on modularization patterns
## Metadata
**Confidence breakdown:**
- Standard stack: HIGH - Based on official n8n documentation
- Architecture patterns: MEDIUM - Based on workflow analysis + best practices
- Pitfalls: MEDIUM - Community patterns, verified against documentation
- Extraction plan: MEDIUM - Based on codebase analysis
**Research date:** 2026-02-04
**Valid until:** 2026-03-04 (30 days - n8n stable, patterns unlikely to change)