Approved design for a Nuxt 3 site at claudedo.kuns.dev: "the page is the app" concept (3-island layout), build-time release fetch, and a Nitro release proxy that fronts the self-updater to hide the Gitea URL. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
201 lines
9.9 KiB
Markdown
201 lines
9.9 KiB
Markdown
# 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
|
||
```
|