feat: complete Nextcloud Deck integration with English emoji stack names
- Renamed all stacks to English with emojis (Backlog, Planning, In Progress, Complete)
- Updated sync script to use new stack names
- Created all 3 initiative cards (IDs 189-191)
- Enhanced error handling with detailed debug output
- Updated documentation with API limitations and troubleshooting
- Fixed stack fallback from 'eingang' to '📥 Backlog'
Changes:
- scripts/sync-roadmap-to-deck.py: Updated STATUS_TO_STACK mapping, added verbose logging
- docs/NEXTCLOUD_DECK_SYNC.md: Updated stack table, added Known Limitations section, enhanced troubleshooting
Note: 6 duplicate/test cards (184-188, 192) must be deleted manually from Nextcloud UI
due to API limitations (DELETE returns 405)
This commit is contained in:
@@ -32,10 +32,10 @@ This will:
|
|||||||
|
|
||||||
| Deck Stack | Roadmap Status | Purpose |
|
| Deck Stack | Roadmap Status | Purpose |
|
||||||
|------------|----------------|---------|
|
|------------|----------------|---------|
|
||||||
| `eingang` (inbox) | FUTURE | Backlog items, ideas, future phases |
|
| 📥 Backlog | FUTURE | Backlog items, ideas, future phases |
|
||||||
| `in planung` (planning) | PENDING | Ready to implement, needs detailed specs |
|
| 📋 Planning | PENDING | Ready to implement, needs detailed specs |
|
||||||
| `in arbeit` (in progress) | IN PROGRESS (🔄) | Currently working on |
|
| 🚀 In Progress | IN PROGRESS (🔄) | Currently working on |
|
||||||
| `erledigt` (done) | COMPLETE (✅) | Finished and verified |
|
| ✅ Complete | COMPLETE (✅) | Finished and verified |
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -102,9 +102,34 @@ Nextcloud Deck API: `/index.php/apps/deck/api/v1.0`
|
|||||||
|
|
||||||
Key endpoints used:
|
Key endpoints used:
|
||||||
- `GET /boards` - List all boards
|
- `GET /boards` - List all boards
|
||||||
- `GET /boards/{boardId}` - Get board details
|
- `GET /boards/{boardId}` - Get board details with stacks (no cards included)
|
||||||
- `GET /boards/{boardId}/stacks` - Get stacks
|
- `GET /boards/{boardId}/stacks/{stackId}` - Get stack with cards (this works!)
|
||||||
- `POST /boards/{boardId}/stacks/{stackId}/cards` - Create card
|
- `POST /boards/{boardId}/stacks/{stackId}/cards` - Create card
|
||||||
|
- `PUT /boards/{boardId}/stacks/{stackId}` - Rename stack
|
||||||
|
|
||||||
|
**Note:** Many endpoints return 405 Method Not Allowed:
|
||||||
|
- `GET /boards/{boardId}/stacks/{stackId}/cards` - Not supported
|
||||||
|
- `DELETE /boards/{boardId}/cards/{cardId}` - Not supported
|
||||||
|
- `GET /boards/{boardId}/cards/{cardId}` - Not supported
|
||||||
|
|
||||||
|
## Known Limitations
|
||||||
|
|
||||||
|
1. **No Duplicate Detection**: The Deck API v1.0 doesn't support listing cards by stack, so:
|
||||||
|
- Running `--init` multiple times creates duplicate cards
|
||||||
|
- Delete duplicates manually from the Nextcloud Deck UI
|
||||||
|
- Always use `--dry-run` first to preview changes
|
||||||
|
|
||||||
|
2. **No Card Deletion API**: The DELETE endpoint returns 405, so:
|
||||||
|
- Test cards must be deleted manually from the web UI
|
||||||
|
- No automated cleanup possible
|
||||||
|
|
||||||
|
3. **Limited GET Support**: Most card-level GET endpoints return 405:
|
||||||
|
- Cannot verify card creation without checking full stack
|
||||||
|
- Use `GET /boards/{boardId}/stacks/{stackId}` to view cards
|
||||||
|
|
||||||
|
4. **No Bidirectional Sync**: Card position changes in Deck don't update markdown files
|
||||||
|
|
||||||
|
5. **Initiative-Level Only**: Currently only syncs high-level initiatives, not individual phases
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
@@ -114,15 +139,25 @@ Key endpoints used:
|
|||||||
- Verify name contains "trader" (case insensitive)
|
- Verify name contains "trader" (case insensitive)
|
||||||
|
|
||||||
**"405 Method Not Allowed"**
|
**"405 Method Not Allowed"**
|
||||||
- Nextcloud Deck version may have different API
|
- Normal for most GET/DELETE card endpoints
|
||||||
- Check Nextcloud Deck version in settings
|
- Use stack endpoint instead: `GET /boards/{boardId}/stacks/{stackId}`
|
||||||
- Some GET endpoints may not be available
|
- Check Nextcloud Deck API documentation for your version
|
||||||
|
|
||||||
|
**"Cards not showing in board"**
|
||||||
|
- Cards ARE created but not visible in `GET /boards/{boardId}` response
|
||||||
|
- Use `GET /boards/{boardId}/stacks/{stackId}` to view cards properly
|
||||||
|
- Or check the Nextcloud Deck web UI
|
||||||
|
|
||||||
**"Cards not syncing"**
|
**"Cards not syncing"**
|
||||||
- Check `/tmp/deck-config.json` exists
|
- Check `/tmp/deck-config.json` exists
|
||||||
- Verify credentials in config
|
- Verify credentials in config
|
||||||
- Run with `--dry-run` first to test
|
- Run with `--dry-run` first to test
|
||||||
|
|
||||||
|
**"Duplicate cards"**
|
||||||
|
- This is expected - API doesn't support duplicate checking
|
||||||
|
- Delete extras manually from Nextcloud Deck UI
|
||||||
|
- Always run `--dry-run` before `--init`
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
**Adding new roadmap files:**
|
**Adding new roadmap files:**
|
||||||
@@ -140,7 +175,7 @@ ROADMAP_FILES = [
|
|||||||
Edit `STATUS_TO_STACK` dict:
|
Edit `STATUS_TO_STACK` dict:
|
||||||
```python
|
```python
|
||||||
STATUS_TO_STACK = {
|
STATUS_TO_STACK = {
|
||||||
'IN PROGRESS': 'in arbeit',
|
'IN PROGRESS': '🚀 In Progress',
|
||||||
'YOUR_STATUS': 'your_stack', # Add here
|
'YOUR_STATUS': '📋 Your Stack', # Add here (with emoji)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -32,14 +32,14 @@ STACKS = {stack['name']: stack['id'] for stack in DECK_CONFIG['stacks']}
|
|||||||
|
|
||||||
# Status to stack mapping
|
# Status to stack mapping
|
||||||
STATUS_TO_STACK = {
|
STATUS_TO_STACK = {
|
||||||
'IN PROGRESS': 'in arbeit',
|
'IN PROGRESS': '🚀 In Progress',
|
||||||
'🔄 IN PROGRESS': 'in arbeit',
|
'🔄 IN PROGRESS': '🚀 In Progress',
|
||||||
'COMPLETE': 'erledigt',
|
'COMPLETE': '✅ Complete',
|
||||||
'✅ COMPLETE': 'erledigt',
|
'✅ COMPLETE': '✅ Complete',
|
||||||
'PENDING': 'in planung',
|
'PENDING': '📋 Planning',
|
||||||
'🔜 NEXT': 'in planung',
|
'🔜 NEXT': '📋 Planning',
|
||||||
'FUTURE': 'eingang',
|
'FUTURE': '📥 Backlog',
|
||||||
'🎯 FUTURE': 'eingang',
|
'🎯 FUTURE': '📥 Backlog',
|
||||||
}
|
}
|
||||||
|
|
||||||
# Roadmap files to parse
|
# Roadmap files to parse
|
||||||
@@ -133,8 +133,8 @@ class RoadmapParser:
|
|||||||
content = filepath.read_text()
|
content = filepath.read_text()
|
||||||
tasks = []
|
tasks = []
|
||||||
|
|
||||||
# Parse initiatives (main sections)
|
# Parse initiatives (main sections) - handle different emoji prefixes
|
||||||
initiative_pattern = r'## 🎯 Initiative (\d+): (.+?)(?=\n##|\Z)'
|
initiative_pattern = r'## (?:🎯|📐|📊) Initiative (\d+): (.+?)(?=\n##|\Z)'
|
||||||
initiatives = re.finditer(initiative_pattern, content, re.DOTALL)
|
initiatives = re.finditer(initiative_pattern, content, re.DOTALL)
|
||||||
|
|
||||||
for initiative in initiatives:
|
for initiative in initiatives:
|
||||||
@@ -247,25 +247,39 @@ def sync_roadmap_to_deck(dry_run: bool = False):
|
|||||||
title = task['title']
|
title = task['title']
|
||||||
|
|
||||||
# Create new card
|
# Create new card
|
||||||
stack_name = STATUS_TO_STACK.get(task['status'], 'eingang')
|
stack_name = STATUS_TO_STACK.get(task['status'], '📥 Backlog')
|
||||||
stack_id = STACKS[stack_name]
|
|
||||||
|
|
||||||
|
# Debug output
|
||||||
print(f"✨ Create: {title}")
|
print(f"✨ Create: {title}")
|
||||||
print(f" Stack: {stack_name}")
|
print(f" Status from roadmap: {task['status']!r}")
|
||||||
|
print(f" Mapped to stack: {stack_name!r}")
|
||||||
|
|
||||||
|
if stack_name not in STACKS:
|
||||||
|
print(f" ❌ ERROR: Stack {stack_name!r} not found in STACKS")
|
||||||
|
print(f" Available stacks: {list(STACKS.keys())}")
|
||||||
|
skipped += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
stack_id = STACKS[stack_name]
|
||||||
|
print(f" Stack ID: {stack_id}")
|
||||||
|
|
||||||
if task['progress']:
|
if task['progress']:
|
||||||
print(f" Progress: {task['progress']}")
|
print(f" Progress: {task['progress']}")
|
||||||
|
|
||||||
if not dry_run:
|
if not dry_run:
|
||||||
try:
|
try:
|
||||||
api.create_card(
|
result = api.create_card(
|
||||||
stack_id=stack_id,
|
stack_id=stack_id,
|
||||||
title=title,
|
title=title,
|
||||||
description=task['description'],
|
description=task['description'],
|
||||||
due_date=task['due_date'],
|
due_date=task['due_date'],
|
||||||
)
|
)
|
||||||
|
print(f" ✅ Created card ID: {result['id']}")
|
||||||
created += 1
|
created += 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" ❌ Error: {e}")
|
print(f" ❌ Error: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
skipped += 1
|
skipped += 1
|
||||||
else:
|
else:
|
||||||
created += 1
|
created += 1
|
||||||
|
|||||||
Reference in New Issue
Block a user