From b7cefd931ed83808a0d69ec838b7fe28dded0a23 Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Sat, 31 Jan 2026 21:00:51 -0500 Subject: [PATCH] docs(05): create phase plan Phase 05: Polish & Deploy - 3 plans in 3 waves - 1 parallel (Wave 1), 2 sequential (Waves 2-3) - Ready for execution Co-Authored-By: Claude Opus 4.5 --- .planning/ROADMAP.md | 7 + .../phases/05-polish-deploy/05-01-PLAN.md | 172 +++++++++++++++ .../phases/05-polish-deploy/05-02-PLAN.md | 157 ++++++++++++++ .../phases/05-polish-deploy/05-03-PLAN.md | 203 ++++++++++++++++++ 4 files changed, 539 insertions(+) create mode 100644 .planning/phases/05-polish-deploy/05-01-PLAN.md create mode 100644 .planning/phases/05-polish-deploy/05-02-PLAN.md create mode 100644 .planning/phases/05-polish-deploy/05-03-PLAN.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index d6d42e7..6665e6e 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -93,6 +93,13 @@ Plans: **Delivers:** Production readiness +**Plans:** 3 plans + +Plans: +- [ ] 05-01-PLAN.md — Remove NLU nodes and add keyword routing with persistent menu +- [ ] 05-02-PLAN.md — Standardize error messages and migrate credentials +- [ ] 05-03-PLAN.md — Write deployment README and end-to-end testing + **Status:** 🔲 Not started --- diff --git a/.planning/phases/05-polish-deploy/05-01-PLAN.md b/.planning/phases/05-polish-deploy/05-01-PLAN.md new file mode 100644 index 0000000..dba635c --- /dev/null +++ b/.planning/phases/05-polish-deploy/05-01-PLAN.md @@ -0,0 +1,172 @@ +--- +phase: 05-polish-deploy +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: [n8n-workflow.json] +autonomous: true + +must_haves: + truths: + - "User sees persistent menu buttons in Telegram" + - "Typing 'status' triggers container list (no Claude API call)" + - "Typing 'start plex' triggers start flow (no Claude API call)" + - "Unknown commands show menu instead of error" + artifacts: + - path: "n8n-workflow.json" + provides: "Keyword Router Switch node" + contains: "Keyword Router" + - path: "n8n-workflow.json" + provides: "Persistent menu reply markup" + contains: "is_persistent" + key_links: + - from: "Telegram Trigger" + to: "Keyword Router" + via: "Route Message path" + pattern: "Keyword Router" + - from: "Keyword Router" + to: "Docker List Containers" + via: "status output" + pattern: "status.*Docker List" +--- + + +Replace Claude/NLU nodes with keyword-based routing and add persistent Telegram menu buttons. + +Purpose: Remove external Claude API dependency, enable offline-first operation with simple keyword matching. +Output: Working keyword routing with persistent menu, no Claude API calls in workflow. + + + +@/home/luc/.claude/get-shit-done/workflows/execute-plan.md +@/home/luc/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/05-polish-deploy/05-CONTEXT.md +@.planning/phases/05-polish-deploy/05-RESEARCH.md +@n8n-workflow.json + + + + + + Task 1: Remove NLU/Claude nodes and add Keyword Router + n8n-workflow.json + +Remove these nodes from the workflow: +- Prepare Claude Request +- Claude Intent Parser (HTTP Request node calling api.anthropic.com) +- Parse Intent (Code node) +- Intent Router (old Switch node routing on parsed intent) +- Send Unknown Intent +- Send Intent Error +- Remove Anthropic API Key credential reference + +Replace with a single Switch node called "Keyword Router" with these rules (case-insensitive matching on message.text): +- Contains "status" -> output "status" -> connect to Docker List Containers +- Contains "start" -> output "start" -> connect to Parse Action Command (with action set to start) +- Contains "stop" -> output "stop" -> connect to Parse Action Command (with action set to stop) +- Contains "restart" -> output "restart" -> connect to Parse Action Command (with action set to restart) +- Contains "update" -> output "update" -> connect to existing update flow entry point +- Contains "logs" -> output "logs" -> connect to existing logs flow entry point +- Fallback (extra) -> connect to new "Show Menu" node + +Use the Switch node pattern from RESEARCH.md: +```json +{ + "conditions": { + "options": { "caseSensitive": false }, + "conditions": [{ + "leftValue": "={{ $json.message.text }}", + "rightValue": "status", + "operator": { "type": "string", "operation": "contains" } + }] + } +} +``` + +Update "Route Message" node to connect directly to "Keyword Router" instead of the old Claude flow. + + +Open workflow in n8n UI. Send "status" - should trigger Docker List Containers path. +Check that no nodes reference api.anthropic.com or Anthropic API Key credential. + + +Keyword Router handles all 6 commands (status, start, stop, restart, update, logs) plus fallback. +No Claude/NLU nodes remain in workflow. + + + + + Task 2: Add persistent Telegram menu + n8n-workflow.json + +Create a new "Show Menu" node (HTTP Request type, not native Telegram node - per project pattern for keyboards). + +Configure HTTP Request: +- URL: `https://api.telegram.org/bot{{ $credentials.telegramApi.token }}/sendMessage` +- Method: POST +- Body (JSON): +```json +{ + "chat_id": "={{ $json.message.chat.id }}", + "text": "Use buttons below or type commands:", + "parse_mode": "HTML", + "reply_markup": { + "keyboard": [ + [{"text": "Status"}], + [{"text": "Start"}, {"text": "Stop"}], + [{"text": "Restart"}, {"text": "Update"}], + [{"text": "Logs"}] + ], + "is_persistent": true, + "resize_keyboard": true, + "one_time_keyboard": false + } +} +``` + +Connect Keyword Router fallback output to Show Menu node. + +NOTE: Research suggests emojis optional (Claude's discretion from CONTEXT.md). Start without emojis for cleaner keyword matching - button text "Status" matches "status" keyword. + +Also wire /start command to Show Menu: +- In Keyword Router, add rule: Contains "/start" -> output "menu" -> connect to Show Menu + + +Send any unknown command (e.g., "hello") - should receive menu with persistent keyboard. +Send "/start" - should receive same menu. +Keyboard should persist after sending other messages. + + +Persistent menu visible in Telegram chat. +Menu buttons trigger corresponding actions when tapped. +/start and unknown commands show menu. + + + + + + +1. All Claude/NLU nodes removed (grep for "anthropic", "Claude", "Intent" in workflow JSON) +2. Keyword Router handles: status, start, stop, restart, update, logs, /start, fallback +3. Persistent menu shows 6 buttons in grouped layout +4. Button taps trigger corresponding keyword routes +5. No errors in n8n execution logs for any command + + + +- Zero references to Anthropic API or Claude in workflow +- All 6 container commands work via typed keywords +- Persistent menu visible and functional +- Unknown input shows menu (not error) + + + +After completion, create `.planning/phases/05-polish-deploy/05-01-SUMMARY.md` + diff --git a/.planning/phases/05-polish-deploy/05-02-PLAN.md b/.planning/phases/05-polish-deploy/05-02-PLAN.md new file mode 100644 index 0000000..2722fd4 --- /dev/null +++ b/.planning/phases/05-polish-deploy/05-02-PLAN.md @@ -0,0 +1,157 @@ +--- +phase: 05-polish-deploy +plan: 02 +type: execute +wave: 2 +depends_on: [05-01] +files_modified: [n8n-workflow.json] +autonomous: true + +must_haves: + truths: + - "Docker socket errors show 'Cannot connect to Docker' (not stack trace)" + - "Failed actions show 'Failed to X' format (not verbose details)" + - "User ID stored in n8n credentials (not hardcoded in workflow JSON)" + artifacts: + - path: "n8n-workflow.json" + provides: "Terse error messages in response nodes" + contains: "Cannot connect to Docker" + - path: "n8n-workflow.json" + provides: "Credential reference for user auth" + contains: "$credentials" + key_links: + - from: "IF User Authenticated" + to: "n8n credentials" + via: "credential reference expression" + pattern: "\\$credentials" +--- + + +Harden error handling with minimal user-facing messages and migrate user ID to n8n credentials system. + +Purpose: Production-ready error UX and secure credential storage for workflow sharing. +Output: Terse error messages, credential-based auth, exportable workflow without sensitive data. + + + +@/home/luc/.claude/get-shit-done/workflows/execute-plan.md +@/home/luc/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/05-polish-deploy/05-CONTEXT.md +@.planning/phases/05-polish-deploy/05-RESEARCH.md +@.planning/phases/05-polish-deploy/05-01-SUMMARY.md +@n8n-workflow.json + + + + + + Task 1: Standardize error messages + n8n-workflow.json + +Find all error response nodes and update their message text to follow minimal format: + +**Docker/infrastructure errors (detect "docker.sock" or "ECONNREFUSED" in error):** +- Message: "Cannot connect to Docker" + +**Action failures:** +- Pattern: "Failed to {action} {container}" +- Examples: "Failed to start plex", "Failed to stop nginx" + +**No match errors:** +- Keep existing "No container matching 'X'" format (already terse) + +Update these nodes to use terse format: +- Send Docker Error -> "Cannot connect to Docker" +- Send Action Result (error case) -> "Failed to {action} {container}" +- Send Update Error -> "Failed to update {container}" +- Send Logs Error -> "Failed to get logs for {container}" + +Do NOT include: +- Stack traces +- HTTP status codes +- Docker API error details +- Technical debugging info + +Per CONTEXT.md: "Minimal error messages - 'Failed to start plex' without verbose details" + + +Grep workflow JSON for error messages - should be terse, no technical details. +Manually test by stopping n8n's Docker socket access and sending command - should see "Cannot connect to Docker". + + +All user-facing error messages follow terse format. +Infrastructure errors show "Cannot connect to Docker". +Action errors show "Failed to X Y" pattern. + + + + + Task 2: Migrate user ID to n8n credentials + n8n-workflow.json + +Currently the workflow has hardcoded user ID in IF nodes for auth check. Per CONTEXT.md and RESEARCH.md, migrate to n8n credentials system. + +**Step 1: Create credential type reference in workflow** + +n8n credentials will be created manually by user during deployment, but workflow must reference them. + +**Step 2: Update auth check nodes** + +Find "IF User Authenticated" and "IF Callback Authenticated" nodes. + +Change the condition from hardcoded ID comparison to credential reference: +``` +// Old (hardcoded): +$json.message.from.id === 123456789 + +// New (credential reference): +$json.message.from.id === parseInt($credentials.telegramAuth.userId) +``` + +Note: The credential name "telegramAuth" with field "userId" follows RESEARCH.md pattern. +User will create this credential during deployment (documented in README from Plan 03). + +**Step 3: Clean up sensitive data** + +Search workflow JSON for any hardcoded numeric IDs that look like Telegram user IDs (8+ digit numbers). +Remove or replace with credential references. + +Per CONTEXT.md: "Sensitive values (Telegram user ID) moved to n8n credentials system - not hardcoded in workflow JSON" + + +Grep workflow JSON for 8+ digit numbers - should find none (except node position coordinates). +Auth check nodes should reference $credentials.telegramAuth.userId. + + +No hardcoded user ID in workflow JSON. +Auth nodes use credential reference. +Workflow can be safely exported/shared. + + + + + + +1. All error messages terse (no stack traces, no verbose details) +2. Docker socket errors produce "Cannot connect to Docker" +3. Action failures produce "Failed to X Y" format +4. No hardcoded Telegram user ID in workflow JSON +5. Auth nodes reference $credentials.telegramAuth.userId +6. Workflow exports cleanly without embedded secrets + + + +- Error messages fit in single Telegram line (no scrolling needed) +- Zero hardcoded sensitive values in workflow JSON +- grep -E '[0-9]{9,}' workflow.json returns only position coordinates + + + +After completion, create `.planning/phases/05-polish-deploy/05-02-SUMMARY.md` + diff --git a/.planning/phases/05-polish-deploy/05-03-PLAN.md b/.planning/phases/05-polish-deploy/05-03-PLAN.md new file mode 100644 index 0000000..4887602 --- /dev/null +++ b/.planning/phases/05-polish-deploy/05-03-PLAN.md @@ -0,0 +1,203 @@ +--- +phase: 05-polish-deploy +plan: 03 +type: execute +wave: 3 +depends_on: [05-02] +files_modified: [README.md, n8n-workflow.json] +autonomous: false + +must_haves: + truths: + - "README has step-by-step deployment instructions" + - "README documents credential creation in n8n" + - "README documents Docker socket setup for n8n container" + - "All 6 commands tested end-to-end via Telegram" + artifacts: + - path: "README.md" + provides: "Deployment guide" + min_lines: 50 + contains: "Installation" + - path: "n8n-workflow.json" + provides: "Production-ready workflow" + key_links: + - from: "README.md" + to: "n8n credentials" + via: "documentation" + pattern: "telegramAuth" +--- + + +Write deployment README and perform end-to-end testing of complete bot functionality. + +Purpose: Enable users to deploy the bot on their own Unraid servers with clear instructions. +Output: Complete README, verified workflow, production-ready deployment package. + + + +@/home/luc/.claude/get-shit-done/workflows/execute-plan.md +@/home/luc/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/05-polish-deploy/05-CONTEXT.md +@.planning/phases/05-polish-deploy/05-RESEARCH.md +@.planning/phases/05-polish-deploy/05-01-SUMMARY.md +@.planning/phases/05-polish-deploy/05-02-SUMMARY.md +@n8n-workflow.json + + + + + + Task 1: Write deployment README + README.md + +Replace the stub README with a complete deployment guide. Per CONTEXT.md: "README only - step-by-step instructions in markdown" and "No troubleshooting section - focused on initial setup only". + +Structure (following RESEARCH.md template): + +# Docker Manager Bot + +One-line description: Telegram bot for managing Docker containers on Unraid. + +## Prerequisites + +- Unraid server with Docker enabled +- n8n container running on Unraid +- Telegram Bot Token (from @BotFather) +- Your Telegram User ID (from @userinfobot) + +## Installation + +### 1. Configure n8n Container + +Document the Docker run flags needed: +```bash +docker run -d \ + --name n8n \ + --group-add 281 \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /path/to/curl:/usr/bin/curl:ro \ + n8nio/n8n +``` + +Explain: +- `--group-add 281` for Docker socket access +- Socket mount requirement +- Static curl binary mount (hardened n8n image) + +### 2. Create n8n Credentials + +**Telegram API credential:** +- Type: Telegram API +- Access Token: your bot token from @BotFather + +**Telegram Auth credential:** +- Type: Header Auth (or custom) +- Field: userId = your Telegram user ID + +### 3. Import Workflow + +- Copy n8n-workflow.json to server +- In n8n: Workflows -> Import from File +- Map credentials when prompted + +### 4. Activate Workflow + +- Open workflow +- Click Active toggle +- Test with "status" message + +## Usage + +List the 6 commands: +- status - View all containers +- start - Start container +- stop - Stop container +- restart - Restart container +- update - Pull and recreate container +- logs [lines] - View container logs + +Mention persistent menu buttons available. + +Per CONTEXT.md: No troubleshooting section. + + +README exists at root. +Contains all 4 installation sections. +No troubleshooting section. +Markdown renders correctly. + + +Complete deployment guide in README.md. +Step-by-step instructions for fresh Unraid installation. + + + + + Task 2: End-to-end testing + +Complete Docker Manager Bot: +- Keyword routing (no Claude dependency) +- Persistent Telegram menu +- All 6 container commands +- Terse error messages +- Credential-based auth + + +Test each command via Telegram bot: + +1. **Menu:** Send /start or any unknown text + - Expected: Persistent keyboard appears with 6 buttons + +2. **Status:** Tap Status button or type "status" + - Expected: List of containers with status indicators + +3. **Start:** Type "start " + - Expected: Container starts, confirmation message + +4. **Stop:** Type "stop " + - Expected: Container stops, confirmation message + +5. **Restart:** Type "restart " + - Expected: Container restarts, confirmation message + +6. **Update:** Type "update " + - Expected: Image pulled, container recreated (or silent if no update) + +7. **Logs:** Type "logs " + - Expected: Last 50 log lines displayed + +8. **Error handling:** Stop n8n's Docker socket access briefly + - Expected: "Cannot connect to Docker" (not stack trace) + +9. **Auth:** Message bot from different Telegram account + - Expected: No response (silent ignore per Phase 1 decision) + + Type "approved" if all tests pass, or describe which tests failed + + + + + +1. README exists and has all required sections +2. All 6 commands work end-to-end +3. Persistent menu functions correctly +4. Error messages are terse +5. Unauthorized users get no response +6. Workflow exports without sensitive data + + + +- Fresh user can follow README to deploy bot +- All container management commands functional +- Bot ready for production use on Unraid + + + +After completion, create `.planning/phases/05-polish-deploy/05-03-SUMMARY.md` +