feat: news system v1 — dated news items, List module, paginated news list, RSS (harness add news) #80

Merged
dominik.polakovics merged 6 commits from afk/79 into main 2026-07-17 22:47:28 +02:00

Implements the TYPO3-news-style news system designed in the 2026-07-17 grilling session, as six self-contained commits in dependency order (each builds and passes tests on its own):

  1. feat(element)datetime field type end-to-end: RFC3339 strings through sidecar load, save validation, coercion, and a native datetime-local picker with pure RFC3339↔local conversion helpers (step=1 avoids native constraint validation silently blocking submits on seconds-bearing values). AGENTS.md drift test covers the new vocabulary.
  2. feat(pagetype) — generic page-type keys childOrder: date-desc (tree children ordered newest-first, manual reorder rejected server-side), hideChildPages (flag only — children stay in the tree payload so route repair and the List module can see them), and defaults (validated creation-time front matter; the news type stamps outputs: [html, rss]). Date decoding + effective-type resolution in internal/pagetree, mirrored from pageops.
  3. feat(web) — the fifth, generic List module: table of the selected section's direct children (title/type/date/status/actions) in server order; create dialog seeds the child type's required fields (required datetime prefilled with now) via a new optional fields param on POST /api/page/create; tree stops drawing hidden children and disables reorder where dates own the order; Page module gains an "Open list" affordance.
  4. feat(theme) — the embedded news bundle (scaffold/features/news/): news/news-item page types, news-list element (successor to page-teasers, latest-N with section+limit params), paginated newest-first section list with the theme's first pager partial, branch-bundle-aware detail template, and a per-section RSS feed opted in via front matter — the scaffold's global no-feeds stance is untouched, verified by a real-Hugo fixture build (pagination, buildFuture, sole index.xml).
  5. feat(cli)harness add <feature>: vendors a bundle into an existing site all-or-nothing (conflict refusal before any write), surgically inserts buildFuture = true as a top-level hugo.toml key before the first table, and prints the remaining manual wiring (allowlist news in a parent type's children). Documented in the scaffolded AGENTS.md.
  6. fix(web) — e2e verification caught that born-draft news items had no reachable enable control (the only toggle lived on tree rows, and news items are hidden from the tree): List module rows now carry the same Enable/Disable toggle.

Verification

  • Full Go suite (including real-Hugo theme + addcmd build gates) and web suite (38 files / 773 tests) green; go vet and tsc --noEmit clean.
  • Real-browser e2e (playwright-core + chromium against harness serve on a freshly init'd + add news site): section creation stamps outputs: [html, rss]; items hidden from the tree but managed date-sorted in the List module; enable via the new toggle; rendered /news/ lists newest-first including a year-2100 item (buildFuture); /news/index.xml is the site's only feed with all items; disable/delete round-trips keep the preview truthful.

Deliberate judgment calls (the two spots triage left open): the List create dialog collects title + the child type's required fields only, atomically via create-with-fields; the hugo.toml edit is a byte-preserving top-level key insertion, refusing nothing and idempotent when the key exists.

Closes #79

Implements the TYPO3-news-style news system designed in the 2026-07-17 grilling session, as six self-contained commits in dependency order (each builds and passes tests on its own): 1. **feat(element)** — `datetime` field type end-to-end: RFC3339 strings through sidecar load, save validation, coercion, and a native datetime-local picker with pure RFC3339↔local conversion helpers (`step=1` avoids native constraint validation silently blocking submits on seconds-bearing values). AGENTS.md drift test covers the new vocabulary. 2. **feat(pagetype)** — generic page-type keys `childOrder: date-desc` (tree children ordered newest-first, manual reorder rejected server-side), `hideChildPages` (flag only — children stay in the tree payload so route repair and the List module can see them), and `defaults` (validated creation-time front matter; the news type stamps `outputs: [html, rss]`). Date decoding + effective-type resolution in `internal/pagetree`, mirrored from pageops. 3. **feat(web)** — the fifth, generic **List module**: table of the selected section's direct children (title/type/date/status/actions) in server order; create dialog seeds the child type's required fields (required datetime prefilled with now) via a new optional `fields` param on `POST /api/page/create`; tree stops drawing hidden children and disables reorder where dates own the order; Page module gains an "Open list" affordance. 4. **feat(theme)** — the embedded news bundle (`scaffold/features/news/`): news/news-item page types, `news-list` element (successor to page-teasers, latest-N with section+limit params), paginated newest-first section list with the theme's first pager partial, branch-bundle-aware detail template, and a per-section RSS feed opted in via front matter — the scaffold's global no-feeds stance is untouched, verified by a real-Hugo fixture build (pagination, buildFuture, sole index.xml). 5. **feat(cli)** — `harness add <feature>`: vendors a bundle into an existing site all-or-nothing (conflict refusal before any write), surgically inserts `buildFuture = true` as a top-level hugo.toml key before the first table, and prints the remaining manual wiring (allowlist `news` in a parent type's `children`). Documented in the scaffolded AGENTS.md. 6. **fix(web)** — e2e verification caught that born-draft news items had no reachable enable control (the only toggle lived on tree rows, and news items are hidden from the tree): List module rows now carry the same Enable/Disable toggle. ## Verification - Full Go suite (including real-Hugo theme + addcmd build gates) and web suite (38 files / 773 tests) green; `go vet` and `tsc --noEmit` clean. - Real-browser e2e (playwright-core + chromium against `harness serve` on a freshly init'd + `add news` site): section creation stamps `outputs: [html, rss]`; items hidden from the tree but managed date-sorted in the List module; enable via the new toggle; rendered `/news/` lists newest-first including a year-2100 item (buildFuture); `/news/index.xml` is the site's only feed with all items; disable/delete round-trips keep the preview truthful. Deliberate judgment calls (the two spots triage left open): the List create dialog collects title + the child type's *required* fields only, atomically via create-with-fields; the hugo.toml edit is a byte-preserving top-level key insertion, refusing nothing and idempotent when the key exists. Closes #79
Eighth member of the closed field-type set: RFC3339 timestamp strings
validated at sidecar load (defaults) and save time, trimmed like text on
coercion, rendered as a native datetime-local picker in the web UI with
pure RFC3339<->local-time conversion helpers. step=1 on the input keeps
seconds-bearing values from silently blocking native form submission.

Part of #79 (news system, commit 1/5).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three generic page-type sidecar keys: childOrder (only date-desc) makes a
section's children sort by front-matter date newest-first in the tree API
with manual reorder rejected server-side; hideChildPages flags nodes whose
children the editor tree should not render (children stay in the payload —
route repair and the List module judge against it); defaults stamps
validated creation-time front matter (scalars or string lists) on new
pages of the type. pagetree decodes dates to RFC3339 and resolves each
node's effective type locally, mirroring pageops byte for byte.

Part of #79 (news system, commit 2/5).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fifth web module (TYPO3 List analog): direct children of the selected
tree item as a table (title, type, date, publish state, delete), in the
server's authoritative order; create dialog seeds the child type's
required fields (a required datetime prefills with now) through a new
optional 'fields' param on POST /api/page/create, validated against the
type's field schema with requiredness of absent fields relaxed. The page
tree stops drawing children of hideChildPages sections and suppresses
in-tree create/reorder where dates own the order; the Page module grows
an 'Open list' affordance for such sections.

Part of #79 (news system, commit 3/5).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New scaffold/features/news/ subtree (embedded, skipped by harness init)
holding everything 'harness add news' will vendor into a site: news and
news-item page-type sidecars (date-desc ordering, hidden children, rss
outputs default, required datetime date + teaser/image/author fields),
the news-list element, and site-level layout overrides — paginated
newest-first section list, pager partial (the theme's first pagination),
branch-bundle-aware detail template (kind=section resolves through list
lookup), and a per-section RSS feed opted into by front matter so the
scaffold's global no-feeds stance stays untouched. A real-Hugo fixture
build pins pagination, buildFuture visibility, the latest-N element, the
detail contract, and that the news feed is the only feed emitted.

Part of #79 (news system, commit 4/5).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New generic subcommand vendoring an embedded bundle (scaffold/features/,
today: news) into an existing site: all-or-nothing with conflict refusal
before a single byte is written, mirroring init's register, followed by
the feature's config steps — news surgically inserts buildFuture = true
as a top-level hugo.toml key before the first table, leaving every other
byte intact. Success output prints the manual wiring left to the
developer (allowlist "news" in a page type's children). Documented in
the scaffolded AGENTS.md; an end-to-end test gates on a real hugo build
with a future-dated item visible.

Part of #79 (news system, commit 5/5).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix(web): expose the enable/disable draft toggle on List module rows
All checks were successful
ci / build-and-test (pull_request) Successful in 5m39s
3af905860e
Pages of a hideChildPages section never appear in the page tree, so the
tree row menu's Enable/Disable — the only control clearing the born-draft
flag — was unreachable for them: UI-created news items could never
surface in the news list or RSS feed. The List module's action cell now
carries the same toggle with the tree's exact semantics (setPageDraft,
flipped flag, tree refetch, no confirmation), keeping preview truthful
about what is live.

Part of #79 (news system).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
Owner

This was generated by AI while landing a PR.

Validation verdict: PASS

Verification signal relied on: Forgejo Actions CI ci / build-and-testsuccess (run #69, 5m39s). Not re-run. Its scope covers the full Go suite (incl. the real-Hugo theme build gate and the addcmd build gate), the web suite (773 tests), go vet, tsc --noEmit, and the internal/element/agentsdoc_test.go AGENTS.md drift test.

Conventions: Title is Conventional Commits (feat:). Six self-contained commits, one surface each, in the dependency order triage requested. Closes #79 present and well-formed on an afk/79 head — the merge will auto-close the issue and release the run's claim.

Diff review — the two spots triage left to conservative judgment both check out:

  • hugo.toml edit (internal/addcmd/buildfuture.go): a real top-level TOML scanner, not a blind append — inserts buildFuture = true after the last top-level key and before the first table (a naive append would scope it inside [outputs]), idempotent when the key already exists (leaves the file byte-identical), and it refuses the edit on any unrecognized top-level line. Fail-safe.
  • RSS / global no-feeds stance: rather than relaxing theme_test.go:359 as the issue suggested, news ships as an isolated scaffold/features/news/ bundle with its own news_test.go; the base scaffold keeps zero feeds and its assertion stays valid unchanged. Cleaner than the proposed relaxation, and CI proves both pass.

harness add safety: all-or-nothing — pre-scans every destination and refuses the whole op with a ConflictError before writing a byte; features/ is excluded from init; prints the manual wiring left (allowlist news in a parent type's children).

Mergeable, no conflict with main. Clean — awaiting explicit free-text merge go-ahead.

> *This was generated by AI while landing a PR.* **Validation verdict: PASS** **Verification signal relied on:** Forgejo Actions CI `ci / build-and-test` — **success** (run #69, 5m39s). Not re-run. Its scope covers the full Go suite (incl. the real-Hugo theme build gate and the addcmd build gate), the web suite (773 tests), `go vet`, `tsc --noEmit`, and the `internal/element/agentsdoc_test.go` AGENTS.md drift test. **Conventions:** Title is Conventional Commits (`feat:`). Six self-contained commits, one surface each, in the dependency order triage requested. `Closes #79` present and well-formed on an `afk/79` head — the merge will auto-close the issue and release the run's claim. **Diff review — the two spots triage left to conservative judgment both check out:** - **`hugo.toml` edit (`internal/addcmd/buildfuture.go`):** a real top-level TOML scanner, not a blind append — inserts `buildFuture = true` after the last top-level key and before the first table (a naive append would scope it inside `[outputs]`), idempotent when the key already exists (leaves the file byte-identical), and it *refuses* the edit on any unrecognized top-level line. Fail-safe. - **RSS / global no-feeds stance:** rather than relaxing `theme_test.go:359` as the issue suggested, news ships as an isolated `scaffold/features/news/` bundle with its own `news_test.go`; the base scaffold keeps zero feeds and its assertion stays valid unchanged. Cleaner than the proposed relaxation, and CI proves both pass. **`harness add` safety:** all-or-nothing — pre-scans every destination and refuses the whole op with a `ConflictError` before writing a byte; `features/` is excluded from `init`; prints the manual wiring left (allowlist `news` in a parent type's `children`). Mergeable, no conflict with `main`. Clean — awaiting explicit free-text merge go-ahead.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/deckle!80
No description provided.