ClickDown

ClickDown

Enables AI agents to manage Kanban tasks, boards, teams, and checklists via natural language, with full CRUD operations and live updates.

Category
访问服务器

README

ClickDown

<p align="center"> <img src="screenshots/board.png" alt="ClickDown board — Kanban task manager" width="1280" /> </p>

A fast, lightweight, multi-team Kanban task manager built on Bun and SQLite. ClickDown uses a hypermedia-driven architecture — server-side rendering with HTMX and Alpine.js — to deliver a responsive, app-like experience without a heavy client-side framework or build step.

It is local-first: a single Bun process provides the database (embedded SQLite), file storage (data/uploads/), and real-time updates (in-process WebSockets). No CDN, cloud service, or external broker is required — the app runs fully offline or on a LAN.

✨ Features

Tasks

  • Title, description (with Markdown rendering + Write/Preview toggle), priority (low / medium / high / urgent), assignee, and due date
  • Inline editing of every field from a task detail modal
  • Checklists, comments, labels, and file attachments (stored under data/uploads/)
  • Duplicate a task, or bulk-select and delete many at once
  • Archive tasks (soft-hide) with a recycle-bin style archive view; permanent purge (single task or empty archive)
  • Activity log per task tracking who changed what
  • Shareable deep links — every task has a /tasks/:id URL that opens its board with the task modal expanded
  • Priority color-coding and overdue / due-soon badges
  • Dashboard summary of assigned tasks with team/board context

Boards

  • Boards created with a default Backlog → To Do → In Progress → Done flow
  • Customizable columns (add, edit, delete, reorder, color, WIP limits) — admin/owner only
  • Drag-and-drop tasks within a column, across columns; column reorder for admins
  • Live task search across the board, "My tasks only" filter, and "Show archived"
  • Keyboard shortcuts (/ focuses search, n adds a task, Esc closes modals)

Teams & collaboration

  • Create teams, or join via a tokenized invite link (slug alone is not enough; owners/admins can regenerate the link)
  • Owner / admin / member roles, with a member-management UI to change roles and remove members
  • Isolated boards and tasks per team with membership-based access control
  • Board/column structure mutations require admin or owner; task work is open to all members

Real-time (WebSocket)

  • Live presence — avatars appear/disappear as team members open or close the board; new viewers receive a roster of who's already there
  • Live task updates — create, edit, move, delete, and archive operations broadcast to all viewers instantly
  • Refresh safety — remote changes reload the board with your search/filters preserved, and are deferred (with a notice) while you have a dialog open so unsaved edits are never lost
  • Built on Bun's native server.publish() + HTMX WS Extension + Alpine.js; no external message broker required

Accounts & UX

  • Registration / login / logout with bcrypt-hashed passwords (cost 12) and strength validation (8+ chars with upper, lower, digit, and special character)
  • Profile settings to update display name, email, and password (email or password change requires your current password; other sessions are revoked)
  • API tokens for AI agents — create/revoke personal tokens from the profile page (see MCP below)
  • Auto-generated initials avatars
  • Light / dark theme toggle (persisted to localStorage)
  • Toast notifications for all actions — visible even above open modals, and on network failures
  • Responsive layout and a custom design system over a modernized Pico CSS base
  • Structured logging via pino; health probes at /health and /ready

AI agent API (MCP)

  • Model Context Protocol endpoint at POST /api/mcp (Streamable HTTP, JSON-RPC 2.0)
  • Personal bearer tokens (SHA-256 hashed at rest) created from the profile page, with a one-step claude mcp add command shown on creation
  • 16 tools covering teams, boards, tasks, checklists, comments, and search — mutations broadcast live to open boards

🛠 Tech Stack

Layer Technology
Runtime & server Bun (Bun.serve)
Database SQLite via bun:sqlite
Templating @kitajs/html (server-side JSX → HTML)
Interactivity HTMX + Alpine.js
Styling Pico CSS + a custom design system
Auth bcrypt password hashing, cookie sessions, SHA-256-hashed API tokens
Agent API MCP Streamable HTTP (JSON-RPC 2.0, no SDK dependency)
IDs nanoid
Logging pino
Lint / Format Biome
Testing bun test (unit + integration) + Playwright (E2E, Chromium + Firefox)

🚀 Getting Started

Prerequisites

Bun 1.3.14 is the only requirement. Install or upgrade it if needed:

curl -fsSL https://bun.sh/install | bash
bun upgrade

If you use mise, the pinned mise.toml provides the same version automatically (mise install).

Installation

git clone <repository-url>
cd ClickDown
bun install

Database Setup

bun run dev and bun run start apply pending SQLite migrations automatically. You can also run them explicitly:

bun run db:migrate

By default the database lives at data/clickdown.db (override with DB_PATH).

Running the App

bun run dev     # development, with hot reload (recommended)
bun run start   # production

The app is then available at http://localhost:3000.

Health checks: GET /health (liveness) and GET /ready (schema and writable local upload storage).

All browser runtime assets are served locally from installed packages. Running ClickDown does not require CDN or cloud-service access.

Docker

A production-ready Dockerfile is included:

docker build -t clickdown .
docker run -p 3000:3000 -v clickdown-data:/app/data -e NODE_ENV=production clickdown

The container:

  • Applies pending migrations before accepting traffic, and ships a HEALTHCHECK on /ready
  • Installs production dependencies only in the runtime stage (no Playwright/TypeScript/Biome)
  • Runs as the non-root bun user with the base image pinned by digest
  • Persists SQLite data (and uploads) in a named volume (clickdown-data)
  • Sets NODE_ENV=production (strict CSRF Origin checks)
  • Declares STOPSIGNAL SIGTERM — the app shuts down gracefully (stops accepting requests, closes WebSocket connections, closes the database)
  • Exposes port 3000

The SQLite, in-memory rate limit, and WebSocket design supports one application process. Do not run multiple replicas against the same database volume.

.dockerignore excludes test files, local DBs, and dev tooling for a minimal image.

Optional smoke: bun run smoke:docker — builds the image, polls /ready, checks /health, and always cleans up (requires Docker).

⚙️ Configuration

ClickDown is configured through environment variables (Bun auto-loads .env):

Variable Default Description
PORT 3000 Port the HTTP server listens on
DB_PATH data/clickdown.db SQLite database file path
NODE_ENV Set to production for CSRF Origin requirements and quieter logs
APP_URL request origin Browser-facing base URL used for invite links and Origin checks; set this behind a reverse proxy
TRUST_PROXY false Trust X-Forwarded-For for rate-limit keys; enable only behind a controlled proxy
COOKIE_SECURE inferred from APP_URL Force (true) or disable (false) the Secure cookie flag
E2E_TEST Test-only flag that disables rate limiting; set automatically by Playwright, never in production
UPLOAD_DIR data/uploads Local directory for task attachments
LOG_LEVEL debug / info Pino log level (debug in dev, info in production by default)

🤖 MCP (AI agent) endpoint

ClickDown exposes a Model Context Protocol endpoint so AI agents (Claude Code, Cursor, custom scripts, etc.) can find and work on tasks directly.

Endpoint: POST /api/mcp (Streamable HTTP transport, JSON-RPC 2.0)

Setup

  1. Open Profile → API Tokens (MCP) and create a token. It is shown once — copy it.

  2. Register ClickDown with Claude Code (the profile page shows this command pre-filled with your token and URL):

    claude mcp add --transport http clickdown http://localhost:3000/api/mcp \
      --header "Authorization: Bearer cd_your_token_here"
    
  3. In Claude Code, run /mcp to verify the connection.

For config-file based clients (Cursor, etc.):

{
  "mcpServers": {
    "clickdown": {
      "type": "http",
      "url": "http://localhost:3000/api/mcp",
      "headers": { "Authorization": "Bearer cd_your_token_here" }
    }
  }
}

Tokens act as your user (full team access) and can be revoked at any time from the profile page. Only the SHA-256 hash is stored; session cookies are not accepted on the endpoint.

Available tools

Tool Purpose
list_teams / list_boards / get_board Navigate teams → boards → columns
list_tasks Tasks on a board (filter by column, assignee, archived)
get_task Full detail: description, checklist, comments, labels, attachments
create_task / update_task / move_task / archive_task / delete_task Task lifecycle
add_comment Leave progress notes on a task
add_checklist_item / toggle_checklist_item / delete_checklist_item Checklist management
search_tasks Text search across all accessible boards
get_my_tasks Everything assigned to the token's user

All mutations broadcast over the existing WebSocket layer, so open boards update live when an agent makes a change. A typical agent flow: list_teamslist_boardslist_tasksget_taskmove_task + add_comment.

📁 Project Structure

src/
├── index.tsx             # Entry point: handleRequest() + Bun.serve()
├── config/               # Database + migrations runner
├── middleware/           # Session auth
├── mcp/                  # MCP protocol (JSON-RPC) + agent tool definitions
├── models/               # TypeScript types
├── realtime/             # WebSocket pub/sub + presence
├── routes/               # HTTP route handlers
├── services/             # Business logic
├── schemas/              # Zod validation
├── utils/                # access helpers, logger, password, HTML safety
└── components/           # Kita JSX pages, fragments, modals
public/                   # Static assets (custom.css, app.js, favicon)
migrations/               # SQL migrations (001–018, checksummed + auto-applied)
scripts/                  # migrate.ts, e2e-reset.ts
tests/                    # unit, integration, e2e
.github/workflows/        # CI: static gates, E2E, Docker smoke
mise.toml                 # Bun 1.3.14 toolchain pin
data/                     # SQLite DB + uploads (gitignored)

Request flow: Browser → HTMX → handleRequest → auth/access → service → SQLite → Kita JSX → HTML fragment.

🔒 Security notes

  • XSS prevention is enforced in CI@kitajs/ts-html-plugin (bun run xss:scan) fails the build on unescaped JSX; user content is escaped at render, and Markdown is sanitized with http(s)-only links
  • Local-only CSP — all scripts/styles/fonts load from the same origin (vendored, no CDN), with default-src 'self'
  • CSRF — Origin/Referer must match on every mutating request (required in production; APP_URL defines the external origin behind a proxy). The MCP endpoint is exempt: bearer tokens are never sent ambiently by browsers, and session cookies are rejected there
  • Sessions — HttpOnly + SameSite=Lax cookies, 7-day expiry; password and email changes require the current password and revoke other sessions (including live WebSockets)
  • API tokens — shown once at creation, stored as SHA-256 hashes, revocable instantly, deleted with the owning user; a periodic sweep closes WebSockets whose sessions or team access have been revoked
  • Invites — secret, regenerable tokens; team slugs alone never grant access
  • Rate limits — in-memory, scoped per endpoint and per user for auth, join, profile, token creation, markdown preview, uploads (10 MB per file), and task/board/team mutations
  • Attachments — served only to team members, forced Content-Disposition: attachment

💾 SQLite backups

The database is a single file (default data/clickdown.db, plus -wal/-shm in WAL mode).

# Safe online backup while the app is running (SQLite CLI)
sqlite3 data/clickdown.db ".backup 'data/clickdown-backup.db'"

# Or stop the app and copy the files
cp data/clickdown.db data/clickdown.db-wal data/clickdown.db-shm /path/to/backup/

Also back up data/uploads/ if you use attachments. Prefer volume snapshots when running under Docker.

🧪 Testing

  • Unit (tests/unit) — services/utils against in-memory SQLite
  • Integration (tests/integration) — real handleRequest in-process, including the MCP endpoint
  • E2E (tests/e2e) — Playwright against a server on port 3001, including security/hardening regressions (XSS, offline, realtime) and the MCP token flow. Runs on both Chromium and Firefox (two suites skip on Firefox: JS coverage and clipboard permission, which are Chromium-only Playwright APIs).

Install the browser binaries once before running E2E tests:

bunx playwright install chromium firefox
bun run test              # unit + integration
bun run test:coverage
bun run test:e2e          # full Playwright suite
bun run test:e2e:smoke    # smaller auth + security subset
bun run xss:scan          # JSX escaping audit (@kitajs/ts-html-plugin)
bun run ci                # typecheck + XSS scan + lint + unit/integration
bun run ci:full           # ci + full e2e

GitHub Actions (.github/workflows/ci.yml) runs the full gate set on push/PR: static checks + unit/integration, the Playwright suite, and a Docker build with a readiness-probed smoke test.

📋 Available Commands

Command Description
bun run dev Start with hot reload
bun run start Start server (applies migrations first)
bun run build Bundle entry to dist/ (Bun target)
bun run db:migrate Run database migrations
bun run test Unit + integration tests
bun run test:coverage Tests with coverage report
bun run test:e2e Playwright E2E
bun run test:e2e:smoke Fast E2E subset
bun run lint / lint:fix Biome
bun run typecheck tsc --noEmit
bun run xss:scan JSX escaping audit
bun run ci typecheck + XSS scan + lint + unit/integration
bun run ci:full ci + full E2E
bun run smoke:docker Build image, poll /ready, check /health

📄 License

MIT © 2026 amscotti — free to use, modify, and self-host, with attribution.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选