168 lines
11 KiB
Markdown
168 lines
11 KiB
Markdown
# Kontra Day — Phase One Plan
|
|
|
|
## 1. Goal
|
|
|
|
A news-opinion website ("Kontra Day") with an admin panel. Pages are mainly text with images, links, video. Subject areas in navigation. Admin can add/remove/change pages, set subject areas, control what's on the front page, and edit media. Hosted on the home network (192.168.20.13), exposed via Caddy. SEO-friendly.
|
|
|
|
## 2. Decisions (from conversation)
|
|
|
|
| Decision | Choice | Why |
|
|
|---|---|---|
|
|
| **Stack** | **Go + templ + htmx + Alpine + Tailwind** ("GOTH") | Single static binary, server-rendered (SEO), no runtime deps. htmx for interactivity. |
|
|
| **Content format** | **Markdown (.md) + front-matter** | You write in never loses portability. Obsidian/Neovim native. Render via Goldmark (Go's CommonMark lib). |
|
|
| **Admin** | **Decap CMS** (at `admin.kontra.day`) | Free, open-source, browser-based UI that edits the same `.md` files directly and commits to git. No custom admin to build/maintain. |
|
|
| **Content source of truth** | **Git repo on Gitea (.35)** | History, rollback, multi-editor sync, off-site backup path. Matches your Gitea/Obsidian habits. |
|
|
| **Templates** | **templ components** chosen per page (front-matter `template:`) | See §6 — page-level → subject-level → site-level → theme fallback. |
|
|
| **Media** | **Git files beside each article** (`{{media:<slug>/<file>}}`) — Garage S3 dropped 2026-09-10 | Robust, versioned, backed up with content; no object-store auth/sync. |
|
|
| **Colours** | **CSS design tokens** (CSS custom properties), admin-editable values, not code | Per-subject accent colours as data, no template edits. |
|
|
| **Deploy** | **Git push → systemd timer `git pull` every 30s on .13** (no build step; Go renders on request) | Instant content updates; .27 can be offline. Timer chosen over webhook (fewer moving parts). |
|
|
| **Email phase (V)** | Revisit later — Go mail libs or hand off to network tooling | Defer until requirements are real. |
|
|
|
|
## 3. Topology (verified)
|
|
|
|
| Machine | IP | Role | Relevant bits |
|
|
|---|---|---|---|
|
|
| **.27** sam-4screen-desktop | 192.168.20.27 | Dev box — Neovim + Obsidian | Obsidian vault at `/home/sam/obsidian/` |
|
|
| **.13** nixos-desktop | 192.168.20.13 | **Web host, always-on** | Sites in `/var/www/`. Runs: Docker (Garage S3, Outline, PocketBase, family-home-lab stack), cluster of websites. Go binary + site lives here. |
|
|
| **.35** sam-ubuntu1 | 192.168.20.35 | Docker server | **Gitea** (web :3001, SSH :2222) = repo origin. **Caddy master reverse proxy** (`/Docker/Containers/caddy/`). Multiple other containers. |
|
|
| **.23** file-server | 192.168.20.23 | NFS file server | Backup target (via `.35` `/mnt/nfs_usb_3tb`). |
|
|
| **Garage S3** | — | Object storage **on .13** | S3 API `.13:3900`, admin `.13:3902`, `s3.lab.audasmedia.com.au`. Web UI intended at `garage-ui.lab.audasmedia.com.au`. |
|
|
|
|
### Key service locations (verified from notes)
|
|
|
|
| Service | Where | Note |
|
|
|---|---|---|
|
|
| **Gitea** | Docker on **.35** (`gitea-server-1`) | web `.35:3001`, SSH `.35:2222`, `gitea.lab.audasmedia.com.au` |
|
|
| **Caddy (master proxy)** | Docker on **.35** | Caddyfile in `/Docker/Containers/caddy/`. Routes `*.lab.audasmedia.com.au` + `kontra.day` |
|
|
| **Garage S3** | Docker on **.13** | `/home/sam/deployment/garage/`. Buckets per user + `shared-media`. v1.0.0 |
|
|
| **Outline** | Docker on **.13:3000** | `outline.lab.audasmedia.com.au`. Uses Garage S3 storage. REST API + MCP |
|
|
| **Vikunja** | vikunja.lab.audasmedia.com.au | Tasks + kanban. REST API `.../api/v1`. Token in `~/.config/environment.d/10-secrets.conf` |
|
|
| **Web files** | `.13:/var/www/` | NixOS `users` group → new folders need `sudo chown -R sam:users /var/www/<folder>` |
|
|
|
|
## 4. File / storage layout
|
|
|
|
### 4.1 Content repo (single git repo, origin on Gitea .35)
|
|
|
|
Proposed repo: `sam/kontra-day-content` on Gitea.
|
|
|
|
```
|
|
kontra-day-content/
|
|
├── config/
|
|
│ ├── site.yaml # site name, default template, nav, SEO defaults
|
|
│ ├── templates.yaml # template list
|
|
│ └── frontpage.yaml # front-page composition (blocks, order, featured)
|
|
├── subjects/ # one dir per subject area
|
|
│ ├── politics/
|
|
│ │ ├── _subject.yaml # name, slug, template default, accent colour
|
|
│ │ └── post-1.md
|
|
│ └── tech/
|
|
│ ├── _subject.yaml
|
|
│ └── article-2.md
|
|
├── articles/ # (optional flat pool w/ subject in front-matter)
|
|
├── pages/ # standalone pages (about, contact, 404)
|
|
└── media/ # (optional local fallback; primary = Garage S3)
|
|
```
|
|
|
|
Front-matter per page:
|
|
```yaml
|
|
---
|
|
title: My Opinion Piece
|
|
author: Sam
|
|
date: 2026-01-01
|
|
tags: [politics, tech]
|
|
template: article # which template
|
|
subject: politics # which subject area
|
|
image: {{media:cover.jpg}}
|
|
excerpt: A short summary...
|
|
published: true
|
|
publish_at: 2026-01-01 # optional scheduled publish
|
|
---
|
|
Body markdown here...
|
|
```
|
|
|
|
### 4.2 Distribution of copies
|
|
|
|
| Machine | Role | Path |
|
|
|---|---|---|
|
|
| **.35** (Gitea) | **Origin** — single source of truth | `sam/kontra-day-content` |
|
|
| **.13** (web host) | **Production clone** the Go binary serves | `/var/www/kontra_day/` |
|
|
| **.27** (dev) | **Authoring clone** — Obsidian vault + Neovim | `/home/sam/obsidian/kontra_day/` (separate small vault) |
|
|
|
|
- **Obsidian (DECIDED: option b)**: the content repo folder is a **separate small Obsidian vault** at `/home/sam/obsidian/kontra_day/`. It IS the `kontra-day-content` git repo → clean git-sync + deploy; main vault untouched. Obsidian's **git-sync plugin** pushes to Gitea automatically. User switches vaults in Obsidian when writing.
|
|
- **.13 never depends on .27** — it pulls from Gitea. Dev box can be offline; site stays live.
|
|
|
|
### 4.3 Sync / deploy flow
|
|
|
|
```
|
|
Editor on .27 Gitea on .35 Production on .13
|
|
Neovim / Obsidian ──push──▶ origin ──webhook/poll──▶ git pull
|
|
(clone) ▲ │
|
|
│ ▼
|
|
Decap (admin.kontra.day) ──commit──┘ Go binary renders .md → HTML
|
|
```
|
|
|
|
- **Trigger** (DECIDED): **systemd timer `git pull` every 30s on .13**. No webhook.
|
|
- **Obsidian git-sync** plugin auto-syncs (commit+push) on .27 (separate kontra_day vault). Neovim saves → auto-commit via small file-watcher if desired.
|
|
|
|
## 5. Media (Garage S3, on .13)
|
|
|
|
- **Bucket**: Garage on `.13` (S3 API `.13:3900`, admin `.13:3902`). **New dedicated bucket `kontra-day`** (DECIDED) — **do NOT rename/repurpose `shared-media`** (other systems depend on it). New bucket gets its own access keys; media isolated, independently wiped/backed up.
|
|
- **Access**: public reads via **Caddy route** (`/media/*` → bucket) rather than exposing Garage's port; private buckets can use presigned URLs. S3 root domain `.s3.lab.audasmedia.com.au`.
|
|
- **Admin shows media from Garage**: **Decap CMS media library** (DECIDED).
|
|
- **Shortcodes in .md**: `{{media:cover.jpg}}`, `{{vimeo:12345}}` → renderer resolves slug → actual URL at render time. Rename/migrate media without touching articles.
|
|
- **Reference notes**: [[Garage Web UI — handoff]] (web UI at `garage-ui.lab.audasmedia.com.au`, `khairul169/garage-webui` matching Garage v1.x), credentials in `.env` (admin token `GARAGE_ADMIN_TOKEN`).
|
|
|
|
## 6. Templates & design control (where template choice lives)
|
|
|
|
Resolution order: **page front-matter → subject `_subject.yaml` → site config → theme fallback**.
|
|
|
|
| Level | Field | Stored in |
|
|
|---|---|---|
|
|
| Page | `template: article` | front-matter |
|
|
| Subject | `template: photo-essay` (default for its pages) | `subjects/x/_subject.yaml` |
|
|
| Site | default template | `config/site.yaml` |
|
|
| Fallback | base template | theme folder |
|
|
|
|
- **Front page**: a special `home` template whose *composition* (blocks list: which subjects, order, featured stories) is an editable config (`config/frontpage.yaml`) — admin reorders/feeds blocks without touching code.
|
|
- **Colours**: CSS custom properties (design tokens like `--accent`). Per-subject overrides via a data attribute. Admin edits token *values*, never templates.
|
|
- **New templates = code = a deploy step** (fine; Phase 3).
|
|
|
|
## 7. Deploy config notes
|
|
|
|
- **Go binary runs in `/var/www/kontra_day` on .13** (per user decision).
|
|
- **Caddy on .35 is the master reverse proxy.** It routes `kontra.day` → `.13` Go binary, `admin.kontra.day` → Decap on `.13`.
|
|
- **.13 Nix config note**: The user indicated a note needs adding to `home.nix` or `configuration.nix` on .13 for Caddy/site serving. (Likely a Caddyfile or reverse-proxy snippet on .13 to serve `/var/www/kontra_day`; the exact Nix file — `configuration.nix` for services vs `home.nix` — to be confirmed when the .13 Caddy/Nix layout is inspected in Phase 3.)
|
|
- Permissions (.13): web folders use NixOS `users` group — new folders need `sudo chown -R sam:users /var/www/kontra_day`.
|
|
- Current sites deploy via manual lsyncd .27→.13; this site uses git-based deploy instead (see §4.3). Retire lsyncd for this site.
|
|
|
|
## 8. Phase One deliverables (this plan + tasks)
|
|
|
|
- [ ] This PLAN.md (decisions, topology, file layout)
|
|
- [ ] Register tasks in **Vikunja** (projects, stages) and **Outline** (docs) — see PHASE ONE section
|
|
- [ ] Confirm open items: exact Caddy/Nix file on .13, webhook vs timer, Decap media library approach, Garage bucket name
|
|
- [ ] Phase 2 (design) kickoff when approved
|
|
|
|
## 9. Phases (from AGENT.md)
|
|
|
|
1. **Phase One — Planning**: tech stack, content model, admin, storage layout ✅ (this file)
|
|
2. **Phase Two — Design**: front-end + admin design options, demo images/templates
|
|
3. **Phase Three — Build & test**: Go binary, templates, Decap admin, media, deploy
|
|
4. **Phase Four — Create Live**: see system-architect skill when ready
|
|
5. **Phase Five — Link email & DNS**: see Website Host Migration plan when ready
|
|
6. **Phase Six — Integration**: console, backups
|
|
7. **Phase Seven — Marketing**: populate website, marketing
|
|
|
|
## 10. Decisions & remaining open items
|
|
|
|
### Decided (confirmed)
|
|
- Garage bucket: **new dedicated `kontra-day`** (shared-media untouched)
|
|
- Deploy trigger: **systemd timer `git pull` every 30s** on .13
|
|
- Admin media: **Decap CMS media library**
|
|
- Obsidian: **separate small vault** `/home/sam/obsidian/kontra_day/` = the content repo
|
|
|
|
### Remaining open items
|
|
- Exact Nix file on .13 for Caddy/site (configuration.nix vs home.nix) — inspect in Phase 3
|
|
- Whether to auto-commit Neovim saves via file-watcher (vs rely on git-sync in Obsidian + timer on .13)
|
|
|
|
---
|
|
*Cross-references: AGENT.md; Obsidian notes: Garage Web UI — handoff, Backup Architecture — Offsite to AWS S3, Filesystem Drive Map, Dev-Ops Tooling — Mermaid/Archify/Vikunja/Outline, Docker Containers.* |