# ClaudeDo distribution website — design **Date:** 2026-06-04 **Status:** Approved (design), ready for implementation planning **Repo:** new standalone repo `claudedo-web` (not part of the ClaudeDo app solution) **Domain:** `claudedo.kuns.dev` (Coolify on the user's VPS) ## Purpose Give friends a public place to download ClaudeDo and learn what it does, without sending them to the Gitea repo — so the source repo can be made more private. The site also fronts the app's self-updater so the Gitea URL is never exposed in the app or on the page. ## Goals / non-goals **Goals** - Public, no-auth landing page at `claudedo.kuns.dev` that matches the app's visual identity. - A primary download (installer `.exe`) plus the portable `.zip` and checksums. - A release proxy that (a) feeds the page the current version and (b) serves the app's self-updater the same JSON shape Gitea returns, with download URLs rewritten to route through `claudedo.kuns.dev` — hiding Gitea entirely. **Non-goals** - No docs site / getting-started page (the app ships an installer that handles setup). - No changelog page (release notes already live on Gitea releases). - No auth, accounts, analytics, or CMS. - No CI/PR tooling for this repo beyond what Coolify needs to deploy. ## Access & distribution decisions - **Access:** fully public. No password/login. Relies on the unadvertised URL. - **Download source:** build-time fetch of the latest Gitea release for the displayed version; actual download links route through the proxy and resolve the latest asset at request time (so a stale page still downloads the current build). - **Self-updater proxy:** in scope for v1 (not deferred). ## Tech stack - **Nuxt 3** (Vue 3) — single framework, single repo, single Coolify deploy. - **Nitro** server routes for the release proxy + asset streaming. - **No DB, no auth, no secrets** (the `releases/ClaudeDo` repo is public). - Fonts: **Inter Tight** (display/body) + **JetBrains Mono** (mono), self-hosted or via Google Fonts. Design tokens ported from `docs/UI Rewrite/design_handoff_claudedo/Tokens.axaml` and `styles.css` (moss/sage/peat palette, dark-first, 14px island radius, grain texture). ## Concept: "the page IS the app" The landing page is a faithful, in-browser rendering of the ClaudeDo desktop — the window chrome + the three islands — rather than a conventional marketing page. This is the chosen direction (over a cinematic single-window scroll and a worklog feed). ### Layout — three islands on the app "desktop" Desktop background = the app's layered moss gradients + 3px grain overlay. A centered app `window` (titlebar + body) holds a 3-column island grid: 1. **Lists island (left)** — repurposed as page nav. - Header "Lists" + a decorative search box (`Ctrl K` kbd chip). - "Pages" group: Overview · Features (6) · How it works · Screenshots (3) · Download, each with a colored swatch dot; active item gets the accent left-bar. - Footer styled like the app's user footer: avatar, "For friends", `claudedo.kuns.dev`. 2. **Tasks island (middle)** — features rendered as **task cards**. - Header: date eyebrow, big title (the hero line "Queue the work. Claude does it."), a `running · review` badge, eye/gear icon buttons, and a subtitle. - A decorative "Add a task…" row. - Six **feature cards** (circle check — done cards filled; title; a status chip `done`/`running`/`waiting for review`; a star). The features: 1. Isolated worktrees 2. The task queue 3. Review & merge 4. Live session log 5. Per-list & per-task config 6. Self-updating - A "Ready" group with the final **"↓ Download ClaudeDo"** card. 3. **Detail island (right)** — faithful to the reworked Task-Detail island. - **Source of truth for the detail visuals:** `docs/superpowers/specs/2026-06-04-task-detail-redesign-design.md` (the app's in-progress rework). The website's detail pane must track that design. - Three-zone stack: - **Task header** — mono id (`#F01…`), title, trash/gear action icons. - **DETAILS bar** — `DETAILS` eyebrow + `Edit` / copy / `⋯`, then a **markdown body** (headings, paragraphs, inline `code`, ordered/unordered lists) describing the feature. - **WorkConsole** docked at the bottom — traffic-light dots, `· N turns · +x −y`, tabs **Output / Actions / Session**, and a `Created …` footer. - Per-feature mapping: - Feature panels: markdown writeup in DETAILS + a short relevant **Output** log. - "Review & merge": opens on the **Actions** tab with `Merge target` + `Open Diff` / `Approve & merge`. - **Download**: DETAILS shows requirements (`.NET 8 Desktop Runtime`, `Claude CLI`, `Git`); the **Actions** tab holds the install controls, with `Merge target` repurposed as a **Build** selector and buttons `↓ Download installer` / `Portable .zip` / `checksums.txt`. 4. **Statusbar (bottom)** — `● Online · claudedo.kuns.dev · private build`. ### Interaction - Clicking a task card selects it (accent bar + card highlight) and swaps the active detail panel; the WorkConsole tabs are clickable within a panel. - **All panels are server-rendered and present in the DOM**, toggled by class — the page is fully readable and downloadable **without JavaScript** (progressive enhancement). Vue handles the selection state on the client. ### Responsive - ≤ ~1100px: drop the Detail island; show Lists + Tasks. - ≤ ~780px: single column — the Tasks list; tapping a feature pushes to a full-screen Detail view (mirrors the app's narrow-window behavior) with a back affordance. ## Server: release proxy (Nitro) The app's `ReleaseClient` (`src/ClaudeDo.Releases/ReleaseClient.cs`) calls `{apiBase}/releases/latest` and reads `tag_name`, `name`, and `assets[].browser_download_url`; `DownloadAsync` GETs an asset URL directly. - **`GET /api/releases/latest`** — fetches `https://git.kuns.dev/api/v1/repos/releases/ClaudeDo/releases/latest`, returns the **same JSON shape**, but every `assets[].browser_download_url` is rewritten from the Gitea URL to `https://claudedo.kuns.dev/api/download/`. Cached briefly (e.g. 5 min) server-side. - **`GET /api/download/[...path]`** — reconstructs the Gitea asset URL from the path and **streams** the binary back (no redirect to Gitea, so the URL stays hidden). Sets appropriate `Content-Type`/`Content-Disposition`. - **`server/utils/gitea.ts`** — shared base URL (`GITEA_API`, `REPO` from env), fetch helper, and the URL-rewrite/asset-path round-trip. - The page's download buttons point at the same `/api/download/...` routes (with a stable "latest installer" path), so links never go stale between deploys. ### App-side coordinating change (separate, in the ClaudeDo repo) Point `ReleaseClient`'s `apiBase` at `https://claudedo.kuns.dev/api` instead of the Gitea default (one-line DI change where `ReleaseClient`/`UpdateCheckService` are constructed). Tracked as a follow-up; not part of the `claudedo-web` repo. The proxy path (`/api/releases/latest`) is chosen to match the existing `{apiBase}/releases/latest` call so the parser is untouched. ## Content / assets - **Screenshots (provided):** main 3-column view (hero), diff review modal, worktrees panel. Stored in `public/screenshots/`. Placeholders sized for them until dropped in. - Copy: hero "Queue the work. Claude does it."; six feature writeups as above (final wording during implementation). ## Error handling - **Build-time release fetch fails:** render the page with a last-known/placeholder version label; download buttons still work because they resolve via the runtime proxy route. - **Proxy `/api/releases/latest` upstream failure:** return a 502/`null`-equivalent the way Gitea would on miss; the app's `UpdateCheckService` already treats null/exception as `CheckFailed` and degrades gracefully. - **`/api/download` upstream failure:** surface a 502; the button shows an error state. - No retries beyond a single upstream attempt for v1 (low traffic, friends-only). ## Testing - **Vitest** unit tests for `server/utils/gitea.ts`: URL rewrite (Gitea → proxy) and the asset-path round-trip (proxy path → Gitea URL), and release-JSON shape preservation. - A light component smoke test that the page renders the islands and the download controls without JS errors. - No real-network/Gitea calls in tests — mock the upstream fetch. ## Deployment (Coolify) - **Dockerfile**: `node:20-alpine` build → `nuxt build` → run `.output/server/index.mjs`. - Coolify app bound to `claudedo.kuns.dev` with TLS via its reverse proxy. - Env: `GITEA_API` (default `https://git.kuns.dev/api/v1`), `REPO` (`releases/ClaudeDo`), `PUBLIC_BASE_URL` (`https://claudedo.kuns.dev`) for URL rewriting. - Deploy on push to `main`; re-deploy (or a periodic rebuild) refreshes the displayed version. No PR/CI tooling beyond Coolify's build. ## Open risk - The reworked Detail island in the app is still in flux. The website's detail pane must be kept in sync with `2026-06-04-task-detail-redesign-design.md`; expect a visual-polish pass once that rework lands. ## Repo layout ``` claudedo-web/ ├── nuxt.config.ts ├── app.vue ├── pages/index.vue # the one landing page ├── components/ │ ├── AppWindow.vue # window chrome + statusbar │ ├── ListsIsland.vue # page nav │ ├── TasksIsland.vue # feature cards + download card │ ├── DetailIsland.vue # three-zone detail (header / DETAILS md / WorkConsole) │ ├── WorkConsole.vue # tabs: Output / Actions / Session │ └── content/ # per-feature markdown/blurbs + download panel ├── server/ │ ├── api/releases/latest.get.ts │ ├── api/download/[...path].get.ts │ └── utils/gitea.ts ├── assets/css/tokens.css # palette + type ported from Tokens.axaml/styles.css ├── public/screenshots/ # 3 PNGs └── Dockerfile ```