feat(atlas): Phase B — data-driven /api/atlas.json, CI stage generated from cd.yml
CD / Detect unsubstituted template (push) Successful in 0s
CD / Lint / Test / Vet (push) Successful in 5s
CD / Build & Import (push) Successful in 14s
CD / Deploy via GitOps (push) Successful in 1s

The atlas no longer hand-maintains its content. Authored data lives in one place
(internal/atlas/atlas.json); the Go layer overlays sourced facts and serves the
result at /api/atlas.json; the frontend fetches + renders (inline arrays kept only
as an offline fallback). First generated source: the CI/CD stage's nodes are parsed
from the repo's own .gitea/workflows/cd.yml — so the viz shows the pipeline that
actually runs (guard/check/build/deploy), dropping the aspirational var-go/oath-gate
node that isn't wired yet. That's the point: it can't drift from the real pipeline.

New internal/atlas package (JobsFromWorkflow, Build) built test-first. Adds
gopkg.in/yaml.v3 (justified: parsing the workflow YAML; stdlib has no YAML).

Verified: go build/vet/lint(0)/test green; /api/atlas.json → 9 stages, CI = real
jobs; frontend renders from the fetch (screenshot).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-20 00:34:06 +02:00
co-authored by Claude Opus 4.8
parent c3fda9b26b
commit a9c72d6ca8
12 changed files with 375 additions and 24 deletions
+16 -8
View File
@@ -1,20 +1,22 @@
package web
import (
"context"
_ "embed"
"encoding/json"
"net/http"
cadatlas "git.d-ma.be/mathias/cad-atlas"
"git.d-ma.be/mathias/cad-atlas/internal/atlas"
)
// atlasHTML is the Phase-A static hero visualization. Phase C replaces this
// self-contained file with a Templ view hydrated from live CAD trace data
// (assessor-loop ledger, session_log, Gitea run API, Flux events).
// atlasHTML is the Phase-A/B static shell. It fetches /api/atlas.json at load
// and renders from that data (no inline arrays), so the content is sourced.
//
//go:embed static/cad-atlas.html
var atlasHTML []byte
// NewHandler serves the CAD Atlas. Root ("/") returns the static atlas;
// /api/hello is a leftover template probe kept until Phase C wires real endpoints.
// NewHandler serves the CAD Atlas: the shell at "/", and the sourced data at
// "/api/atlas.json" (authored data + CI stage generated from the real cd.yml).
func NewHandler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
@@ -25,8 +27,14 @@ func NewHandler() http.Handler {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
_, _ = w.Write(atlasHTML)
})
mux.HandleFunc("/api/hello", func(w http.ResponseWriter, r *http.Request) {
_ = Hello("world").Render(context.Background(), w)
mux.HandleFunc("/api/atlas.json", func(w http.ResponseWriter, r *http.Request) {
a, err := atlas.Default(cadatlas.CDWorkflow)
if err != nil {
http.Error(w, "atlas build failed", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
_ = json.NewEncoder(w).Encode(a)
})
return mux
}