# Changelog ## 2026-05-08 13:19 CEST — feat(go): M6.5 — member-detail modal JS module - Added `static/js/member-detail.js`: fetches `/api/adults` or `/api/juniors` once on page load, caches the response, renders a per-member detail modal on `[i]` row click. - Modal sections: status-per-month table, fee exceptions, other transactions, matched payment history, toggleable raw-payments debug view. - Keyboard nav: `Esc` closes, `↑`/`↓` walk visible (name-filtered) rows; click outside modal content closes it. - Added `[i]` info icon and `#memberModal` markup to `adults.tmpl` and `juniors.tmpl`; all CSS was already in place from M6.1. - Added `TestModalMarkup` assertions to `html_handler_test.go`. ## 2026-05-08 12:48 CEST — feat(go): M6.4 — Go-native /payments page - Extracted `AssemblePayments(ctx)` from the inlined JSON handler body, following the M6.2/M6.3 `AssembleAdults`/`AssembleJuniors` pattern. - Added `PaymentsPageData` to `render.go`; wired `HTMLHandler.ServePayments` to call `AssemblePayments` and render the new template. - Replaced the "Coming in M6.4" placeholder in `payments.tmpl` with the full grouped-by-person ledger: alphabetical `

` member blocks, each with a `txn-table` (Date / Amount / Purpose / Bank Message), newest-first rows, `"Unmatched / Unknown"` bucket. - Appended ledger CSS classes to `app.css` (`.ledger-container`, `.member-block`, `.txn-table`, `.txn-{date,amount,purpose,message}`, `tr:hover`). - Added `TestPaymentsPage` markup test. No filters, no JS — matches the Python page. ## 2026-05-08 11:25 CEST — feat(go): M6.3 — Go-native /juniors page - Extracted `AssembleJuniors(ctx)` from the JSON handler so HTML and JSON share one view-model path (mirrors `AssembleAdults`). - Added `JuniorsPageData` to `render.go`; wired `HTMLHandler.ServeJuniors` to call `AssembleJuniors` and render the new template. - Replaced the 4-line "Coming in M6.3" placeholder in `juniors.tmpl` with the full template: member table, name/month-range filters, totals row, Credits + Debts sections, Pay / Pay All links to `/qr`. No Unmatched section (parity with Python). - J/A attendance breakdown and `"?"` sentinel rendered via `MonthCell.Text` produced by `buildJuniorMemberRow` — no extra template logic. - `make parity` reports 3/3 routes OK; all Go tests pass. ## 2026-05-08 11:11 CEST — fix: period selector showed only Dec 2025+ on adults - Restored the `2025-09 → 2025-10` adult merge in `scripts/attendance.py` and `go/internal/services/membership/sources.go` (commented-out by `1257f0d`); the `2025-12 → 2026-01` mapping stays disabled per product decision (Dec and Jan are billed separately for adults). - Dropped the `defaultFrom = maxMonthIdx − 4` JS auto-default in `templates/adults.html` and `templates/juniors.html` (introduced by `7774301`); the From-selector now starts at the oldest available month so all non-future periods render on first load. Future-month removal is preserved. - `go/internal/services/membership/sources_test.go`: `TestLoadAdults` / `TestLoadAdults_Fee` now assert that Sep dates land in the merged `2025-10` bucket. - **Independent of these code changes**: the live adults attendance Google Sheet header had been pruned to start at `02.12.2025` (Sep/Oct/Nov 2025 columns deleted); restoring those columns from Sheets version history is required to actually see those periods on the dashboard. ## 2026-05-08 10:15 CEST — fix(go): adults template — use lifted CSS classes for visual parity - Use existing `.balance-pos` / `.balance-neg` (drop invented `balance-cell` / `balance-negative`); Pay-All button now lives inside the balance cell with `position: relative` (matches Python; no separate trailing column). - Credits / Debts / Unmatched sections rewritten from `