docs: add OVERVIEW.md (what/use/tools/locations/handover) mirroring Obsidian Kontra Day page
This commit is contained in:
153
docs/OVERVIEW.md
Normal file
153
docs/OVERVIEW.md
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
# Kontra — Project Overview
|
||||||
|
|
||||||
|
> **Kontra** is a self-hosted news-opinion site engine. Content is plain Markdown in a git repo;
|
||||||
|
> a single static Go binary renders it into a fast, SEO-friendly editorial site; a Decap CMS admin
|
||||||
|
> (authenticated with Gitea OAuth) lets editors work in the browser; and a git-driven pull loop
|
||||||
|
> publishes changes live within ~30 seconds of a save.
|
||||||
|
|
||||||
|
**Live:** https://kontra.lab.audasmedia.com.au · **Admin:** https://admin.kontra.lab.audasmedia.com.au/web/admin/
|
||||||
|
**Repo (public):** https://gitea.lab.audasmedia.com.au/sam/kontra
|
||||||
|
|
||||||
|
> 🗺 **Interactive architecture map:** https://maps.lab.audasmedia.com.au/kontra_day/docs/kontra-architecture-map.html
|
||||||
|
> (pan/zoom, search, route tracing, dark/light themes)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What it is
|
||||||
|
|
||||||
|
A complete, self-hosted news/opinion publishing platform designed to run on the home lab:
|
||||||
|
|
||||||
|
- **Markdown-first content** — articles are `.md` files with YAML front-matter. No database to manage.
|
||||||
|
- **One static binary** — Go (golang) + templ + htmx + design-token CSS. No runtime, no Node, no PHP.
|
||||||
|
- **Three edit paths** — Obsidian vault, Neovim/CLI, or the Decap CMS browser editor. All converge on one git repo.
|
||||||
|
- **Git is the API** — full history, rollback, branch review, backups included.
|
||||||
|
- **Autopublish** — `git push` → container pulls every 30s → live. Proven for add + delete.
|
||||||
|
- **Self-hosted everything** — Gitea (origin), Garage S3 (media), Caddy (TLS), Decap (admin), Docker (runtime).
|
||||||
|
|
||||||
|
## Architecture (Mermaid)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph editors["Content Editors"]
|
||||||
|
O[Obsidian vault<br/>/obsidian/kontra_content] -->|git push| G
|
||||||
|
N[Neovim / CLI] -->|git push| G
|
||||||
|
D[Decap CMS<br/>admin.kontra.lab] -->|OAuth + git commit| G
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph gitea["Gitea (192.168.20.35 :3001 Docker)"]
|
||||||
|
G[(sam/kontra-content<br/>markdown origin of truth)]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph prod["Kontra container (192.168.20.13 :8600 Docker)"]
|
||||||
|
P[git pull loop<br/>every 30s] -->|restart on change| B
|
||||||
|
B[Go binary<br/>templ + htmx + Goldmark]
|
||||||
|
B --> MD[(Markdown render<br/>front-matter + shortcodes)]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph media["Media (Garage S3 on .13)"]
|
||||||
|
S3[(Garage S3<br/>kontra-day bucket)]
|
||||||
|
end
|
||||||
|
|
||||||
|
G -->|"SSH git"| P
|
||||||
|
B -->|"shortcode: media"| S3
|
||||||
|
B -->|"emits HTML"| CB[Caddy master<br/>.35 :80/:443]
|
||||||
|
CB -->|"reverse_proxy :8600"| B
|
||||||
|
|
||||||
|
subgraph net["Network"]
|
||||||
|
CB -->|https| WWW[kontra.lab.audasmedia.com.au]
|
||||||
|
CB -->|https| ADM[admin.kontra.lab.audasmedia.com.au]
|
||||||
|
end
|
||||||
|
|
||||||
|
WWW -->|browser| B
|
||||||
|
ADM -->|browser| D
|
||||||
|
```
|
||||||
|
|
||||||
|
**Interactive version:** [maps.lab](https://maps.lab.audasmedia.com.au/kontra_day/docs/kontra-architecture-map.html) ·
|
||||||
|
Rendered PNG: `docs/diagrams/kontra-architecture.png` · Mermaid source: `docs/kontra-architecture.mmd`
|
||||||
|
|
||||||
|
## How to use it
|
||||||
|
|
||||||
|
### As an editor
|
||||||
|
1. Open **https://admin.kontra.lab.audasmedia.com.au/web/admin/** → **Login with Gitea** (needs push access to `sam/kontra-content`).
|
||||||
|
2. **Articles** collection: create/edit, set subject/kicker/excerpt/featured, write Markdown body, Save. Wait ~30 s — the site updates.
|
||||||
|
|
||||||
|
Or edit files directly: Obsidian vault (`/home/sam/obsidian/kontra_content`) or clone
|
||||||
|
`ssh://git@gitea.lab.audasmedia.com.au:2222/sam/kontra-content.git`, edit, push.
|
||||||
|
|
||||||
|
### Content model
|
||||||
|
```
|
||||||
|
content/
|
||||||
|
├── config/site.yaml # site name, tagline, nav order
|
||||||
|
├── subjects/<slug>/
|
||||||
|
│ ├── _subject.yaml # name, template, accent color
|
||||||
|
│ └── <slug>.md # article
|
||||||
|
└── pages/<slug>.md
|
||||||
|
```
|
||||||
|
Template resolution: page front-matter → subject `_subject.yaml` → site config → fallback.
|
||||||
|
Media: `{{media:file.jpg}}` (Garage S3), `{{embed:vimeo:ID}}`.
|
||||||
|
|
||||||
|
### As an operator
|
||||||
|
- Restart/redeploy: `ssh sam@192.168.20.13` → `cd /home/sam/Docker/Containers/kontra && docker compose up -d --build`
|
||||||
|
- Pull loop: `entrypoint.sh` in the container (git pull every 30s, restart on change).
|
||||||
|
- Logs: `docker logs -f kontra`
|
||||||
|
- Content: `/var/www/kontra_day/content` on .13 (rw mount into container).
|
||||||
|
|
||||||
|
## Tools used
|
||||||
|
|
||||||
|
| Tool | Role | Where |
|
||||||
|
|---|---|---|
|
||||||
|
| Go (golang) 1.26 | App language — one static binary | `app/` |
|
||||||
|
| templ v0.3 | HTML templates compile-to-Go | `app/src/*.templ` |
|
||||||
|
| htmx | Server-rendered interactivity | templates |
|
||||||
|
| goldmark | CommonMark renderer | `app/src/content.go` |
|
||||||
|
| goccy/go-yaml | Front-matter/config parsing | `app/src/content.go` |
|
||||||
|
| Decap CMS | Browser admin | `app/src/web/admin/` |
|
||||||
|
| Gitea | Git origin (both repos) | .35 Docker :3001 |
|
||||||
|
| Garage S3 | Media (`kontra-day` bucket) | .13 Docker :3900 |
|
||||||
|
| Caddy | TLS + routing | .35 :80/:443 |
|
||||||
|
| Docker / compose | Runtime container | .13 |
|
||||||
|
| Design tokens (CSS vars) | Theming from `DESIGN.md` | `app/src/web/assets/kontra.css` |
|
||||||
|
| Mermaid + Archify | Docs + interactive map | `docs/` |
|
||||||
|
| Obsidian Git | Vault auto-push | .27 |
|
||||||
|
|
||||||
|
## Where things are
|
||||||
|
|
||||||
|
| Thing | Location |
|
||||||
|
|---|---|
|
||||||
|
| App source + deploy + docs | `/home/sam/home_network/web_sites/kontra_day/` (.27) |
|
||||||
|
| Public repo | `https://gitea.lab.audasmedia.com.au/sam/kontra` |
|
||||||
|
| Content repo (origin) | `https://gitea.lab.audasmedia.com.au/sam/kontra-content` |
|
||||||
|
| Production content clone | `.13:/var/www/kontra_day/content` |
|
||||||
|
| Docker project | `.13:/home/sam/Docker/Containers/kontra/` |
|
||||||
|
| Obsidian vault | `/home/sam/obsidian/kontra_content` |
|
||||||
|
| Interactive map | `https://maps.lab.audasmedia.com.au/kontra_day/docs/` |
|
||||||
|
| Plan/decisions | `PLAN.md` |
|
||||||
|
| Design system | `DESIGN.md` |
|
||||||
|
|
||||||
|
## Configs for the future (handover notes)
|
||||||
|
|
||||||
|
### Networking
|
||||||
|
- Master Caddy (.35, `/Docker/Containers/caddy/Caddyfile`) → both `kontra.lab…` and `admin.kontra…` → `reverse_proxy 192.168.20.13:8600`.
|
||||||
|
- .13 Caddy config is back to pre-Kontra. **Kontra runs in Docker — do not re-add to configuration.nix** (NixOS system units are Nix-store-managed).
|
||||||
|
|
||||||
|
### Gitea / OAuth
|
||||||
|
- OAuth app `decap-kontra` (non-confidential / PKCE) in Gitea → Settings → Applications.
|
||||||
|
- Gitea CORS enabled for the admin origin (`GITEA__cors__*` in `/Docker/Containers/gitea/docker-compose.yml`).
|
||||||
|
- Decap `config.yml`: `backend: name: gitea`, simple workflow (no editorial workflow PRs — Gitea backend limitation).
|
||||||
|
|
||||||
|
### Secrets
|
||||||
|
- Gitea deploy token + API base: `.env` at repo root (.27), **gitignored, never commit**. chmod 600.
|
||||||
|
|
||||||
|
### Deploy specifics
|
||||||
|
- Docker image builds Go+templ in-image; runner is slim. Port 8600.
|
||||||
|
- Container mounts content (rw) + `/home/sam/.ssh/id_ed25519` (ro) for the pull.
|
||||||
|
- Pull loop uses `exec` so the server PID is always direct (prior nested-subshell bug caused "address already in use" on restart — fixed).
|
||||||
|
|
||||||
|
### Known-good state (verified 2026-09-09)
|
||||||
|
- Add/delete content → live in ~30 s. Clean restarts.
|
||||||
|
- Front page, `/articles/<slug>`, `/subjects/<slug>` all 200.
|
||||||
|
- Admin renders Decap login; "Login with Gitea" OAuth flow works.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Portfolio/showcase: https://gitea.lab.audasmedia.com.au/sam/kontra (public) — README includes the interactive map, stack, and deploy story. Map: https://maps.lab.audasmedia.com.au/kontra_day/docs/kontra-architecture-map.html*
|
||||||
Reference in New Issue
Block a user