obsidian/01 Projects/DevOps_Click_UP_sync/DevOps ClickUp Sync.md
2026-04-29 14:50:31 +01:00

197 lines
No EOL
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: "DevOps ↔ ClickUp Sync"
client: Oliver Internal
status: active
tech: [Python, FastAPI, SQLAlchemy, SQLite, Docker, Pydantic, HTTPX]
local_path: /Users/ai_leed/Documents/Projects/Oliver/DevOps_Click_UP_sync
deploy: docker compose up -d --build
url: http://localhost:8080
tags: [oliver, devops, ado, clickup, sync, webhook]
created: 2026-04-14
server: local
port: 8080
db: SQLite
---
## Overview
DevOps_Click_UP_sync is a FastAPI webhook service that bi-directionally synchronises Azure DevOps work items with ClickUp tasks in real time. It creates, updates, and mirrors comments and attachments across both platforms, preventing echo-event loops through deduplication logic. The service exposes a simple web dashboard for managing project mappings and viewing sync history, and is deployable as a Docker container with SQLite persistence.
## Tech Stack
- **Frontend:** Vanilla JavaScript + HTML + Tailwind CSS (dashboard at `frontend/index.html`)
- **Backend:** Python 3.x + FastAPI + Uvicorn + Pydantic
- **Database:** SQLite with SQLAlchemy ORM (async via `aiosqlite`)
- **Infrastructure:** Docker Compose (single service, volume-mounted data directory)
- **AI/ML:** N/A
- **Key libraries:** `httpx` (async HTTP client for ADO/ClickUp REST APIs), `markdownify` (HTML↔Markdown conversion), `python-dotenv` (env config), `aiofiles` (async file I/O)
## Architecture
The service is a synchronisation engine that listens for webhooks from both Azure DevOps and ClickUp, then mirrors changes bidirectionally:
1. **Webhook Handlers** (`src/api/webhooks.py`):
- `POST /webhooks/ado` — receives ADO work item events
- `POST /webhooks/clickup` — receives ClickUp task events
- HMAC validation via `WEBHOOK_SECRET` prevents spoofing
2. **Sync Engine** (`src/sync/engine.py`):
- Core logic that determines what to create, update, or skip
- Calls Field Mapper to translate between ADO and ClickUp schemas
- Invokes REST clients to push changes back to origin system
3. **Field Mapper** (`src/sync/mapper.py`):
- Transforms ADO work item fields ↔ ClickUp task fields
- Handles title, description, state, assignee, priority, custom fields
- Converts HTML ↔ Markdown for comment bodies
4. **Echo-Event Deduplication** (`src/sync/dedup.py`):
- Maintains a `dedup` table: tracks (entity_id, direction, timestamp)
- Incoming webhook is **skipped** if the same entity was synced from the opposite direction within a TTL window (prevents A→B→A loops)
5. **REST Clients**:
- `src/clients/ado.py` — Azure DevOps REST API (work items, comments, attachments)
- `src/clients/clickup.py` — ClickUp API (tasks, comments, attachments)
6. **Database Models** (`src/database.py`):
- `SyncMap` — maps ADO work item ID ↔ ClickUp task ID
- `ProjectMap` — maps ADO project ↔ ClickUp space/folder
- `CommentMap` — maps ADO comment ↔ ClickUp comment for updates
- `DedupLog` — echo-event prevention records
7. **Dashboard APIs** (`src/api/dashboard.py`):
- `GET /api/dashboard/stats` — sync counts and health
- `GET /api/dashboard/project-maps` — view configured mappings
- `GET /api/dashboard/sync-log` — paginated sync history
8. **Setup API** (`src/api/setup.py`):
- `POST /api/setup/register-webhooks` — auto-registers webhook subscriptions with ADO/ClickUp
```
┌─────────────┐ ┌──────────────┐
│ Azure │ │ ClickUp │
│ DevOps │ │ │
└──────┬──────┘ └──────┬───────┘
│ │
│ POST /webhooks/ado │ POST /webhooks/clickup
│ (work item created/updated) │ (task created/updated)
│ │
└────────────┬─────────────────────────┘
┌───────▼────────┐
│ FastAPI │
│ Service │
│ (port 8080) │
└───────┬────────┘
┌────────────┼────────────┐
│ │ │
│ Sync │ Dedup │
│ Engine │ Check │
│ │ │
└──┬─────────┴────────┬───┘
│ │
┌─────▼──────┐ ┌──────▼────┐
│ Field │ │ Database │
│ Mapper │ │ (SQLite) │
│ │ │ │
└─────┬──────┘ └──────┬────┘
│ │
┌─────▼──────────────────▼────┐
│ REST Clients │
│ (ADO + ClickUp APIs) │
└──────────────────────────────┘
```
## Dev Commands
```bash
# Copy and configure environment variables
cp .env.example .env
# → Edit .env with ADO_PAT, CLICKUP_API_TOKEN, WEBHOOK_SECRET, PUBLIC_URL, etc.
# Start service in Docker (builds image, mounts ./data volume, runs on port 8080)
docker compose up -d
# Rebuild after code changes
docker compose up -d --build
# View live logs
docker compose logs -f sync-service
# Health check
curl http://localhost:8080/api/health
# Run locally without Docker (requires venv + pip install -r requirements.txt)
pip install -r requirements.txt
uvicorn src.main:app --host 0.0.0.0 --port 8080 --reload
# Access dashboard in browser
http://localhost:8080/
```
## Deployment
- **Server:** Unknown (no server hostname provided in config)
- **Deploy:** `docker compose up -d --build` (from project directory)
- **URL:** Controlled by `PUBLIC_URL` environment variable (must be HTTPS and reachable by ADO and ClickUp for webhook callbacks)
- **Port:** 8080
- **Service:** Docker Compose service named `sync-service` (not a systemd service)
- **Local path:** `/Users/ai_leed/Documents/Projects/Oliver/DevOps_Click_UP_sync`
- **Data persistence:** SQLite database stored in `./data/sync.db` (Docker volume `./data:/app/data`)
- **Health check:** Built-in Docker healthcheck (`GET /api/health` every 30s)
## Environment Variables
- `ADO_ORGANIZATION` — Azure DevOps organization name (required)
- `ADO_PROJECT` — Azure DevOps project name (required)
- `ADO_PAT` — Azure DevOps Personal Access Token with work item read/write scopes (required)
- `ADO_ASSIGNED_TO` — WIQL filter for assigned-to field; leave empty to sync all items, use `@Me` to sync all (optional)
- `CLICKUP_API_TOKEN` — ClickUp API token (format: `pk_...`); required
- `CLICKUP_WORKSPACE_ID` — ClickUp workspace ID (required)
- `WEBHOOK_SECRET` — Random secret for HMAC signature validation of incoming webhooks (required; **must not be `changeme`** or echo-event dedup will not activate)
- `PUBLIC_URL` — Public HTTPS URL where this service is reachable (required for webhook registration; e.g., `https://your-domain.com`)
- `LOG_LEVEL` — Logging level for uvicorn/app (`DEBUG`, `INFO`, `WARNING`, `ERROR`; default: `INFO`)
- `DATABASE_URL` — SQLAlchemy database URL (default: `sqlite+aiosqlite:///./data/sync.db`); supports PostgreSQL or MySQL if changed
## API / Endpoints
### Webhooks (External)
- `POST /webhooks/ado` — Azure DevOps webhook receiver (validates HMAC with `WEBHOOK_SECRET`)
- `POST /webhooks/clickup` — ClickUp webhook receiver (validates HMAC with `WEBHOOK_SECRET`)
### Setup
- `POST /api/setup/register-webhooks` — Automatically registers webhook subscriptions with ADO and ClickUp (idempotent)
### Dashboard
- `GET /` — Serve `frontend/index.html` (vanilla JS dashboard)
- `GET /api/health` — Health check endpoint (used by Docker healthcheck)
- `GET /api/dashboard/stats` — Sync statistics (total synced, last sync time, error count)
- `GET /api/dashboard/project-maps` — List all configured ADO↔ClickUp project mappings
- `GET /api/dashboard/sync-log?page=1&limit=20` — Paginated sync history log
### Config
- Routes defined in `src/main.py` (routers from `webhooks.py`, `setup.py`, `dashboard.py`)
## Known Issues
- **No test suite** — no unit or integration tests configured; no linting setup
- **Production hardening needed** — before deploying to production:
- Add pytest + test coverage
- Add black/flake8 linting
- Validate all exception handling (especially in sync engine)
- Add request rate-limiting
- Implement robust logging/monitoring
- **SSH access constraint** — no SSH to server without explicit user instruction
- **Field mapping gaps** — some custom fields may not be handled; ADO→ClickUp HTML→Markdown conversion may lose formatting in edge cases
- **No automatic webhook re-registration
## Sessions
### 2026-04-14 Project catalogued
**Done:** Added to Obsidian second brain.
---
## Change Log
| Date | Requested | Changed | Files |
|------|-----------|---------|-------|
| 2026-04-14 | Initial setup | Note created | — |