docs(14): create phase plan
This commit is contained in:
@@ -0,0 +1,244 @@
|
||||
---
|
||||
phase: 14-unraid-api-access
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- .env.unraid-api
|
||||
- .gitignore
|
||||
- n8n-workflow.json
|
||||
autonomous: true
|
||||
user_setup:
|
||||
- service: unraid-api
|
||||
why: "GraphQL API authentication for container update sync"
|
||||
env_vars:
|
||||
- name: UNRAID_API_KEY
|
||||
source: "Unraid WebGUI -> Settings -> Management Access -> API Keys -> Create, or SSH: unraid-api apikey --create --name 'Docker Manager Bot' --permissions 'DOCKER:UPDATE_ANY' --description 'Container update status sync' --json"
|
||||
- name: UNRAID_HOST
|
||||
source: "User's Unraid WebGUI URL (e.g., http://192.168.1.100 or http://tower.local). If using host.docker.internal, must add '--add-host=host.docker.internal:host-gateway' to n8n container Extra Parameters in Unraid Docker template editor."
|
||||
dashboard_config:
|
||||
- task: "Create API key with DOCKER:UPDATE_ANY permission"
|
||||
location: "Unraid WebGUI -> Settings -> Management Access -> API Keys, or via SSH"
|
||||
- task: "Add --add-host=host.docker.internal:host-gateway to n8n container Extra Parameters (if using host.docker.internal)"
|
||||
location: "Unraid WebGUI -> Docker -> n8n container -> Edit -> Extra Parameters"
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "Credential template file exists with correct variable names matching .env.n8n-api pattern"
|
||||
- "Credential file is gitignored and will not be committed"
|
||||
- "n8n workflow contains HTTP Request node configured for Unraid GraphQL API"
|
||||
- "n8n workflow contains error handling for GraphQL response validation"
|
||||
- "Test query requests fields needed by downstream phases (id, names, state, isUpdateAvailable)"
|
||||
artifacts:
|
||||
- path: ".env.unraid-api"
|
||||
provides: "Credential template with UNRAID_HOST and UNRAID_API_KEY"
|
||||
contains: "UNRAID_HOST"
|
||||
- path: ".gitignore"
|
||||
provides: "Gitignore entry for .env.unraid-api"
|
||||
contains: ".env.unraid-api"
|
||||
- path: "n8n-workflow.json"
|
||||
provides: "Unraid GraphQL test query nodes in main workflow"
|
||||
contains: "Unraid"
|
||||
key_links:
|
||||
- from: "n8n-workflow.json (HTTP Request node)"
|
||||
to: "Unraid GraphQL API"
|
||||
via: "POST to UNRAID_HOST/graphql with x-api-key header"
|
||||
pattern: "/graphql"
|
||||
- from: "n8n-workflow.json (Code node)"
|
||||
to: "HTTP Request node"
|
||||
via: "Response validation and error handling"
|
||||
pattern: "data\\.docker\\.containers"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Set up credential infrastructure and build Unraid GraphQL API test nodes in the main n8n workflow.
|
||||
|
||||
Purpose: Establishes the foundation for Unraid API connectivity — credential storage mirroring the existing `.env.n8n-api` pattern, gitignore protection, and actual n8n workflow nodes that query the Unraid GraphQL API to validate connectivity, authentication, and container data structure.
|
||||
|
||||
Output: `.env.unraid-api` template file, updated `.gitignore`, and new nodes in `n8n-workflow.json` for Unraid API testing.
|
||||
</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/14-unraid-api-access/14-CONTEXT.md
|
||||
@.planning/phases/14-unraid-api-access/14-RESEARCH.md
|
||||
@ARCHITECTURE.md
|
||||
@CLAUDE.md
|
||||
@.gitignore
|
||||
@n8n-workflow.json
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Create credential infrastructure</name>
|
||||
<files>.env.unraid-api, .gitignore</files>
|
||||
<action>
|
||||
1. Create `.env.unraid-api` file with template values, mirroring the existing `.env.n8n-api` pattern:
|
||||
```
|
||||
UNRAID_HOST=http://host.docker.internal
|
||||
UNRAID_API_KEY=your-unraid-api-key-here
|
||||
```
|
||||
|
||||
2. Add `.env.unraid-api` to `.gitignore` on a new line after the existing `.env.n8n-api` entry. Keep the comment header relevant (update if needed, e.g., "Environment files with sensitive credentials").
|
||||
|
||||
3. Update `CLAUDE.md` — add a new section "## Unraid API Access" (after the existing "## n8n API Access" section) documenting:
|
||||
- Credential file location and structure (`.env.unraid-api`)
|
||||
- Loading pattern: `. .env.unraid-api; curl -X POST "${UNRAID_HOST}/graphql" ...`
|
||||
- GraphQL query pattern for testing
|
||||
- Note that this mirrors the n8n API access pattern
|
||||
|
||||
Per user decision: Dual storage approach — `.env.unraid-api` for CLI/deploy scripts, n8n Header Auth credential for workflow nodes. The n8n credential creation is a user setup step (documented in plan's user_setup frontmatter), not automated here.
|
||||
</action>
|
||||
<verify>
|
||||
- `.env.unraid-api` exists with `UNRAID_HOST` and `UNRAID_API_KEY` variables
|
||||
- `grep -q ".env.unraid-api" .gitignore` returns 0
|
||||
- `CLAUDE.md` contains "Unraid API Access" section
|
||||
</verify>
|
||||
<done>Credential template file exists with correct variables, is gitignored, and usage is documented in CLAUDE.md</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Add Unraid GraphQL test nodes to main workflow</name>
|
||||
<files>n8n-workflow.json</files>
|
||||
<action>
|
||||
Add a new branch to the main workflow's Keyword Router (Switch node) that handles an "unraid" keyword. This creates a test path: user sends "unraid" -> Keyword Router -> Unraid test nodes -> Telegram response.
|
||||
|
||||
The branch needs 3 new nodes:
|
||||
|
||||
**Node 1: HTTP Request node ("Unraid API Test")**
|
||||
- Method: POST
|
||||
- URL: `={{ $env.UNRAID_HOST }}/graphql` (reads from n8n environment variable, OR use expression that can be overridden)
|
||||
- Authentication: Header Auth
|
||||
- Credential name: "Unraid API Key" (Header Auth type, header name: `x-api-key`)
|
||||
- NOTE: The credential must be created manually by the user in n8n. Use credential ID placeholder — the user will need to update this after creating the credential.
|
||||
- Body (JSON): `{ "query": "query { docker { containers { id names state isUpdateAvailable } } }" }`
|
||||
- Options: "Ignore SSL Issues" = true (handles self-signed certs per research pitfall #2)
|
||||
- On Error: "Continue on Error" (so the Code node can handle errors gracefully)
|
||||
|
||||
**Node 2: Code node ("Validate Unraid Response")**
|
||||
- Validates the GraphQL response:
|
||||
```javascript
|
||||
const response = $input.item.json;
|
||||
|
||||
// Check for HTTP errors (from continueOnError)
|
||||
if (response.error) {
|
||||
return {
|
||||
json: {
|
||||
action: 'send_message',
|
||||
text: `❌ <b>Unraid API Error</b>\n\n` +
|
||||
`<b>Error:</b> ${response.error.message || JSON.stringify(response.error)}\n\n` +
|
||||
`<b>Check:</b>\n` +
|
||||
`• Is UNRAID_HOST correct?\n` +
|
||||
`• Is the API key valid?\n` +
|
||||
`• Can n8n reach the Unraid host? (--add-host flag)\n` +
|
||||
`• Is Unraid GraphQL API enabled? (v7.2+ or Connect plugin)`,
|
||||
chatId: $('Telegram Trigger').item.json.message.chat.id
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Check for GraphQL errors
|
||||
if (response.errors) {
|
||||
const errorMsg = response.errors.map(e => e.message).join(', ');
|
||||
return {
|
||||
json: {
|
||||
action: 'send_message',
|
||||
text: `❌ <b>Unraid GraphQL Error</b>\n\n${errorMsg}`,
|
||||
chatId: $('Telegram Trigger').item.json.message.chat.id
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Validate response structure
|
||||
if (!response.data?.docker?.containers) {
|
||||
return {
|
||||
json: {
|
||||
action: 'send_message',
|
||||
text: '❌ <b>Unexpected response</b>\n\nNo container data in GraphQL response.',
|
||||
chatId: $('Telegram Trigger').item.json.message.chat.id
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const containers = response.data.docker.containers;
|
||||
const sampleId = containers[0]?.id || 'N/A';
|
||||
const updateCount = containers.filter(c => c.isUpdateAvailable).length;
|
||||
|
||||
return {
|
||||
json: {
|
||||
action: 'send_message',
|
||||
text: `✅ <b>Unraid API Connected</b>\n\n` +
|
||||
`<b>Containers:</b> ${containers.length}\n` +
|
||||
`<b>Updates available:</b> ${updateCount}\n` +
|
||||
`<b>ID format:</b> <code>${sampleId}</code>\n\n` +
|
||||
`Sample:\n` +
|
||||
containers.slice(0, 5).map(c =>
|
||||
`• ${c.names?.[0] || c.id} (${c.state})${c.isUpdateAvailable ? ' 🔄' : ''}`
|
||||
).join('\n'),
|
||||
chatId: $('Telegram Trigger').item.json.message.chat.id
|
||||
}
|
||||
};
|
||||
```
|
||||
- Uses clear, descriptive error messages per user decision (what failed, why, what to check)
|
||||
- Uses existing error logging pattern (structured return, same shape as Docker API errors)
|
||||
|
||||
**Node 3: Telegram Send Message node ("Send Unraid Test Result")**
|
||||
- Chat ID: `={{ $json.chatId }}`
|
||||
- Text: `={{ $json.text }}`
|
||||
- Parse Mode: HTML
|
||||
- Use existing Telegram credential (ID: `I0xTTiASl7C1NZhJ`)
|
||||
|
||||
**Wiring:**
|
||||
- Connect Keyword Router's new "unraid" output -> HTTP Request node -> Code node -> Telegram Send node
|
||||
- Add "unraid" as a new `contains` rule in the Keyword Router Switch node. Place it AFTER existing `startsWith` rules but the order among `contains` rules doesn't matter since "unraid" is unique.
|
||||
- Update the Keyword Router's `rules` array and `connections` accordingly.
|
||||
|
||||
**Important n8n JSON patterns (from CLAUDE.md):**
|
||||
- Telegram credential: `{ "id": "I0xTTiASl7C1NZhJ", "name": "Telegram account" }`
|
||||
- Node IDs: Generate unique UUIDs for each new node
|
||||
- Position: Place nodes visually below/after existing keyword branches (check existing node positions for Y-offset pattern)
|
||||
- For the Header Auth credential: Use a placeholder credential reference. The user creates "Unraid API Key" credential in n8n manually and the credential ID gets set. Use name "Unraid API Key" in the node JSON.
|
||||
|
||||
**Auth check:** The "unraid" command goes through the existing Auth IF node (same path as all other text commands), so it's already protected.
|
||||
</action>
|
||||
<verify>
|
||||
- `python3 -c "import json; wf=json.load(open('n8n-workflow.json')); nodes=[n['name'] for n in wf['nodes']]; print('Unraid API Test' in nodes, 'Validate Unraid Response' in nodes, 'Send Unraid Test Result' in nodes)"`
|
||||
All three should print True.
|
||||
- Keyword Router Switch node contains "unraid" rule.
|
||||
- Connections wire: Keyword Router -> Unraid API Test -> Validate Unraid Response -> Send Unraid Test Result.
|
||||
- Push workflow to n8n: `. .env.n8n-api; ...` push recipe from CLAUDE.md. Verify HTTP 200.
|
||||
</verify>
|
||||
<done>Main workflow contains a working "unraid" keyword branch with HTTP Request (GraphQL query), validation Code node (error handling with descriptive messages), and Telegram response node. Workflow pushes to n8n successfully.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `.env.unraid-api` exists with template values
|
||||
- `.gitignore` includes `.env.unraid-api`
|
||||
- `CLAUDE.md` documents Unraid API access pattern
|
||||
- `n8n-workflow.json` contains 3 new nodes: "Unraid API Test", "Validate Unraid Response", "Send Unraid Test Result"
|
||||
- Keyword Router has "unraid" rule
|
||||
- All connections properly wired
|
||||
- Workflow pushes to n8n without errors
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Credential infrastructure mirrors existing `.env.n8n-api` pattern exactly
|
||||
- Test workflow branch is wired into main workflow's existing auth-protected text path
|
||||
- Error handling provides clear, actionable feedback (what failed, why, what to check)
|
||||
- Test query includes fields needed by Phase 15+: id, names, state, isUpdateAvailable
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/14-unraid-api-access/14-01-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user