# Dashboard & Kanban Review: Data Sync Issues & Solutions

**Review Date:** 2026-02-09  
**Reviewer:** Subagent (kanban-dashboard-opus-review)  
**For:** Adner (Windows/WSL environment)

---

## Executive Summary

The static `file://` dashboard and kanban pages fail to reflect updated data reliably due to:

1. **CORS restrictions**: Modern browsers block `fetch()` on `file://` URLs
2. **Embedded snapshot drift**: HTML contains stale JSON; requires manual rebuild after every data update
3. **Manual rebuild friction**: Two-step process (update data → run build scripts → refresh) is error-prone

**Recommended Solution:** Run a simple local Python HTTP server (5 lines of code, zero dependencies). Eliminates all rebuild steps and works seamlessly across Windows/WSL.

---

## Current Architecture

### Dashboard (`/workspace/dashboard/`)

```
dashboard/
├── data.json                    # Project data (source of truth)
├── index.html                   # Static HTML with embedded JSON fallback
└── build-dashboard-embed.py     # Embeds data.json into index.html
```

**How it works:**
1. JavaScript tries `fetch('./data.json')`
2. If fetch fails (file:// blocks it), falls back to embedded `<script id="embedded-data">` tag
3. Embedded data is stale unless `build-dashboard-embed.py` runs after every `data.json` update

### Kanban (`/workspace/kanban/`)

```
kanban/
├── data.json                    # Generated/transformed data
├── index.html                   # Static HTML with embedded JSON fallback
├── kanban-state.json            # Overlay state (column assignments, manual cards)
└── build-kanban-data.py         # Builds data.json from dashboard + state, embeds into HTML
```

**How it works:**
1. `build-kanban-data.py` reads `dashboard/data.json` + `kanban-state.json`
2. Transforms projects → kanban cards, applies column assignments
3. Writes `kanban/data.json` AND embeds into `kanban/index.html`
4. Browser tries `fetch('./data.json')`, falls back to embedded data if blocked

---

## Root Cause Analysis

### Issue 1: file:// Protocol CORS Restrictions

**Problem:**  
Modern browsers block `fetch()` on `file://` URLs for security. Even same-directory requests fail.

**Evidence:**
```javascript
// In both dashboard/index.html and kanban/index.html
const res = await fetch('./data.json', {cache:'no-store'});
// ❌ Fails on file:// → browser console shows CORS error
```

**Impact:**  
- Live data never loads
- Always shows embedded snapshot
- User doesn't realize data is stale

### Issue 2: Embedded Snapshot Drift

**Problem:**  
Embedded JSON in HTML becomes outdated immediately after `data.json` updates.

**Example workflow (current):**
```bash
# 1. Agent updates dashboard data
echo '{"meta": {...}, "projects": [...]}' > dashboard/data.json

# 2. User opens file:///mnt/c/.../.openclaw/workspace/dashboard/index.html
# → Shows OLD embedded data (last time build script ran)

# 3. Must manually run:
python3 dashboard/build-dashboard-embed.py  # Update dashboard HTML
python3 kanban/build-kanban-data.py         # Rebuild kanban data + HTML
# → Then refresh browser

# 4. Repeat for every update
```

**Impact:**
- High cognitive load (remember to rebuild)
- Error-prone (forget a step → stale data)
- Breaks agent workflows (can't auto-update dashboards)

### Issue 3: Windows/WSL Path Friction

**Problem:**  
- Files live in WSL: `/home/isthekid/.openclaw/workspace/`
- Windows File Explorer uses: `\\wsl.localhost\Ubuntu-22.04\home\isthekid\.openclaw\workspace\`
- Double-clicking `index.html` opens `file:///mnt/c/...` or `file:///home/...` depending on where you click
- No unified access pattern

**Impact:**
- Confusing for Adner
- Hard to bookmark
- Path inconsistencies

---

## Solution: Simple Local HTTP Server (RECOMMENDED)

### Why This Works

- **No CORS restrictions**: HTTP server = same-origin requests work
- **Zero rebuild steps**: Browser always fetches latest `data.json`
- **Minimal complexity**: 5-line Python script, no dependencies
- **Cross-platform**: Works from Windows browser or WSL terminal
- **Bookmarkable**: `http://localhost:8080/dashboard/` (consistent URL)

### Implementation

#### File 1: `serve.py` (at workspace root)

```python
#!/usr/bin/env python3
"""Simple HTTP server for dashboard & kanban. Zero dependencies."""
import http.server
import socketserver
from pathlib import Path

PORT = 8080
DIR = Path(__file__).parent  # /home/isthekid/.openclaw/workspace

class Handler(http.server.SimpleHTTPRequestHandler):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, directory=str(DIR), **kwargs)
    
    def end_headers(self):
        # Disable caching so data.json always reloads
        self.send_header('Cache-Control', 'no-store, no-cache, must-revalidate')
        self.send_header('Pragma', 'no-cache')
        self.send_header('Expires', '0')
        super().end_headers()

def main():
    with socketserver.TCPServer(("", PORT), Handler) as httpd:
        print(f"✓ Serving workspace at http://localhost:{PORT}/")
        print(f"  Dashboard: http://localhost:{PORT}/dashboard/")
        print(f"  Kanban:    http://localhost:{PORT}/kanban/")
        print("Press Ctrl+C to stop.")
        httpd.serve_forever()

if __name__ == '__main__':
    main()
```

**Make it executable:**
```bash
chmod +x /home/isthekid/.openclaw/workspace/serve.py
```

#### File 2: `start-server.sh` (convenience wrapper)

```bash
#!/bin/bash
# Start the dashboard/kanban server in background
cd /home/isthekid/.openclaw/workspace
python3 serve.py &
echo $! > /tmp/workspace-server.pid
echo "✓ Server started (PID $(cat /tmp/workspace-server.pid))"
echo "  Dashboard: http://localhost:8080/dashboard/"
echo "  Kanban:    http://localhost:8080/kanban/"
```

**Make it executable:**
```bash
chmod +x /home/isthekid/.openclaw/workspace/start-server.sh
```

#### File 3: `stop-server.sh` (convenience wrapper)

```bash
#!/bin/bash
# Stop the dashboard/kanban server
if [ -f /tmp/workspace-server.pid ]; then
  kill $(cat /tmp/workspace-server.pid) 2>/dev/null
  rm /tmp/workspace-server.pid
  echo "✓ Server stopped"
else
  echo "⚠ Server not running (no PID file)"
fi
```

**Make it executable:**
```bash
chmod +x /home/isthekid/.openclaw/workspace/stop-server.sh
```

### Usage

#### Start server (from WSL or Windows Terminal):
```bash
cd /home/isthekid/.openclaw/workspace
./start-server.sh
# Or: python3 serve.py
```

#### Open in browser:
```
http://localhost:8080/dashboard/
http://localhost:8080/kanban/
```

#### Update data (agent workflow):
```bash
# Agent updates dashboard/data.json
# → Browser auto-fetches latest data on refresh (no rebuild!)

# Kanban still needs build (transforms data), but HTML embed is optional:
python3 kanban/build-kanban-data.py
# → Browser fetches kanban/data.json (no HTML rebuild needed!)
```

#### Stop server:
```bash
./stop-server.sh
```

---

## Alternative Solution: Automated Rebuild (Fallback)

If Adner prefers keeping `file://` workflow (e.g., for offline access), automate the rebuild:

### File: `watch-and-rebuild.sh`

```bash
#!/bin/bash
# Watch data.json files and auto-rebuild HTML embeds
cd /home/isthekid/.openclaw/workspace

echo "Watching for changes..."
while true; do
  inotifywait -e modify dashboard/data.json kanban/kanban-state.json 2>/dev/null
  echo "→ Detected change, rebuilding..."
  python3 dashboard/build-dashboard-embed.py
  python3 kanban/build-kanban-data.py
  echo "✓ Rebuilt at $(date '+%H:%M:%S')"
done
```

**Install inotify-tools (if needed):**
```bash
sudo apt update && sudo apt install -y inotify-tools
```

**Run watcher:**
```bash
chmod +x watch-and-rebuild.sh
./watch-and-rebuild.sh &
```

**Pros:**
- Keeps `file://` workflow
- Auto-rebuilds on data changes
- Works offline

**Cons:**
- Still requires manual browser refresh
- Adds inotify-tools dependency
- More complex than HTTP server
- Doesn't solve CORS issue (still uses embedded fallback)

---

## Comparison Matrix

| Aspect | HTTP Server (Recommended) | Auto-Rebuild Watcher | Current (Manual) |
|--------|---------------------------|----------------------|-------------------|
| **Setup complexity** | ⭐ Simple (5-line script) | ⭐⭐ Medium (inotify-tools) | ⭐⭐⭐ None |
| **Rebuild steps** | ✅ Zero | ⚠️ Auto (but still rebuilds) | ❌ Manual (2 scripts) |
| **Browser refresh** | ✅ F5 loads latest | ⚠️ F5 after rebuild | ❌ F5 after manual rebuild |
| **CORS issues** | ✅ Solved (HTTP) | ❌ Still file:// | ❌ Still file:// |
| **Offline access** | ⚠️ Server must run | ✅ Works offline | ✅ Works offline |
| **Bookmarkable URL** | ✅ `localhost:8080` | ❌ file:// paths | ❌ file:// paths |
| **Windows access** | ✅ Same URL | ⚠️ WSL path confusion | ⚠️ WSL path confusion |
| **Agent integration** | ✅ Just update data.json | ⚠️ Watcher must run | ❌ Agent must run builds |

---

## Recommended Implementation Plan

### Phase 1: HTTP Server (Primary Solution)

1. **Create server files** (5 min):
   ```bash
   cd /home/isthekid/.openclaw/workspace
   # Copy serve.py, start-server.sh, stop-server.sh from above
   chmod +x serve.py start-server.sh stop-server.sh
   ```

2. **Test locally** (2 min):
   ```bash
   ./start-server.sh
   # Open http://localhost:8080/dashboard/ in browser
   # Verify dashboard loads
   ```

3. **Update agent workflows** (10 min):
   - Agent updates `dashboard/data.json` → no rebuild needed
   - Agent runs `kanban/build-kanban-data.py` for kanban → no HTML embed needed
   - User refreshes browser → latest data loads

4. **Optional: Auto-start server**:
   Add to `.bashrc` or create systemd service:
   ```bash
   # .bashrc
   if ! pgrep -f "python3.*serve.py" > /dev/null; then
     /home/isthekid/.openclaw/workspace/start-server.sh
   fi
   ```

### Phase 2: Remove Embedded Data (Optional Cleanup)

Once HTTP server is stable, simplify HTML files:

1. **Remove embedded `<script>` tags** from `index.html` files
2. **Remove embed logic** from build scripts
3. **Simplify JavaScript** (no fallback needed)

This reduces file sizes and eliminates drift risk entirely.

### Phase 3: Windows Shortcut (Convenience)

Create a desktop shortcut for Adner:

**File: `Dashboard.url` (on Windows desktop)**
```ini
[InternetShortcut]
URL=http://localhost:8080/dashboard/
IconIndex=0
```

**File: `Kanban.url` (on Windows desktop)**
```ini
[InternetShortcut]
URL=http://localhost:8080/kanban/
IconIndex=0
```

---

## Technical Notes

### Security Considerations

- **Localhost only**: Server binds to `0.0.0.0` but firewall blocks external access
- **No authentication**: Not needed (local files)
- **No HTTPS**: Not needed (localhost trusted)

### Port Conflicts

If port 8080 is taken, change `PORT = 8080` in `serve.py` to:
- `8000` (common alternative)
- `3000` (Node.js convention)
- `8888` (Jupyter convention)

### WSL Networking

- WSL2 uses virtualized networking: `localhost` in Windows → WSL works automatically
- If issues, use WSL IP: `ip addr show eth0 | grep inet`

### Browser Caching

The `Cache-Control` headers in `serve.py` prevent stale data. If issues persist:
- **Chrome**: Hard refresh (`Ctrl+Shift+R`)
- **Firefox**: Hard refresh (`Ctrl+F5`)
- **Edge**: Hard refresh (`Ctrl+F5`)

---

## Migration Checklist

- [ ] Create `serve.py`, `start-server.sh`, `stop-server.sh`
- [ ] Test server: `./start-server.sh`
- [ ] Verify dashboard loads: `http://localhost:8080/dashboard/`
- [ ] Verify kanban loads: `http://localhost:8080/kanban/`
- [ ] Update agent workflows (remove manual rebuild steps)
- [ ] Create Windows desktop shortcuts (optional)
- [ ] Add auto-start to `.bashrc` (optional)
- [ ] Remove embedded data from HTML (optional cleanup)

---

## Conclusion

**The HTTP server solution is strongly recommended** because it:

1. ✅ **Eliminates all manual rebuild steps**
2. ✅ **Solves CORS issues completely**
3. ✅ **Works seamlessly across Windows/WSL**
4. ✅ **Requires minimal code** (5 lines Python)
5. ✅ **Zero dependencies** (uses stdlib only)
6. ✅ **Bookmarkable URLs** (no path confusion)

**Total implementation time:** ~15 minutes  
**Maintenance overhead:** None (server just runs)

The alternative (auto-rebuild watcher) is viable but doesn't solve the core CORS issue and adds complexity. The current manual approach is unsustainable for frequent updates.

---

**Next Steps:**  
1. Review this document with Adner
2. Implement HTTP server (Phase 1)
3. Test with real workflow
4. Optionally proceed to Phase 2/3 for polish

**Questions?** Ping main agent or update this document.
