Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions .github/workflows/site-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,20 @@ jobs:
with:
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}

- name: Prepare site
- name: Prepare deploy bundle
run: |
mkdir -p _site
cp docs/mindmap.html _site/index.html
set -euo pipefail
mkdir -p _bundle/public
# Static tree → artifact public/ (Deploy copies only _bundle/public and _bundle/worker into cloudflare_site/).
# Root page: interactive graph (source of truth: web/public/index.html).
# When a Vite app exists under web/, extend this step (e.g. _bundle/public/admin/).
cp web/public/index.html _bundle/public/index.html
# Worker source from this checkout (PR head on PR builds) — deploy never clones PR for Wrangler; only this tree is untrusted.
mkdir -p _bundle/worker
cp -a cloudflare_site/worker/. _bundle/worker/

- uses: actions/upload-artifact@v4
with:
name: site
path: _site/
path: _bundle/
retention-days: 5
34 changes: 31 additions & 3 deletions .github/workflows/site-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,44 @@ jobs:
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
steps:
# Trusted tree only: wrangler.toml must not come from PR checkout (no PR-controlled [build] on the deploy runner).
# PR/fork Worker + static files ship in the Build Site artifact under _bundle/; we copy only public/ and worker/ (never extract TOML from the zip into cloudflare_site/).
- uses: actions/checkout@v6.0.2

- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: site
path: site/public
path: _bundle
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}

- name: Apply artifact to Cloudflare project
run: |
set -euo pipefail
if [[ ! -d _bundle ]]; then
echo "::error::Missing _bundle after artifact download"
exit 1
fi
while IFS= read -r -d '' entry; do
b=$(basename "$entry")
if [[ "$b" != "public" && "$b" != "worker" ]]; then
echo "::error::Disallowed path in site artifact: $b (only public/ and worker/ may exist at the top level of _bundle/)"
exit 1
fi
if [[ ! -d "$entry" ]]; then
echo "::error::_bundle/$b must be a directory"
exit 1
fi
done < <(find _bundle -mindepth 1 -maxdepth 1 -print0)
if [[ ! -d _bundle/public ]] || [[ ! -d _bundle/worker ]]; then
echo "::error::Artifact must contain _bundle/public/ and _bundle/worker/"
exit 1
fi
mkdir -p cloudflare_site/public cloudflare_site/worker
cp -a _bundle/public/. cloudflare_site/public/
cp -a _bundle/worker/. cloudflare_site/worker/

- name: Resolve preview context (PR number + preview alias)
id: preview-context
if: success()
Expand Down Expand Up @@ -86,7 +114,7 @@ jobs:
uses: cloudflare/wrangler-action@v3.14.1
with:
wranglerVersion: "4.30.0"
workingDirectory: site
workingDirectory: cloudflare_site
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: deploy --name="${{ vars.CLOUDFLARE_PROJECT_NAME }}"
Expand All @@ -97,7 +125,7 @@ jobs:
uses: cloudflare/wrangler-action@v3.14.1
with:
wranglerVersion: "4.30.0"
workingDirectory: site
workingDirectory: cloudflare_site
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: >-
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ fmt:
uvx ruff format .

mindmap:
@xdg-open docs/mindmap.html 2>/dev/null || open docs/mindmap.html 2>/dev/null || echo "Open docs/mindmap.html in your browser"
@xdg-open web/public/index.html 2>/dev/null || open web/public/index.html 2>/dev/null || echo "Open web/public/index.html in your browser"

VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ This is not a product spec. It's an evolving exploration of a hard problem space
- **[docs/problems/applied/](docs/problems/applied/)** — Organization-specific considerations for downstream consumers:
- [konflux-ci](docs/problems/applied/konflux-ci/) — Kubernetes-native CI/CD platform (the original proving ground)
- **[docs/ADRs/](docs/ADRs/)** — Architecture Decision Records for crystallizing specific decisions (see [ADR 0001](docs/ADRs/0001-use-adrs-for-decision-making.md))
- **[web/](web/)** — Browser-delivered assets for the public site (document graph today; future Vite app here). Cloudflare Worker config lives in [`cloudflare_site/`](cloudflare_site/) ([ADR 0019](docs/ADRs/0019-web-source-and-cloudflare-site-layout.md)).
- **[docs/landscape.md](docs/landscape.md)** — Survey of AI code review tools, orchestration patterns, and connectivity gateways; how they relate to our goals (time-sensitive — check the date)
- **[experiments/](experiments/)** — Logs and results from trying things in practice

Expand Down
File renamed without changes.
20 changes: 20 additions & 0 deletions cloudflare_site/worker/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/// <reference types="@cloudflare/workers-types" />

/**
* Minimal Worker: serve static assets from `[assets]` only.
* Future OAuth or API routes extend this file; Wrangler project layout stays stable.
*/
export interface Env {
ASSETS?: Fetcher;
}

export default {
async fetch(request: Request, env: Env): Promise<Response> {
if (env.ASSETS != null) {
return env.ASSETS.fetch(request);
}
return new Response("Worker misconfigured: ASSETS binding missing", {
status: 503,
});
},
};
14 changes: 14 additions & 0 deletions cloudflare_site/wrangler.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Cloudflare Worker + static assets. User Worker entry is worker/src/index.ts (stub passes through ASSETS).
# Deploy: site-deploy.yml checks out the default branch (trusted TOML), downloads the Build Site artifact to _bundle/, copies only ./public/ and ./worker/ from it, then runs Wrangler here.
# The workflow passes --name to match your account Worker name (GitHub variable CLOUDFLARE_PROJECT_NAME).
# See: https://developers.cloudflare.com/workers/static-assets/

name = "documentation-site"
main = "worker/src/index.ts"
compatibility_date = "2026-04-09"
workers_dev = true
preview_urls = true

[assets]
directory = "./public"
not_found_handling = "single-page-application"
35 changes: 35 additions & 0 deletions docs/ADRs/0019-web-source-and-cloudflare-site-layout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
title: "0019. Web source under web/ and Cloudflare project under cloudflare_site/"
status: Accepted
relates_to:
- contributor-guidance
topics:
- repository-layout
- ci
- cloudflare
---

# 0019. Web source under `web/` and Cloudflare project under `cloudflare_site/`

Date: 2026-04-15

## Status

Accepted

## Context

This repository mixes design documents, Go CLI code (`cmd/`), and a small **browser-delivered** surface (today the interactive document graph). That surface was previously rooted at `docs/mindmap.html` while Cloudflare Wrangler lived under `site/`, which read as a generic “website” folder rather than “Cloudflare deploy boundary,” and blurred documentation versus deployable HTML. Separating **`web/`** (browser source) from **`cloudflare_site/`** (Wrangler + deploy-time static) makes layout and CI obvious for contributors.

## Decision

1. **Browser-oriented source** (static HTML today; future Vite entrypoints and assets) lives under **`web/`**, starting with the document graph as **`web/public/index.html`** (served at `/` in production). **Node tooling** (`package.json`, lockfile, and scripts such as `npm run dev` / `npm run build`) stays at the **repository root** so day-to-day work does not require `cd web`; Vite config may still point `root` at `web/` (or a subdirectory) for resolution.
2. The **sole Wrangler project** in this repository lives under **`cloudflare_site/`** (`wrangler.toml` from the default-branch checkout on deploy, plus **`public/`** and **`worker/`** filled from the Build Site artifact). The GitHub Actions **Deploy Site** workflow continues to use **`workingDirectory: cloudflare_site`**, downloads the artifact to **`_bundle/`**, and copies only **`public/`** and **`worker/`** into **`cloudflare_site/`**; workflow **names** (`Build Site`, artifact `site`, environments `site-preview` / `site-production`) stay stable for existing automation and operators.
3. **Build Site** assembles **`_bundle/`** from `web/` (and later from JS build outputs) without changing that deploy contract.

## Consequences

- Contributors edit the live mindmap at **`web/public/index.html`** instead of **`docs/mindmap.html`**.
- Paths in runbooks and local Wrangler preview use **`cloudflare_site/`** instead of **`site/`**.
- Future SPA work adds **Vite** (and related devDependencies) using the **root** `package.json`, with source and config under **`web/`**, and extends **`site-build.yml`** to merge build output into **`_bundle/public/`** (and keep **`_bundle/worker/`** in sync) without renaming **`cloudflare_site/`** again.
- Links and docs that referred to `site/wrangler.toml` or `docs/mindmap.html` must be updated when backporting older instructions.
4 changes: 4 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,7 @@ ADR 0002: [Building block 12](ADRs/0002-initial-fullsend-design.md#12-coordinato

Traceability layer across issue, **Triage**, **Code**, **Review**, checks, and merge for incident response and correlation across automation runs.
ADR 0002: [Building block 13](ADRs/0002-initial-fullsend-design.md#13-observability).

## Repository layout (design workspace vs. web delivery)

The repository combines design documents, Go CLI code, and a small **public web** surface. **Decided:** Browser-oriented static source and future bundled UI live under **`web/`** (the interactive document graph is `web/public/index.html` at `/`). Cloudflare Wrangler configuration and deploy-time static assets live under **`cloudflare_site/`** (single `wrangler.toml`; CI stages **`_bundle/`** on the deploy runner and copies only **`public/`** and **`worker/`** from the artifact into that tree so **`wrangler.toml` is never taken from the PR-built zip**). See [ADR 0019](ADRs/0019-web-source-and-cloudflare-site-layout.md).
12 changes: 6 additions & 6 deletions docs/site-deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@

## Overview

This repository publishes a static documentation site built from `docs/mindmap.html` (copied to `_site/index.html` in CI, then deployed from `site/public/`). Deployment uses **Cloudflare Workers with [static assets](https://developers.cloudflare.com/workers/static-assets/)** (not the legacy **Pages direct-upload** / `wrangler pages deploy` flow).
This repository publishes a static documentation site whose root page is built from [`web/public/index.html`](../web/public/index.html). **Build Site** packs **`public/`** (static files) and **`worker/`** (TypeScript Worker from the same checkout—PR head on PR builds) under **`_bundle/`** in one artifact. **Deploy Site** checks out **only the default branch** (trusted [`cloudflare_site/wrangler.toml`](../cloudflare_site/wrangler.toml); never PR-controlled config on the secret-bearing runner), downloads the artifact to **`_bundle/`**, then **copies only** **`_bundle/public/`** and **`_bundle/worker/`** into **`cloudflare_site/`** (so a malicious artifact cannot overwrite `wrangler.toml` or other repo files), then runs Wrangler. Deployment uses **Cloudflare Workers with [static assets](https://developers.cloudflare.com/workers/static-assets/)** (not the legacy **Pages direct-upload** / `wrangler pages deploy` flow).

Two GitHub Actions workflows:

- **Build Site** — on `pull_request` and `push` to `main`, checks out the PR head when relevant, builds `_site/`, uploads artifact **`site`**.
- **Deploy Site** — on successful **Build Site** via `workflow_run`, checks out the repo (for [`site/wrangler.toml`](../site/wrangler.toml)), downloads the artifact into `site/public/`, then:
- **Build Site** — on `pull_request` and `push` to `main`, checks out the PR head when relevant, assembles **`_bundle/public/`** and **`_bundle/worker/`**, uploads artifact **`site`** (`_bundle/` contents).
- **Deploy Site** — on successful **Build Site** via `workflow_run`, checks out the repo default ref (trusted Wrangler project files), downloads artifact **`site`** into **`_bundle/`**, copies **`public/`** and **`worker/`** into **`cloudflare_site/`**, then:
- **push to `main`:** `wrangler deploy` → production Worker traffic.
- **pull_request:** `wrangler versions upload --preview-alias pr-<pr-number>` → preview URL on `*.workers.dev` without changing production (alias falls back to `pr-<workflow_run.id>` only when the same fork branch matches more than one open PR).

GitHub **Deployments** use environments **`site-preview`** and **`site-production`**; PRs also get a single upserted comment with the preview link.

For architecture and naming, see [2026-04-09-site-cloudflare-pages-design.md](superpowers/specs/2026-04-09-site-cloudflare-pages-design.md) (document filename still says “pages” for history; content describes Workers).
For architecture and naming, see [2026-04-09-site-cloudflare-pages-design.md](superpowers/specs/2026-04-09-site-cloudflare-pages-design.md) (document filename still says “pages” for history; content describes Workers). Repository layout for `web/` vs `cloudflare_site/` is decided in [ADR 0019](ADRs/0019-web-source-and-cloudflare-site-layout.md).

## Cloudflare setup

Expand Down Expand Up @@ -64,8 +64,8 @@ Disable **GitHub Pages** under **Settings → Pages** if it was only used for th
From the repository root:

```bash
mkdir -p site/public && cp docs/mindmap.html site/public/index.html
cd site && npx wrangler@4 dev
mkdir -p cloudflare_site/public && cp web/public/index.html cloudflare_site/public/index.html
cd cloudflare_site && npx wrangler@4 dev
```

Requires a Cloudflare login or API token in the environment per [Wrangler docs](https://developers.cloudflare.com/workers/wrangler/).
Expand Down
Loading
Loading