# 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/<encoded-asset-path>`.
  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
```
