docs(08): create inline keyboard infrastructure plans
Phase 8: Inline Keyboard Infrastructure - 3 plans in 3 waves (sequential dependency) - Plan 01: Container list keyboard and submenu navigation - Plan 02: Action execution and confirmation flow - Plan 03: Progress feedback and completion messages Covers KEY-01 through KEY-05 requirements. Ready for execution. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,317 @@
|
||||
---
|
||||
phase: 08-inline-keyboard-infrastructure
|
||||
plan: 02
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on: [08-01]
|
||||
files_modified: [n8n-workflow.json]
|
||||
autonomous: true
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "Tapping Start button starts a stopped container"
|
||||
- "Tapping Stop button shows confirmation dialog"
|
||||
- "Tapping Update button shows confirmation dialog"
|
||||
- "Tapping Restart button executes restart immediately"
|
||||
- "Confirming Stop/Update executes the action"
|
||||
- "Cancelling returns to container submenu"
|
||||
- "Confirmation expires after 30 seconds"
|
||||
artifacts:
|
||||
- path: "n8n-workflow.json"
|
||||
provides: "Action execution routing and confirmation flow"
|
||||
contains: "Route Action Type"
|
||||
- path: "n8n-workflow.json"
|
||||
provides: "Confirmation keyboard builder"
|
||||
contains: "Build Confirmation"
|
||||
key_links:
|
||||
- from: "Route Callback"
|
||||
to: "Route Action Type"
|
||||
via: "action: callback routing"
|
||||
pattern: "action:"
|
||||
- from: "Route Action Type"
|
||||
to: "existing container ops"
|
||||
via: "start/stop/restart/update wiring"
|
||||
pattern: "containers/.*/start"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Wire action buttons to container operations and add confirmation flow for dangerous actions.
|
||||
|
||||
Purpose: When users tap action buttons in the container submenu, the corresponding action executes. Stop and Update require confirmation (per user decision). Start and Restart execute immediately.
|
||||
|
||||
Output: Updated n8n-workflow.json with action routing, confirmation flow, and wiring to existing container operations.
|
||||
</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/08-inline-keyboard-infrastructure/08-CONTEXT.md
|
||||
@.planning/phases/08-inline-keyboard-infrastructure/08-RESEARCH.md
|
||||
@.planning/phases/08-inline-keyboard-infrastructure/08-01-SUMMARY.md
|
||||
@n8n-workflow.json
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Route Action Callbacks to Container Operations</name>
|
||||
<files>n8n-workflow.json</files>
|
||||
<action>
|
||||
Add routing to handle `action:{type}:{name}` callbacks and wire to existing container operations.
|
||||
|
||||
1. Update "Parse Callback Data" to recognize `action:` prefix:
|
||||
```javascript
|
||||
// Add to existing parsing logic
|
||||
if (data.startsWith('action:')) {
|
||||
const parts = data.split(':');
|
||||
return {
|
||||
json: {
|
||||
isAction: true,
|
||||
actionType: parts[1], // start, stop, restart, update, logs
|
||||
containerName: parts[2],
|
||||
queryId: callbackQuery.id,
|
||||
chatId: callbackQuery.message.chat.id,
|
||||
messageId: callbackQuery.message.message_id
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
2. Add "isAction" output to "Route Callback" switch node:
|
||||
- Rule: `isAction === true` -> output "action"
|
||||
- This catches all action callbacks before routing by type
|
||||
|
||||
3. Create Switch node "Route Action Type":
|
||||
- Input: from Route Callback "action" output
|
||||
- Outputs:
|
||||
- "start": `actionType === 'start'`
|
||||
- "restart": `actionType === 'restart'`
|
||||
- "logs": `actionType === 'logs'`
|
||||
- "stop": `actionType === 'stop'` (needs confirmation)
|
||||
- "update": `actionType === 'update'` (needs confirmation)
|
||||
|
||||
4. For immediate actions (start, restart, logs), wire to existing container operation nodes:
|
||||
|
||||
**Start flow:**
|
||||
- Create Code node "Prepare Start Action":
|
||||
```javascript
|
||||
const { queryId, chatId, messageId, containerName } = $json;
|
||||
return {
|
||||
json: {
|
||||
queryId,
|
||||
chatId,
|
||||
messageId,
|
||||
containerName,
|
||||
// Format for existing Start Container node
|
||||
container: containerName
|
||||
}
|
||||
};
|
||||
```
|
||||
- Answer callback query immediately
|
||||
- Wire to existing "Start Container" HTTP Request node
|
||||
- After start completes, show success message (handled in Plan 03)
|
||||
|
||||
**Restart flow:**
|
||||
- Similar to start, wire to existing "Restart Container" node
|
||||
|
||||
**Logs flow:**
|
||||
- Wire to existing "Get Logs" flow
|
||||
- Logs may need special handling (send as new message, not edit)
|
||||
|
||||
5. For dangerous actions (stop, update), route to confirmation builder (Task 2)
|
||||
|
||||
6. Wire flows - ensuring callback is answered FIRST:
|
||||
- Route Action Type (start) -> Answer Start Callback -> Prepare Start Action -> Start Container -> (completion handling in Plan 03)
|
||||
- Route Action Type (restart) -> Answer Restart Callback -> Prepare Restart Action -> Restart Container -> (completion handling)
|
||||
- Route Action Type (logs) -> Answer Logs Callback -> existing logs flow
|
||||
- Route Action Type (stop) -> Build Stop Confirmation (Task 2)
|
||||
- Route Action Type (update) -> Build Update Confirmation (Task 2)
|
||||
</action>
|
||||
<verify>
|
||||
1. From container submenu, tap "Start" on a stopped container
|
||||
2. Verify: Container starts (check n8n execution or docker ps)
|
||||
3. Tap "Restart" on a running container
|
||||
4. Verify: Container restarts
|
||||
5. Tap "Logs"
|
||||
6. Verify: Logs returned (may be separate message for now)
|
||||
7. Tap "Stop" on running container
|
||||
8. Verify: Shows confirmation (not executed yet - Task 2)
|
||||
</verify>
|
||||
<done>
|
||||
- Start button starts containers immediately
|
||||
- Restart button restarts containers immediately
|
||||
- Logs button triggers log retrieval
|
||||
- Stop/Update route to confirmation flow
|
||||
- All callbacks answered (no loading indicator)
|
||||
</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Add Confirmation Flow for Dangerous Actions</name>
|
||||
<files>n8n-workflow.json</files>
|
||||
<action>
|
||||
Add confirmation dialog for Stop and Update actions with 30-second timeout.
|
||||
|
||||
1. Create Code node "Build Stop Confirmation":
|
||||
```javascript
|
||||
const { queryId, chatId, messageId, containerName } = $json;
|
||||
const timestamp = Math.floor(Date.now() / 1000); // Unix seconds
|
||||
|
||||
const keyboard = {
|
||||
inline_keyboard: [
|
||||
[
|
||||
{ text: '✅ Yes, Stop', callback_data: `confirm:stop:${containerName}:${timestamp}` },
|
||||
{ text: '❌ Cancel', callback_data: `cancel:${containerName}` }
|
||||
]
|
||||
]
|
||||
};
|
||||
|
||||
return {
|
||||
json: {
|
||||
queryId,
|
||||
chatId,
|
||||
messageId,
|
||||
text: `⚠️ <b>Stop ${containerName}?</b>\n\nThis will stop the container immediately.\n\n<i>Expires in 30 seconds</i>`,
|
||||
reply_markup: keyboard
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
2. Create Code node "Build Update Confirmation":
|
||||
```javascript
|
||||
const { queryId, chatId, messageId, containerName } = $json;
|
||||
const timestamp = Math.floor(Date.now() / 1000);
|
||||
|
||||
const keyboard = {
|
||||
inline_keyboard: [
|
||||
[
|
||||
{ text: '✅ Yes, Update', callback_data: `confirm:update:${containerName}:${timestamp}` },
|
||||
{ text: '❌ Cancel', callback_data: `cancel:${containerName}` }
|
||||
]
|
||||
]
|
||||
};
|
||||
|
||||
return {
|
||||
json: {
|
||||
queryId,
|
||||
chatId,
|
||||
messageId,
|
||||
text: `⬆️ <b>Update ${containerName}?</b>\n\nThis will pull the latest image and recreate the container.\n\n<i>Expires in 30 seconds</i>`,
|
||||
reply_markup: keyboard
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
3. Create HTTP Request nodes to answer callback and show confirmation:
|
||||
- "Answer Stop Callback" -> answerCallbackQuery
|
||||
- "Show Stop Confirmation" -> editMessageText with confirmation keyboard
|
||||
- Same pattern for Update
|
||||
|
||||
4. Wire confirmation display:
|
||||
- Route Action Type (stop) -> Answer Stop Callback -> Build Stop Confirmation -> Show Stop Confirmation
|
||||
- Route Action Type (update) -> Answer Update Callback -> Build Update Confirmation -> Show Update Confirmation
|
||||
|
||||
5. Update "Parse Callback Data" to handle `confirm:` and `cancel:` callbacks:
|
||||
```javascript
|
||||
// confirm:stop:plex:1738595200
|
||||
if (data.startsWith('confirm:')) {
|
||||
const parts = data.split(':');
|
||||
const timestamp = parseInt(parts[3]);
|
||||
const currentTime = Math.floor(Date.now() / 1000);
|
||||
const expired = (currentTime - timestamp) > 30;
|
||||
|
||||
return {
|
||||
json: {
|
||||
isConfirm: true,
|
||||
expired: expired,
|
||||
actionType: parts[1], // stop or update
|
||||
containerName: parts[2],
|
||||
queryId: callbackQuery.id,
|
||||
chatId: callbackQuery.message.chat.id,
|
||||
messageId: callbackQuery.message.message_id
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// cancel:plex
|
||||
if (data.startsWith('cancel:')) {
|
||||
const containerName = data.split(':')[1];
|
||||
return {
|
||||
json: {
|
||||
isCancel: true,
|
||||
containerName: containerName,
|
||||
queryId: callbackQuery.id,
|
||||
chatId: callbackQuery.message.chat.id,
|
||||
messageId: callbackQuery.message.message_id
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
6. Add "isConfirm" output to "Route Callback":
|
||||
- Rule: `isConfirm === true && !expired` -> output "confirm"
|
||||
- The existing "expired" output handles expired confirmations
|
||||
|
||||
7. Create Switch node "Route Confirmed Action":
|
||||
- Input: from Route Callback "confirm" output
|
||||
- Outputs: "stop", "update" based on actionType
|
||||
|
||||
8. Wire confirmed actions to actual operations:
|
||||
- Route Confirmed Action (stop) -> Answer Confirm Callback -> Stop Container -> (completion in Plan 03)
|
||||
- Route Confirmed Action (update) -> Answer Confirm Callback -> existing Update flow -> (completion)
|
||||
|
||||
9. Handle cancel callback:
|
||||
- isCancel should route back to container submenu
|
||||
- Reuse/extend existing cancel handling
|
||||
- On cancel: fetch container details again -> show submenu
|
||||
</action>
|
||||
<verify>
|
||||
1. Tap "Stop" on a running container
|
||||
2. Verify: Confirmation dialog appears with Yes/Cancel buttons
|
||||
3. Wait 35 seconds, then tap "Yes"
|
||||
4. Verify: Shows "Confirmation expired" message
|
||||
5. Tap "Stop" again, immediately tap "Yes"
|
||||
6. Verify: Container stops
|
||||
7. Start a container, tap "Stop", tap "Cancel"
|
||||
8. Verify: Returns to container submenu (not list)
|
||||
9. Test same flow for "Update" button
|
||||
</verify>
|
||||
<done>
|
||||
- Stop shows confirmation dialog
|
||||
- Update shows confirmation dialog
|
||||
- Confirmation includes 30-second timeout warning
|
||||
- Tapping "Yes" within 30s executes action
|
||||
- Tapping "Yes" after 30s shows expired message
|
||||
- Tapping "Cancel" returns to container submenu
|
||||
</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
After completing all tasks:
|
||||
1. Start button works immediately (no confirmation)
|
||||
2. Restart button works immediately (no confirmation)
|
||||
3. Stop button shows confirmation, then executes on confirm
|
||||
4. Update button shows confirmation, then executes on confirm
|
||||
5. Cancel returns to container submenu
|
||||
6. Expired confirmations are rejected with message
|
||||
7. Logs button retrieves container logs
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- KEY-02 requirement met: Action buttons perform operations
|
||||
- KEY-03 requirement met: Dangerous actions show confirmation
|
||||
- Actions wire correctly to existing container operation nodes
|
||||
- Confirmation timeout enforced at 30 seconds
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/08-inline-keyboard-infrastructure/08-02-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user