- docs/kontra-architecture.mmd (mermaid source) + rendered PNG/SVG - docs/kontra-architecture-map.html (interactive Archify, validated + visual-checked) - docs/architecture.md (doc with embedded mermaid) - README.md (showcase: stack, content model, design system, deploy, security) - published docs/ to https://maps.lab.audasmedia.com.au/kontra_day/docs/ [secret-scan: skip - false positive on generated mermaid SVG path data]
64 lines
3.3 KiB
Markdown
64 lines
3.3 KiB
Markdown
---
|
|
type: action
|
|
id: action.kontra-day.kontra-phase-3-build-goth-app-complete-golang-gotchas
|
|
title: Kontra Phase 3 build — GOTH app complete + golang gotchas
|
|
status: active
|
|
source_of_truth: false
|
|
freshness: current
|
|
last_reviewed: 2026-09-08
|
|
tags:
|
|
- pack/kontra-day
|
|
- agent-memory/action
|
|
- kontra
|
|
- golang
|
|
- templ
|
|
- goldmark
|
|
- goth
|
|
- build
|
|
---
|
|
|
|
# Kontra Phase 3 build — GOTH app complete + golang gotchas
|
|
|
|
# Kontra — Phase 3 build complete (verified local)
|
|
|
|
## What was built (2026-09-08)
|
|
GOTH stack app at `/home/sam/home_network/web_sites/kontra_day/app`:
|
|
- **golang 1.26.2** (the "Go" in GOTH is golang, NOT Rust-like Go — vgo.mod uses `require (...)` blocks, `package main`, `func main()`).
|
|
- **templ v0.3.1020** — CLI at `~/go/bin/templ` (installed via `go install github.com/a-h/templ/cmd/templ@latest`, path must be on PATH). `.templ` files in `app/src/`, generated with `templ generate` (writes `*_templ.go`), build with `go build -o kontra-bin .` from `app/src/`. Build script: `app/build.sh`.
|
|
- **goldmark v1.8.6** markdown + **goccy/go-yaml v1.19.2**.
|
|
- Single static binary ~11.5MB. `PORT` and `KONTRA_CONTENT` and `KONTRA_MEDIA` env vars.
|
|
|
|
## Key golang gotchas (learned the hard way)
|
|
- `[start:end]` slices PANIC (bounds) if end > len — clamp first! Use helper `firstArticles(a, n)`/`firstSubjects`.
|
|
- No ternary operator; templ `{}` interpolation doesn't support inline `if/else { }` expressions — use block-level `if` between elements, and `templ.KV(" active", cond)` for conditional classes.
|
|
- `//go:embed web` keeps FULL path in the virtual FS → root = `web/`, files at `web/assets/kontra.css`. Serve with `http.Handle("/web/", http.FileServerFS(web))`. Route patterns need trailing-slash (`/web/`) plus `/` catch-all registered LAST.
|
|
- Route specificity works but registers specific before `/`.
|
|
- go-yaml lowers struct field names for keys by default — use lowercase YAML keys (name/tagline/defaulttemplate/subjects/label/slug).
|
|
- log: `log.Printf`/`log.Fatalf` (no log.Errorf).
|
|
- golang stdlib net/http: `http.Handle(pattern, handler)`, `http.HandleFunc`, `http.ListenAndServe(":8080", nil)`, `r.URL.Path`, `r.PathValue("slug")`. Patterns: `/subjects/{slug}`.
|
|
- All source files `package main`; go.mod `module day`.
|
|
|
|
## Content model
|
|
`content/` tree: `config/site.yaml`, `subjects/<slug>/_subject.yaml` + `*.md`, `pages/*.md`. Front-matter keys lowercase: title/author/date/kicker/template/subject/image/excerpt/featured/published. Shortcodes `{{media:name}}`→`KONTRA_MEDIA` base + `/name`; `{{embed:vimeo:ID}}`→iframe. Resolved on RAW markdown BEFORE goldmark so links work.
|
|
|
|
## Admin
|
|
Decap CMS at `app/src/web/admin/` (index.html + config.yml): git-gateway backend → Gitea, collections articles/subjects/pages + editorial workflow. Served at `/web/admin/`.
|
|
|
|
## Verified routes (local smoke test, PORT=8691)
|
|
/, /articles/{slug}, /subjects/{slug}, /web/assets/kontra.css, /web/admin/ → all 200. 404 for missing article/subject.
|
|
|
|
## Git
|
|
Committed to local repo (no remote yet): commit 31e9a70. `.pi/` memory vault is inside the repo too.
|
|
|
|
## Not done yet (task 7)
|
|
Gitea remotes (.35), Obsidian vault, .13 systemd service + 30s git pull timer, Caddy routes (kontra.domain + admin), Decap git-gateway OAuth app.
|
|
|
|
## Evidence
|
|
|
|
- Confidence: 100%
|
|
- Reason: Manual memctx_save
|
|
|
|
## Related
|
|
|
|
- [[packs/kontra-day/00-system/pi-agent/memory-manifest|Memory Manifest]]
|