leDailySquirrel/STATUS.md

60 lines
5.6 KiB
Markdown
Raw Permalink Normal View History

2026-07-05 03:39:09 +00:00
# Le Daily Squirrel — Project Status
**Date:** 2026-07-04
**Repo:** `AutomationWise/leDailySquirrel` on Forgejo (`gf.automationwise.com`)
**Production:** https://news.opelousas.org (Cloudflare Pages, project `news-opelousas-org`)
A satirical daily newspaper for Opelousas — vintage faded-newsprint aesthetic, edition-based publishing, self-hosted GitOps pipeline, with AI journalist agents planned as the content authors.
---
## Architecture
| Piece | Where | Notes |
|---|---|---|
| Git forge (Forgejo 9) | `kiln` (Fedora), rootless Podman Quadlet | HTTP `127.0.0.1:3000` behind Caddy at `gf.automationwise.com`; SSH on host port `3022` (LAN only, blocked at edge) |
| Reverse proxy | Caddy on `kiln` | Owns 80/443, auto TLS; also fronts Vaultwarden and Tuwunel |
| CI runner | `kiln`, Podman Quadlet (`forgejo-runner` 3.4.1) | Org-level runner `kiln-worker`, label `ubuntu-latest:docker://node:20-bookworm`, uses host Podman socket (`UserNS=keep-id`, `SecurityLabelDisable=true`, socket path identical inside/outside container) |
| Static site generator | Eleventy v3.1.6 | Input `content/`, includes `../_includes`, output `dist/` |
| Hosting | Cloudflare Pages, Direct Upload mode | Deployed via `wrangler pages deploy dist --project-name=news-opelousas-org --branch main` from `.forgejo/workflows/deploy.yml` on push to `main` |
| Dev box | `anvil` | Git remote over SSH: `ssh://git@gf.automationwise.com:3022/...` with `~/.ssh/config` host override to kiln's LAN IP (NAT hairpin workaround) |
**Secrets:** `CF_ACCOUNT_ID` + `CF_API_TOKEN` in Forgejo repo Actions secrets. Token permissions: Account→Cloudflare Pages→Edit, Account→Workers Scripts→Edit, User→User Details→Read, scoped to the account.
## Site mechanics
- **Editions** live at `content/editions/YYYY-MM-DD/index.md`; URLs are `/editions/YYYY-MM-DD/`.
- **Front matter:** `layout: edition`, `edition_number` (int), `volume` (int — must be a number, the `roman` filter converts; storing "I" breaks it), `date`, `status: draft|published`, `title`.
- **Collections** (`eleventy.config.js`): `publishedEditions` (all published, newest first), `currentEdition` (newest one only).
- **Homepage** (`content/index.njk`): paginates over `currentEdition` (size 1) and renders it at `/` — render, not redirect. `content/index.11tydata.js` maps `title`, `date`, `edition_number`, `volume` up from the paginated item.
- **Filters:** `newsDate` (UTC-forced long date — fixes the CST off-by-one-day), `roman` (int → Roman numeral).
- **404:** `content/404.md``dist/404.html`. Required — without it Cloudflare Pages SPA-fallbacks every unknown path to `/` with a 200 (this was the "every URL shows the current edition" bug). Todo → more Squirreliness.
- **Masthead:** inline SVG (Inkscape export, single path, mm-scale coordinates, `viewBox="0 0 381 170"`). Fill flows from `fill="var(--ink)"` on the `<g>` (path's inline `fill` style removed). CSS `squirrel-flip` animation rotates it 180° on a 50/50 duty cycle (~24s period), with a `prefers-reduced-motion` opt-out.
- **Lifecycle tooling:** `make publication` (scaffolds next edition, enforces one open draft, creates `edition/<date>/open` branch), `make publish` (seds `status: draft``published`), `make build` / `make serve`.
## Hard-won gotchas (do not relearn these)
- Quadlet units can't be `systemctl enable`d — the `[Install]` block in the `.container` file handles boot; just `daemon-reload` + `start`. Lingering is enabled for the user on kiln.
- Rootless Podman + SELinux: never `:Z` a socket mount; socket path must match host↔container when the runner asks the host to mount it into job containers.
- Wrangler CI deploys need `--branch main` or they land as Preview, not Production.
- Eleventy config must be a **single** `module.exports`; run builds from repo root only.
- Front matter beats directory data files (`editions.json`) — data bugs hide there.
## Current status
**Working end-to-end:** push to `main` → runner builds → Cloudflare production deploy. Volume renders as Roman numerals, archive URLs serve the correct historical edition, fake URLs 404, custom domain live, SVG masthead in place with periodic flip.
**In development / not yet done:**
1. **Edition immutability (freeze-at-publish)** — designed, not implemented. Plan: `make publish` builds once, snapshots rendered HTML to committed `frozen/editions/<date>/`, marks source `frozen: true`; `editions.11tydata.js` returns `permalink: false` for frozen editions; `addPassthroughCopy({ "frozen/editions": "editions" })` serves snapshots verbatim. Homepage stays dynamic; only `/editions/<date>/` freezes. Past editions from the pre-freeze era are expendable (still in dev).
2. **Archive ledger** — no `/archive/` (or `/editions/`) index page listing past editions yet.
3. **AI journalist pipeline** — the actual point of the project. Agents ingest daily material, write articles in the three-column structure, and open PRs against the open `edition/<date>/open` draft branch. Likely `imp` (OpenClaw on liminal) via NadirClaw routing, following the spec-first handoff pattern. Not started.
4. **Maintenance-mode toggle** — deferred; plan is a Cloudflare Page Rule redirect to a `/maintenance/` page.
5. **Masthead spacing polish** — minor viewBox/padding nudges deferred.
## Suggested next steps, in order
1. Implement the freeze-at-publish flow while there's only throwaway content to test against (touching `publish.sh`, `eleventy.config.js`, new `content/editions/editions.11tydata.js`).
2. Build the archive index page off `collections.publishedEditions`.
3. Define the agent contract: article markdown format, column assignment, front-matter rules, PR-to-draft-branch workflow — then wire the first agent.