docs: complete v1.3 project research (STACK, FEATURES, ARCHITECTURE, PITFALLS, SUMMARY)
This commit is contained in:
+440
-296
@@ -1,356 +1,500 @@
|
|||||||
# Architecture Research: v1.1
|
# Architecture Research: Unraid Update Status Sync Integration
|
||||||
|
|
||||||
**Researched:** 2026-02-02
|
**Domain:** Telegram Bot Docker Management Extension
|
||||||
**Domain:** Integration architecture for v1.1 features
|
**Researched:** 2026-02-08
|
||||||
**Confidence:** HIGH (n8n API, Docker socket proxy), MEDIUM (Telegram keyboards), LOW (Unraid update sync)
|
**Confidence:** MEDIUM
|
||||||
|
|
||||||
## Executive Summary
|
## Integration Overview
|
||||||
|
|
||||||
The v1.1 features require careful integration with the existing single-workflow architecture. The key finding is that all four features (n8n API access, Docker socket security, Telegram keyboards, Unraid update sync) can be implemented without major refactoring of the existing workflow structure. However, Docker socket proxy is the most impactful change, requiring container-level infrastructure modifications before workflow changes.
|
This research focuses on integrating Unraid update status sync into the existing 287-node n8n workflow system (1 main + 7 sub-workflows). The goal is to clear Unraid's "update available" badges after the bot successfully updates a container.
|
||||||
|
|
||||||
## Current Architecture
|
### Current Architecture (Baseline)
|
||||||
|
|
||||||
```
|
```
|
||||||
+-------------------+ +------------------+ +-------------------+
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
| Telegram User |---->| n8n Workflow |---->| Docker Socket |
|
│ Telegram User │
|
||||||
| (Webhook) | | (3,200 lines) | | (/var/run/...) |
|
└───────────────────────┬─────────────────────────────────────┘
|
||||||
+-------------------+ +------------------+ +-------------------+
|
│
|
||||||
|
|
┌───────────────────────▼─────────────────────────────────────┐
|
||||||
v
|
│ n8n-workflow.json (Main) │
|
||||||
+------------------+
|
│ 166 nodes │
|
||||||
| Telegram Bot |
|
├─────────────────────────────────────────────────────────────┤
|
||||||
| API (Response) |
|
│ Telegram Trigger → Auth → Correlation ID → Keyword Router │
|
||||||
+------------------+
|
│ │ │
|
||||||
|
│ Execute Workflow nodes (17) │
|
||||||
|
│ │ │
|
||||||
|
│ ┌────────────┼────────────┐ │
|
||||||
|
│ ▼ ▼ ▼ │
|
||||||
|
│ n8n-update n8n-actions n8n-status │
|
||||||
|
│ (34 nodes) (11 nodes) (11 nodes) │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ [5 more sub-workflows: logs, batch-ui, │
|
||||||
|
│ confirmation, matching] │
|
||||||
|
└───────────────────────┬─────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
┌───────────────────────▼─────────────────────────────────────┐
|
||||||
|
│ docker-socket-proxy:2375 │
|
||||||
|
│ (Tecnativa/LinuxServer) │
|
||||||
|
└───────────────────────┬─────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
┌───────────────────────▼─────────────────────────────────────┐
|
||||||
|
│ Docker Engine (Unraid Host) │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
**Current Components:**
|
### Target Architecture (With Unraid Sync)
|
||||||
| Component | Description | Modification Risk |
|
|
||||||
|-----------|-------------|-------------------|
|
```
|
||||||
| Telegram Trigger | Webhook receiving messages & callbacks | LOW - add callback_query handling |
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
| Route Update Type | Switch node: message vs callback | LOW - already exists |
|
│ Telegram User │
|
||||||
| Auth Check | IF nodes checking user ID | NONE - unchanged |
|
└───────────────────────┬─────────────────────────────────────┘
|
||||||
| Keyword Router | Switch node with contains rules | LOW - add new routes |
|
│
|
||||||
| Docker operations | Execute Command + curl | HIGH - needs socket proxy changes |
|
┌───────────────────────▼─────────────────────────────────────┐
|
||||||
| Response formatting | Code nodes + Telegram send | LOW - extend existing |
|
│ n8n-workflow.json (Main) │
|
||||||
|
│ 166 nodes │
|
||||||
|
├─────────────────────────────────────────────────────────────┤
|
||||||
|
│ Telegram Trigger → Auth → Correlation ID → Keyword Router │
|
||||||
|
│ │ │
|
||||||
|
│ Execute Workflow nodes (17) │
|
||||||
|
│ │ │
|
||||||
|
│ ┌────────────┼────────────┐ │
|
||||||
|
│ ▼ ▼ ▼ │
|
||||||
|
│ n8n-update n8n-actions n8n-status │
|
||||||
|
│ (34 nodes) (11 nodes) (11 nodes) │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ [5 more sub-workflows] │
|
||||||
|
└───────────┬───────────────────────┬─────────────────────────┘
|
||||||
|
│ │
|
||||||
|
│ ┌───▼──────────────────────┐
|
||||||
|
│ │ NEW: Clear Unraid │
|
||||||
|
│ │ Update Status (node) │
|
||||||
|
│ └───┬──────────────────────┘
|
||||||
|
│ │
|
||||||
|
┌───────────▼───────────────────────▼─────────────────────────┐
|
||||||
|
│ docker-socket-proxy:2375 │
|
||||||
|
│ (Tecnativa/LinuxServer) │
|
||||||
|
└───────────────────────┬─────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
┌───────────────────────▼─────────────────────────────────────┐
|
||||||
|
│ Docker Engine (Unraid Host) │
|
||||||
|
│ │
|
||||||
|
│ /var/lib/docker/unraid-update-status.json ← DELETE HERE │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
## Integration Points
|
## Integration Points
|
||||||
|
|
||||||
### 1. n8n API Access
|
### Where to Add Sync Logic
|
||||||
|
|
||||||
**What needs to change:** Enable n8n REST API and create API key for external access.
|
**Option A: Extend n8n-update.json sub-workflow (RECOMMENDED)**
|
||||||
|
|
||||||
**Integration approach:** Configuration change only, no workflow modifications needed.
|
| Pros | Cons |
|
||||||
|
|------|------|
|
||||||
|
| Single responsibility: update sub-workflow owns all update-related actions | Couples Unraid-specific logic to generic update flow |
|
||||||
|
| Minimal changes to main workflow | Breaks if called from non-Unraid systems (not a concern here) |
|
||||||
|
| Sync executes immediately after successful update | None significant |
|
||||||
|
| Easier to test in isolation | |
|
||||||
|
|
||||||
**Configuration required:**
|
**Option B: Add to main workflow after Execute Update returns**
|
||||||
```bash
|
|
||||||
# n8n container environment variables
|
| Pros | Cons |
|
||||||
N8N_PUBLIC_API_DISABLED=false # Default - API is enabled
|
|------|------|
|
||||||
# No additional env vars needed for basic API access
|
| Keeps Unraid logic separate from generic update | More complex routing in main workflow |
|
||||||
|
| Could conditionally enable based on environment | Requires checking sub-workflow success result |
|
||||||
|
| | Adds latency between update and sync |
|
||||||
|
| | Harder to test (requires full workflow execution) |
|
||||||
|
|
||||||
|
**Option C: New sub-workflow (n8n-unraid-sync.json)**
|
||||||
|
|
||||||
|
| Pros | Cons |
|
||||||
|
|------|------|
|
||||||
|
| Complete separation of concerns | Overkill for single operation (file deletion) |
|
||||||
|
| Reusable if other Unraid integrations added | Adds 8th sub-workflow to manage |
|
||||||
|
| | Main workflow needs new Execute Workflow node |
|
||||||
|
| | Extra complexity for minimal benefit |
|
||||||
|
|
||||||
|
**Recommendation:** Option A (extend n8n-update.json) because:
|
||||||
|
1. Sync is tightly coupled to update success
|
||||||
|
2. Single responsibility: "update a container AND clear its Unraid status"
|
||||||
|
3. Minimal architectural impact
|
||||||
|
4. Easiest to test and maintain
|
||||||
|
|
||||||
|
### Modification to n8n-update.json
|
||||||
|
|
||||||
|
**Current End State (Return Success node, line 499):**
|
||||||
|
```javascript
|
||||||
|
return {
|
||||||
|
json: {
|
||||||
|
success: true,
|
||||||
|
updated: true,
|
||||||
|
message: data.message,
|
||||||
|
oldDigest: data.oldDigest,
|
||||||
|
newDigest: data.newDigest,
|
||||||
|
correlationId: data.correlationId || ''
|
||||||
|
}
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
**How Claude Code can use it:**
|
**New Flow:**
|
||||||
```bash
|
```
|
||||||
# Get workflow (requires API key)
|
Remove Old Image (Success) → Clear Unraid Status → Return Success
|
||||||
curl -X GET "http://n8n:5678/api/v1/workflows" \
|
│
|
||||||
-H "X-N8N-API-KEY: <api-key>"
|
▼
|
||||||
|
(Execute Command node)
|
||||||
# Get specific workflow
|
rm -f /var/lib/docker/unraid-update-status.json
|
||||||
curl -X GET "http://n8n:5678/api/v1/workflows/<workflow-id>" \
|
|
||||||
-H "X-N8N-API-KEY: <api-key>"
|
|
||||||
|
|
||||||
# Update workflow
|
|
||||||
curl -X PUT "http://n8n:5678/api/v1/workflows/<workflow-id>" \
|
|
||||||
-H "X-N8N-API-KEY: <api-key>" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d @workflow.json
|
|
||||||
|
|
||||||
# Get execution logs
|
|
||||||
curl -X GET "http://n8n:5678/api/v1/executions" \
|
|
||||||
-H "X-N8N-API-KEY: <api-key>"
|
|
||||||
|
|
||||||
# Execute workflow manually
|
|
||||||
curl -X POST "http://n8n:5678/api/v1/workflows/<workflow-id>/activate" \
|
|
||||||
-H "X-N8N-API-KEY: <api-key>"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Impact on existing workflow:** NONE - this is infrastructure configuration.
|
**Node Addition (1 new node):**
|
||||||
|
- **Type:** Execute Command
|
||||||
|
- **Position:** After "Remove Old Image (Success)", before "Return Success"
|
||||||
|
- **Command:** `rm -f /var/lib/docker/unraid-update-status.json`
|
||||||
|
- **Error Handling:** `continueRegularOutput` (don't fail update if sync fails)
|
||||||
|
- **Total Nodes:** 34 → 35
|
||||||
|
|
||||||
**Sources:**
|
## Data Flow
|
||||||
- [n8n public REST API](https://docs.n8n.io/api/)
|
|
||||||
- [n8n API authentication](https://docs.n8n.io/api/authentication/)
|
|
||||||
- [Disable the public REST API](https://docs.n8n.io/hosting/securing/disable-public-api/)
|
|
||||||
|
|
||||||
### 2. Docker Socket Security (Socket Proxy)
|
### Update Completion to Unraid Status Clear
|
||||||
|
|
||||||
**What needs to change:** Replace direct Docker socket mount with socket proxy container.
|
|
||||||
|
|
||||||
**Current architecture (INSECURE):**
|
|
||||||
```
|
```
|
||||||
n8n container ----mount----> /var/run/docker.sock (host)
|
1. User: "update plex"
|
||||||
|
↓
|
||||||
|
2. Main workflow → n8n-update.json
|
||||||
|
↓
|
||||||
|
3. Update sub-workflow:
|
||||||
|
Inspect Container → Parse Config → Pull Image → Check Pull Success
|
||||||
|
→ Inspect New Image → Compare Digests → Stop Container
|
||||||
|
→ Remove Container → Build Create Body → Create Container
|
||||||
|
→ Start Container → Format Update Success → Send Response
|
||||||
|
→ Remove Old Image (Success)
|
||||||
|
↓
|
||||||
|
4. NEW: Clear Unraid Status
|
||||||
|
Execute Command: rm -f /var/lib/docker/unraid-update-status.json
|
||||||
|
↓
|
||||||
|
5. Return Success (existing)
|
||||||
|
↓
|
||||||
|
6. Main workflow routes result to Telegram response
|
||||||
```
|
```
|
||||||
|
|
||||||
**Target architecture (SECURE):**
|
**Key Properties:**
|
||||||
```
|
- Sync happens AFTER container is updated and old image removed
|
||||||
n8n container ---tcp---> socket-proxy container ---mount---> docker.sock (host)
|
- Sync happens BEFORE sub-workflow returns (ensures completion)
|
||||||
```
|
- Sync failure does NOT fail the update (onError: continueRegularOutput)
|
||||||
|
- User receives success message regardless of sync status
|
||||||
|
|
||||||
**New container required:** LinuxServer or Tecnativa docker-socket-proxy
|
### Why Delete the Entire Status File?
|
||||||
|
|
||||||
**Recommended configuration (LinuxServer):**
|
**Unraid's Update Tracking Mechanism:**
|
||||||
|
1. Unraid stores update status in `/var/lib/docker/unraid-update-status.json`
|
||||||
|
2. File contains: `{"containerName": "true|false", ...}` (true = updated, false = needs update)
|
||||||
|
3. When bot updates externally, Unraid's file is stale
|
||||||
|
4. Unraid only checks for **newly available** updates, not "containers now current"
|
||||||
|
5. Deleting file forces Unraid to recheck ALL containers on next "Check for Updates"
|
||||||
|
|
||||||
|
**Why Not Modify the JSON?**
|
||||||
|
- File format is internal to Unraid's DockerClient.php
|
||||||
|
- Could change between Unraid versions
|
||||||
|
- Parsing/modifying JSON from Execute Command is fragile
|
||||||
|
- Deletion is simpler and forces full recheck (HIGH confidence)
|
||||||
|
|
||||||
|
**User Impact:**
|
||||||
|
- After bot update, Unraid badge may show "outdated" for ~30 seconds until next UI refresh
|
||||||
|
- User can manually click "Check for Updates" in Unraid Docker tab to force immediate recheck
|
||||||
|
- Next automatic Unraid check will rebuild status file correctly
|
||||||
|
|
||||||
|
## Container Access Requirements
|
||||||
|
|
||||||
|
### How n8n Accesses Unraid Host Filesystem
|
||||||
|
|
||||||
|
**Current n8n Container Configuration:**
|
||||||
|
|
||||||
|
The n8n container must be able to delete `/var/lib/docker/unraid-update-status.json` on the Unraid host.
|
||||||
|
|
||||||
|
**Access Pattern Options:**
|
||||||
|
|
||||||
|
| Method | Implementation | Pros | Cons |
|
||||||
|
|--------|----------------|------|------|
|
||||||
|
| **Volume Mount (RECOMMENDED)** | `-v /var/lib/docker:/host/var/lib/docker:rw` | Direct filesystem access, simple | Grants access to entire /var/lib/docker |
|
||||||
|
| **Docker API via exec** | `docker exec unraid-host rm -f /var/lib/docker/...` | No volume mount needed | Requires exec API (security risk) |
|
||||||
|
| **SSH into host** | Execute Command with SSH | No volume mount | Requires SSH credentials in workflow |
|
||||||
|
| **Unraid API (future)** | GraphQL mutation to clear status | Proper API layer | Requires Unraid 7.2+, API key setup |
|
||||||
|
|
||||||
|
**Recommendation:** Volume mount `/var/lib/docker` as read-write because:
|
||||||
|
1. n8n already accesses Docker via socket proxy (security boundary established)
|
||||||
|
2. Unraid status file is Docker-internal data (reasonable scope)
|
||||||
|
3. No additional credentials or services needed
|
||||||
|
4. Direct file operations are faster than API calls
|
||||||
|
5. Works on all Unraid versions (no version dependency)
|
||||||
|
|
||||||
|
**Security Consideration:**
|
||||||
|
- `/var/lib/docker` contains Docker data, not general host filesystem
|
||||||
|
- Socket proxy already limits Docker API access
|
||||||
|
- File deletion is least-privilege operation (no read of sensitive data)
|
||||||
|
- Alternative is exec API (worse security than filesystem mount)
|
||||||
|
|
||||||
|
### Volume Mount Configuration
|
||||||
|
|
||||||
|
**Add to n8n Container:**
|
||||||
```yaml
|
```yaml
|
||||||
# docker-compose.yml
|
|
||||||
services:
|
services:
|
||||||
socket-proxy:
|
|
||||||
image: lscr.io/linuxserver/socket-proxy:latest
|
|
||||||
container_name: socket-proxy
|
|
||||||
environment:
|
|
||||||
- CONTAINERS=1 # List containers
|
|
||||||
- POST=0 # Disable general POST (security)
|
|
||||||
- ALLOW_START=1 # Allow container start
|
|
||||||
- ALLOW_STOP=1 # Allow container stop
|
|
||||||
- ALLOW_RESTARTS=1 # Allow restart/kill
|
|
||||||
- IMAGES=1 # For image operations (update flow)
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
||||||
restart: unless-stopped
|
|
||||||
read_only: true
|
|
||||||
tmpfs:
|
|
||||||
- /run
|
|
||||||
|
|
||||||
n8n:
|
n8n:
|
||||||
# Remove: -v /var/run/docker.sock:/var/run/docker.sock
|
# ... existing config ...
|
||||||
environment:
|
volumes:
|
||||||
- DOCKER_HOST=tcp://socket-proxy:2375
|
- /var/lib/docker:/host/var/lib/docker:rw # NEW
|
||||||
depends_on:
|
# ... existing volumes ...
|
||||||
- socket-proxy
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Impact on existing workflow:** HIGH - all curl commands must change
|
**Execute Command Node:**
|
||||||
|
|
||||||
| Current Pattern | New Pattern |
|
|
||||||
|-----------------|-------------|
|
|
||||||
| `curl --unix-socket /var/run/docker.sock http://localhost/...` | `curl http://socket-proxy:2375/...` |
|
|
||||||
|
|
||||||
**Workflow changes needed:**
|
|
||||||
1. All Execute Command nodes using `--unix-socket` flag need modification
|
|
||||||
2. Host changes from `localhost` to `socket-proxy`
|
|
||||||
3. Socket path removed from curl commands
|
|
||||||
|
|
||||||
**Search & replace pattern:**
|
|
||||||
```
|
|
||||||
FROM: curl -s --unix-socket /var/run/docker.sock 'http://localhost/v1.47/
|
|
||||||
TO: curl -s 'http://socket-proxy:2375/v1.47/
|
|
||||||
```
|
|
||||||
|
|
||||||
**Node count affected:** ~15 Execute Command nodes (Docker List, Inspect, Start, Stop, etc.)
|
|
||||||
|
|
||||||
**Security benefit:**
|
|
||||||
- n8n no longer has root-equivalent host access
|
|
||||||
- Socket proxy limits which Docker API endpoints are accessible
|
|
||||||
- Read-only mount on socket-proxy container
|
|
||||||
|
|
||||||
**Sources:**
|
|
||||||
- [LinuxServer socket-proxy](https://docs.linuxserver.io/images/docker-socket-proxy/)
|
|
||||||
- [Tecnativa docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy)
|
|
||||||
|
|
||||||
### 3. Telegram Inline Keyboards
|
|
||||||
|
|
||||||
**What needs to change:** Add persistent menu buttons and expand inline keyboard usage.
|
|
||||||
|
|
||||||
**Integration with existing architecture:**
|
|
||||||
- Existing callback_query handling already in place (suggestions, batch confirmations)
|
|
||||||
- HTTP Request nodes already used for complex Telegram API calls
|
|
||||||
- Switch node (Route Callback) handles different callback types
|
|
||||||
|
|
||||||
**Current callback flow (already exists):**
|
|
||||||
```
|
|
||||||
Telegram Trigger (callback_query)
|
|
||||||
-> IF Callback Authenticated
|
|
||||||
-> Parse Callback Data
|
|
||||||
-> Route Callback (Switch)
|
|
||||||
-> cancel / expired / batch / single action
|
|
||||||
```
|
|
||||||
|
|
||||||
**Additions needed:**
|
|
||||||
|
|
||||||
1. **Persistent keyboard on /start or unknown input:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"reply_markup": {
|
|
||||||
"keyboard": [
|
|
||||||
[{"text": "Status"}],
|
|
||||||
[{"text": "Start"}, {"text": "Stop"}],
|
|
||||||
[{"text": "Restart"}, {"text": "Update"}],
|
|
||||||
[{"text": "Logs"}]
|
|
||||||
],
|
|
||||||
"is_persistent": true,
|
|
||||||
"resize_keyboard": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Container selection keyboards:**
|
|
||||||
After user sends "start" without container name, show inline keyboard with running/stopped containers.
|
|
||||||
|
|
||||||
**Known limitation:** n8n's native Telegram node doesn't support dynamic inline keyboards well. Continue using HTTP Request nodes for complex keyboards (already the pattern in v1.0).
|
|
||||||
|
|
||||||
**New callback routing needed:**
|
|
||||||
| Callback Type | Action Code | Handler |
|
|
||||||
|---------------|-------------|---------|
|
|
||||||
| Container selection | `sel:{containerId}` | New route in Route Callback |
|
|
||||||
| Menu action | `menu:{action}` | New route for keyboard-triggered actions |
|
|
||||||
|
|
||||||
**Impact on existing workflow:** MEDIUM
|
|
||||||
- Add 1-2 new outputs to Route Callback switch
|
|
||||||
- Add nodes for container selection keyboard generation
|
|
||||||
- Modify "Show Menu" response to include persistent keyboard
|
|
||||||
|
|
||||||
**Sources:**
|
|
||||||
- [n8n Telegram callback operations](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.telegram/callback-operations/)
|
|
||||||
- [Telegram Bot API ReplyKeyboardMarkup](https://core.telegram.org/bots/api#replykeyboardmarkup)
|
|
||||||
- [n8n community: inline keyboard callback query](https://community.n8n.io/t/n8n-telegram-inline-keyboard-callback-query-workflow-example/112588)
|
|
||||||
|
|
||||||
### 4. Unraid Update Sync
|
|
||||||
|
|
||||||
**What needs to change:** After bot updates a container, clear Unraid's "update available" badge.
|
|
||||||
|
|
||||||
**How Unraid tracks updates:**
|
|
||||||
- File: `/var/lib/docker/unraid-update-status.json`
|
|
||||||
- Managed by: `/usr/local/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php`
|
|
||||||
- Update check compares local image digest vs registry digest
|
|
||||||
|
|
||||||
**Known issue:** When containers are updated by external tools (Watchtower, our bot), Unraid doesn't automatically clear the "update available" badge. Workaround is deleting the status file.
|
|
||||||
|
|
||||||
**Integration approach:**
|
|
||||||
|
|
||||||
**Option A: Delete status file (simple but blunt)**
|
|
||||||
```bash
|
```bash
|
||||||
# After successful container update
|
# Path accessible from inside n8n container
|
||||||
rm /var/lib/docker/unraid-update-status.json
|
rm -f /host/var/lib/docker/unraid-update-status.json
|
||||||
```
|
|
||||||
This forces Unraid to recheck all containers on next "Check for Updates".
|
|
||||||
|
|
||||||
**Option B: Trigger Unraid's check (cleaner)**
|
|
||||||
```bash
|
|
||||||
# Call Unraid's update check endpoint (if exposed)
|
|
||||||
# Requires research into Unraid API
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Option C: Modify status file directly**
|
**Why `/host/` prefix:**
|
||||||
```bash
|
- Inside container, `/var/lib/docker` is container's own filesystem
|
||||||
# Update the specific container's entry in the JSON
|
- Volume mount at `/host/var/lib/docker` is Unraid host's filesystem
|
||||||
# Requires understanding the JSON schema
|
- Prevents accidental deletion of n8n's own Docker files
|
||||||
```
|
|
||||||
|
|
||||||
**Challenges:**
|
## Component Modifications
|
||||||
1. Status file is on host, not in n8n container
|
|
||||||
2. n8n doesn't have host filesystem access
|
|
||||||
3. Socket proxy won't help (not a Docker API operation)
|
|
||||||
|
|
||||||
**Possible solutions:**
|
### Modified Components
|
||||||
1. **Mount status file into n8n:** `-v /var/lib/docker/unraid-update-status.json:/unraid-status.json`
|
|
||||||
2. **Create helper script on host:** Cron job that monitors for updates
|
|
||||||
3. **Use Unraid API:** If Unraid exposes an endpoint to trigger update checks
|
|
||||||
|
|
||||||
**Confidence:** LOW - This requires host-level access that may not be available via Docker. Needs further investigation with actual Unraid system access.
|
| Component | Type | Change | Impact |
|
||||||
|
|-----------|------|--------|--------|
|
||||||
|
| **n8n container** | Infrastructure | Add volume mount `/var/lib/docker:/host/var/lib/docker:rw` | MEDIUM - requires container recreation |
|
||||||
|
| **n8n-update.json** | Sub-workflow | Add 1 Execute Command node after "Remove Old Image (Success)" | LOW - workflow edit only |
|
||||||
|
| **Clear Unraid Status (NEW)** | Node | Execute Command: `rm -f /host/var/lib/docker/unraid-update-status.json` | NEW - single operation |
|
||||||
|
|
||||||
**Sources:**
|
### Unchanged Components
|
||||||
- [Unraid forums: incorrect docker update notification](https://forums.unraid.net/bug-reports/stable-releases/regression-incorrect-docker-update-notification-r2807/)
|
|
||||||
- [Unraid Docker management docs](https://docs.unraid.net/unraid-os/manual/docker-management/)
|
|
||||||
|
|
||||||
## Component Changes Summary
|
- Main workflow (n8n-workflow.json): No changes
|
||||||
|
- Other 6 sub-workflows: No changes
|
||||||
|
- Socket proxy configuration: No changes
|
||||||
|
- Docker socket access pattern: No changes
|
||||||
|
- Telegram integration: No changes
|
||||||
|
|
||||||
| Component | Change Type | Description | Effort |
|
## Build Order
|
||||||
|-----------|-------------|-------------|--------|
|
|
||||||
| socket-proxy | NEW | Docker socket proxy container | Medium |
|
|
||||||
| n8n container | MODIFY | Remove socket mount, add DOCKER_HOST env | Low |
|
|
||||||
| n8n API key | NEW | Create API key in n8n settings | Low |
|
|
||||||
| Execute Command nodes | MODIFY | Change curl commands to use proxy | Medium |
|
|
||||||
| Show Menu node | MODIFY | Add persistent keyboard | Low |
|
|
||||||
| Route Callback switch | MODIFY | Add new callback types | Low |
|
|
||||||
| Container selection | NEW | Generate dynamic keyboards | Medium |
|
|
||||||
| Unraid sync | NEW | Status file update mechanism | High (uncertain) |
|
|
||||||
|
|
||||||
## Data Flow Changes
|
|
||||||
|
|
||||||
### Before v1.1 (current)
|
|
||||||
```
|
|
||||||
User -> Telegram -> n8n webhook -> curl -> docker.sock -> Docker Engine
|
|
||||||
```
|
|
||||||
|
|
||||||
### After v1.1
|
|
||||||
```
|
|
||||||
User -> Telegram -> n8n webhook -> curl -> socket-proxy:2375 -> docker.sock -> Docker Engine
|
|
||||||
^
|
|
||||||
|
|
|
||||||
Claude Code -> n8n API --+
|
|
||||||
```
|
|
||||||
|
|
||||||
## Suggested Build Order
|
|
||||||
|
|
||||||
Based on dependencies and risk:
|
Based on dependencies and risk:
|
||||||
|
|
||||||
### Phase 1: Infrastructure (no workflow changes)
|
### Phase 1: Infrastructure Setup
|
||||||
1. **n8n API enablement** - Configuration only, enables faster iteration
|
**Delivers:** n8n container has host filesystem access
|
||||||
2. **Socket proxy setup** - Container deployment, test connectivity
|
**Tasks:**
|
||||||
|
1. Add volume mount to n8n container configuration
|
||||||
|
2. Recreate n8n container with new mount
|
||||||
|
3. Verify mount accessible: `docker exec n8n ls /host/var/lib/docker`
|
||||||
|
4. Test file deletion: `docker exec n8n rm -f /host/var/lib/docker/test-file`
|
||||||
|
|
||||||
**Rationale:** API access first means Claude Code can more easily modify the workflow for subsequent phases. Socket proxy is infrastructure that must exist before workflow changes.
|
**Rationale:** Infrastructure change first, before workflow modifications. Ensures mount works before relying on it.
|
||||||
|
|
||||||
### Phase 2: Workflow Migration
|
**Risks:**
|
||||||
3. **Update all curl commands** - Migrate from socket to proxy
|
- Container recreation causes brief downtime (~10 seconds)
|
||||||
4. **Test all existing functionality** - Verify no regressions
|
- Mount path typo breaks functionality
|
||||||
|
|
||||||
**Rationale:** This is the highest-risk change. Must be completed and tested before adding new features.
|
**Mitigation:**
|
||||||
|
- Schedule during low-traffic window
|
||||||
|
- Test mount manually before workflow change
|
||||||
|
- Document rollback: remove volume mount, recreate container
|
||||||
|
|
||||||
### Phase 3: UX Enhancements
|
### Phase 2: Workflow Modification
|
||||||
5. **Persistent keyboard** - Quick win, minimal integration
|
**Delivers:** Update sub-workflow clears Unraid status
|
||||||
6. **Container selection keyboards** - Depends on callback routing
|
**Tasks:**
|
||||||
|
1. Read n8n-update.json via n8n API
|
||||||
|
2. Add Execute Command node after "Remove Old Image (Success)"
|
||||||
|
3. Configure command: `rm -f /host/var/lib/docker/unraid-update-status.json`
|
||||||
|
4. Set error handling: `continueRegularOutput`
|
||||||
|
5. Connect to "Return Success" node
|
||||||
|
6. Push updated workflow via n8n API
|
||||||
|
7. Test with single container update
|
||||||
|
|
||||||
**Rationale:** UX improvements can proceed once core functionality is stable.
|
**Rationale:** Modify workflow only after infrastructure proven working. Single node addition is minimal risk.
|
||||||
|
|
||||||
### Phase 4: Advanced Integration
|
**Risks:**
|
||||||
7. **Unraid update sync** - Requires further research, may need host access
|
- File path wrong (typo in command)
|
||||||
|
- Permissions issue (mount is read-only)
|
||||||
|
- Delete fails silently
|
||||||
|
|
||||||
**Rationale:** Most uncertain feature, defer until other features are stable.
|
**Mitigation:**
|
||||||
|
- Test command manually first (Phase 1 testing)
|
||||||
|
- Verify mount is `:rw` not `:ro`
|
||||||
|
- Check execution logs for errors
|
||||||
|
|
||||||
## Risk Assessment
|
### Phase 3: Validation
|
||||||
|
**Delivers:** Confirmed end-to-end functionality
|
||||||
|
**Tasks:**
|
||||||
|
1. Update container via bot
|
||||||
|
2. Check Unraid UI - badge should still show "update available" (file deleted)
|
||||||
|
3. Click "Check for Updates" in Unraid Docker tab
|
||||||
|
4. Verify badge clears (Unraid rechecked and found container current)
|
||||||
|
5. Verify workflow execution logs show no errors
|
||||||
|
|
||||||
| Feature | Risk Level | Mitigation |
|
**Rationale:** Prove the integration works before considering it complete.
|
||||||
|---------|------------|------------|
|
|
||||||
| n8n API | LOW | Configuration only, easy rollback |
|
|
||||||
| Socket proxy | MEDIUM | Test in isolation before workflow changes |
|
|
||||||
| Curl migration | MEDIUM | Use search/replace, comprehensive testing |
|
|
||||||
| Persistent keyboard | LOW | Additive change, no existing code modified |
|
|
||||||
| Inline container selection | LOW | Extends existing callback pattern |
|
|
||||||
| Unraid sync | HIGH | May require host access not available |
|
|
||||||
|
|
||||||
## Open Questions
|
**Success Criteria:**
|
||||||
|
- Container updates successfully
|
||||||
|
- Status file deleted (verify via `ls /var/lib/docker/unraid-update-status.json` returns "not found")
|
||||||
|
- Unraid recheck clears badge
|
||||||
|
- No errors in n8n execution log
|
||||||
|
|
||||||
1. **Unraid API:** Does Unraid expose an API endpoint to trigger "Check for Updates"?
|
## Architectural Patterns
|
||||||
2. **Status file format:** What is the exact JSON structure of `unraid-update-status.json`?
|
|
||||||
3. **Socket proxy port:** Should socket-proxy be exposed only on internal Docker network (recommended) or also externally?
|
|
||||||
4. **n8n API network:** Should n8n API be exposed on LAN or only via Tailscale/VPN?
|
|
||||||
|
|
||||||
## Recommendations
|
### Pattern 1: Post-Action Sync
|
||||||
|
|
||||||
1. **Start with n8n API enablement** - Low risk, high value for development velocity
|
**What:** Execute external system sync after primary operation completes successfully
|
||||||
2. **Deploy socket proxy as sidecar** - Same Docker network as n8n, not exposed externally
|
**When to use:** When primary operation (update container) should trigger related state updates (clear Unraid cache)
|
||||||
3. **Use HTTP Request nodes for keyboards** - Native Telegram node has limitations with dynamic keyboards
|
**Trade-offs:**
|
||||||
4. **Defer Unraid sync** - Needs host access investigation, may not be feasible via Docker alone
|
- PRO: Keeps systems consistent
|
||||||
5. **Test socket proxy thoroughly** - All container operations (start, stop, restart, update, logs) before proceeding
|
- PRO: User doesn't need manual sync step
|
||||||
|
- CON: Couples unrelated systems
|
||||||
|
- CON: Sync failure can confuse (update worked, but Unraid shows stale state)
|
||||||
|
|
||||||
## Sources Summary
|
**Example (this implementation):**
|
||||||
|
```
|
||||||
|
Update Container → Remove Old Image → Clear Unraid Status → Return Success
|
||||||
|
```
|
||||||
|
|
||||||
**HIGH confidence (official docs):**
|
**Error Handling Strategy:** Sync failure does NOT fail the primary operation. Use `continueRegularOutput` to log error but continue to success return.
|
||||||
- [n8n public REST API](https://docs.n8n.io/api/)
|
|
||||||
- [n8n API authentication](https://docs.n8n.io/api/authentication/)
|
|
||||||
- [LinuxServer socket-proxy](https://docs.linuxserver.io/images/docker-socket-proxy/)
|
|
||||||
- [Telegram Bot API](https://core.telegram.org/bots/api)
|
|
||||||
|
|
||||||
**MEDIUM confidence (verified patterns):**
|
### Pattern 2: Filesystem Access from Containerized Workflow
|
||||||
- [Tecnativa docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy)
|
|
||||||
- [n8n Telegram callback operations](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.telegram/callback-operations/)
|
|
||||||
|
|
||||||
**LOW confidence (community reports):**
|
**What:** Mount host filesystem into container to enable file operations from workflow
|
||||||
- [Unraid forums: docker update notification](https://forums.unraid.net/bug-reports/stable-releases/regression-incorrect-docker-update-notification-r2807/)
|
**When to use:** When workflow needs to manipulate host-specific files (e.g., clear cache, trigger recheck)
|
||||||
- [Unraid Docker management](https://docs.unraid.net/unraid-os/manual/docker-management/)
|
**Trade-offs:**
|
||||||
|
- PRO: Direct access, no additional services
|
||||||
|
- PRO: Works regardless of API availability
|
||||||
|
- CON: Breaks container isolation
|
||||||
|
- CON: Path changes between environments (host vs container)
|
||||||
|
|
||||||
|
**Example (this implementation):**
|
||||||
|
```yaml
|
||||||
|
# Host path -> Container path
|
||||||
|
-v /var/lib/docker:/host/var/lib/docker:rw
|
||||||
|
```
|
||||||
|
|
||||||
|
**Security Boundary:** Limit mount scope to minimum required directory. Here: `/var/lib/docker` (Docker-internal) not `/var/lib` (too broad).
|
||||||
|
|
||||||
|
### Pattern 3: Best-Effort External Sync
|
||||||
|
|
||||||
|
**What:** Attempt sync with external system but don't fail primary operation if sync fails
|
||||||
|
**When to use:** When sync is nice-to-have but not critical to primary operation success
|
||||||
|
**Trade-offs:**
|
||||||
|
- PRO: Primary operation reliability unaffected
|
||||||
|
- PRO: Degrades gracefully (manual sync still possible)
|
||||||
|
- CON: Silent failures can go unnoticed
|
||||||
|
- CON: Systems drift out of sync
|
||||||
|
|
||||||
|
**Example (this implementation):**
|
||||||
|
```javascript
|
||||||
|
// Execute Command node configuration
|
||||||
|
{
|
||||||
|
"onError": "continueRegularOutput", // Don't throw on sync failure
|
||||||
|
"command": "rm -f /host/var/lib/docker/unraid-update-status.json"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Monitoring:** Log sync failures but return success. User can manually sync if needed (Unraid "Check for Updates").
|
||||||
|
|
||||||
|
## Anti-Patterns
|
||||||
|
|
||||||
|
### Anti-Pattern 1: Parsing Unraid Status File
|
||||||
|
|
||||||
|
**What people might do:** Read `/var/lib/docker/unraid-update-status.json`, parse JSON, update only the changed container's status, write back
|
||||||
|
|
||||||
|
**Why it's wrong:**
|
||||||
|
- File format is internal to Unraid's DockerClient.php implementation
|
||||||
|
- Could change between Unraid versions without notice
|
||||||
|
- Parsing JSON in Execute Command (bash) is fragile
|
||||||
|
- Risk of corrupting file if concurrent Unraid writes happen
|
||||||
|
|
||||||
|
**Do this instead:** Delete entire file to force full recheck. Simpler, more robust, version-agnostic.
|
||||||
|
|
||||||
|
### Anti-Pattern 2: Using Docker exec for File Deletion
|
||||||
|
|
||||||
|
**What people might do:** `docker exec unraid-host rm -f /var/lib/docker/unraid-update-status.json`
|
||||||
|
|
||||||
|
**Why it's wrong:**
|
||||||
|
- Requires EXEC API access on socket proxy (major security risk)
|
||||||
|
- `unraid-host` container doesn't exist (Unraid itself is host, not container)
|
||||||
|
- More complex than direct filesystem access
|
||||||
|
|
||||||
|
**Do this instead:** Volume mount for direct filesystem access (more secure than exec API).
|
||||||
|
|
||||||
|
### Anti-Pattern 3: Blocking Update on Sync Failure
|
||||||
|
|
||||||
|
**What people might do:** Fail entire update if Unraid status file deletion fails
|
||||||
|
|
||||||
|
**Why it's wrong:**
|
||||||
|
- Update already completed (container recreated with new image)
|
||||||
|
- Failing at this point leaves system in inconsistent state (container updated, user told it failed)
|
||||||
|
- User can manually sync (click "Check for Updates")
|
||||||
|
|
||||||
|
**Do this instead:** Log sync failure, return success, document manual sync option.
|
||||||
|
|
||||||
|
## Scaling Considerations
|
||||||
|
|
||||||
|
| Scale | Approach | Notes |
|
||||||
|
|-------|----------|-------|
|
||||||
|
| **1-10 containers** | Current approach works | File deletion is <1ms operation |
|
||||||
|
| **10-50 containers** | Current approach works | Unraid recheck time increases linearly but still <10s |
|
||||||
|
| **50+ containers** | Current approach works | Deleting status file forces full recheck (may take 30-60s) but acceptable as one-time cost |
|
||||||
|
|
||||||
|
**Optimization Not Needed:**
|
||||||
|
- File deletion is instant regardless of container count
|
||||||
|
- Unraid recheck is user-initiated (not blocking bot operation)
|
||||||
|
- No performance bottleneck identified
|
||||||
|
|
||||||
|
**Alternative for Many Containers (future):**
|
||||||
|
If Unraid provides GraphQL API to selectively clear single container status (not found in research), could optimize to:
|
||||||
|
- Clear only updated container's status
|
||||||
|
- Avoid forcing full recheck
|
||||||
|
- Requires Unraid 7.2+ and API discovery
|
||||||
|
|
||||||
|
## Integration Testing Strategy
|
||||||
|
|
||||||
|
### Test Cases
|
||||||
|
|
||||||
|
| Test | Expected Behavior | Verification |
|
||||||
|
|------|-------------------|--------------|
|
||||||
|
| **Update single container** | Container updates, status file deleted | Check file gone: `ls /var/lib/docker/unraid-update-status.json` |
|
||||||
|
| **Update container, sync fails** | Update succeeds, error logged | Check execution log for error, container still updated |
|
||||||
|
| **Batch update multiple containers** | Each update clears status file | File deleted after first update, remains deleted |
|
||||||
|
| **Update with no status file** | Update succeeds, no error | `rm -f` tolerates missing file |
|
||||||
|
| **Mount not accessible** | Update succeeds, sync error logged | Execution log shows file not found error |
|
||||||
|
|
||||||
|
### Rollback Plan
|
||||||
|
|
||||||
|
If integration causes issues:
|
||||||
|
|
||||||
|
1. **Quick rollback (workflow only):**
|
||||||
|
- Revert n8n-update.json to previous version via n8n API
|
||||||
|
- Status sync stops happening
|
||||||
|
- Core update functionality unaffected
|
||||||
|
|
||||||
|
2. **Full rollback (infrastructure):**
|
||||||
|
- Remove volume mount from n8n container config
|
||||||
|
- Recreate n8n container
|
||||||
|
- Revert workflow
|
||||||
|
- Manual Unraid sync only
|
||||||
|
|
||||||
|
**Rollback triggers:**
|
||||||
|
- Sync consistently fails (execution log errors)
|
||||||
|
- Permissions issues prevent file deletion
|
||||||
|
- Unraid behavior changes unexpectedly
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
|
||||||
|
### Primary (HIGH confidence)
|
||||||
|
- [Unraid Docker Manager Source Code](https://github.com/limetech/dynamix/blob/master/plugins/dynamix.docker.manager/include/DockerClient.php) - Update status file location and format
|
||||||
|
- [Unraid Managing Containers](https://docs.unraid.net/unraid-os/using-unraid-to/run-docker-containers/managing-and-customizing-containers/) - Volume mount patterns
|
||||||
|
|
||||||
|
### Secondary (MEDIUM confidence)
|
||||||
|
- [Unraid Forum: Incorrect Update Notification](https://forums.unraid.net/bug-reports/stable-releases/regression-incorrect-docker-update-notification-r2807/) - Status file deletion workaround
|
||||||
|
- [Watchtower + Unraid Discussion](https://github.com/containrrr/watchtower/discussions/1389) - External update tracking issues
|
||||||
|
- [Docker Volume Mounting](https://docs.unraid.net/unraid-os/using-unraid-to/run-docker-containers/managing-and-customizing-containers/) - Best practices
|
||||||
|
|
||||||
|
### Tertiary (LOW confidence)
|
||||||
|
- n8n Execute Command documentation (operational patterns)
|
||||||
|
- Community reports of Unraid update badge behavior (anecdotal)
|
||||||
|
|
||||||
|
---
|
||||||
|
*Architecture research for: Unraid Update Status Sync Integration*
|
||||||
|
*Researched: 2026-02-08*
|
||||||
|
|||||||
+214
-318
@@ -1,381 +1,277 @@
|
|||||||
# Features Research: v1.1
|
# Feature Research: Unraid Update Status Sync (v1.3)
|
||||||
|
|
||||||
**Domain:** Telegram Bot for Docker Container Management
|
**Domain:** Docker container management integration with Unraid server
|
||||||
**Researched:** 2026-02-02
|
**Researched:** 2026-02-08
|
||||||
**Confidence:** MEDIUM-HIGH (WebSearch verified with official docs where available)
|
**Confidence:** MEDIUM
|
||||||
|
|
||||||
## Telegram Inline Keyboards
|
## Context
|
||||||
|
|
||||||
### Table Stakes
|
This research focuses on v1.3 milestone: syncing update status back to Unraid after bot-initiated container updates. The bot already updates containers successfully, but Unraid's UI continues showing "update available" badges and sending false-positive notifications afterward.
|
||||||
|
|
||||||
| Feature | Why Expected | Complexity | Dependencies |
|
**Existing capabilities (v1.0-v1.2):**
|
||||||
|---------|--------------|------------|--------------|
|
- Container update via bot (pull image, recreate container)
|
||||||
| Callback button handling | Core inline keyboard functionality - buttons must trigger actions | Low | Telegram Trigger already handles callback_query |
|
- "Update All :latest" batch operation
|
||||||
| answerCallbackQuery response | Required by Telegram - clients show loading animation until answered (up to 1 minute) | Low | None |
|
- Container status display with inline keyboards
|
||||||
| Edit message after button press | Standard pattern - update existing message rather than send new one to reduce clutter | Low | None |
|
- Confirmation dialogs for dangerous actions
|
||||||
| Container action buttons | Users expect tap-to-action for start/stop/restart without typing | Medium | Existing container matching logic |
|
- Progress feedback during operations
|
||||||
| Status view with action buttons | Show container list with inline buttons for each container | Medium | Existing status command |
|
|
||||||
|
|
||||||
### Differentiators
|
**New scope:** Two directions for Unraid integration:
|
||||||
|
1. **Sync-back:** Clear Unraid's "update available" badge after bot updates container
|
||||||
| Feature | Value Proposition | Complexity | Dependencies |
|
2. **Read-forward:** Use Unraid's update detection data as source of truth for which containers need updates
|
||||||
|---------|-------------------|------------|--------------|
|
|
||||||
| Confirmation dialogs for dangerous actions | "Are you sure?" before stop/restart/update prevents accidental actions | Low | None - edit message with Yes/No buttons |
|
|
||||||
| Contextual button removal | Remove buttons after action completes (prevents double-tap issues) | Low | None |
|
|
||||||
| Dynamic container list keyboards | Generate buttons based on actual running containers | Medium | Container listing logic |
|
|
||||||
| Progress indicators via message edit | Update message with "Updating..." then "Complete" states | Low | None |
|
|
||||||
| Pagination for many containers | "Next page" button when >8-10 containers | Medium | None |
|
|
||||||
|
|
||||||
### Anti-features
|
|
||||||
|
|
||||||
| Anti-Feature | Why Avoid | What to Do Instead |
|
|
||||||
|--------------|-----------|-------------------|
|
|
||||||
| Reply keyboards for actions | Takes over user keyboard space, sends visible messages to chat | Use inline keyboards attached to bot messages |
|
|
||||||
| More than 5 buttons per row | Wraps poorly on mobile/desktop, breaks muscle memory | Max 3-4 buttons per row for container actions |
|
|
||||||
| Complex callback_data structures | 64-byte limit, easy to exceed with JSON | Use short action codes: `start_plex`, `stop_sonarr` |
|
|
||||||
| Buttons without feedback | Users think tap didn't work, tap again | Always answerCallbackQuery, even for errors |
|
|
||||||
| Auto-refreshing keyboards | High API traffic, rate limiting risk | Refresh on explicit user action only |
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
**Critical constraint:** callback_data is limited to 64 bytes. Use short codes like `action:containername` rather than JSON structures.
|
|
||||||
|
|
||||||
**n8n native node limitation:** The Telegram node doesn't support dynamic inline keyboards well. Workaround is HTTP Request node calling Telegram Bot API directly for `sendMessage` with `reply_markup` parameter.
|
|
||||||
|
|
||||||
**Pattern for confirmations:**
|
|
||||||
1. User taps "Stop plex"
|
|
||||||
2. Edit message: "Stop plex container?" with [Yes] [Cancel] buttons
|
|
||||||
3. User taps Yes -> perform action, edit message with result, remove buttons
|
|
||||||
4. User taps Cancel -> edit message back to original state
|
|
||||||
|
|
||||||
**Sources:**
|
|
||||||
- [Telegram Bot Features](https://core.telegram.org/bots/features) (HIGH confidence)
|
|
||||||
- [Telegram Bot API Buttons](https://core.telegram.org/api/bots/buttons) (HIGH confidence)
|
|
||||||
- [n8n Telegram Callback Operations](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.telegram/callback-operations/) (HIGH confidence)
|
|
||||||
- [n8n Community: Dynamic Inline Keyboard](https://community.n8n.io/t/dynamic-inline-keyboard-for-telegram-bot/86568) (MEDIUM confidence)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Batch Operations
|
## Feature Landscape
|
||||||
|
|
||||||
### Table Stakes
|
### Table Stakes (Users Expect These)
|
||||||
|
|
||||||
| Feature | Why Expected | Complexity | Dependencies |
|
Features users assume exist when managing containers outside Unraid's UI.
|
||||||
|---------|--------------|------------|--------------|
|
|
||||||
| Update multiple specified containers | Core batch use case - `update plex sonarr radarr` | Medium | Existing update logic, loop handling |
|
|
||||||
| Sequential execution | Process one at a time to avoid resource contention | Low | None |
|
|
||||||
| Per-container status feedback | "Updated plex... Updated sonarr..." progress | Low | Existing message sending |
|
|
||||||
| Error handling per container | One failure shouldn't abort the batch | Low | Try-catch per iteration |
|
|
||||||
| Final summary message | "3 updated, 1 failed: jellyfin" | Low | Accumulator pattern |
|
|
||||||
|
|
||||||
### Differentiators
|
| Feature | Why Expected | Complexity | Notes |
|
||||||
|
|---------|--------------|------------|-------|
|
||||||
|
| Clear "update available" badge after bot update | Users expect Unraid UI to reflect reality after external updates | MEDIUM | Requires writing to `/var/lib/docker/unraid-update-status.json` - known workaround for Watchtower/Portainer users |
|
||||||
|
| Prevent duplicate update notifications | After bot updates a container, Unraid shouldn't send false-positive Telegram notifications | MEDIUM | Same mechanism as clearing badge - update status file tracks whether updates are pending |
|
||||||
|
| Avoid breaking Unraid's update tracking | External tools shouldn't corrupt Unraid's internal state | LOW | Docker API operations are safe - Unraid tracks via separate metadata files |
|
||||||
|
| No manual "Apply Update" clicks | Point of remote management is to eliminate manual steps | HIGH | Core pain point - users want "update from bot = done" not "update from bot = still need to click in Unraid" |
|
||||||
|
|
||||||
| Feature | Value Proposition | Complexity | Dependencies |
|
### Differentiators (Competitive Advantage)
|
||||||
|---------|-------------------|------------|--------------|
|
|
||||||
| "Update all" command | Single command to update everything (with confirmation) | Medium | Container listing |
|
|
||||||
| "Update all except X" | Exclude specific containers from batch | Medium | Exclusion pattern |
|
|
||||||
| Parallel status checks | Check which containers have updates available first | Medium | None |
|
|
||||||
| Batch operation confirmation | Show what will happen before doing it | Low | Keyboard buttons |
|
|
||||||
| Cancel mid-batch | Stop processing remaining containers | High | State management |
|
|
||||||
|
|
||||||
### Anti-features
|
Features that set the bot apart from other Docker management tools.
|
||||||
|
|
||||||
| Anti-Feature | Why Avoid | What to Do Instead |
|
| Feature | Value Proposition | Complexity | Notes |
|
||||||
|--------------|-----------|-------------------|
|
|---------|-------------------|------------|-------|
|
||||||
| Parallel container updates | Resource contention, disk I/O saturation, network bandwidth | Sequential with progress feedback |
|
| Automatic sync after every update | Bot updates container AND clears Unraid badge in single operation - zero user intervention | MEDIUM | Requires detecting update success and writing status file atomically |
|
||||||
| Silent batch operations | User thinks bot is frozen during long batch | Send progress message per container |
|
| Use Unraid's update detection data | If Unraid already knows which containers need updates, bot could use that source of truth instead of its own Docker image comparison | HIGH | Requires parsing Unraid's update status JSON and integrating with existing container selection/matching logic |
|
||||||
| Update without checking first | Wastes time on already-updated containers | Check for updates, report "3 containers have updates" |
|
| Bidirectional status awareness | Bot shows which containers Unraid thinks need updates, not just Docker image digest comparison | MEDIUM-HIGH | Depends on reading update status file - enhances accuracy for edge cases (registry issues, multi-arch images) |
|
||||||
| Auto-update on schedule | Out of scope - user might be using system when update causes downtime | User-initiated only, this is reactive tool |
|
| Manual sync command | Users can manually trigger "sync status to Unraid" if they updated containers through another tool | LOW | Simple command that iterates running containers and updates status file |
|
||||||
|
|
||||||
### Implementation Notes
|
### Anti-Features (Commonly Requested, Often Problematic)
|
||||||
|
|
||||||
**Existing update flow:** Current implementation pulls image, recreates container, cleans up old image. Batch needs to wrap this in a loop.
|
Features that seem good but create problems.
|
||||||
|
|
||||||
|
| Feature | Why Requested | Why Problematic | Alternative |
|
||||||
|
|---------|---------------|-----------------|-------------|
|
||||||
|
| Full Unraid API integration (authentication, template parsing) | "Properly" integrate with Unraid's web interface instead of file manipulation | Adds authentication complexity, XML parsing, API version compatibility, web session management - all for a cosmetic badge | Direct file writes are the established community workaround - simpler and more reliable |
|
||||||
|
| Automatic template XML regeneration | Update container templates so Unraid thinks it initiated the update | Template XML is generated by Community Applications and Docker Manager - modifying it risks breaking container configuration | Clearing update status file is sufficient - templates are source of truth for config, not update state |
|
||||||
|
| Sync status for ALL containers on every operation | Keep Unraid 100% in sync with Docker state at all times | Performance impact (Docker API queries for all containers on every update), unnecessary for user's pain point | Sync only the container(s) just updated by the bot - targeted and efficient |
|
||||||
|
| Persistent monitoring daemon | Background process that watches Docker events and updates Unraid status in real-time | Requires separate container/service, adds operational complexity, duplicates n8n's event model | On-demand sync triggered by bot operations - aligns with n8n's workflow execution model |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Feature Dependencies
|
||||||
|
|
||||||
**Progress pattern:**
|
|
||||||
```
|
```
|
||||||
User: update all
|
Clear Update Badge (sync-back)
|
||||||
Bot: Found 5 containers with updates. Update now? [Yes] [Cancel]
|
└──requires──> Update operation success detection (existing)
|
||||||
User: Yes
|
└──requires──> File write to /var/lib/docker/unraid-update-status.json
|
||||||
Bot: Updating plex (1/5)...
|
|
||||||
Bot: (edit) Updated plex. Updating sonarr (2/5)...
|
Read Unraid Update Status (read-forward)
|
||||||
...
|
└──requires──> Parse update status JSON file
|
||||||
Bot: (edit) Batch complete: 5 updated, 0 failed.
|
└──requires──> Container ID to name mapping (existing)
|
||||||
|
└──enhances──> Container selection UI (show Unraid's view)
|
||||||
|
|
||||||
|
Manual Sync Command
|
||||||
|
└──requires──> Clear Update Badge mechanism
|
||||||
|
└──requires──> Container list enumeration (existing)
|
||||||
|
|
||||||
|
Bidirectional Status Awareness
|
||||||
|
└──requires──> Read Unraid Update Status
|
||||||
|
└──requires──> Clear Update Badge
|
||||||
|
└──conflicts──> Current Docker-only update detection (source of truth ambiguity)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Watchtower-style options (NOT recommended for this bot):**
|
### Dependency Notes
|
||||||
- Watchtower does automatic updates on schedule
|
|
||||||
- This bot is intentionally reactive (user asks, bot does)
|
|
||||||
- Automation can cause downtime at bad times
|
|
||||||
|
|
||||||
**Sources:**
|
- **Clear Update Badge requires Update success detection:** Already have this - n8n-update.json returns `success: true, updated: true` with digest comparison
|
||||||
- [Watchtower Documentation](https://containrrr.dev/watchtower/) (HIGH confidence)
|
- **Read Unraid Status enhances Container selection:** Could show "(Unraid: update available)" badge in status keyboard - helps users see what Unraid sees
|
||||||
- [Docker Multi-Container Apps](https://docs.docker.com/get-started/docker-concepts/running-containers/multi-container-applications/) (HIGH confidence)
|
- **Bidirectional Status conflicts with Docker-only detection:** Need to decide: is Unraid's update status file the source of truth, or is Docker image digest comparison? Mixing both creates confusion about "which containers need updates"
|
||||||
- [How to Update Docker Containers](https://phoenixnap.com/kb/update-docker-image-container) (MEDIUM confidence)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Development API Workflow
|
## MVP Definition
|
||||||
|
|
||||||
### Table Stakes
|
### Launch With (v1.3)
|
||||||
|
|
||||||
| Feature | Why Expected | Complexity | Dependencies |
|
Minimum viable - eliminates the core pain point.
|
||||||
|---------|--------------|------------|--------------|
|
|
||||||
| API key authentication | Standard n8n API auth method | Low | n8n configuration |
|
|
||||||
| Get workflow by ID | Read current workflow JSON | Low | n8n REST API |
|
|
||||||
| Update workflow | Push modified workflow back | Low | n8n REST API |
|
|
||||||
| Activate/deactivate workflow | Turn workflow on/off programmatically | Low | n8n REST API |
|
|
||||||
| Get execution list | See recent runs | Low | n8n REST API |
|
|
||||||
| Get execution details/logs | Debug failed executions | Low | n8n REST API |
|
|
||||||
|
|
||||||
### Differentiators
|
- [ ] Clear update badge after bot-initiated updates - Write to `/var/lib/docker/unraid-update-status.json` after successful update operation
|
||||||
|
- [ ] Prevent false-positive notifications - Ensure status file write happens before user sees "update complete" message
|
||||||
|
- [ ] Integration with existing n8n-update.json sub-workflow - Add status sync as final step in update flow (text, inline, batch modes)
|
||||||
|
|
||||||
| Feature | Value Proposition | Complexity | Dependencies |
|
**Rationale:** This solves the stated pain: "after updating containers through the bot, Unraid still shows update available badges and sends false-positive Telegram notifications."
|
||||||
|---------|-------------------|------------|--------------|
|
|
||||||
| Execute workflow on demand | Trigger test run via API | Medium | n8n REST API with test data |
|
|
||||||
| Version comparison | Diff local vs deployed workflow | High | JSON diff tooling |
|
|
||||||
| Backup before update | Save current version before pushing changes | Low | File system or git |
|
|
||||||
| Rollback capability | Restore previous version on failure | Medium | Version history |
|
|
||||||
| MCP integration | Claude Code can manage workflows via MCP | High | MCP server setup |
|
|
||||||
|
|
||||||
### Anti-features
|
### Add After Validation (v1.4+)
|
||||||
|
|
||||||
| Anti-Feature | Why Avoid | What to Do Instead |
|
Features to add once core sync-back is working.
|
||||||
|--------------|-----------|-------------------|
|
|
||||||
| Direct n8n database access | Bypasses API, can corrupt state | Use REST API only |
|
|
||||||
| Credential exposure via API | API returns credential IDs, not values | Never try to extract credential values |
|
|
||||||
| Auto-deploy on git push | Adds CI/CD complexity, not needed for single-user | Manual deploy via API call |
|
|
||||||
| Real-time workflow editing | n8n UI is better for this | API for read/bulk operations only |
|
|
||||||
|
|
||||||
### Implementation Notes
|
- [ ] Manual sync command (`/sync` or `/sync <container>`) - Trigger when user updates via other tools (Portainer, CLI, Watchtower)
|
||||||
|
- [ ] Read Unraid update status for better detection - Parse `/var/lib/docker/unraid-update-status.json` to see which containers Unraid thinks need updates
|
||||||
|
- [ ] Show Unraid's view in status keyboard - Display "(Unraid: update ready)" badge alongside container state
|
||||||
|
|
||||||
**n8n REST API key endpoints:**
|
**Trigger:** User requests ability to see "what Unraid sees" or needs to sync status after non-bot updates.
|
||||||
|
|
||||||
| Operation | Method | Endpoint |
|
### Future Consideration (v2+)
|
||||||
|-----------|--------|----------|
|
|
||||||
| List workflows | GET | `/api/v1/workflows` |
|
|
||||||
| Get workflow | GET | `/api/v1/workflows/{id}` |
|
|
||||||
| Update workflow | PUT | `/api/v1/workflows/{id}` |
|
|
||||||
| Activate | POST | `/api/v1/workflows/{id}/activate` |
|
|
||||||
| Deactivate | POST | `/api/v1/workflows/{id}/deactivate` |
|
|
||||||
| List executions | GET | `/api/v1/executions` |
|
|
||||||
| Get execution | GET | `/api/v1/executions/{id}` |
|
|
||||||
| Execute workflow | POST | `/rest/workflows/{id}/run` |
|
|
||||||
|
|
||||||
**Authentication:** Header `X-N8N-API-KEY: your_api_key`
|
Features to defer until core functionality is proven.
|
||||||
|
|
||||||
**Workflow structure:** n8n workflows are JSON documents (~3,200 lines for this bot). Key sections:
|
- [ ] Bidirectional status awareness - Use Unraid's update detection as source of truth instead of Docker digest comparison
|
||||||
- `nodes[]` - Array of workflow nodes
|
- [ ] Sync on container list view - Automatically update status file when user views container list (proactive sync)
|
||||||
- `connections` - How nodes connect
|
- [ ] Batch status sync - `/sync all` command to reconcile all containers
|
||||||
- `settings` - Workflow-level settings
|
|
||||||
|
|
||||||
**MCP option:** There's an unofficial n8n MCP server (makafeli/n8n-workflow-builder) that could enable Claude Code to manage workflows directly, but this adds complexity. Standard REST API is simpler for v1.1.
|
**Why defer:** Unraid's update detection has known bugs (doesn't detect external updates, false positives persist). Using it as source of truth may import those bugs. Better to prove sync-back works first, then evaluate whether read-forward adds value.
|
||||||
|
|
||||||
**Sources:**
|
|
||||||
- [n8n API Documentation](https://docs.n8n.io/api/) (HIGH confidence)
|
|
||||||
- [n8n API Reference](https://docs.n8n.io/api/api-reference/) (HIGH confidence)
|
|
||||||
- [n8n Workflow Manager API Template](https://n8n.io/workflows/4166-n8n-workflow-manager-api/) (MEDIUM confidence)
|
|
||||||
- [Python n8n API Guide](https://martinuke0.github.io/posts/2025-12-10-a-detailed-guide-to-using-the-n8n-api-with-python/) (MEDIUM confidence)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Update Notification Sync
|
## Feature Prioritization Matrix
|
||||||
|
|
||||||
### Table Stakes
|
| Feature | User Value | Implementation Cost | Priority |
|
||||||
|
|---------|------------|---------------------|----------|
|
||||||
|
| Clear update badge after bot update | HIGH | MEDIUM | P1 |
|
||||||
|
| Prevent false-positive notifications | HIGH | LOW | P1 |
|
||||||
|
| Manual sync command | MEDIUM | LOW | P2 |
|
||||||
|
| Read Unraid update status | MEDIUM | MEDIUM | P2 |
|
||||||
|
| Show Unraid's view in UI | LOW | MEDIUM | P3 |
|
||||||
|
| Bidirectional status (Unraid as source of truth) | MEDIUM | HIGH | P3 |
|
||||||
|
|
||||||
| Feature | Why Expected | Complexity | Dependencies |
|
**Priority key:**
|
||||||
|---------|--------------|------------|--------------|
|
- P1: Must have for v1.3 launch - solves core pain point
|
||||||
| Update clears bot's "update available" state | Bot should know container is now current | Low | Already works - re-check after update |
|
- P2: Should have for v1.4 - adds convenience, not critical
|
||||||
| Accurate update status reporting | Status command shows which have updates | Medium | Image digest comparison |
|
- P3: Nice to have for v2+ - explore after validating core
|
||||||
|
|
||||||
### Differentiators
|
|
||||||
|
|
||||||
| Feature | Value Proposition | Complexity | Dependencies |
|
|
||||||
|---------|-------------------|------------|--------------|
|
|
||||||
| Sync with Unraid UI | Clear "update available" badge in Unraid web UI | High | Unraid API or file manipulation |
|
|
||||||
| Pre-update check | Show what version you're on, what version available | Medium | Image tag inspection |
|
|
||||||
| Update notification to user | "3 containers have updates available" proactive message | Medium | Scheduled check, notification logic |
|
|
||||||
|
|
||||||
### Anti-features
|
|
||||||
|
|
||||||
| Anti-Feature | Why Avoid | What to Do Instead |
|
|
||||||
|--------------|-----------|-------------------|
|
|
||||||
| Taking over Unraid notifications | Explicitly out of scope per PROJECT.md | Keep Unraid notifications, bot is for control |
|
|
||||||
| Proactive monitoring | Bot is reactive per PROJECT.md | User checks status manually |
|
|
||||||
| Blocking Unraid auto-updates | User may want both systems | Coexist with Unraid's own update mechanism |
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
**The core problem:** When you update a container via the bot (or Watchtower), Unraid's web UI may still show "update available" because it has its own tracking.
|
|
||||||
|
|
||||||
**Unraid update status file:** `/var/lib/docker/unraid-update-status.json`
|
|
||||||
- This file tracks which containers have updates
|
|
||||||
- Deleting it forces Unraid to recheck
|
|
||||||
- Can also trigger recheck via: Settings > Docker > Check for Updates
|
|
||||||
|
|
||||||
**Unraid API (v7.2+):**
|
|
||||||
- GraphQL API for Docker containers
|
|
||||||
- Can query container status
|
|
||||||
- Mutations for notifications exist
|
|
||||||
- API key auth: `x-api-key` header
|
|
||||||
|
|
||||||
**Practical approach for v1.1:**
|
|
||||||
1. **Minimum:** Document that Unraid UI may lag behind - user can click "Check for Updates" in Unraid
|
|
||||||
2. **Better:** After bot update, delete `/var/lib/docker/unraid-update-status.json` to force Unraid recheck
|
|
||||||
3. **Best (requires Unraid 7.2+):** Use Unraid GraphQL API to clear notification state
|
|
||||||
|
|
||||||
**Known issue:** Users report Unraid shows "update ready" even after container is updated. This is a known Unraid bug where it only checks for new updates, not whether containers are now current.
|
|
||||||
|
|
||||||
**Sources:**
|
|
||||||
- [Unraid API Documentation](https://docs.unraid.net/API/how-to-use-the-api/) (HIGH confidence)
|
|
||||||
- [Unraid Docker Integration DeepWiki](https://deepwiki.com/unraid/api/2.4.1-docker-integration) (MEDIUM confidence)
|
|
||||||
- [Watchtower + Unraid Discussion](https://github.com/containrrr/watchtower/discussions/1389) (MEDIUM confidence)
|
|
||||||
- [Unraid Forum: Update Badge Issues](https://forums.unraid.net/topic/157820-docker-shows-update-ready-after-updating/) (MEDIUM confidence)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Docker Socket Security
|
## Implementation Notes
|
||||||
|
|
||||||
### Table Stakes
|
### File Format: /var/lib/docker/unraid-update-status.json
|
||||||
|
|
||||||
| Feature | Why Expected | Complexity | Dependencies |
|
Based on community forum discussions, this file tracks update status per container. When Unraid checks for updates, it compares registry manifests and writes results here. To clear the badge, remove the container's entry from this JSON.
|
||||||
|---------|--------------|------------|--------------|
|
|
||||||
| Remove direct socket from internet-exposed n8n | Security requirement per PROJECT.md scope | Medium | Socket proxy setup |
|
|
||||||
| Maintain all existing functionality | Bot should work identically after security change | Medium | API compatibility |
|
|
||||||
| Container start/stop/restart/update | Core actions must still work | Low | Proxy allows these APIs |
|
|
||||||
| Container list/inspect | Status command must still work | Low | Proxy allows read APIs |
|
|
||||||
| Image pull | Update command needs this | Low | Proxy configuration |
|
|
||||||
|
|
||||||
### Differentiators
|
**Example structure (inferred from community discussions):**
|
||||||
|
```json
|
||||||
| Feature | Value Proposition | Complexity | Dependencies |
|
{
|
||||||
|---------|-------------------|------------|--------------|
|
"containerId1": { "status": "update_available", "checked": "timestamp" },
|
||||||
| Granular API restrictions | Only allow APIs the bot actually uses | Low | Socket proxy env vars |
|
"containerId2": { "status": "up_to_date", "checked": "timestamp" }
|
||||||
| Block dangerous APIs | Prevent exec, create, system commands | Low | Socket proxy defaults |
|
}
|
||||||
| Audit logging | Log all Docker API calls through proxy | Medium | Proxy logging config |
|
|
||||||
|
|
||||||
### Anti-features
|
|
||||||
|
|
||||||
| Anti-Feature | Why Avoid | What to Do Instead |
|
|
||||||
|--------------|-----------|-------------------|
|
|
||||||
| Read-only socket mount (:ro) | Doesn't actually protect - socket as pipe stays writable | Use proper socket proxy |
|
|
||||||
| Direct socket access from internet-facing container | Full root access if n8n is compromised | Socket proxy isolates access |
|
|
||||||
| Allowing exec API | Enables arbitrary command execution in containers | Block exec in proxy |
|
|
||||||
| Allowing create/network APIs | Bot doesn't need to create containers | Block creation APIs |
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
**Recommended: Tecnativa/docker-socket-proxy or LinuxServer.io/docker-socket-proxy**
|
|
||||||
|
|
||||||
Both provide HAProxy-based filtering of Docker API requests.
|
|
||||||
|
|
||||||
**Minimal proxy configuration for this bot:**
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# docker-compose.yml
|
|
||||||
services:
|
|
||||||
socket-proxy:
|
|
||||||
image: tecnativa/docker-socket-proxy
|
|
||||||
environment:
|
|
||||||
- CONTAINERS=1 # List/inspect containers
|
|
||||||
- IMAGES=1 # Pull images
|
|
||||||
- POST=1 # Allow write operations
|
|
||||||
- SERVICES=0 # Swarm services (not needed)
|
|
||||||
- TASKS=0 # Swarm tasks (not needed)
|
|
||||||
- NETWORKS=0 # Network management (not needed)
|
|
||||||
- VOLUMES=0 # Volume management (not needed)
|
|
||||||
- EXEC=0 # CRITICAL: Block exec
|
|
||||||
- BUILD=0 # CRITICAL: Block build
|
|
||||||
- COMMIT=0 # CRITICAL: Block commit
|
|
||||||
- SECRETS=0 # CRITICAL: Block secrets
|
|
||||||
- CONFIGS=0 # CRITICAL: Block configs
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
||||||
networks:
|
|
||||||
- docker-proxy
|
|
||||||
|
|
||||||
n8n:
|
|
||||||
# ... existing config ...
|
|
||||||
environment:
|
|
||||||
- DOCKER_HOST=tcp://socket-proxy:2375
|
|
||||||
networks:
|
|
||||||
- docker-proxy
|
|
||||||
# Plus existing networks
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Key security benefits:**
|
**Operation:** After bot updates a container successfully:
|
||||||
1. n8n no longer has direct socket access
|
1. Read existing JSON file
|
||||||
2. Only whitelisted API categories are available
|
2. Remove entry for updated container (or set status to "up_to_date")
|
||||||
3. EXEC=0 prevents arbitrary command execution
|
3. Write JSON back atomically
|
||||||
4. Proxy is on internal network only, not internet-exposed
|
|
||||||
|
|
||||||
**Migration path:**
|
**Confidence: LOW** - exact format not documented officially, needs verification by reading actual file.
|
||||||
1. Deploy socket-proxy container
|
|
||||||
2. Update n8n to use `DOCKER_HOST=tcp://socket-proxy:2375`
|
|
||||||
3. Remove direct socket mount from n8n
|
|
||||||
4. Test all bot commands still work
|
|
||||||
|
|
||||||
**Sources:**
|
### Integration Points
|
||||||
- [Tecnativa docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) (HIGH confidence)
|
|
||||||
- [LinuxServer.io docker-socket-proxy](https://docs.linuxserver.io/images/docker-socket-proxy/) (HIGH confidence)
|
**Existing bot architecture:**
|
||||||
- [Docker Socket Security Guide](https://www.paulsblog.dev/how-to-secure-your-docker-environment-by-using-a-docker-socket-proxy/) (MEDIUM confidence)
|
- n8n-update.json sub-workflow already returns `success: true, updated: true, oldDigest, newDigest` on successful update
|
||||||
|
- Three callers: Execute Text Update, Execute Callback Update, Execute Batch Update
|
||||||
|
- All three modes need status sync (text, inline keyboard, batch operations)
|
||||||
|
|
||||||
|
**New node requirements:**
|
||||||
|
- Read Update Status File (HTTP Request or Execute Command node - read JSON file)
|
||||||
|
- Parse Update Status (Code node - JSON manipulation)
|
||||||
|
- Write Update Status File (HTTP Request or Execute Command node - write JSON file)
|
||||||
|
- Update n8n-update.json to call status sync before returning success
|
||||||
|
|
||||||
|
**File access:** n8n runs in Docker container, needs volume mount or HTTP access to Unraid filesystem. Docker socket proxy already provides access - may need to add file system access or use Unraid API.
|
||||||
|
|
||||||
|
### Update Status Sync Mechanism
|
||||||
|
|
||||||
|
**Current state:** Unraid checks for updates by comparing local image digest with registry manifest digest. Results stored in `/var/lib/docker/unraid-update-status.json`. When container is updated externally (bot, Watchtower, CLI), Unraid doesn't re-check - status file shows stale "update available" until manually cleared.
|
||||||
|
|
||||||
|
**Community workaround:** Delete `/var/lib/docker/unraid-update-status.json` to force complete reset, OR edit JSON to remove specific container entry.
|
||||||
|
|
||||||
|
**Bot approach:** After successful update (pull + recreate), programmatically edit JSON file to mark container as up-to-date. This is what Unraid would do if it had performed the update itself.
|
||||||
|
|
||||||
|
**Alternatives considered:**
|
||||||
|
1. Call Unraid's "Check for Updates" API endpoint - requires authentication, web session, not documented
|
||||||
|
2. Trigger Unraid's update check via CLI - no known CLI command for this
|
||||||
|
3. Reboot server - clears status (per forum posts) but obviously unacceptable
|
||||||
|
4. Edit XML templates - risky, templates are config source of truth
|
||||||
|
|
||||||
|
**Selected approach:** Direct JSON file edit (community-proven workaround, lowest risk).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Feature Summary Table
|
## Competitor Analysis
|
||||||
|
|
||||||
| Feature | Complexity | Dependencies | Priority | Notes |
|
### Watchtower
|
||||||
|---------|------------|--------------|----------|-------|
|
- Automatically updates containers on schedule
|
||||||
| **Inline Keyboards** | | | | |
|
- Does NOT sync status back to Unraid
|
||||||
| Basic callback handling | Low | Existing trigger | Must Have | Foundation for all buttons |
|
- Community complaint: "Watchtower running on unraid but containers still say update after it runs"
|
||||||
| Container action buttons | Medium | Container matching | Must Have | Core UX improvement |
|
- Workaround: Manual deletion of update status file
|
||||||
| Confirmation dialogs | Low | None | Should Have | Prevents accidents |
|
|
||||||
| Dynamic keyboard generation | Medium | HTTP Request node | Must Have | n8n native node limitation workaround |
|
|
||||||
| **Batch Operations** | | | | |
|
|
||||||
| Update multiple containers | Medium | Existing update | Must Have | Sequential with progress |
|
|
||||||
| "Update all" command | Medium | Container listing | Should Have | With confirmation |
|
|
||||||
| Per-container feedback | Low | None | Must Have | Progress visibility |
|
|
||||||
| **n8n API** | | | | |
|
|
||||||
| API key setup | Low | n8n config | Must Have | Enable programmatic access |
|
|
||||||
| Read workflow | Low | REST API | Must Have | Development workflow |
|
|
||||||
| Update workflow | Low | REST API | Must Have | Development workflow |
|
|
||||||
| Activate/deactivate | Low | REST API | Should Have | Testing workflow |
|
|
||||||
| **Update Sync** | | | | |
|
|
||||||
| Delete status file | Low | SSH/exec access | Should Have | Simple Unraid sync |
|
|
||||||
| Unraid GraphQL API | High | Unraid 7.2+, API key | Nice to Have | Requires version check |
|
|
||||||
| **Security** | | | | |
|
|
||||||
| Socket proxy deployment | Medium | New container | Must Have | Security requirement |
|
|
||||||
| API restriction config | Low | Proxy env vars | Must Have | Minimize attack surface |
|
|
||||||
| Migration testing | Low | All commands | Must Have | Verify no regression |
|
|
||||||
|
|
||||||
## MVP Recommendation for v1.1
|
### Portainer
|
||||||
|
- UI-based container management
|
||||||
|
- Shows its own "update available" indicator (independent of Unraid)
|
||||||
|
- Does NOT sync with Unraid's update tracking
|
||||||
|
- Users run both Portainer and Unraid UI, see conflicting status
|
||||||
|
|
||||||
**Phase 1: Foundation (Must Have)**
|
### Unraid Docker Compose Manager
|
||||||
1. Docker socket security via proxy - security first
|
- Manages docker-compose stacks
|
||||||
2. n8n API access setup - enables faster development
|
- Known issue: "Docker tab reports updates available after even after updating stack"
|
||||||
3. Basic inline keyboard infrastructure - callback handling
|
- No automatic sync with Unraid Docker Manager
|
||||||
|
|
||||||
**Phase 2: UX Improvements (Should Have)**
|
### Our Approach
|
||||||
4. Container action buttons from status view
|
- Automatic sync after every bot-initiated update
|
||||||
5. Confirmation dialogs for stop/update actions
|
- Transparent to user - no manual steps after update completes
|
||||||
6. Batch update with progress feedback
|
- Solves pain point that all other tools ignore
|
||||||
|
- Differentiator: tight integration with Unraid's native tracking system
|
||||||
|
|
||||||
**Phase 3: Polish (Nice to Have)**
|
---
|
||||||
7. Unraid update status sync (file deletion method)
|
|
||||||
8. "Update all" convenience command
|
|
||||||
|
|
||||||
## Confidence Assessment
|
## Edge Cases & Considerations
|
||||||
|
|
||||||
| Area | Confidence | Reason |
|
### Race Conditions
|
||||||
|------|------------|--------|
|
- Unraid's update checker runs on schedule (user configurable)
|
||||||
| Telegram Inline Keyboards | HIGH | Official Telegram docs + n8n docs verified |
|
- If checker runs between bot update and status file write, may re-detect update
|
||||||
| Batch Operations | MEDIUM-HIGH | Standard Docker patterns, well-documented |
|
- Mitigation: Write status file immediately after image pull, before container recreate
|
||||||
| n8n API | MEDIUM | API exists but detailed endpoint docs required fetching |
|
|
||||||
| Unraid Update Sync | MEDIUM | Community knowledge, API docs limited |
|
|
||||||
| Docker Socket Security | HIGH | Well-documented proxy solutions |
|
|
||||||
|
|
||||||
## Gaps to Address in Phase Planning
|
### Multi-Arch Images
|
||||||
|
- Unraid uses manifest digests for update detection
|
||||||
|
- Bot uses `docker inspect` image ID comparison
|
||||||
|
- May disagree on whether update is needed (manifest vs image layer digest)
|
||||||
|
- Research needed: Does Unraid use manifest digest or image digest in status file?
|
||||||
|
|
||||||
1. **Exact n8n API endpoints** - Need to verify full endpoint list during implementation
|
### Failed Updates
|
||||||
2. **Unraid version compatibility** - GraphQL API requires Unraid 7.2+, need version check
|
- Bot update may fail after pulling image (recreate fails, container won't start)
|
||||||
3. **n8n Telegram node workarounds** - HTTP Request approach needs testing
|
- Should NOT clear update badge if container is broken
|
||||||
4. **Socket proxy on Unraid** - Deployment specifics for Unraid environment
|
- Status sync must be conditional on full update success (container running)
|
||||||
|
|
||||||
|
### Infrastructure Containers
|
||||||
|
- Bot already excludes n8n and docker-socket-proxy from batch operations
|
||||||
|
- Status sync should respect same exclusions (don't clear badge for bot's own container)
|
||||||
|
|
||||||
|
### File Permissions
|
||||||
|
- `/var/lib/docker/` typically requires root access
|
||||||
|
- n8n container may not have write permissions
|
||||||
|
- Need to verify access method: direct mount, docker exec, or Unraid API
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
|
||||||
|
**Community Forums & Issue Discussions:**
|
||||||
|
- [Regression: Incorrect docker update notification - Unraid Forums](https://forums.unraid.net/bug-reports/stable-releases/regression-incorrect-docker-update-notification-r2807/)
|
||||||
|
- [Docker Update Check not reliable for external container - Unraid Forums](https://forums.unraid.net/bug-reports/stable-releases/691-docker-update-check-not-reliable-for-external-container-r940/)
|
||||||
|
- [Watchtower running on unraid but containers still say update after it runs - GitHub Discussion](https://github.com/containrrr/watchtower/discussions/1389)
|
||||||
|
- [Docker update via Watchtower - Status not reflected in Unraid - Unraid Forums](https://forums.unraid.net/topic/149953-docker-update-via-watchtower-status-not-reflected-in-unraid/)
|
||||||
|
- [Docker compose: Docker tab reports updates available after updating stack - Unraid Forums](https://forums.unraid.net/topic/149264-docker-compose-docker-tab-reports-updates-available-after-even-after-updating-stack/)
|
||||||
|
|
||||||
|
**Workarounds & Solutions:**
|
||||||
|
- [Containers show update available even when up-to-date - Unraid Forums](https://forums.unraid.net/topic/142238-containers-show-update-available-even-when-it-is-up-to-date/)
|
||||||
|
- [binhex Documentation - Docker FAQ for Unraid](https://github.com/binhex/documentation/blob/master/docker/faq/unraid.md)
|
||||||
|
|
||||||
|
**Unraid API & Architecture:**
|
||||||
|
- [Docker and VM Integration - Unraid API DeepWiki](https://deepwiki.com/unraid/api/2.4.2-notification-system)
|
||||||
|
- [Using the Unraid API - Official Docs](https://docs.unraid.net/API/how-to-use-the-api/)
|
||||||
|
- [Dynamix Docker Manager - GitHub Source](https://github.com/limetech/dynamix/blob/master/plugins/dynamix.docker.manager/include/DockerClient.php)
|
||||||
|
|
||||||
|
**Docker Digest Comparison:**
|
||||||
|
- [Image digests - Docker Docs](https://docs.docker.com/dhi/core-concepts/digests/)
|
||||||
|
- [Digests in Docker - Mike Newswanger](https://www.mikenewswanger.com/posts/2020/docker-image-digests/)
|
||||||
|
|
||||||
|
---
|
||||||
|
*Feature research for: Unraid Update Status Sync (v1.3)*
|
||||||
|
*Researched: 2026-02-08*
|
||||||
|
|||||||
+410
-176
@@ -1,224 +1,458 @@
|
|||||||
# Pitfalls Research: v1.1
|
# Pitfalls Research
|
||||||
|
|
||||||
**Project:** Unraid Docker Manager
|
**Domain:** Unraid Update Status Sync for Existing Docker Management Bot
|
||||||
**Milestone:** v1.1 - n8n Integration & Polish
|
**Researched:** 2026-02-08
|
||||||
**Researched:** 2026-02-02
|
**Confidence:** MEDIUM
|
||||||
**Confidence:** MEDIUM-HIGH (verified with official docs where possible)
|
|
||||||
|
|
||||||
## Context
|
Research combines verified Unraid architecture (HIGH confidence) with integration patterns from community sources (MEDIUM confidence). File format and API internals have LIMITED documentation — risk areas flagged for phase-specific investigation.
|
||||||
|
|
||||||
This research identifies pitfalls specific to **adding** these features to an existing working system:
|
## Critical Pitfalls
|
||||||
- n8n API access (programmatic workflow read/update/test/logs)
|
|
||||||
- Docker socket proxy (security hardening)
|
|
||||||
- Telegram inline keyboards (UX improvements)
|
|
||||||
- Unraid update sync (clear "update available" badge)
|
|
||||||
|
|
||||||
**Risk focus:** Breaking existing functionality while adding new features.
|
### Pitfall 1: State Desync Between Docker API and Unraid's Internal Tracking
|
||||||
|
|
||||||
|
**What goes wrong:**
|
||||||
|
After bot-initiated updates via Docker API (pull + recreate), Unraid's Docker tab continues showing "update ready" status. Unraid doesn't detect that the container was updated externally. This creates user confusion ("I just updated, why does it still show?") and leads to duplicate update attempts.
|
||||||
|
|
||||||
|
**Why it happens:**
|
||||||
|
Unraid tracks update status through multiple mechanisms that aren't automatically synchronized with Docker API operations:
|
||||||
|
- `/var/lib/docker/unraid-update-status.json` — cached update status file (stale after external updates)
|
||||||
|
- DockerManifestService cache — compares local image digests to registry manifests
|
||||||
|
- Real-time DockerEventService — monitors Docker daemon events but doesn't trigger update status recalculation
|
||||||
|
|
||||||
|
The bot bypasses Unraid's template system entirely, so Unraid "probably doesn't check if a container has magically been updated and change its UI" (watchtower discussion).
|
||||||
|
|
||||||
|
**How to avoid:**
|
||||||
|
Phase 1 (Investigation) must determine ALL state locations:
|
||||||
|
1. **Verify update status file format** — inspect `/var/lib/docker/unraid-update-status.json` structure (undocumented, requires reverse engineering)
|
||||||
|
2. **Document cache invalidation triggers** — what causes DockerManifestService to recompute?
|
||||||
|
3. **Test event-based refresh** — does recreating a container trigger update check, or only on manual "Check for Updates"?
|
||||||
|
|
||||||
|
Phase 2 (Sync Implementation) options (in order of safety):
|
||||||
|
- **Option A (safest):** Delete stale entries from `unraid-update-status.json` for updated containers (forces recalculation on next check)
|
||||||
|
- **Option B (if A insufficient):** Call Unraid API update check endpoint after bot updates (triggers full recalc)
|
||||||
|
- **Option C (last resort):** Directly modify `unraid-update-status.json` with current digest (highest risk of corruption)
|
||||||
|
|
||||||
|
**Warning signs:**
|
||||||
|
- "Apply Update" shown in Unraid UI immediately after bot reports successful update
|
||||||
|
- Unraid notification shows update available for container that bot just updated
|
||||||
|
- `/var/lib/docker/unraid-update-status.json` modified timestamp doesn't change after bot update
|
||||||
|
|
||||||
|
**Phase to address:**
|
||||||
|
Phase 1 (Investigation & File Format Analysis) — understand state structure
|
||||||
|
Phase 2 (Sync Implementation) — implement chosen sync strategy
|
||||||
|
Phase 3 (UAT) — verify sync works across Unraid versions
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## n8n API Access Pitfalls
|
### Pitfall 2: Race Condition Between Unraid's Periodic Update Check and Bot Sync-Back
|
||||||
|
|
||||||
| Pitfall | Warning Signs | Prevention | Phase |
|
**What goes wrong:**
|
||||||
|---------|---------------|------------|-------|
|
Unraid periodically checks for updates (user-configurable interval, often 15-60 minutes). If the bot writes to `unraid-update-status.json` while Unraid's update check is running, data corruption or lost updates occur. Symptoms: Unraid shows containers as "update ready" immediately after sync, or sync writes are silently discarded.
|
||||||
| **API key with full access** | API key created without scopes; all workflows accessible | Enterprise: use scoped API keys (read-only for Claude Code initially). Non-enterprise: accept risk, rotate keys every 6-12 months | API Setup |
|
|
||||||
| **Missing X-N8N-API-KEY header** | 401 Unauthorized errors on all API calls | Store API key in Claude Code MCP config; always send as `X-N8N-API-KEY` header, not Bearer token | API Setup |
|
|
||||||
| **Workflow ID mismatch after import** | API calls return 404; workflow actions fail | Workflow IDs change on import; query `/api/v1/workflows` first to get current IDs, don't hardcode | API Setup |
|
|
||||||
| **Editing active workflow via API** | Production workflow changes unexpectedly; users see partial updates | n8n 2.0: Save vs Publish are separate actions. Use API to read only; manual publish via UI | API Setup |
|
|
||||||
| **N8N_BLOCK_ENV_ACCESS_IN_NODE default** | Code nodes can't access env vars; returns undefined | n8n 2.0+ blocks env vars by default. Use credentials system instead, or explicitly set `N8N_BLOCK_ENV_ACCESS_IN_NODE=false` | API Setup |
|
|
||||||
| **API not enabled on instance** | Connection refused on /api/v1 endpoints | Self-hosted: API is available by default. Cloud trial: API not available. Verify with `curl http://localhost:5678/api/v1/workflows` | API Setup |
|
|
||||||
| **Rate limiting on rapid API calls** | 429 errors when reading workflow repeatedly | Add delay between API calls (1-2 seconds); use caching for workflow data that doesn't change frequently | API Usage |
|
|
||||||
|
|
||||||
**Sources:**
|
**Why it happens:**
|
||||||
- [n8n API Authentication](https://docs.n8n.io/api/authentication/)
|
Two processes writing to the same file without coordination:
|
||||||
- [n8n API Reference](https://docs.n8n.io/api/)
|
- Unraid's update check: reads file → queries registries → writes full file
|
||||||
- [n8n v2.0 Breaking Changes](https://docs.n8n.io/2-0-breaking-changes/)
|
- Bot sync: reads file → modifies entry → writes full file
|
||||||
|
|
||||||
|
If both run concurrently, last writer wins (lost update problem). No evidence of file locking in Unraid's update status handling.
|
||||||
|
|
||||||
|
**How to avoid:**
|
||||||
|
1. **Read-modify-write atomicity:** Use file locking or atomic write (write to temp file, atomic rename)
|
||||||
|
2. **Timestamp verification:** Read file, modify, check mtime before write — retry if changed
|
||||||
|
3. **Idempotent sync:** Deleting entries (Option A above) is safer than modifying — delete is idempotent
|
||||||
|
4. **Rate limiting:** Don't sync immediately after update — wait 5-10 seconds to avoid collision with Unraid's Docker event handler
|
||||||
|
|
||||||
|
Phase 2 implementation requirements:
|
||||||
|
- Use Python's `fcntl.flock()` or atomic file operations
|
||||||
|
- Include retry logic with exponential backoff (max 3 attempts)
|
||||||
|
- Log all file modification failures for debugging
|
||||||
|
|
||||||
|
**Warning signs:**
|
||||||
|
- Sync reports success but Unraid state unchanged
|
||||||
|
- File modification timestamp inconsistent with sync execution time
|
||||||
|
- "Resource temporarily unavailable" errors when accessing the file
|
||||||
|
|
||||||
|
**Phase to address:**
|
||||||
|
Phase 2 (Sync Implementation) — implement atomic file operations and retry logic
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Docker Socket Security Pitfalls
|
### Pitfall 3: Unraid Version Compatibility — Internal Format Changes Break Integration
|
||||||
|
|
||||||
| Pitfall | Warning Signs | Prevention | Phase |
|
**What goes wrong:**
|
||||||
|---------|---------------|------------|-------|
|
Unraid updates change the structure of `/var/lib/docker/unraid-update-status.json` or introduce new update tracking mechanisms. Bot's sync logic breaks silently (no status updates) or corrupts the file (containers disappear from UI, update checks fail).
|
||||||
| **Proxy exposes POST by default** | Container can create/delete containers; security scan flags | Set `POST=0` on socket proxy; most read operations work with GET only | Socket Proxy |
|
|
||||||
| **Using `--privileged` unnecessarily** | Security audit fails; container has excessive permissions | Remove `--privileged` flag; Tecnativa proxy works without it on standard Docker | Socket Proxy |
|
|
||||||
| **Outdated socket proxy image** | Using `latest` tag which is 3+ years old | Pin to specific version: `tecnativa/docker-socket-proxy:0.2.0` or use `linuxserver/socket-proxy` | Socket Proxy |
|
|
||||||
| **Proxy port exposed publicly** | Port 2375 accessible from network; security scan fails | Never expose proxy port; run on internal Docker network only | Socket Proxy |
|
|
||||||
| **Insufficient permissions for n8n** | "Permission denied" or empty responses from Docker API | Enable minimum required: `CONTAINERS=1`, `ALLOW_START=1`, `ALLOW_STOP=1`, `ALLOW_RESTARTS=1` for actions | Socket Proxy |
|
|
||||||
| **Breaking existing curl commands** | Existing workflow fails after adding proxy; commands timeout | Socket proxy uses TCP, not Unix socket. Update curl commands: `curl http://socket-proxy:2375/...` instead of `--unix-socket` | Socket Proxy |
|
|
||||||
| **Network isolation breaks connectivity** | n8n can't reach proxy; "connection refused" errors | Both containers must be on same Docker network; verify with `docker network inspect` | Socket Proxy |
|
|
||||||
| **Permissions too restrictive** | Container list works but start/stop fails | Must explicitly enable action endpoints: `ALLOW_START=1`, `ALLOW_STOP=1`, `ALLOW_RESTARTS=1` (separate from `CONTAINERS=1`) | Socket Proxy |
|
|
||||||
| **Missing INFO or VERSION permissions** | Some Docker API calls fail unexpectedly | `VERSION=1` and `PING=1` are enabled by default; may need `INFO=1` for system queries | Socket Proxy |
|
|
||||||
|
|
||||||
**Minimum safe configuration for this project:**
|
**Why it happens:**
|
||||||
```yaml
|
- File format is undocumented (no schema, no version field)
|
||||||
environment:
|
- Unraid 7.x introduced major API changes (GraphQL, new DockerService architecture)
|
||||||
- CONTAINERS=1 # Read container info
|
- Past example: Unraid 6.12.8 template errors that "previously were silently ignored could cause Docker containers to fail to start"
|
||||||
- ALLOW_START=1 # Start containers
|
- No backward compatibility guarantees for internal files
|
||||||
- ALLOW_STOP=1 # Stop containers
|
|
||||||
- ALLOW_RESTARTS=1 # Restart containers
|
Historical evidence of breaking changes:
|
||||||
- IMAGES=1 # Pull images (for updates)
|
- Unraid 7.2.1 (Nov 2025): Docker localhost networking broke
|
||||||
- POST=1 # Required for start/stop/restart actions
|
- Unraid 6.12.8: Docker template validation strictness increased
|
||||||
- NETWORKS=0 # Not needed
|
- Unraid API open-sourced Jan 2025 — likely more changes incoming
|
||||||
- VOLUMES=0 # Not needed
|
|
||||||
- BUILD=0 # Not needed
|
**How to avoid:**
|
||||||
- COMMIT=0 # Not needed
|
1. **Version detection:** Read Unraid version from `/etc/unraid-version` or API
|
||||||
- CONFIGS=0 # Not needed
|
2. **Format validation:** Before modifying file, validate expected structure (reject unknown formats)
|
||||||
- SECRETS=0 # Security critical - keep disabled
|
3. **Graceful degradation:** If file format unrecognized, log error and skip sync (preserve existing bot functionality)
|
||||||
- EXEC=0 # Security critical - keep disabled
|
4. **Testing matrix:** Test against Unraid 6.11, 6.12, 7.0, 7.2 (Phase 3)
|
||||||
- AUTH=0 # Security critical - keep disabled
|
|
||||||
|
Phase 1 requirements:
|
||||||
|
- Document current file format for Unraid 7.x
|
||||||
|
- Check Unraid forums for known format changes across versions
|
||||||
|
- Identify version-specific differences (if any)
|
||||||
|
|
||||||
|
Phase 2 implementation:
|
||||||
|
```python
|
||||||
|
SUPPORTED_VERSIONS = ['6.11', '6.12', '7.0', '7.1', '7.2']
|
||||||
|
version = read_unraid_version()
|
||||||
|
if not version_compatible(version):
|
||||||
|
log_error(f"Unsupported Unraid version: {version}")
|
||||||
|
return # Skip sync, preserve bot functionality
|
||||||
```
|
```
|
||||||
|
|
||||||
**Sources:**
|
**Warning signs:**
|
||||||
- [Tecnativa docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy)
|
- After Unraid upgrade, sync stops working (no errors, just no state change)
|
||||||
- [LinuxServer socket-proxy](https://docs.linuxserver.io/images/docker-socket-proxy/)
|
- Unraid Docker tab shows errors or missing containers after bot update
|
||||||
- [Docker Community Forums - Socket Proxy Security](https://forums.docker.com/t/does-a-docker-socket-proxy-improve-security/136305)
|
- File size changes significantly after Unraid upgrade (format change)
|
||||||
|
|
||||||
|
**Phase to address:**
|
||||||
|
Phase 1 (Investigation) — document current format, check version differences
|
||||||
|
Phase 2 (Implementation) — add version detection and validation
|
||||||
|
Phase 3 (UAT) — test across Unraid versions
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Telegram Keyboard Pitfalls
|
### Pitfall 4: Docker Socket Proxy Blocks Filesystem Access — n8n Can't Reach Unraid State Files
|
||||||
|
|
||||||
| Pitfall | Warning Signs | Prevention | Phase |
|
**What goes wrong:**
|
||||||
|---------|---------------|------------|-------|
|
The bot runs inside n8n container, which accesses Docker via socket proxy (security layer). Socket proxy filters Docker API endpoints but doesn't provide filesystem access. `/var/lib/docker/unraid-update-status.json` is on the Unraid host, unreachable from n8n container.
|
||||||
| **Native node rejects dynamic keyboards** | Error: "The value '[[...]]' is not supported!" | Use HTTP Request node for inline keyboards instead of native Telegram node; this is a known n8n limitation | Keyboards |
|
|
||||||
| **callback_data exceeds 64 bytes** | Buttons don't respond; no callback_query received; 400 BUTTON_DATA_INVALID | Use short codes: `s:plex` not `start_container:plex-media-server`. Hash long names to 8-char IDs | Keyboards |
|
|
||||||
| **Callback auth path missing** | Keyboard clicks ignored; no response to button press | Existing workflow already handles callback_query (line 56-74 in workflow). Ensure new keyboards use same auth flow | Keyboards |
|
|
||||||
| **Multiple additional fields ignored** | Button has both callback_data and URL; only URL works | n8n Telegram node limitation - can't use both. Choose one per button: either action (callback) or link (URL) | Keyboards |
|
|
||||||
| **Keyboard flickers on every message** | Visual glitches; keyboard re-renders constantly | Send `reply_markup` only on /start or menu requests; omit from action responses (keyboard persists) | Keyboards |
|
|
||||||
| **Inline vs Reply keyboard confusion** | Wrong keyboard type appears; buttons don't trigger callbacks | Inline keyboards (InlineKeyboardMarkup) for callbacks; Reply keyboards (ReplyKeyboardMarkup) for persistent menus. Use inline for container actions | Keyboards |
|
|
||||||
| **answerCallbackQuery not called** | "Loading..." spinner persists after button click; Telegram shows timeout | Must call `answerCallbackQuery` within 10 seconds of receiving callback_query, even if just to acknowledge | Keyboards |
|
|
||||||
| **Button layout exceeds limits** | Buttons don't appear; API error | Bot API 7.0: max 100 buttons total per message. For container lists, paginate or limit to 8-10 buttons | Keyboards |
|
|
||||||
|
|
||||||
**Recommended keyboard structure for container actions:**
|
Attempting to mount host paths into n8n violates security boundary and creates maintenance burden (n8n updates require preserving mounts).
|
||||||
|
|
||||||
|
**Why it happens:**
|
||||||
|
Current architecture (from ARCHITECTURE.md):
|
||||||
|
```
|
||||||
|
n8n container → docker-socket-proxy → Docker Engine
|
||||||
|
```
|
||||||
|
|
||||||
|
Socket proxy security model:
|
||||||
|
- Grants specific Docker API endpoints (containers, images, exec)
|
||||||
|
- Blocks direct filesystem access
|
||||||
|
- n8n has no `/host` mount (intentional security decision)
|
||||||
|
|
||||||
|
Mounting `/var/lib/docker` into n8n container:
|
||||||
|
- Bypasses socket proxy security (defeats the purpose)
|
||||||
|
- Requires n8n container restart when file path changes
|
||||||
|
- Couples n8n deployment to Unraid internals
|
||||||
|
|
||||||
|
**How to avoid:**
|
||||||
|
Three architectural options (order of preference):
|
||||||
|
|
||||||
|
**Option A: Unraid API Integration (cleanest, highest effort)**
|
||||||
|
- Use Unraid's native API (GraphQL or REST) if update status endpoints exist
|
||||||
|
- Requires: API key management, authentication flow, endpoint documentation
|
||||||
|
- Benefits: Version-safe, no direct file access, official interface
|
||||||
|
- Risk: API may not expose update status mutation endpoints
|
||||||
|
|
||||||
|
**Option B: Helper Script on Host (recommended for v1.3)**
|
||||||
|
- Small Python script runs on Unraid host (not in container)
|
||||||
|
- n8n triggers via `docker exec` to host helper or webhook
|
||||||
|
- Helper has direct filesystem access, performs sync
|
||||||
|
- Benefits: Clean separation, no n8n filesystem access, minimal coupling
|
||||||
|
- Implementation: `.planning/research/ARCHITECTURE.md` should detail this pattern
|
||||||
|
|
||||||
|
**Option C: Controlled Host Mount (fallback, higher risk)**
|
||||||
|
- Mount only `/var/lib/docker/unraid-update-status.json` (not entire `/var/lib/docker`)
|
||||||
|
- Read-only mount + separate write mechanism (requires Docker API or exec)
|
||||||
|
- Benefits: Direct access
|
||||||
|
- Risk: Tight coupling, version fragility
|
||||||
|
|
||||||
|
**Phase 1 must investigate:**
|
||||||
|
1. Does Unraid API expose update status endpoints? (check GraphQL schema)
|
||||||
|
2. Can Docker exec reach host scripts? (test in current deployment)
|
||||||
|
3. Security implications of each option
|
||||||
|
|
||||||
|
**Warning signs:**
|
||||||
|
- "Permission denied" when attempting to read/write status file from n8n
|
||||||
|
- File not found errors (path doesn't exist in container filesystem)
|
||||||
|
- n8n container has no visibility of host filesystem
|
||||||
|
|
||||||
|
**Phase to address:**
|
||||||
|
Phase 1 (Architecture Decision) — choose integration pattern
|
||||||
|
Phase 2 (Implementation) — implement chosen pattern
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Pitfall 5: Unraid Update Check Triggers While Bot Is Syncing — Notification Spam
|
||||||
|
|
||||||
|
**What goes wrong:**
|
||||||
|
Bot updates container → syncs status back to Unraid → Unraid's periodic update check runs during sync → update check sees partially-written file or stale cache → sends duplicate "update available" notification to user. User receives notification storm when updating multiple containers.
|
||||||
|
|
||||||
|
**Why it happens:**
|
||||||
|
Unraid's update check is asynchronous and periodic:
|
||||||
|
- Notification service triggers on update detection
|
||||||
|
- No debouncing for rapid state changes
|
||||||
|
- File write + cache invalidation not atomic
|
||||||
|
|
||||||
|
Community evidence:
|
||||||
|
- "Excessive notifications from unRAID" — users report notification spam
|
||||||
|
- "Duplicate notifications" — longstanding issue in notification system
|
||||||
|
- System excludes duplicates from archive but not from active stream
|
||||||
|
|
||||||
|
**How to avoid:**
|
||||||
|
1. **Sync timing:** Delay sync by 10-30 seconds after update completion (let Docker events settle)
|
||||||
|
2. **Batch sync:** If updating multiple containers, sync all at once (not per-container)
|
||||||
|
3. **Cache invalidation signal:** If Unraid API provides cache invalidation, trigger AFTER all syncs complete
|
||||||
|
4. **Idempotent sync:** Delete entries (forces recalc) rather than writing new digests (avoids partial state)
|
||||||
|
|
||||||
|
Phase 2 implementation pattern:
|
||||||
```javascript
|
```javascript
|
||||||
// Short callback_data pattern: action:container_short_id
|
// In Update sub-workflow
|
||||||
// Example: "s:abc123" for start, "x:abc123" for stop
|
if (responseMode === 'batch') {
|
||||||
{
|
return { success: true, skipSync: true } // Sync after batch completes
|
||||||
"inline_keyboard": [
|
|
||||||
[
|
|
||||||
{"text": "Start", "callback_data": "s:" + containerId.slice(0,8)},
|
|
||||||
{"text": "Stop", "callback_data": "x:" + containerId.slice(0,8)}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{"text": "Restart", "callback_data": "r:" + containerId.slice(0,8)},
|
|
||||||
{"text": "Logs", "callback_data": "l:" + containerId.slice(0,8)}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In main workflow (after batch completion)
|
||||||
|
const updatedContainers = [...] // Collect all updated
|
||||||
|
await syncAllToUnraid(updatedContainers) // Single sync operation
|
||||||
```
|
```
|
||||||
|
|
||||||
**Sources:**
|
**Warning signs:**
|
||||||
- [n8n GitHub Issue #19955 - Inline Keyboard Expression](https://github.com/n8n-io/n8n/issues/19955)
|
- Multiple "update available" notifications for same container within 1 minute
|
||||||
- [n8n Telegram Callback Operations](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.telegram/callback-operations/)
|
- Notifications triggered immediately after bot update completes
|
||||||
- [Telegram Bot API - InlineKeyboardButton](https://core.telegram.org/bots/api#inlinekeyboardbutton)
|
- Unraid notification log shows duplicate entries with close timestamps
|
||||||
|
|
||||||
|
**Phase to address:**
|
||||||
|
Phase 2 (Sync Implementation) — add batch sync and timing delays
|
||||||
|
Phase 3 (UAT) — verify no notification spam during batch updates
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Unraid Integration Pitfalls
|
### Pitfall 6: n8n Workflow State Doesn't Persist — Can't Queue Sync Operations
|
||||||
|
|
||||||
| Pitfall | Warning Signs | Prevention | Phase |
|
**What goes wrong:**
|
||||||
|---------|---------------|------------|-------|
|
Developer assumes n8n workflow static data persists between executions (like Phase 10.2 error logging attempt). Builds queue of "pending syncs" to batch them. Queue is lost between workflow executions. Each update triggers immediate sync attempt → file access contention, race conditions.
|
||||||
| **Update badge persists after bot update** | Unraid UI shows "update available" after container updated via bot | Delete `/var/lib/docker/unraid-update-status.json` to force recheck; or trigger Unraid's check mechanism | Unraid Sync |
|
|
||||||
| **unraid-update-status.json format unknown** | Attempted to modify file directly; broke Unraid Docker tab | File format is undocumented. Safest approach: delete file and let Unraid regenerate. Don't modify directly | Unraid Sync |
|
|
||||||
| **Unraid only checks for new updates** | Badge never clears; only sees new updates, not cleared updates | This is known Unraid behavior. Deletion of status file is current workaround per Unraid forums | Unraid Sync |
|
|
||||||
| **Race condition on status file** | Status file deleted but badge still shows; file regenerated too fast | Wait for Unraid's update check interval, or manually trigger "Check for Updates" from Unraid UI after deletion | Unraid Sync |
|
|
||||||
| **Bot can't access Unraid filesystem** | Permission denied when accessing /var/lib/docker/ | n8n container needs additional volume mount: `/var/lib/docker:/var/lib/docker` or execute via SSH | Unraid Sync |
|
|
||||||
| **Breaking Unraid's Docker management** | Unraid Docker tab shows errors; containers appear in wrong state | Never modify Unraid's internal files (in /boot/config/docker or /var/lib/docker) except update-status.json deletion | Unraid Sync |
|
|
||||||
|
|
||||||
**Unraid sync approach (safest):**
|
**Why it happens:**
|
||||||
1. After bot successfully updates container
|
Known limitation from STATE.md:
|
||||||
2. Execute: `rm -f /var/lib/docker/unraid-update-status.json`
|
> **n8n workflow static data does NOT persist between executions** (execution-scoped, not workflow-scoped)
|
||||||
3. Unraid will regenerate on next "Check for Updates" or automatically
|
|
||||||
|
|
||||||
**Sources:**
|
Phase 10.2 attempted ring buffer + debug commands — entirely removed due to this limitation.
|
||||||
- [Unraid Forums - Update notification regression](https://forums.unraid.net/bug-reports/stable-releases/regression-incorrect-docker-update-notification-r2807/)
|
|
||||||
- [Unraid Forums - Update badge persists](https://forums.unraid.net/topic/157820-docker-shows-update-ready-after-updating/)
|
Implications for sync-back:
|
||||||
- [Unraid Forums - Containers show update available incorrectly](https://forums.unraid.net/topic/142238-containers-show-update-available-even-when-it-is-up-to-date/)
|
- Can't queue sync operations across multiple update requests
|
||||||
|
- Can't implement retry queue for failed syncs
|
||||||
|
- Each workflow execution is stateless
|
||||||
|
|
||||||
|
**How to avoid:**
|
||||||
|
Don't rely on workflow state for sync coordination. Options:
|
||||||
|
|
||||||
|
**Option A: Synchronous sync (simplest)**
|
||||||
|
- Update container → immediately sync (no queue)
|
||||||
|
- Atomic file operations handle contention
|
||||||
|
- Acceptable for single updates, problematic for batch
|
||||||
|
|
||||||
|
**Option B: External queue (Redis, file-based)**
|
||||||
|
- Write pending syncs to external queue
|
||||||
|
- Separate workflow polls queue and processes batch
|
||||||
|
- Higher complexity, requires infrastructure
|
||||||
|
|
||||||
|
**Option C: Batch-aware sync (recommended)**
|
||||||
|
- Single updates: sync immediately
|
||||||
|
- Batch updates: collect all container IDs in batch loop, sync once after completion
|
||||||
|
- No cross-execution state needed (batch completes in single execution)
|
||||||
|
|
||||||
|
Implementation in Phase 2:
|
||||||
|
```javascript
|
||||||
|
// Batch loop already collects results
|
||||||
|
const batchResults = []
|
||||||
|
for (const container of containers) {
|
||||||
|
const result = await updateContainer(container)
|
||||||
|
batchResults.push({ containerId, updated: result.updated })
|
||||||
|
}
|
||||||
|
// After loop completes (still in same execution):
|
||||||
|
const toSync = batchResults.filter(r => r.updated).map(r => r.containerId)
|
||||||
|
await syncToUnraid(toSync) // Single sync call
|
||||||
|
```
|
||||||
|
|
||||||
|
**Warning signs:**
|
||||||
|
- Developer adds static data writes for sync queue
|
||||||
|
- Testing shows queue is empty on next execution
|
||||||
|
- Sync attempts happen per-container instead of batched
|
||||||
|
|
||||||
|
**Phase to address:**
|
||||||
|
Phase 1 (Architecture) — document stateless constraint, reject queue-based designs
|
||||||
|
Phase 2 (Implementation) — use in-execution batching, not cross-execution state
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Integration Pitfalls (Breaking Existing Functionality)
|
### Pitfall 7: Unraid's br0 Network Recreate Breaks Container Resolution After Bot Update
|
||||||
|
|
||||||
| Pitfall | Warning Signs | Prevention | Phase |
|
**What goes wrong:**
|
||||||
|---------|---------------|------------|-------|
|
Bot updates container using Docker API (remove + create) → Unraid recreates bridge network (`br0`) → Docker network ID changes → other containers using `br0` fail to resolve updated container by name → service disruption beyond just the updated container.
|
||||||
| **Socket proxy breaks existing curl** | All Docker commands fail after adding proxy | Existing workflow uses `--unix-socket`. Migrate curl commands to use proxy TCP endpoint: `http://socket-proxy:2375` | Socket Proxy |
|
|
||||||
| **Auth flow bypassed on new paths** | New keyboard handlers skip user ID check; anyone can click buttons | Existing workflow has auth at lines 92-122 and 126-155. Copy same pattern for any new callback handlers | All |
|
|
||||||
| **Workflow test vs production mismatch** | Works in test mode; fails when activated | Test with actual Telegram messages, not just manual execution. Production triggers differ from manual runs | All |
|
|
||||||
| **n8n 2.0 upgrade breaks workflow** | After n8n update, workflow stops working; nodes missing | n8n 2.0 has breaking changes: Execute Command disabled by default, Start node removed, env vars blocked. Check [migration guide](https://docs.n8n.io/2-0-breaking-changes/) before upgrading | All |
|
|
||||||
| **Credential reference breaks after import** | Imported workflow can't decrypt credentials; all nodes fail | n8n uses N8N_ENCRYPTION_KEY. After import, must recreate credentials manually in n8n UI | All |
|
|
||||||
| **HTTP Request node vs Execute Command** | HTTP Request can't reach Docker socket; timeout errors | HTTP Request node doesn't support Unix sockets. Keep using Execute Command with curl for Docker API (or migrate to TCP proxy) | Socket Proxy |
|
|
||||||
| **Parallel execution race conditions** | Two button clicks cause conflicting container states | Add debounce logic: ignore rapid duplicate callbacks within 2-3 seconds. Store last action timestamp | Keyboards |
|
|
||||||
| **Error workflow doesn't fire** | Errors occur but no notification; silent failures | Error Trigger only fires on automatic executions, not manual test runs. Test by triggering via Telegram with intentional failure | All |
|
|
||||||
| **Save vs Publish confusion (n8n 2.0)** | Edited workflow but production still uses old version | n8n 2.0 separates Save (preserves edits) from Publish (updates production). Must explicitly publish changes | All |
|
|
||||||
|
|
||||||
**Pre-migration checklist:**
|
**Why it happens:**
|
||||||
- [ ] Export current workflow JSON as backup
|
Community report: "Unraid recreates 'br0' when the docker service restarts, and then services using 'br0' cannot be started because the ID of 'br0' has changed."
|
||||||
- [ ] Document current curl commands and endpoints
|
|
||||||
- [ ] Test each existing command works after changes
|
|
||||||
- [ ] Verify auth flow applies to new handlers
|
|
||||||
- [ ] Test error handling triggers correctly
|
|
||||||
|
|
||||||
**Sources:**
|
Bot update flow: `docker pull` → `docker stop` → `docker rm` → `docker run` with same config
|
||||||
- [n8n v2.0 Breaking Changes](https://docs.n8n.io/2-0-breaking-changes/)
|
- If container uses custom bridge network, recreation may trigger network ID change
|
||||||
- [n8n Manual vs Production Executions](https://docs.n8n.io/workflows/executions/manual-partial-and-production-executions/)
|
- Unraid's Docker service monitors for container lifecycle events
|
||||||
- [n8n Community - Test vs Production Behavior](https://community.n8n.io/t/workflow-behaves-differently-in-test-vs-production/139973)
|
- Network recreation is asynchronous to container operations
|
||||||
|
|
||||||
|
**How to avoid:**
|
||||||
|
1. **Preserve network settings:** Ensure container recreation uses identical network config (Phase 2)
|
||||||
|
2. **Test network-dependent scenarios:** UAT must include containers with custom networks (Phase 3)
|
||||||
|
3. **Graceful degradation:** If network issue detected (container unreachable after update), log error and notify user
|
||||||
|
4. **Documentation:** Warn users about potential network disruption during updates (README)
|
||||||
|
|
||||||
|
Phase 2 implementation check:
|
||||||
|
- Current update sub-workflow uses Docker API recreate — verify network config preservation
|
||||||
|
- Check if `n8n-update.json` copies network settings from old container to new
|
||||||
|
- Test: update container on `br0`, verify other containers still resolve it
|
||||||
|
|
||||||
|
**Warning signs:**
|
||||||
|
- Container starts successfully but is unreachable by hostname
|
||||||
|
- Other containers report DNS resolution failures after update
|
||||||
|
- `docker network ls` shows new network ID for `br0` after container update
|
||||||
|
|
||||||
|
**Phase to address:**
|
||||||
|
Phase 2 (Update Flow Verification) — ensure network config preservation
|
||||||
|
Phase 3 (UAT) — test multi-container network scenarios
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Summary: Top 5 Risks
|
## Technical Debt Patterns
|
||||||
|
|
||||||
Ranked by likelihood x impact for this specific milestone:
|
Shortcuts that seem reasonable but create long-term problems.
|
||||||
|
|
||||||
### 1. Socket Proxy Breaks Existing Commands (HIGH likelihood, HIGH impact)
|
| Shortcut | Immediate Benefit | Long-term Cost | When Acceptable |
|
||||||
**Why:** Current workflow uses `--unix-socket` flag. Socket proxy uses TCP. All existing functionality breaks if not migrated correctly.
|
|----------|-------------------|----------------|-----------------|
|
||||||
**Prevention:**
|
| Skip Unraid version detection | Faster implementation | Silent breakage on Unraid upgrades | Never — version changes are documented |
|
||||||
1. Add socket proxy container first (don't remove direct socket yet)
|
| Mount `/var/lib/docker` into n8n | Direct file access | Security bypass, tight coupling, upgrade fragility | Only if helper script impossible |
|
||||||
2. Update curl commands one-by-one to use proxy
|
| Sync immediately after update (no delay) | Simpler code | Race conditions with Unraid update check | Only for single-container updates (not batch) |
|
||||||
3. Test each command works via proxy
|
| Assume file format from one Unraid version | Works on dev system | Breaks for users on different versions | Only during Phase 1 investigation (must validate before Phase 2) |
|
||||||
4. Only then remove direct socket mount
|
| Write directly to status file without locking | Avoids complexity | File corruption on concurrent access | Never — use atomic operations |
|
||||||
|
| Hardcode file paths | Works today | Breaks if Unraid changes internal structure | Acceptable if combined with version detection + validation |
|
||||||
|
|
||||||
### 2. Native Telegram Node Rejects Dynamic Keyboards (HIGH likelihood, MEDIUM impact)
|
## Integration Gotchas
|
||||||
**Why:** n8n's native Telegram node has a known bug (Issue #19955) where it rejects array expressions for inline keyboards.
|
|
||||||
**Prevention:** Use HTTP Request node to call Telegram API directly for any dynamic keyboard generation. Keep native node for simple text responses only.
|
|
||||||
|
|
||||||
### 3. Unraid Update Badge Never Clears (HIGH likelihood, LOW impact)
|
Common mistakes when connecting to external services.
|
||||||
**Why:** Unraid doesn't check for "no longer outdated" containers - only new updates. Documented behavior, not a bug.
|
|
||||||
**Prevention:** Delete `/var/lib/docker/unraid-update-status.json` after successful bot update. Requires additional volume mount or SSH access.
|
|
||||||
|
|
||||||
### 4. n8n 2.0 Breaking Changes on Upgrade (MEDIUM likelihood, HIGH impact)
|
| Integration | Common Mistake | Correct Approach |
|
||||||
**Why:** n8n 2.0 (released Dec 2025) has multiple breaking changes: Execute Command disabled by default, env vars blocked, Save/Publish separation.
|
|-------------|----------------|------------------|
|
||||||
**Prevention:**
|
| Unraid update status file | Assume JSON structure is stable | Validate structure before modification, reject unknown formats |
|
||||||
1. Check current n8n version before starting
|
| Docker socket proxy | Expect filesystem access like Docker socket mount | Use helper script on host OR Unraid API if available |
|
||||||
2. If upgrading, run Migration Report first (Settings > Migration Report)
|
| Unraid API (if used) | Assume unauthenticated localhost access | Check auth requirements, API key management |
|
||||||
3. Don't upgrade n8n during this milestone unless necessary
|
| File modification timing | Write immediately after container update | Delay 5-10 seconds to avoid collision with Docker event handlers |
|
||||||
|
| Batch operations | Sync after each container update | Collect all updates, sync once after batch completes |
|
||||||
|
| Network config preservation | Assume Docker API preserves settings | Explicitly copy network settings from old container inspect to new create |
|
||||||
|
|
||||||
### 5. callback_data Exceeds 64 Bytes (MEDIUM likelihood, MEDIUM impact)
|
## Performance Traps
|
||||||
**Why:** Container names can be long (e.g., `linuxserver-plex-media-server`). Adding action prefix easily exceeds 64 bytes.
|
|
||||||
**Prevention:** Use short action codes (`s:`, `x:`, `r:`, `l:`) and container ID prefix (8 chars) instead of full names. Map back via lookup.
|
Patterns that work at small scale but fail as usage grows.
|
||||||
|
|
||||||
|
| Trap | Symptoms | Prevention | When It Breaks |
|
||||||
|
|------|----------|------------|----------------|
|
||||||
|
| Sync per container in batch | File contention, slow batch updates | Batch sync after all updates complete | 5+ containers in batch |
|
||||||
|
| Full file rewrite for each sync | High I/O, race window increases | Delete stale entries OR modify only changed entries | 10+ containers tracked |
|
||||||
|
| No retry logic for file access | Silent sync failures | Exponential backoff retry (max 3 attempts) | Concurrent Unraid update check |
|
||||||
|
| Sync blocks workflow execution | Slow Telegram responses | Async sync (fire and forget) OR move to separate workflow | 3+ second file operations |
|
||||||
|
|
||||||
|
Note: Current system has 8-15 containers (from UAT scenarios). Performance traps unlikely to manifest, but prevention is low-cost.
|
||||||
|
|
||||||
|
## Security Mistakes
|
||||||
|
|
||||||
|
Domain-specific security issues beyond general web security.
|
||||||
|
|
||||||
|
| Mistake | Risk | Prevention |
|
||||||
|
|---------|------|------------|
|
||||||
|
| Mount entire `/var/lib/docker` into n8n | n8n gains root-level access to all Docker data | Mount only specific file OR use helper script |
|
||||||
|
| World-writable status file permissions | Any container can corrupt Unraid state | Verify file permissions, use host-side helper with proper permissions |
|
||||||
|
| No validation before writing to status file | Malformed data corrupts Unraid Docker UI | Validate JSON structure, reject unknown formats |
|
||||||
|
| Expose Unraid API key in workflow | API key visible in n8n execution logs | Use n8n credentials, not hardcoded keys |
|
||||||
|
| Execute arbitrary commands on host | Container escape vector | Whitelist allowed operations in helper script |
|
||||||
|
|
||||||
|
## UX Pitfalls
|
||||||
|
|
||||||
|
Common user experience mistakes in this domain.
|
||||||
|
|
||||||
|
| Pitfall | User Impact | Better Approach |
|
||||||
|
|---------|-------------|-----------------|
|
||||||
|
| Silent sync failure | User thinks status updated, Unraid still shows "update ready" | Log error to correlation ID, send Telegram notification on sync failure |
|
||||||
|
| No indication of sync status | User doesn't know if sync worked | Include in update success message: "Updated + synced to Unraid" |
|
||||||
|
| Sync delay causes confusion | User checks Unraid immediately, sees old status | Document 10-30 second sync delay in README troubleshooting |
|
||||||
|
| Unraid badge still shows after sync | User thinks update failed | README: explain Unraid caches aggressively, manual "Check for Updates" forces refresh |
|
||||||
|
| Batch update spam notifications | 10 updates = 10 Unraid notifications | Batch sync prevents this (if implemented correctly) |
|
||||||
|
|
||||||
|
## "Looks Done But Isn't" Checklist
|
||||||
|
|
||||||
|
Things that appear complete but are missing critical pieces.
|
||||||
|
|
||||||
|
- [ ] **File modification:** Wrote to status file — verify atomic operation (temp file + rename, not direct write)
|
||||||
|
- [ ] **Batch sync:** Syncs after each update — verify batching for multi-container operations
|
||||||
|
- [ ] **Version compatibility:** Works on dev Unraid — verify against 6.11, 6.12, 7.0, 7.2
|
||||||
|
- [ ] **Error handling:** Sync returns success — verify retry logic for file contention
|
||||||
|
- [ ] **Network preservation:** Container starts after update — verify DNS resolution from other containers
|
||||||
|
- [ ] **Race condition testing:** Works in sequential tests — verify concurrent update + Unraid check scenario
|
||||||
|
- [ ] **Filesystem access:** Works on dev system — verify n8n container can actually reach file (or helper script exists)
|
||||||
|
- [ ] **Notification validation:** No duplicate notifications in single test — verify batch scenario (5+ containers)
|
||||||
|
|
||||||
|
## Recovery Strategies
|
||||||
|
|
||||||
|
When pitfalls occur despite prevention, how to recover.
|
||||||
|
|
||||||
|
| Pitfall | Recovery Cost | Recovery Steps |
|
||||||
|
|---------|---------------|----------------|
|
||||||
|
| Corrupted status file | LOW | Delete `/var/lib/docker/unraid-update-status.json`, Unraid recreates on next update check |
|
||||||
|
| State desync (Unraid shows stale) | LOW | Manual "Check for Updates" in Unraid UI forces recalculation |
|
||||||
|
| Unraid version breaks format | MEDIUM | Disable sync feature via feature flag, update sync logic for new format |
|
||||||
|
| Network resolution broken | MEDIUM | Restart Docker service in Unraid (`Settings -> Docker -> Enable: No -> Yes`) |
|
||||||
|
| File permission errors | LOW | Helper script with proper permissions, OR mount file read-only + use API |
|
||||||
|
| n8n can't reach status file | HIGH | Architecture change required (add helper script OR switch to API) |
|
||||||
|
| Notification spam | LOW | Unraid notification settings: disable Docker update notifications temporarily |
|
||||||
|
|
||||||
|
## Pitfall-to-Phase Mapping
|
||||||
|
|
||||||
|
How roadmap phases should address these pitfalls.
|
||||||
|
|
||||||
|
| Pitfall | Prevention Phase | Verification |
|
||||||
|
|---------|------------------|--------------|
|
||||||
|
| State desync (Docker API vs Unraid) | Phase 1 (Investigation) + Phase 2 (Sync) | UAT: update via bot, verify Unraid shows "up to date" |
|
||||||
|
| Race condition (concurrent access) | Phase 2 (Sync Implementation) | Stress test: simultaneous bot update + manual Unraid check |
|
||||||
|
| Unraid version compatibility | Phase 1 (Format Documentation) + Phase 3 (Multi-version UAT) | Test on Unraid 6.12, 7.0, 7.2 |
|
||||||
|
| Filesystem access from container | Phase 1 (Architecture Decision) | Deploy to prod, verify file access or helper script works |
|
||||||
|
| Notification spam | Phase 2 (Batch Sync) | UAT: batch update 5+ containers, count notifications |
|
||||||
|
| n8n state persistence assumption | Phase 1 (Architecture) | Code review: reject any `staticData` usage for sync queue |
|
||||||
|
| Network recreation (br0) | Phase 2 (Update Flow) + Phase 3 (UAT) | Test: update container on custom network, verify resolution |
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
|
||||||
|
**HIGH confidence (official/authoritative):**
|
||||||
|
- [Unraid API — Docker and VM Integration](https://deepwiki.com/unraid/api/2.4.2-notification-system) — DockerService, DockerEventService architecture
|
||||||
|
- [Unraid API — Notifications Service](https://deepwiki.com/unraid/api/2.4.1-notifications-service) — Race condition handling, duplicate detection
|
||||||
|
- [Docker Socket Proxy Security](https://github.com/Tecnativa/docker-socket-proxy) — Security model, endpoint filtering
|
||||||
|
- [Docker Socket Security Critical Vulnerability Guide](https://medium.com/@instatunnel/docker-socket-security-a-critical-vulnerability-guide-76f4137a68c5) — Filesystem access risks
|
||||||
|
- [n8n Docker File System Access](https://community.n8n.io/t/file-system-access-in-docker-environment/214017) — Container filesystem limitations
|
||||||
|
|
||||||
|
**MEDIUM confidence (community-verified):**
|
||||||
|
- [Watchtower Discussion #1389](https://github.com/containrrr/watchtower/discussions/1389) — Unraid doesn't detect external updates
|
||||||
|
- [Unraid Docker Troubleshooting](https://docs.unraid.net/unraid-os/troubleshooting/common-issues/docker-troubleshooting/) — br0 network recreation issue
|
||||||
|
- [Unraid Forums: Docker Update Check](https://forums.unraid.net/topic/49041-warning-file_put_contentsvarlibdockerunraid-update-statusjson-blah/) — Status file location
|
||||||
|
- [Unraid Forums: 7.2.1 Docker Issues](https://forums.unraid.net/topic/195255-unraid-721-upgrade-seems-to-break-docker-functionalities/) — Version upgrade breaking changes
|
||||||
|
|
||||||
|
**LOW confidence (single source, needs validation):**
|
||||||
|
- File format structure (`/var/lib/docker/unraid-update-status.json`) — inferred from forum posts, not officially documented
|
||||||
|
- Unraid update check timing/frequency — user-configurable, no default documented
|
||||||
|
- Cache invalidation triggers — inferred from API docs, not explicitly tested
|
||||||
|
|
||||||
|
**Project-specific (from existing codebase):**
|
||||||
|
- STATE.md — n8n static data limitation (Phase 10.2 findings)
|
||||||
|
- ARCHITECTURE.md — Current system architecture, socket proxy usage
|
||||||
|
- CLAUDE.md — n8n workflow patterns, sub-workflow contracts
|
||||||
|
|
||||||
---
|
---
|
||||||
|
*Pitfalls research for: Unraid Update Status Sync*
|
||||||
## Phase Assignment Summary
|
*Researched: 2026-02-08*
|
||||||
|
|
||||||
| Phase | Pitfalls to Address |
|
|
||||||
|-------|---------------------|
|
|
||||||
| **API Setup** | API key scoping, header format, workflow ID discovery, env var blocking |
|
|
||||||
| **Socket Proxy** | Proxy configuration, permission settings, curl command migration, network setup |
|
|
||||||
| **Keyboards** | HTTP Request node for keyboards, callback_data limits, answerCallbackQuery |
|
|
||||||
| **Unraid Sync** | Update status file deletion, volume mount for access |
|
|
||||||
| **All Phases** | Auth flow consistency, test vs production, error workflow testing |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Confidence Assessment
|
|
||||||
|
|
||||||
| Area | Confidence | Rationale |
|
|
||||||
|------|------------|-----------|
|
|
||||||
| n8n API | HIGH | Official docs verified, known breaking changes documented |
|
|
||||||
| Docker Socket Proxy | HIGH | Official Tecnativa docs, community best practices verified |
|
|
||||||
| Telegram Keyboards | MEDIUM-HIGH | n8n GitHub issues confirm limitations, Telegram API docs verified |
|
|
||||||
| Unraid Integration | MEDIUM | Forum posts describe workaround, but file format undocumented |
|
|
||||||
| Integration Risks | MEDIUM | Based on existing v1.0 codebase analysis and general patterns |
|
|
||||||
|
|
||||||
**Research date:** 2026-02-02
|
|
||||||
**Valid until:** 2026-03-02 (30 days - n8n and Telegram APIs stable)
|
|
||||||
|
|||||||
+315
-305
@@ -1,385 +1,395 @@
|
|||||||
# Stack Research: v1.1 Features
|
# Technology Stack — Unraid Update Status Sync
|
||||||
|
|
||||||
**Project:** Unraid Docker Manager
|
**Project:** Unraid Docker Manager
|
||||||
**Researched:** 2026-02-02
|
**Milestone:** Update Status Sync (v1.3)
|
||||||
**Focus:** Stack additions for n8n API, Docker socket security, Telegram keyboards, Unraid integration
|
**Researched:** 2026-02-08
|
||||||
|
|
||||||
## n8n API Access
|
## Executive Summary
|
||||||
|
|
||||||
### Overview
|
**Recommendation:** Use Unraid's native GraphQL API with `updateContainer` mutation to sync status after bot-initiated container updates.
|
||||||
|
|
||||||
n8n provides a public REST API for programmatic workflow management. This enables Claude Code to read, update, and test workflows without manual UI interaction.
|
This approach leverages Unraid's official API (available since 7.2, via Connect plugin for <7.2) to call the same update mechanism the WebGUI uses. The GraphQL `updateContainer` mutation triggers Dynamix Docker Manager's update workflow, which automatically handles image digest comparison and updates `/var/lib/docker/unraid-update-status.json`.
|
||||||
|
|
||||||
### Authentication
|
**Confidence:** HIGH — Based on official Unraid API documentation, source code analysis, and GraphQL schema.
|
||||||
|
|
||||||
**Method:** API Key via HTTP header
|
|
||||||
|
|
||||||
| Setting | Value |
|
|
||||||
|---------|-------|
|
|
||||||
| Header name | `X-N8N-API-KEY` |
|
|
||||||
| Key location | n8n UI: Settings > n8n API > Create an API key |
|
|
||||||
| Base path | `/api/v1` |
|
|
||||||
|
|
||||||
**Environment Variables:**
|
|
||||||
- `N8N_PUBLIC_API_DISABLED=false` (default) - API enabled
|
|
||||||
- `N8N_PUBLIC_API_SWAGGERUI_DISABLED=false` (default) - Swagger UI enabled
|
|
||||||
|
|
||||||
The API is **enabled by default** on self-hosted n8n. No additional configuration needed unless it was explicitly disabled.
|
|
||||||
|
|
||||||
### Key Endpoints
|
|
||||||
|
|
||||||
| Endpoint | Method | Purpose |
|
|
||||||
|----------|--------|---------|
|
|
||||||
| `/api/v1/workflows` | GET | List all workflows |
|
|
||||||
| `/api/v1/workflows/{id}` | GET | Get workflow JSON |
|
|
||||||
| `/api/v1/workflows/{id}` | PUT | Update workflow |
|
|
||||||
| `/api/v1/workflows/{id}/activate` | POST | Activate workflow |
|
|
||||||
| `/api/v1/workflows/{id}/deactivate` | POST | Deactivate workflow |
|
|
||||||
| `/api/v1/executions` | GET | List executions (with logs) |
|
|
||||||
| `/api/v1/executions/{id}` | GET | Get execution details |
|
|
||||||
|
|
||||||
### API Playground
|
|
||||||
|
|
||||||
Self-hosted n8n includes a built-in Swagger UI at `/api/v1/docs` (or similar path based on configuration). This provides interactive documentation for testing API calls.
|
|
||||||
|
|
||||||
### Integration with Claude Code
|
|
||||||
|
|
||||||
To enable Claude Code workflow management:
|
|
||||||
|
|
||||||
1. Create API key in n8n Settings > n8n API
|
|
||||||
2. Store key securely (not in repository)
|
|
||||||
3. Use HTTP requests to n8n API endpoints
|
|
||||||
4. Example: `curl -H "X-N8N-API-KEY: <key>" http://localhost:5678/api/v1/workflows`
|
|
||||||
|
|
||||||
**Confidence:** MEDIUM - Official docs confirm API exists and authentication method. Specific endpoint paths verified through multiple sources but not directly tested.
|
|
||||||
|
|
||||||
**Sources:**
|
|
||||||
- [n8n API Authentication](https://docs.n8n.io/api/authentication/)
|
|
||||||
- [n8n API Reference](https://docs.n8n.io/api/api-reference/)
|
|
||||||
- [Disable Public API](https://docs.n8n.io/hosting/securing/disable-public-api/)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Docker Socket Security
|
## Recommended Stack Additions
|
||||||
|
|
||||||
### The Problem
|
### 1. Unraid GraphQL API Client
|
||||||
|
|
||||||
Current setup mounts Docker socket directly into internet-exposed n8n container:
|
| Component | Version | Purpose | Why |
|
||||||
```
|
|-----------|---------|---------|-----|
|
||||||
-v /var/run/docker.sock:/var/run/docker.sock
|
| HTTP Request (n8n built-in) | n8n 1.x | GraphQL API calls | Already available, no new dependencies |
|
||||||
```
|
| Unraid API | 7.2+ or Connect plugin | Container update status sync | Official Unraid API, supported mechanism |
|
||||||
|
|
||||||
This is a security risk: if n8n is compromised, attacker has full Docker (root) access to the host.
|
**Installation:** None required in n8n container. Requires Unraid API key creation on host.
|
||||||
|
|
||||||
### Solution: Docker Socket Proxy
|
**Network Access:**
|
||||||
|
- From n8n container → Unraid host: `http://host.docker.internal/graphql` (requires `--add-host=host.docker.internal:host-gateway`)
|
||||||
|
- Or use Unraid server IP: `http://192.168.x.x/graphql` or `http://tower.local/graphql`
|
||||||
|
|
||||||
A socket proxy sits between containers and the Docker socket, filtering API requests to only allow specific operations.
|
### 2. Authentication
|
||||||
|
|
||||||
### Option Comparison
|
| Component | Purpose | Storage | Why |
|
||||||
|
|-----------|---------|---------|-----|
|
||||||
| Feature | Tecnativa | LinuxServer | Wollomatic |
|
| Unraid API Key | GraphQL authentication | `.env.unraid-api` (gitignored) | Same pattern as n8n API credentials |
|
||||||
|---------|-----------|-------------|------------|
|
|
||||||
| Base | HAProxy (Alpine) | HAProxy (Alpine) | Go (scratch) |
|
|
||||||
| Image size | ~10MB | ~10MB | ~3MB |
|
|
||||||
| Config method | Environment variables | Environment variables | Regex allowlists |
|
|
||||||
| Granularity | Per-API section | Per-API section | Per-endpoint regex |
|
|
||||||
| Active maintenance | Yes | Yes | Yes |
|
|
||||||
| Unraid compatibility | Yes | Yes | Yes |
|
|
||||||
|
|
||||||
### Recommendation: LinuxServer/socket-proxy
|
|
||||||
|
|
||||||
**Why:** Drop-in replacement for Tecnativa with better documentation and active LinuxServer community support. Familiar to Unraid users.
|
|
||||||
|
|
||||||
### Configuration for This Project
|
|
||||||
|
|
||||||
The bot needs these Docker API operations:
|
|
||||||
- List containers (`/containers/json`)
|
|
||||||
- Inspect container (`/containers/{id}/json`)
|
|
||||||
- Start container (`/containers/{id}/start`)
|
|
||||||
- Stop container (`/containers/{id}/stop`)
|
|
||||||
- Restart container (`/containers/{id}/restart`)
|
|
||||||
- Pull image (`/images/create`)
|
|
||||||
- Create container (`/containers/create`)
|
|
||||||
- Remove container (`/containers/{id}`)
|
|
||||||
- Container logs (`/containers/{id}/logs`)
|
|
||||||
|
|
||||||
**Required Environment Variables:**
|
|
||||||
|
|
||||||
|
**Permissions Required:**
|
||||||
```bash
|
```bash
|
||||||
# LinuxServer socket-proxy configuration
|
unraid-api apikey --create \
|
||||||
CONTAINERS=1 # Container list/inspect
|
--name "Docker Manager Bot" \
|
||||||
IMAGES=1 # Image pull
|
--permissions "DOCKER:UPDATE_ANY" \
|
||||||
POST=1 # Enable POST requests (needed for start/stop/restart/create)
|
--description "Telegram bot container updates" \
|
||||||
ALLOW_START=1 # /containers/{id}/start
|
--json
|
||||||
ALLOW_STOP=1 # /containers/{id}/stop
|
|
||||||
ALLOW_RESTARTS=1 # /containers/{id}/restart (also enables /kill)
|
|
||||||
|
|
||||||
# Keep defaults (already enabled)
|
|
||||||
EVENTS=1 # Default
|
|
||||||
PING=1 # Default
|
|
||||||
VERSION=1 # Default
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Deployment Architecture
|
Minimum permission: `DOCKER:UPDATE_ANY` (allows calling `updateContainer` mutation)
|
||||||
|
|
||||||
```
|
|
||||||
[Internet]
|
|
||||||
|
|
|
||||||
[n8n container]
|
|
||||||
|
|
|
||||||
[socket-proxy] <-- internal network only
|
|
||||||
|
|
|
||||||
[Docker socket]
|
|
||||||
```
|
|
||||||
|
|
||||||
**n8n container changes:**
|
|
||||||
- Remove: `-v /var/run/docker.sock:/var/run/docker.sock`
|
|
||||||
- Add: `DOCKER_HOST=tcp://socket-proxy:2375`
|
|
||||||
- Add: Connect to same Docker network as socket-proxy
|
|
||||||
|
|
||||||
**Socket-proxy container:**
|
|
||||||
```bash
|
|
||||||
docker run -d \
|
|
||||||
--name socket-proxy \
|
|
||||||
--restart=unless-stopped \
|
|
||||||
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
|
||||||
--read-only \
|
|
||||||
--tmpfs /run \
|
|
||||||
-e CONTAINERS=1 \
|
|
||||||
-e IMAGES=1 \
|
|
||||||
-e POST=1 \
|
|
||||||
-e ALLOW_START=1 \
|
|
||||||
-e ALLOW_STOP=1 \
|
|
||||||
-e ALLOW_RESTARTS=1 \
|
|
||||||
--network internal \
|
|
||||||
lscr.io/linuxserver/socket-proxy:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
**CRITICAL:** Never expose socket-proxy port (2375) to external networks. Use internal Docker network only.
|
|
||||||
|
|
||||||
**Confidence:** HIGH - Official documentation from both Tecnativa and LinuxServer confirms configuration options and security model.
|
|
||||||
|
|
||||||
**Sources:**
|
|
||||||
- [Tecnativa docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy)
|
|
||||||
- [LinuxServer socket-proxy](https://docs.linuxserver.io/images/docker-socket-proxy/)
|
|
||||||
- [Wollomatic socket-proxy](https://github.com/wollomatic/socket-proxy)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Telegram Inline Keyboards
|
## Integration Architecture
|
||||||
|
|
||||||
### The Problem
|
### How Unraid Tracks Update Status
|
||||||
|
|
||||||
n8n's native Telegram node has limitations with inline keyboards:
|
**Three-layer system:**
|
||||||
1. Cannot pass dynamic JSON for `reply_markup`
|
|
||||||
2. Expressions in keyboard fields cause "The value is not supported!" errors
|
|
||||||
3. PR #17258 adding JSON keyboard support has been pending since July 2025
|
|
||||||
|
|
||||||
### Solution Options
|
1. **Image Digest Comparison** — Unraid's `DockerManifestService` compares local image digest with registry manifest
|
||||||
|
2. **Update Status File** — `/var/lib/docker/unraid-update-status.json` stores per-container status (`true` = up-to-date, `false` = update available, `undef` = unknown)
|
||||||
|
3. **Template Metadata** — XML templates in `/boot/config/plugins/dockerMan/templates-user/` store container configuration and version info
|
||||||
|
|
||||||
| Option | Approach | Pros | Cons |
|
**Critical Finding:** Unraid does NOT auto-detect external updates (e.g., via Watchtower or direct Docker API). The `updateContainer` mutation must be called to sync status.
|
||||||
|--------|----------|------|------|
|
|
||||||
| HTTP Request node | Direct Telegram API calls | Full control, no dependencies | Token in URL, more setup |
|
|
||||||
| Custom community node | @topvisor/n8n-nodes-telegram-send-message-custom | Easy JSON support | External dependency |
|
|
||||||
| Wait for PR #17258 | Native n8n support | No workarounds needed | Indefinite timeline |
|
|
||||||
|
|
||||||
### Recommendation: HTTP Request Node
|
**Source:** [limetech/dynamix DockerClient.php](https://github.com/limetech/dynamix/blob/master/plugins/dynamix.docker.manager/include/DockerClient.php) — `syncVersions()` function updates status file after successful update.
|
||||||
|
|
||||||
**Why:** No external dependencies, full Telegram API access, already proven pattern in similar projects.
|
### Update Sync Workflow
|
||||||
|
|
||||||
### Implementation
|
```
|
||||||
|
Bot updates container (current approach)
|
||||||
|
↓ docker pull + recreate via Docker API
|
||||||
|
↓ Container running new image
|
||||||
|
↓ Unraid still shows "update available" ← PROBLEM
|
||||||
|
↓
|
||||||
|
Call Unraid GraphQL API (new addition)
|
||||||
|
↓ mutation { docker { updateContainer(id: "...") { ... } } }
|
||||||
|
↓ Unraid's DockerService → Dynamix scripts
|
||||||
|
↓ syncVersions() writes to unraid-update-status.json
|
||||||
|
↓ Unraid UI shows "up-to-date" ← SOLVED
|
||||||
|
```
|
||||||
|
|
||||||
**Send Message with Inline Keyboard:**
|
**Idempotency:** Safe to call `updateContainer` even if already updated — Unraid checks current vs. remote digest and no-ops if already synced.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GraphQL API Details
|
||||||
|
|
||||||
|
### Endpoint
|
||||||
|
|
||||||
|
```
|
||||||
|
http://<unraid-host>/graphql
|
||||||
|
```
|
||||||
|
|
||||||
|
**Authentication:** Header `x-api-key: <your-api-key>`
|
||||||
|
|
||||||
|
### Key Mutations
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
mutation UpdateSingleContainer {
|
||||||
|
docker {
|
||||||
|
updateContainer(id: "docker:HmiXBlJefBRPMS0m4iNYc") {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation UpdateMultipleContainers {
|
||||||
|
docker {
|
||||||
|
updateContainers(ids: ["docker:abc123", "docker:def456"]) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Container ID Format:** `docker:<container_name>` or retrieve via query first.
|
||||||
|
|
||||||
|
**Source:** [Unraid API generated-schema.graphql](https://raw.githubusercontent.com/unraid/api/main/api/generated-schema.graphql)
|
||||||
|
|
||||||
|
### n8n Integration Pattern
|
||||||
|
|
||||||
|
**Node:** HTTP Request (built-in)
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
- Method: `POST`
|
||||||
|
- URL: `http://host.docker.internal/graphql` (or Unraid IP)
|
||||||
|
- Authentication: Header Auth
|
||||||
|
- Name: `x-api-key`
|
||||||
|
- Value: `{{$env.UNRAID_API_KEY}}` (from `.env.unraid-api`)
|
||||||
|
- Body (JSON):
|
||||||
```json
|
```json
|
||||||
// HTTP Request node
|
|
||||||
// URL: https://api.telegram.org/bot{{ $credentials.telegramApi.token }}/sendMessage
|
|
||||||
// Method: POST
|
|
||||||
// Body Type: JSON
|
|
||||||
{
|
{
|
||||||
"chat_id": "={{ $json.message.chat.id }}",
|
"query": "mutation { docker { updateContainer(id: \"docker:{{$json.containerName}}\") { id name state } } }"
|
||||||
"text": "Select a container:",
|
|
||||||
"parse_mode": "HTML",
|
|
||||||
"reply_markup": {
|
|
||||||
"inline_keyboard": [
|
|
||||||
[
|
|
||||||
{"text": "plex", "callback_data": "start:plex"},
|
|
||||||
{"text": "sonarr", "callback_data": "start:sonarr"}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{"text": "radarr", "callback_data": "start:radarr"},
|
|
||||||
{"text": "Cancel", "callback_data": "cancel"}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Handle Callback Query:**
|
**Data Flow:**
|
||||||
|
```
|
||||||
The workflow already handles `callback_query` via the Telegram Trigger node (confirmed in current workflow). The callback_data format `action:container` allows parsing:
|
Telegram callback (container updated)
|
||||||
|
→ Extract container name
|
||||||
```javascript
|
→ HTTP Request to Unraid GraphQL
|
||||||
// In Code node
|
→ Parse response
|
||||||
const callbackData = $json.callback_query.data;
|
→ Telegram confirmation message
|
||||||
const [action, container] = callbackData.split(':');
|
|
||||||
return { action, container };
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Answer Callback Query (remove loading spinner):**
|
---
|
||||||
|
|
||||||
|
## Alternatives Considered
|
||||||
|
|
||||||
|
| Approach | Pros | Cons | Verdict |
|
||||||
|
|----------|------|------|---------|
|
||||||
|
| **GraphQL API `updateContainer`** | Official API, handles all sync logic, idempotent, supported | Requires API key setup | **RECOMMENDED** |
|
||||||
|
| **Direct file write to `unraid-update-status.json`** | Simple, no auth needed | Brittle (file format undocumented), doesn't trigger UI refresh, race conditions with Unraid's update checker | **DO NOT USE** |
|
||||||
|
| **Shell exec via Docker socket** | Could call Dynamix scripts directly | Extremely fragile, requires PHP runtime, breaks on Unraid updates | **DO NOT USE** |
|
||||||
|
| **Watchtower pattern (do nothing)** | No code changes | Leaves stale "update available" badges, false-positive notifications | **Current problem** |
|
||||||
|
| **GraphQL `updateAllContainers`** | Syncs everything | Overkill (re-checks all containers), slower | **Use for batch sync only** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File System Access (NOT Recommended)
|
||||||
|
|
||||||
|
**Investigated but rejected:**
|
||||||
|
|
||||||
|
### `/var/lib/docker/unraid-update-status.json`
|
||||||
|
|
||||||
|
**Structure (observed):**
|
||||||
```json
|
```json
|
||||||
// HTTP Request node
|
|
||||||
// URL: https://api.telegram.org/bot{{ $credentials.telegramApi.token }}/answerCallbackQuery
|
|
||||||
// Method: POST
|
|
||||||
{
|
{
|
||||||
"callback_query_id": "={{ $json.callback_query.id }}",
|
"container1": true,
|
||||||
"text": "Processing..."
|
"container2": false,
|
||||||
|
"container3": "undef"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Callback Data Limits
|
**Why not write directly:**
|
||||||
|
1. **Format undocumented** — File structure found via forum posts, not official docs
|
||||||
|
2. **No UI refresh trigger** — Writing file doesn't notify WebGUI to refresh
|
||||||
|
3. **Race conditions** — Unraid's update checker runs periodically, may overwrite changes
|
||||||
|
4. **Brittle** — File location/format could change without notice
|
||||||
|
|
||||||
Telegram limits `callback_data` to 64 bytes. Use short encodings:
|
**Confidence:** MEDIUM (structure inferred from forum posts, confirmed in source code)
|
||||||
- `s:plex` instead of `start:plex`
|
|
||||||
- Single char actions: s=start, t=stop, r=restart, u=update, l=logs
|
|
||||||
|
|
||||||
### Alternative: Custom Community Node
|
**Source:** [Unraid Forums — Docker Update Status](https://forums.unraid.net/topic/114415-plugin-docker-compose-manager/page/9/)
|
||||||
|
|
||||||
If HTTP Request becomes unwieldy, install:
|
### `/boot/config/plugins/dockerMan/templates-user/`
|
||||||
```
|
|
||||||
Settings > Community Nodes > Install
|
|
||||||
Package: @topvisor/n8n-nodes-telegram-send-message-custom
|
|
||||||
```
|
|
||||||
|
|
||||||
This allows passing any Telegram API parameters as JSON, including `reply_markup`.
|
**Contains:** XML templates with container configuration, including `<Date>` and `<DateInstalled>` fields (internal, auto-managed by Unraid).
|
||||||
|
|
||||||
**Confidence:** MEDIUM - HTTP Request approach confirmed working by multiple community members. Native node limitations confirmed by open issues and PR #17258.
|
**Why not modify:** Templates are for configuration, not runtime status. Unraid ignores template dates for update checking (uses image digests instead).
|
||||||
|
|
||||||
**Sources:**
|
|
||||||
- [n8n Telegram Callback Operations](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.telegram/callback-operations/)
|
|
||||||
- [PR #17258: JSON Keyboard Support](https://github.com/n8n-io/n8n/pull/17258)
|
|
||||||
- [Custom Telegram Node](https://github.com/topvisor/n8n-nodes-telegram-send-message-custom)
|
|
||||||
- [Telegram Bot API - Inline Keyboards](https://core.telegram.org/bots/api#inlinekeyboardmarkup)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Unraid Integration
|
## Network Configuration
|
||||||
|
|
||||||
### How Unraid Detects Updates
|
### Docker Network Modes in Unraid
|
||||||
|
|
||||||
Unraid checks for Docker image updates by comparing local image digests against remote registry digests:
|
| Mode | Access Unraid Host | Use Case |
|
||||||
|
|------|-------------------|----------|
|
||||||
|
| **Bridge** | Via `172.17.0.1` (gateway) or `host.docker.internal` | Default, port mapping |
|
||||||
|
| **Host** | Via `localhost` | Direct host network access |
|
||||||
|
| **Custom:br0** | Via Unraid IP (macvlan, separate network) | Own IP on LAN |
|
||||||
|
|
||||||
1. Local image has digest (e.g., `35049b54ac64`)
|
**n8n container likely uses:** Bridge mode (most common for Unraid containers)
|
||||||
2. Unraid queries registry for `latest` tag digest (e.g., `96c1da19c304`)
|
|
||||||
3. If different, shows "Update Available" badge
|
|
||||||
|
|
||||||
Update status is stored in: `/var/lib/docker/unraid-update-status.json`
|
### Accessing Unraid API from n8n Container
|
||||||
|
|
||||||
### The Problem
|
|
||||||
|
|
||||||
When containers are updated externally (Watchtower, Portainer, or our bot), Unraid doesn't detect the change:
|
|
||||||
- Container updates successfully
|
|
||||||
- Unraid still shows "Update Available" badge
|
|
||||||
- Manual "Check for Updates" doesn't fix it
|
|
||||||
- Only deleting `unraid-update-status.json` and re-checking clears it
|
|
||||||
|
|
||||||
### Root Cause
|
|
||||||
|
|
||||||
Unraid only checks for **newly available** updates, not for containers that are **no longer** out of date. This is a known regression/limitation in Unraid's Docker management.
|
|
||||||
|
|
||||||
### Solution Options
|
|
||||||
|
|
||||||
| Option | Approach | Reliability |
|
|
||||||
|--------|----------|-------------|
|
|
||||||
| Delete status file | `rm /var/lib/docker/unraid-update-status.json` after update | HIGH - forces full recheck |
|
|
||||||
| Trigger recheck | Unraid WebUI "Check for Updates" after file delete | MEDIUM - requires UI or API |
|
|
||||||
| Accept mismatch | Document that badge may be stale | LOW - poor UX |
|
|
||||||
|
|
||||||
### Recommendation: Delete Status File + Document
|
|
||||||
|
|
||||||
**Approach:**
|
|
||||||
1. After bot successfully updates a container, delete the status file
|
|
||||||
2. Document that users should click "Check for Updates" in Unraid UI to refresh badges
|
|
||||||
3. Future enhancement: investigate if Unraid has an API to trigger update check
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
|
|
||||||
Add to update workflow after successful container recreation:
|
|
||||||
|
|
||||||
|
**Option 1: host.docker.internal (recommended)**
|
||||||
```bash
|
```bash
|
||||||
# In Execute Command node (runs on Unraid host)
|
# Add to n8n container config (via Unraid Docker template):
|
||||||
rm -f /var/lib/docker/unraid-update-status.json
|
--add-host=host.docker.internal:host-gateway
|
||||||
|
|
||||||
|
# Then in n8n workflow:
|
||||||
|
URL: http://host.docker.internal/graphql
|
||||||
```
|
```
|
||||||
|
|
||||||
**Caveat:** This requires the n8n container to have access to `/var/lib/docker/` on the host, which is a security consideration. Alternative: document the manual step.
|
**Option 2: Unraid hostname/IP**
|
||||||
|
```
|
||||||
|
URL: http://tower.local/graphql
|
||||||
|
# or
|
||||||
|
URL: http://192.168.1.100/graphql # Replace with actual Unraid IP
|
||||||
|
```
|
||||||
|
|
||||||
### Integration Points
|
**Verification:**
|
||||||
|
```bash
|
||||||
|
# From inside n8n container:
|
||||||
|
docker exec -it n8n curl -I http://host.docker.internal/graphql
|
||||||
|
# Should return HTTP 400 (GraphQL requires POST) or 200
|
||||||
|
```
|
||||||
|
|
||||||
| File/API | Purpose | Access Method |
|
**Source:** [Docker host.docker.internal guide](https://eastondev.com/blog/en/posts/dev/20251217-docker-host-access/)
|
||||||
|----------|---------|---------------|
|
|
||||||
| `/var/lib/docker/unraid-update-status.json` | Update badge status | Host filesystem |
|
|
||||||
| Unraid WebUI | Trigger update check | Manual (no API found) |
|
|
||||||
|
|
||||||
**Confidence:** MEDIUM - File location and behavior confirmed by multiple Unraid forum threads. No official Unraid API documentation found for programmatic update checks.
|
|
||||||
|
|
||||||
**Sources:**
|
|
||||||
- [Unraid Forum: Docker shows "update ready" after updating](https://forums.unraid.net/topic/157820-docker-shows-update-ready-after-updating/)
|
|
||||||
- [Watchtower + Unraid Discussion](https://github.com/containrrr/watchtower/discussions/1389)
|
|
||||||
- [Unraid Forum: Incorrect docker update notification](https://forums.unraid.net/bug-reports/stable-releases/regression-incorrect-docker-update-notification-r2807/)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Recommendations Summary
|
## Security Considerations
|
||||||
|
|
||||||
### Stack Additions
|
### API Key Management
|
||||||
|
|
||||||
| Component | Recommendation | Confidence |
|
**Storage:**
|
||||||
|-----------|----------------|------------|
|
- Add to `.env.unraid-api` (already gitignored)
|
||||||
| n8n API | Use existing public API with API key auth | MEDIUM |
|
- Load in n8n workflow via environment variables
|
||||||
| Docker security | LinuxServer socket-proxy | HIGH |
|
|
||||||
| Telegram keyboards | HTTP Request node to Telegram API | MEDIUM |
|
|
||||||
| Unraid sync | Delete status file after update | MEDIUM |
|
|
||||||
|
|
||||||
### Implementation Order
|
**Permissions:**
|
||||||
|
- Use **least privilege**: `DOCKER:UPDATE_ANY` only
|
||||||
|
- Avoid `--roles ADMIN` (grants full access)
|
||||||
|
|
||||||
1. **Docker socket proxy** - Security improvement, low risk, well-documented
|
**Rotation:**
|
||||||
2. **Telegram inline keyboards** - UX improvement, proven pattern
|
- API keys don't expire, but should be rotated periodically
|
||||||
3. **n8n API access** - Developer tooling, not user-facing
|
- Delete via CLI: `unraid-api apikey --delete <key-id>`
|
||||||
4. **Unraid update sync** - Nice-to-have, requires additional host access
|
|
||||||
|
|
||||||
### No New Dependencies Required
|
**Source:** [Unraid API Key Management](https://docs.unraid.net/API/programmatic-api-key-management/)
|
||||||
|
|
||||||
All solutions use existing n8n capabilities:
|
### Network Exposure
|
||||||
- HTTP Request node (Telegram API, Docker via proxy)
|
|
||||||
- Execute Command node (Unraid file deletion)
|
|
||||||
- n8n public API (existing feature)
|
|
||||||
|
|
||||||
The only new container is `socket-proxy`, which is infrastructure, not application code.
|
**Unraid API runs on:**
|
||||||
|
- HTTP (port 80) or HTTPS (port 443) on Unraid host
|
||||||
|
- Same interface as WebGUI
|
||||||
|
|
||||||
### Key Risks
|
**Risk:** n8n container can access full GraphQL API (not just Docker mutations)
|
||||||
|
|
||||||
| Risk | Mitigation |
|
**Mitigation:** Use scoped API key (limits permissions to Docker operations only)
|
||||||
|------|------------|
|
|
||||||
| Socket proxy misconfiguration | Test each Docker operation after setup |
|
|
||||||
| Telegram API token exposure | Use n8n credentials, never log full URLs |
|
|
||||||
| Unraid status file access | May need additional volume mount or manual step |
|
|
||||||
| n8n API key security | Store outside repository, rotate periodically |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Metadata
|
## Implementation Checklist
|
||||||
|
|
||||||
**Research date:** 2026-02-02
|
- [ ] Create Unraid API key with `DOCKER:UPDATE_ANY` permission
|
||||||
**Valid until:** 2026-03-02 (30 days)
|
- [ ] Add API key to `.env.unraid-api` file
|
||||||
|
- [ ] Verify n8n container can reach `http://host.docker.internal/graphql` (add `--add-host` if needed)
|
||||||
|
- [ ] Create HTTP Request credential in n8n (Header Auth with `x-api-key`)
|
||||||
|
- [ ] Add GraphQL mutation call to Update sub-workflow after successful Docker API update
|
||||||
|
- [ ] Test: Update container via bot → verify Unraid UI shows "up-to-date"
|
||||||
|
- [ ] Handle errors: GraphQL response parsing, network failures, auth errors
|
||||||
|
|
||||||
**Confidence breakdown:**
|
---
|
||||||
- n8n API: MEDIUM - Docs confirm existence, specific endpoints need validation
|
|
||||||
- Docker socket proxy: HIGH - Official docs, multiple implementations
|
|
||||||
- Telegram keyboards: MEDIUM - Community-confirmed workarounds
|
|
||||||
- Unraid integration: MEDIUM - Forum-confirmed behavior, no official API
|
|
||||||
|
|
||||||
**Gaps:**
|
## What NOT to Add
|
||||||
- n8n API specific endpoint paths should be validated via Swagger UI
|
|
||||||
- Unraid may have undocumented API for update checks (not found)
|
**Do NOT add:**
|
||||||
- PR #17258 merge timeline unknown
|
- ❌ File system watchers for `/var/lib/docker/unraid-update-status.json`
|
||||||
|
- ❌ Custom PHP scripts to call Dynamix functions
|
||||||
|
- ❌ Cron jobs to periodically sync status
|
||||||
|
- ❌ Docker socket mounting to execute Unraid shell commands
|
||||||
|
- ❌ Watchtower or similar auto-update tools (conflicts with bot's update control)
|
||||||
|
|
||||||
|
**Why:** These approaches are brittle, unsupported, or conflict with the bot's explicit update model.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Version Compatibility
|
||||||
|
|
||||||
|
| Unraid Version | API Availability | Notes |
|
||||||
|
|----------------|-----------------|-------|
|
||||||
|
| 7.2+ | Built-in | Native GraphQL API |
|
||||||
|
| 6.9 - 7.1 | Via Connect plugin | Install from Community Applications |
|
||||||
|
| <6.9 | Not available | Upgrade Unraid required |
|
||||||
|
|
||||||
|
**Check version:**
|
||||||
|
```bash
|
||||||
|
# SSH to Unraid:
|
||||||
|
cat /etc/unraid-version
|
||||||
|
```
|
||||||
|
|
||||||
|
**Install Connect plugin (pre-7.2):**
|
||||||
|
1. Apps → Search "Unraid Connect"
|
||||||
|
2. Install plugin
|
||||||
|
3. Settings → Management Access → API → Enable
|
||||||
|
|
||||||
|
**Source:** [Unraid API Documentation](https://docs.unraid.net/API/)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Open Questions & Validation Needed
|
||||||
|
|
||||||
|
**Low-priority research flags:**
|
||||||
|
|
||||||
|
1. **Container ID resolution** — Does GraphQL require `docker:<name>` prefix, or just `<name>`?
|
||||||
|
- **Resolution:** Query containers first to get exact ID format
|
||||||
|
- **Impact:** Low (easily testable during implementation)
|
||||||
|
|
||||||
|
2. **Rate limiting** — Does Unraid API have rate limits for mutations?
|
||||||
|
- **Confidence:** LOW (not documented)
|
||||||
|
- **Impact:** Low (bot updates are infrequent, <10/min even in batch mode)
|
||||||
|
|
||||||
|
3. **GraphQL subscription for status changes** — Could bot subscribe to Docker events?
|
||||||
|
- **Finding:** Schema includes subscriptions, but not needed for status sync
|
||||||
|
- **Verdict:** Defer to future enhancement (real-time status monitoring)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sources & Confidence Assessment
|
||||||
|
|
||||||
|
| Finding | Confidence | Primary Source |
|
||||||
|
|---------|-----------|----------------|
|
||||||
|
| GraphQL API exists with updateContainer mutation | HIGH | [Unraid API Schema](https://raw.githubusercontent.com/unraid/api/main/api/generated-schema.graphql) |
|
||||||
|
| updateContainer triggers Dynamix sync workflow | HIGH | [DeepWiki — Docker Integration](https://deepwiki.com/unraid/api/2.4-docker-integration) |
|
||||||
|
| syncVersions() updates status JSON file | HIGH | [limetech/dynamix source](https://github.com/limetech/dynamix/blob/master/plugins/dynamix.docker.manager/include/DockerClient.php) |
|
||||||
|
| API key requires DOCKER:UPDATE_ANY permission | MEDIUM | [API Key Management](https://docs.unraid.net/API/programmatic-api-key-management/) (exact permission not explicitly stated) |
|
||||||
|
| Container ID format is "docker:<name>" | MEDIUM | [Unraid API examples](https://github.com/domalab/unraid-api-client/blob/main/UNRAIDAPI.md) (needs verification) |
|
||||||
|
| host.docker.internal works in Unraid Docker | MEDIUM | [Forum discussions](https://forums.unraid.net/topic/95050-how-to-use-the-hosts-ip-address-inside-a-docker-container/) (standard Docker feature, but Unraid-specific confirmation limited) |
|
||||||
|
| /var/lib/docker/unraid-update-status.json structure | MEDIUM | [Forum posts](https://forums.unraid.net/topic/114415-plugin-docker-compose-manager/page/9/) (observed, not officially documented) |
|
||||||
|
| No rate limiting on GraphQL API | LOW | Assumption (not documented either way) |
|
||||||
|
|
||||||
|
**Overall Confidence: HIGH** — Core approach (GraphQL API) is well-documented and official. Implementation details need testing but low-risk.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps for Roadmap
|
||||||
|
|
||||||
|
**Phase structure recommendations:**
|
||||||
|
|
||||||
|
1. **Phase 1: API Setup & Testing**
|
||||||
|
- Create API key
|
||||||
|
- Test GraphQL query/mutation from command line
|
||||||
|
- Verify network access from n8n container
|
||||||
|
- **Why first:** Validates approach before n8n integration
|
||||||
|
|
||||||
|
2. **Phase 2: n8n Integration**
|
||||||
|
- Add HTTP Request node to Update sub-workflow
|
||||||
|
- GraphQL mutation call after Docker update
|
||||||
|
- Error handling for API failures
|
||||||
|
- **Why second:** Builds on validated API access
|
||||||
|
|
||||||
|
3. **Phase 3: Batch Sync Support**
|
||||||
|
- Optional: Call `updateContainers` (plural) for batch updates
|
||||||
|
- Handle partial failures (some containers sync, others fail)
|
||||||
|
- **Why third:** Enhancement after core functionality works
|
||||||
|
|
||||||
|
**Research flags:**
|
||||||
|
- Phase 1: Likely needs deeper research (network access testing, container ID format verification)
|
||||||
|
- Phase 2: Standard patterns, unlikely to need additional research
|
||||||
|
- Phase 3: Defer until Phase 2 validates approach
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Additional Resources
|
||||||
|
|
||||||
|
**Official Documentation:**
|
||||||
|
- [Unraid API Overview](https://docs.unraid.net/API/)
|
||||||
|
- [Using the Unraid API](https://docs.unraid.net/API/how-to-use-the-api/)
|
||||||
|
- [GraphQL Schema (raw)](https://raw.githubusercontent.com/unraid/api/main/api/generated-schema.graphql)
|
||||||
|
- [API Key Management](https://docs.unraid.net/API/programmatic-api-key-management/)
|
||||||
|
|
||||||
|
**Community Resources:**
|
||||||
|
- [Unraid MCP Server](https://github.com/jmagar/unraid-mcp) — Reference implementation of GraphQL client
|
||||||
|
- [Home Assistant Unraid Integration](https://github.com/domalab/unraid-api-client) — Another GraphQL client example
|
||||||
|
|
||||||
|
**Source Code:**
|
||||||
|
- [limetech/dynamix](https://github.com/limetech/dynamix) — Unraid's Docker Manager plugin
|
||||||
|
- [unraid/api](https://github.com/unraid/api) — Official API monorepo
|
||||||
|
|
||||||
|
**Forum Discussions:**
|
||||||
|
- [Watchtower not syncing status](https://github.com/containrrr/watchtower/discussions/1389)
|
||||||
|
- [Docker update status not reflected](https://forums.unraid.net/topic/149953-docker-update-via-watchtower-status-not-reflected-in-unraid/)
|
||||||
|
|||||||
+178
-196
@@ -1,268 +1,250 @@
|
|||||||
# Research Summary: v1.1 n8n Integration & Polish
|
# Project Research Summary
|
||||||
|
|
||||||
**Project:** Unraid Docker Manager
|
**Project:** Unraid Docker Manager v1.3 — Update Status Sync
|
||||||
**Domain:** Telegram Bot Enhancement / Security Hardening
|
**Domain:** Docker container management integration with Unraid server
|
||||||
**Researched:** 2026-02-02
|
**Researched:** 2026-02-08
|
||||||
**Confidence:** MEDIUM-HIGH
|
**Confidence:** HIGH
|
||||||
|
|
||||||
## Executive Summary
|
## Executive Summary
|
||||||
|
|
||||||
The v1.1 milestone focuses on four areas: Docker socket security (critical), Telegram UX improvements (inline keyboards), n8n API access (development workflow), and Unraid update sync (nice-to-have). Research confirms all features are achievable with existing n8n capabilities and no new application dependencies beyond a Docker socket proxy container.
|
Unraid tracks container update status through an internal state file (`/var/lib/docker/unraid-update-status.json`) that is only updated when updates are initiated through Unraid's WebGUI or GraphQL API. When containers are updated externally via Docker API (as the bot currently does), Unraid's state becomes stale, showing false "update available" badges and sending duplicate notifications. This is the core pain point for v1.3.
|
||||||
|
|
||||||
The recommended approach is security-first: deploy the Docker socket proxy before any workflow changes, then migrate existing curl commands to use TCP instead of Unix socket. This order minimizes risk and provides a clean foundation. Telegram inline keyboards require HTTP Request nodes due to n8n native node limitations with dynamic keyboards. The n8n API is enabled by default on self-hosted instances and requires only an API key for Claude Code access.
|
The recommended approach is to use Unraid's official GraphQL API with the `updateContainer` mutation. This leverages the same mechanism Unraid's WebGUI uses and automatically handles status file synchronization, image digest comparison, and UI refresh. The GraphQL API is available natively in Unraid 7.2+ or via the Connect plugin for earlier versions. This approach is significantly more robust than direct file manipulation, is version-safe, and has proper error handling.
|
||||||
|
|
||||||
Key risk is breaking existing functionality during socket proxy migration. All 15+ Execute Command nodes using `--unix-socket` must be updated simultaneously. The mitigation is incremental migration with comprehensive testing before removing direct socket access. Unraid update sync has the lowest confidence - it works via file deletion but requires additional volume mounts.
|
Key risks include race conditions between bot updates and Unraid's periodic update checker, version compatibility across Unraid 6.x-7.x, and ensuring n8n container has proper network access to the Unraid host's GraphQL endpoint. These are mitigated through atomic operations via the GraphQL API, version detection, and using `host.docker.internal` networking with proper container configuration.
|
||||||
|
|
||||||
---
|
## Key Findings
|
||||||
|
|
||||||
## Stack Additions
|
### Recommended Stack
|
||||||
|
|
||||||
| Component | Purpose | Why This Choice |
|
**Use Unraid's GraphQL API via n8n's built-in HTTP Request node** — no new dependencies required. The GraphQL API is the official Unraid interface and handles all status synchronization internally through the DockerService and Dynamix Docker Manager integration.
|
||||||
|-----------|---------|-----------------|
|
|
||||||
| **LinuxServer socket-proxy** | Docker socket security | HAProxy-based filtering, active maintenance, Unraid community familiarity |
|
|
||||||
| **n8n REST API** | Programmatic workflow management | Already enabled by default, no new dependencies |
|
|
||||||
| **HTTP Request nodes** | Dynamic Telegram keyboards | Workaround for n8n native node limitations with inline keyboards |
|
|
||||||
|
|
||||||
**No new application dependencies** - all solutions use existing n8n capabilities:
|
**Core technologies:**
|
||||||
- HTTP Request node for Telegram API and Docker via proxy
|
- **Unraid GraphQL API (7.2+ or Connect plugin)**: Container update status sync — Official API, same mechanism as WebGUI, handles all internal state updates automatically
|
||||||
- Execute Command node for Unraid file operations
|
- **HTTP Request (n8n built-in)**: GraphQL client — Already available, no new dependencies, simple POST request pattern
|
||||||
- n8n public API for Claude Code workflow management
|
- **Unraid API Key**: Authentication — Same credential pattern as existing n8n API keys, stored in `.env.unraid-api`
|
||||||
|
|
||||||
**Socket proxy environment variables (minimum required):**
|
**Network requirements:**
|
||||||
```bash
|
- n8n container → Unraid host via `http://host.docker.internal/graphql`
|
||||||
CONTAINERS=1 # List/inspect containers
|
- Requires `--add-host=host.docker.internal:host-gateway` in n8n container config
|
||||||
IMAGES=1 # Pull images for updates
|
- Alternative: Use Unraid IP directly (`http://tower.local/graphql` or `http://192.168.x.x/graphql`)
|
||||||
POST=1 # Enable write operations
|
|
||||||
ALLOW_START=1 # Container start
|
**Critical finding from stack research:** Direct file manipulation of `/var/lib/docker/unraid-update-status.json` was investigated but rejected. The file format is undocumented, doesn't trigger UI refresh, and is prone to race conditions. The GraphQL API is the proper abstraction layer.
|
||||||
ALLOW_STOP=1 # Container stop
|
|
||||||
ALLOW_RESTARTS=1 # Container restart/kill
|
### Expected Features
|
||||||
|
|
||||||
|
Based on feature research, the v1.3 scope is tightly focused on solving the core pain point.
|
||||||
|
|
||||||
|
**Must have (table stakes):**
|
||||||
|
- Clear "update available" badge after bot updates container — Users expect Unraid UI to reflect reality after external updates
|
||||||
|
- Prevent duplicate update notifications — After bot updates, Unraid shouldn't send false-positive Telegram notifications
|
||||||
|
- Automatic sync after every update — Zero user intervention, bot handles sync transparently
|
||||||
|
|
||||||
|
**Should have (v1.4+):**
|
||||||
|
- Manual sync command (`/sync`) — Trigger when user updates via other tools (Portainer, CLI, Watchtower)
|
||||||
|
- Read Unraid update status for better detection — Parse Unraid's view to enhance bot's container selection UI
|
||||||
|
- Batch status sync — Optimize multi-container update operations
|
||||||
|
|
||||||
|
**Defer (v2+):**
|
||||||
|
- Bidirectional status awareness — Use Unraid's update detection as source of truth instead of Docker digest comparison
|
||||||
|
- Persistent monitoring daemon — Real-time sync via Docker events (conflicts with n8n's workflow execution model)
|
||||||
|
- Full Unraid API integration — Authentication, template parsing, web session management (overly complex for cosmetic badge)
|
||||||
|
|
||||||
|
**Anti-features identified:**
|
||||||
|
- Automatic template XML regeneration (breaks container configuration)
|
||||||
|
- Sync status for ALL containers on every operation (performance impact, unnecessary)
|
||||||
|
- Full Unraid API integration via authentication/sessions (complexity overkill for status sync)
|
||||||
|
|
||||||
|
### Architecture Approach
|
||||||
|
|
||||||
|
**Extend n8n-update.json sub-workflow with a single HTTP Request node** that calls Unraid's GraphQL `updateContainer` mutation after successful Docker API update. This keeps sync tightly coupled to update operations, requires minimal architectural changes, and maintains single responsibility (update sub-workflow owns all update-related actions).
|
||||||
|
|
||||||
|
**Major components:**
|
||||||
|
1. **Clear Unraid Status (NEW node)** — HTTP Request to GraphQL API after "Remove Old Image (Success)", calls `mutation { docker { updateContainer(id: "docker:containerName") } }`
|
||||||
|
2. **n8n container configuration (modified)** — Add `--add-host=host.docker.internal:host-gateway` for network access to Unraid host
|
||||||
|
3. **Unraid API credential (NEW)** — API key stored in `.env.unraid-api`, loaded via n8n credential system, requires `DOCKER:UPDATE_ANY` permission
|
||||||
|
|
||||||
|
**Data flow:**
|
||||||
|
```
|
||||||
|
Update sub-workflow success → Extract container name → HTTP Request to GraphQL
|
||||||
|
→ Unraid's DockerService executes syncVersions() → Update status file written
|
||||||
|
→ Return to sub-workflow → Success response to user
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
**Rejected alternatives:**
|
||||||
|
- **Direct file write** — Brittle, undocumented format, no UI refresh, race conditions
|
||||||
|
- **New sub-workflow (n8n-unraid-sync.json)** — Overkill for single operation
|
||||||
|
- **Main workflow integration** — Adds latency, harder to test
|
||||||
|
- **Helper script on host** — Unnecessary complexity when GraphQL API exists
|
||||||
|
|
||||||
## Feature Table Stakes
|
### Critical Pitfalls
|
||||||
|
|
||||||
### Must Have
|
Research identified 7 critical pitfalls with phase-specific prevention strategies:
|
||||||
|
|
||||||
| Feature | Rationale |
|
1. **State Desync Between Docker API and Unraid's Internal Tracking** — GraphQL API solves this by using Unraid's official update mechanism instead of direct file manipulation. Validation: Update via bot, verify Unraid shows "up-to-date" after manual "Check for Updates"
|
||||||
|---------|-----------|
|
|
||||||
| **Docker socket proxy** | Security requirement - remove root-equivalent access from internet-exposed n8n |
|
|
||||||
| **Inline keyboard callback handling** | Already partially implemented; must complete for button responses |
|
|
||||||
| **answerCallbackQuery responses** | Telegram requirement - loading spinner persists up to 1 minute without it |
|
|
||||||
| **n8n API key setup** | Enables programmatic workflow management for Claude Code |
|
|
||||||
| **Batch update with progress** | Core batch use case - `update plex sonarr radarr` with per-container feedback |
|
|
||||||
|
|
||||||
### Should Have
|
2. **Race Condition Between Unraid's Periodic Update Check and Bot Sync** — GraphQL `updateContainer` mutation is idempotent and atomic. Even if Unraid's update checker runs concurrently, no file corruption or lost updates occur. The API handles synchronization internally.
|
||||||
|
|
||||||
| Feature | Rationale |
|
3. **Unraid Version Compatibility** — GraphQL API is stable across Unraid 6.9+ (via Connect plugin) and 7.2+ (native). Version detection should check `/etc/unraid-version` and verify API availability before sync. If GraphQL unavailable, log error and skip sync (preserve bot functionality).
|
||||||
|---------|-----------|
|
|
||||||
| **Container action buttons** | Tap-to-action UX improvement over typing commands |
|
|
||||||
| **Confirmation dialogs** | "Are you sure?" before stop/restart/update prevents accidents |
|
|
||||||
| **"Update all" command** | Convenience feature with mandatory confirmation |
|
|
||||||
| **Unraid status file sync** | Clear "update available" badge after bot updates (file deletion method) |
|
|
||||||
|
|
||||||
### Defer to v2+
|
4. **Docker Socket Proxy Blocks Filesystem Access** — Resolved by using GraphQL API instead of direct file access. n8n only needs HTTP access to Unraid host, not filesystem mounts. This preserves security boundaries.
|
||||||
|
|
||||||
| Feature | Rationale |
|
5. **Notification Spam During Batch Updates** — Batch updates should collect all container names and call `updateContainers` (plural) mutation once after batch completes, not per-container. This triggers single status recalculation instead of N notifications.
|
||||||
|---------|-----------|
|
|
||||||
| **Unraid GraphQL API integration** | Requires Unraid 7.2+, adds complexity |
|
|
||||||
| **MCP integration for n8n** | Unofficial server exists but adds significant complexity |
|
|
||||||
| **Cancel mid-batch** | Requires state management complexity |
|
|
||||||
| **Pagination for containers** | Only needed if >10 containers common |
|
|
||||||
|
|
||||||
---
|
6. **n8n Workflow State Doesn't Persist** — Sync happens within same execution (no cross-execution state needed). Batch updates already collect results in single execution, sync after loop completes. No reliance on static data.
|
||||||
|
|
||||||
## Architecture Changes
|
7. **Unraid's br0 Network Recreate** — Not directly related to status sync, but update flow must preserve network config. Current n8n-update.json uses Docker API recreate — verify network settings are copied from old container inspect to new create body.
|
||||||
|
|
||||||
### Target Architecture
|
## Implications for Roadmap
|
||||||
|
|
||||||
```
|
Based on combined research, v1.3 should be structured as 3 focused phases:
|
||||||
User -> Telegram -> n8n webhook -> curl -> socket-proxy:2375 -> docker.sock -> Docker Engine
|
|
||||||
^
|
|
||||||
|
|
|
||||||
Claude Code -> n8n API --+
|
|
||||||
```
|
|
||||||
|
|
||||||
### Key Integration Points
|
### Phase 1: API Setup & Network Access
|
||||||
|
**Rationale:** Validate the GraphQL approach before n8n integration. Infrastructure changes first, workflow changes second.
|
||||||
|
|
||||||
| Component | Change | Impact |
|
**Delivers:**
|
||||||
|-----------|--------|--------|
|
- Unraid API key created with `DOCKER:UPDATE_ANY` permission
|
||||||
| **socket-proxy container** | NEW - sidecar on internal network | Infrastructure |
|
- Network access verified from n8n container to Unraid host
|
||||||
| **n8n container** | MODIFY - `DOCKER_HOST=tcp://socket-proxy:2375`, remove socket mount | Medium |
|
- Container ID format documented (via GraphQL query test)
|
||||||
| **Execute Command nodes** | MODIFY - change curl from `--unix-socket` to TCP | ~15 nodes |
|
|
||||||
| **Route Callback switch** | MODIFY - add new callback types for keyboards | Low |
|
|
||||||
| **HTTP Request nodes** | NEW - for dynamic inline keyboard generation | Medium |
|
|
||||||
|
|
||||||
### Curl Migration Pattern
|
**Tasks:**
|
||||||
|
- Create API key via `unraid-api apikey --create` CLI command
|
||||||
|
- Store in `.env.unraid-api` (gitignored)
|
||||||
|
- Add `--add-host=host.docker.internal:host-gateway` to n8n container config
|
||||||
|
- Test GraphQL query from command line: `curl -X POST http://host.docker.internal/graphql -H "x-api-key: ..." -d '{"query": "{ docker { containers { id name } } }"}'`
|
||||||
|
- Verify container ID format returned (likely `docker:<name>`)
|
||||||
|
|
||||||
```
|
**Avoids:**
|
||||||
FROM: curl -s --unix-socket /var/run/docker.sock 'http://localhost/v1.47/...'
|
- Pitfall 4 (filesystem access issues) — uses API not file mounts
|
||||||
TO: curl -s 'http://socket-proxy:2375/v1.47/...'
|
- Pitfall 3 (version compatibility) — validates API availability before implementation
|
||||||
```
|
|
||||||
|
|
||||||
---
|
**Research flag:** NEEDS DEEPER RESEARCH — Network access testing, container ID format verification, API permission validation
|
||||||
|
|
||||||
## Top Risks
|
### Phase 2: n8n Workflow Integration
|
||||||
|
**Rationale:** Once API access is proven, integrate into update sub-workflow. Single node addition is minimal risk.
|
||||||
|
|
||||||
### 1. Socket Proxy Breaks Existing Commands (CRITICAL)
|
**Delivers:**
|
||||||
|
- n8n-update.json calls GraphQL `updateContainer` after successful Docker API update
|
||||||
|
- Error handling for API failures (continue on error, log for debugging)
|
||||||
|
- Single-container updates sync automatically
|
||||||
|
|
||||||
**Risk:** All Docker commands fail after migration
|
**Tasks:**
|
||||||
**Prevention:**
|
- Add HTTP Request node to n8n-update.json after "Remove Old Image (Success)"
|
||||||
1. Deploy socket-proxy first without removing direct socket
|
- Configure GraphQL mutation: `mutation { docker { updateContainer(id: "docker:{{$json.containerName}}") { id name state } } }`
|
||||||
2. Update curl commands one-by-one to use proxy
|
- Set authentication: Header Auth with `x-api-key: {{$env.UNRAID_API_KEY}}`
|
||||||
3. Test each command via proxy before removing direct socket
|
- Error handling: `continueRegularOutput` (don't fail update if sync fails)
|
||||||
4. Maintain rollback capability throughout
|
- Connect to "Return Success" node
|
||||||
|
- Test with single container update
|
||||||
|
|
||||||
### 2. n8n Native Telegram Node Rejects Dynamic Keyboards (HIGH)
|
**Uses:**
|
||||||
|
- Unraid GraphQL API from Phase 1
|
||||||
|
- n8n HTTP Request node (built-in)
|
||||||
|
|
||||||
**Risk:** Error "The value is not supported!" when using expressions in keyboard fields
|
**Implements:**
|
||||||
**Prevention:** Use HTTP Request node to call Telegram Bot API directly for any dynamic keyboard. Keep native node for simple text responses only.
|
- Clear Unraid Status component from architecture research
|
||||||
|
- Post-Action Sync pattern (sync after primary operation completes)
|
||||||
|
|
||||||
### 3. callback_data Exceeds 64 Bytes (MEDIUM)
|
**Avoids:**
|
||||||
|
- Pitfall 1 (state desync) — uses official sync mechanism
|
||||||
|
- Pitfall 2 (race conditions) — GraphQL API handles atomicity
|
||||||
|
|
||||||
**Risk:** Buttons silently fail when callback_data is too long
|
**Research flag:** STANDARD PATTERNS — HTTP Request node usage well-documented, unlikely to need additional research
|
||||||
**Prevention:** Use short codes: `s:abc12345` (action:container_id_prefix) instead of full names. Map back via container ID lookup.
|
|
||||||
|
|
||||||
### 4. n8n 2.0 Breaking Changes (MEDIUM)
|
### Phase 3: Batch Optimization & UAT
|
||||||
|
**Rationale:** After core functionality works, optimize for batch operations and validate across scenarios.
|
||||||
|
|
||||||
**Risk:** Execute Command disabled by default, env vars blocked, Save/Publish separation
|
**Delivers:**
|
||||||
**Prevention:** Check n8n version before starting. If 2.0+, verify Execute Command is enabled in settings. Don't upgrade n8n during this milestone.
|
- Batch updates use `updateContainers` (plural) mutation for efficiency
|
||||||
|
- Validation across Unraid versions (6.12, 7.0, 7.2)
|
||||||
|
- Confirmation that network config preservation works
|
||||||
|
|
||||||
### 5. Unraid Update Badge Never Clears (LOW impact but HIGH likelihood)
|
**Tasks:**
|
||||||
|
- Modify batch update flow to collect all updated container IDs
|
||||||
|
- Call `updateContainers(ids: ["docker:container1", "docker:container2"])` once after batch loop completes
|
||||||
|
- Test on Unraid 6.12 (with Connect plugin) and 7.2 (native API)
|
||||||
|
- Verify no notification spam during batch updates (5+ containers)
|
||||||
|
- Test container on custom network (`br0`) — verify DNS resolution after update
|
||||||
|
- Document manual sync option in README (if GraphQL sync fails, user clicks "Check for Updates")
|
||||||
|
|
||||||
**Risk:** Unraid UI shows "update available" even after bot updates container
|
**Avoids:**
|
||||||
**Prevention:** Delete `/var/lib/docker/unraid-update-status.json` after successful bot update. Document that user may need to click "Check for Updates" in Unraid UI.
|
- Pitfall 5 (notification spam) — batch mutation prevents per-container notifications
|
||||||
|
- Pitfall 3 (version compatibility) — multi-version UAT catches breaking changes
|
||||||
|
- Pitfall 7 (network issues) — UAT includes network-dependent scenarios
|
||||||
|
|
||||||
---
|
**Research flag:** STANDARD PATTERNS — Batch optimization is iteration of Phase 2 pattern
|
||||||
|
|
||||||
## Recommended Build Order
|
### Phase Ordering Rationale
|
||||||
|
|
||||||
Based on dependencies and risk mitigation:
|
- **Infrastructure before integration** — Phase 1 validates GraphQL API access before modifying workflows. If network access fails, can pivot to alternative (e.g., helper script) without workflow rework.
|
||||||
|
|
||||||
### Phase 1: Socket Security Foundation
|
- **Single-container before batch** — Phase 2 proves core sync mechanism with simplest case. Batch optimization (Phase 3) is safe iteration once foundation works.
|
||||||
**Delivers:** Secure Docker socket access via proxy
|
|
||||||
**What:**
|
|
||||||
1. Deploy socket-proxy container on internal network
|
|
||||||
2. Configure minimum required permissions
|
|
||||||
3. Migrate all curl commands to use TCP endpoint
|
|
||||||
4. Test all existing functionality
|
|
||||||
5. Remove direct socket mount from n8n
|
|
||||||
|
|
||||||
**Rationale:** Security is the primary v1.1 goal. Must complete before adding any new features to avoid compounding risk.
|
- **Validation last** — Phase 3 UAT happens after implementation complete. Testing earlier wastes time if implementation changes.
|
||||||
|
|
||||||
**Pitfalls to avoid:**
|
**Dependencies discovered:**
|
||||||
- Proxy port exposed publicly (keep internal only)
|
- Phase 2 depends on Phase 1 (API access must work)
|
||||||
- Insufficient permissions (test each operation)
|
- Phase 3 depends on Phase 2 (batch builds on single-container pattern)
|
||||||
- Breaking existing curl commands (migrate incrementally)
|
- No parallelization opportunities (sequential phases)
|
||||||
|
|
||||||
### Phase 2: n8n API Access
|
### Research Flags
|
||||||
**Delivers:** Claude Code can read/update/test workflows programmatically
|
|
||||||
**What:**
|
|
||||||
1. Create API key in n8n Settings
|
|
||||||
2. Document API endpoints for workflow management
|
|
||||||
3. Test basic operations (list, get, update workflow)
|
|
||||||
|
|
||||||
**Rationale:** Low risk, high value. Enables faster iteration for subsequent phases.
|
Phases likely needing deeper research during planning:
|
||||||
|
|
||||||
**Pitfalls to avoid:**
|
- **Phase 1:** Network access testing, API permission verification — Some unknowns around container ID format and `host.docker.internal` behavior in Unraid's Docker implementation. Low risk (fallback to IP-based access), but needs validation.
|
||||||
- API key committed to repository (use environment/secrets)
|
|
||||||
- Workflow ID hardcoded (query API to discover)
|
|
||||||
|
|
||||||
### Phase 3: Inline Keyboard Infrastructure
|
Phases with standard patterns (skip research-phase):
|
||||||
**Delivers:** Foundation for button-based UX
|
|
||||||
**What:**
|
|
||||||
1. HTTP Request node pattern for dynamic keyboards
|
|
||||||
2. Callback routing for new action types
|
|
||||||
3. answerCallbackQuery integration
|
|
||||||
4. Short callback_data encoding scheme
|
|
||||||
|
|
||||||
**Rationale:** Foundation needed before adding specific button features.
|
- **Phase 2:** HTTP Request node integration — Well-documented n8n pattern, GraphQL mutation structure is simple
|
||||||
|
- **Phase 3:** Batch optimization and UAT — Iteration of Phase 2, no new concepts
|
||||||
**Pitfalls to avoid:**
|
|
||||||
- Using native Telegram node for keyboards (use HTTP Request)
|
|
||||||
- callback_data exceeding 64 bytes (use short codes)
|
|
||||||
|
|
||||||
### Phase 4: UX Improvements
|
|
||||||
**Delivers:** Button-based container management
|
|
||||||
**What:**
|
|
||||||
1. Container selection keyboards from commands
|
|
||||||
2. Confirmation dialogs for dangerous actions
|
|
||||||
3. Message editing for progress/results
|
|
||||||
4. Batch update with progress feedback
|
|
||||||
|
|
||||||
**Rationale:** User-facing improvements built on Phase 3 foundation.
|
|
||||||
|
|
||||||
### Phase 5: Unraid Sync (Optional)
|
|
||||||
**Delivers:** Clear update badges after bot updates
|
|
||||||
**What:**
|
|
||||||
1. Add volume mount for status file access
|
|
||||||
2. Delete status file after successful updates
|
|
||||||
3. Document user step to refresh Unraid UI
|
|
||||||
|
|
||||||
**Rationale:** Lowest confidence, most uncertain. May require additional host access. Defer if other phases take longer than expected.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Open Questions
|
|
||||||
|
|
||||||
1. **Socket proxy network:** Should socket-proxy be on a dedicated internal network or share n8n's network? (Recommendation: dedicated internal network)
|
|
||||||
|
|
||||||
2. **n8n API exposure:** Should n8n API be accessible only via Tailscale/VPN or also on LAN? (Recommendation: Tailscale only for security)
|
|
||||||
|
|
||||||
3. **Unraid status file access:** Does n8n already have `/var/lib/docker` mounted, or is a new volume mount needed? (Needs verification)
|
|
||||||
|
|
||||||
4. **Batch size limits:** Should "update all" have a maximum container limit or always require confirmation? (Recommendation: always confirm, no limit)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Ready for Requirements
|
|
||||||
|
|
||||||
Research is complete. All four research files provide sufficient detail for roadmap creation:
|
|
||||||
|
|
||||||
- **STACK.md:** Socket proxy configuration, n8n API setup, Telegram keyboard patterns
|
|
||||||
- **FEATURES.md:** Table stakes vs differentiators, complexity estimates, MVP recommendations
|
|
||||||
- **ARCHITECTURE.md:** Integration points, data flow changes, component modifications
|
|
||||||
- **PITFALLS.md:** Top 5 risks ranked, prevention strategies, phase-specific warnings
|
|
||||||
|
|
||||||
**Recommended phase count:** 4-5 phases
|
|
||||||
**Estimated complexity:** Medium (infrastructure change + UX improvements)
|
|
||||||
**Confidence for planning:** HIGH for Phases 1-4, MEDIUM for Phase 5 (Unraid sync)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Confidence Assessment
|
## Confidence Assessment
|
||||||
|
|
||||||
| Area | Confidence | Notes |
|
| Area | Confidence | Notes |
|
||||||
|------|------------|-------|
|
|------|------------|-------|
|
||||||
| Stack | HIGH | Official docs for socket-proxy and n8n API verified |
|
| Stack | HIGH | GraphQL API is official Unraid interface, documented in schema and DeepWiki. HTTP Request node is n8n built-in. |
|
||||||
| Features | MEDIUM-HIGH | Telegram API well-documented; n8n limitations confirmed via GitHub issues |
|
| Features | MEDIUM | Core pain point well-understood from community forums. Feature prioritization based on user impact analysis, but batch optimization impact is estimated. |
|
||||||
| Architecture | HIGH | Clear integration points, existing workflow well understood |
|
| Architecture | HIGH | Extension of existing sub-workflow pattern. GraphQL integration is standard HTTP Request usage. Rejected alternatives are well-reasoned. |
|
||||||
| Pitfalls | MEDIUM-HIGH | Based on official docs + community experience; Unraid behavior forum-confirmed |
|
| Pitfalls | MEDIUM | Critical pitfalls identified from community reports and source code analysis. Race condition and version compatibility need UAT validation. |
|
||||||
|
|
||||||
**Overall confidence:** MEDIUM-HIGH
|
**Overall confidence:** HIGH
|
||||||
|
|
||||||
|
The GraphQL API approach is well-documented and official. Core functionality (sync after single-container update) is low-risk. Batch optimization and multi-version support add complexity but are defer-able if needed.
|
||||||
|
|
||||||
### Gaps to Address
|
### Gaps to Address
|
||||||
|
|
||||||
1. **n8n version check** - Verify current n8n version before starting (2.0 has breaking changes)
|
Areas where research was inconclusive or needs validation during implementation:
|
||||||
2. **Unraid volume mounts** - Verify existing mounts or plan for new ones
|
|
||||||
3. **Telegram keyboard testing** - HTTP Request pattern needs validation with actual workflow
|
|
||||||
|
|
||||||
---
|
- **Container ID format** — GraphQL schema shows `id: ID!` but exact format (`docker:<name>` vs just `<name>`) needs testing. Resolution: Phase 1 queries containers to get actual ID format.
|
||||||
|
|
||||||
|
- **API rate limiting** — Not documented. Impact: LOW (bot updates are infrequent, <10/min even in batch). Resolution: Monitor during UAT, no preemptive handling.
|
||||||
|
|
||||||
|
- **GraphQL subscription for real-time status** — Schema includes subscriptions but unclear if Docker status changes are subscribable. Impact: None for v1.3 (defer to future enhancement). Resolution: Document as v2+ exploration.
|
||||||
|
|
||||||
|
- **Unraid 6.9-7.1 Connect plugin availability** — Research confirms Connect plugin exists but installation process not validated. Impact: MEDIUM (users on pre-7.2 need this). Resolution: Phase 1 should document plugin installation steps and test.
|
||||||
|
|
||||||
|
- **Exact permission name for API key** — Research shows `DOCKER:UPDATE_ANY` but this wasn't explicitly stated in official docs (inferred from schema). Impact: LOW (easily testable). Resolution: Phase 1 tests API key creation and documents exact permission syntax.
|
||||||
|
|
||||||
## Sources
|
## Sources
|
||||||
|
|
||||||
### Primary (HIGH confidence)
|
### Primary (HIGH confidence)
|
||||||
- [n8n API Documentation](https://docs.n8n.io/api/) - Authentication, endpoints
|
- [Unraid API Schema](https://raw.githubusercontent.com/unraid/api/main/api/generated-schema.graphql) — GraphQL mutations, container ID types, query structure
|
||||||
- [LinuxServer socket-proxy](https://docs.linuxserver.io/images/docker-socket-proxy/) - Configuration options
|
- [DeepWiki — Docker Integration](https://deepwiki.com/unraid/api/2.4-docker-integration) — DockerService architecture, updateContainer mutation behavior
|
||||||
- [Telegram Bot API](https://core.telegram.org/bots/api) - Inline keyboards, callback queries
|
- [limetech/dynamix source](https://github.com/limetech/dynamix/blob/master/plugins/dynamix.docker.manager/include/DockerClient.php) — syncVersions() function, update status file handling
|
||||||
|
- [Unraid API Documentation](https://docs.unraid.net/API/) — API key management, version availability
|
||||||
|
- [Unraid API Key Management](https://docs.unraid.net/API/programmatic-api-key-management/) — API key creation, permission scopes
|
||||||
|
|
||||||
### Secondary (MEDIUM confidence)
|
### Secondary (MEDIUM confidence)
|
||||||
- [n8n GitHub Issue #19955](https://github.com/n8n-io/n8n/issues/19955) - Native node keyboard limitations
|
- [Unraid Forum: Incorrect Update Notification](https://forums.unraid.net/bug-reports/stable-releases/regression-incorrect-docker-update-notification-r2807/) — Community-identified pain point, file deletion workaround
|
||||||
- [Tecnativa docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) - Alternative proxy option
|
- [Watchtower + Unraid Discussion](https://github.com/containrrr/watchtower/discussions/1389) — External update detection issues, Unraid doesn't auto-sync
|
||||||
|
- [Unraid Forum: Watchtower Status Not Reflected](https://forums.unraid.net/topic/149953-docker-update-via-watchtower-status-not-reflected-in-unraid/) — Confirmation of stale status after external updates
|
||||||
|
- [Unraid MCP Server](https://github.com/jmagar/unraid-mcp) — Reference GraphQL client implementation
|
||||||
|
- [Home Assistant Unraid Integration](https://github.com/domalab/unraid-api-client) — Additional GraphQL usage examples
|
||||||
|
- [Docker host.docker.internal guide](https://eastondev.com/blog/en/posts/dev/20251217-docker-host-access/) — Network access pattern
|
||||||
|
|
||||||
### Tertiary (LOW confidence)
|
### Tertiary (LOW confidence)
|
||||||
- [Unraid Forums](https://forums.unraid.net/bug-reports/stable-releases/regression-incorrect-docker-update-notification-r2807/) - Update badge behavior workarounds
|
- [Unraid Forums — Docker Update Status](https://forums.unraid.net/topic/114415-plugin-docker-compose-manager/page/9/) — Status file structure (observed, not documented)
|
||||||
|
- Community reports of notification spam — Anecdotal, but consistent pattern across forums
|
||||||
|
|
||||||
---
|
---
|
||||||
*Research completed: 2026-02-02*
|
*Research completed: 2026-02-08*
|
||||||
*Ready for roadmap: yes*
|
*Ready for roadmap: yes*
|
||||||
|
|||||||
Reference in New Issue
Block a user