Commit Graph
195 Commits
Author SHA1 Message Date
kacerr 23633f8cb2 Merge pull request 'feat(fees): adult rates for 2026-07 to 2026-12, default 600' (#46) from feat/adult-fees-2026-h2 into main
Reviewed-on: #46
2026-10-08 11:53:55 +02:00
kacerrandClaude Opus 5.5 2d8aada8d6 feat(fees): adult rates for 2026-07 to 2026-12, default 600
- Default adult monthly rate 700 -> 600 CZK
- 2026-07 and 2026-08 set to 0; 2026-09 through 2026-12 added at 600
- Single-session fee is capped at the month's rate, so a 0-rate month
  is free for one session as well
- Mirrored in Go and legacy Python; new calculate_fee parity fixtures

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:53:18 +02:00
kacerr 14cdbeac21 Merge pull request 'fix(ci): remove kubernetes-deploy workflow that leaked secrets to logs' (#45) from fix/remove-leaky-k8s-deploy-workflow into main
Reviewed-on: #45
2026-10-08 11:49:02 +02:00
kacerrandClaude Opus 5.5 5b162d0030 fix(ci): remove kubernetes-deploy workflow that leaked secrets to logs
The workflow ran on every push to every branch and deployed nothing.
It echoed the raw Vault login response, the Kanidm API token response
and the OIDC token response to the job log, dumped the environment,
and configured kubectl with --insecure-skip-tls-verify.

Deployment is handled by gitops-update.yaml. Docs updated to describe
that flow; T1 marked done in the cleanup task list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:48:35 +02:00
kacerr cfdc5cbb2a Merge pull request 'fix: VS always a string; months_to_show in Python JSON API' (#44) from fix/api-parity-vs-months-to-show into main
Deploy to K8s / deploy (push) Successful in 13s
Reviewed-on: #44
2026-10-08 11:45:53 +02:00
kacerr e2ae5a7ec4 Merge pull request 'refactor: move Python implementation to legacy/, make Go primary' (#43) from feat/python-to-legacy into main
Deploy to K8s / deploy (push) Successful in 13s
Reviewed-on: #43
2026-10-08 11:45:11 +02:00
kacerrandClaude Opus 5.5 82406935ed docs: add pre-feature cleanup task list and API parity plan
Deploy to K8s / deploy (push) Successful in 14s
Task list from the 2026-10-08 repo audit, plus the plan for the two
parity fixes found while validating the legacy/ move.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:34:20 +02:00
kacerrandClaude Opus 5.5 e7c8101c3b fix(python): return months_to_show from the JSON API
Go returns months_to_show in /api/adults and /api/juniors; the Python
API did not, so make parity failed on both routes. The Python HTML
pages already had the feature.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:34:20 +02:00
kacerrandClaude Opus 5.5 97f94afa02 fix: treat VS as a string on read and write
Go stringified sheet cells with fmt.Sprint, so a numeric VS read with
UNFORMATTED_VALUE was rendered as 2.609767878e+09. Text columns of the
payments sheet now go through sheets.CellString, which never uses
exponent form; bank inference uses the same helper.

Both sync implementations now append VS as a text cell so Sheets keeps
it a string and leading zeros survive. Existing rows are not rewritten.

Python already read VS as a digit string; a regression test pins that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:34:20 +02:00
kacerrandClaude Opus 5.5 022facc957 refactor: move Python implementation to legacy/, make Go primary
Deploy to K8s / deploy (push) Successful in 20s
Go (go/) becomes the primary implementation. The original Python
version moves to legacy/ and is kept runnable; new features are still
built in both (see the Dual implementation rule in CLAUDE.md).

- git mv app.py, scripts/, templates/, tests/, pyproject.toml, uv.lock
  and build/ into legacy/
- Makefile: Python targets point at legacy/, venv in legacy/.venv,
  CREDENTIALS_PATH exported for the root .secret/ file
- CI and make image build the Python image with legacy/ as context;
  the Makefile is no longer copied into the image
- legacy/.dockerignore moved to the context root so it takes effect
- CLAUDE.md, docs/README.md, Go comments, fixture README, capture
  script and VS Code launch config updated to the new layout

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:33:57 +02:00
kacerr 96c14f0b22 Merge pull request 'fix(ci): resolve image tag via Gitea API instead of artifact' (#42) from fix/gitops-tag-via-api into main
Deploy to K8s / deploy (push) Successful in 8s
Build and Push / build (push) Successful in 8s
Build and Push / build-go (push) Successful in 40s
Reviewed-on: #42
0.39
2026-06-12 19:59:40 +02:00
kacerrandClaude Opus 4.8 6d7dbfa624 fix(ci): resolve image tag via Gitea API instead of artifact
Deploy to K8s / deploy (push) Successful in 9s
upload/download-artifact@v4 is not supported on Gitea (GHES). Replace
with a direct Gitea API call in gitops-update: look up the tag name
whose commit SHA matches workflow_run.head_sha. Reverts the artifact
upload from build.yaml; no changes to build.yaml logic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:59:24 +02:00
kacerr c00111cff1 Merge pull request 'fix(ci): pass Go image tag from build to gitops via artifact' (#41) from fix/gitops-pass-tag-via-artifact into main
Deploy to K8s / deploy (push) Successful in 8s
Build and Push / build (push) Successful in 7s
Build and Push / build-go (push) Failing after 42s
Reviewed-on: #41
2026-06-12 19:53:19 +02:00
kacerrandClaude Opus 4.8 d263d8a534 fix(ci): pass Go image tag from build to gitops via artifact
Deploy to K8s / deploy (push) Successful in 14s
github.event.workflow_run.head_branch is not populated for tag pushes
in Gitea Actions, causing the image tag to resolve to empty (-go suffix
with no version). Fix: build-go uploads the full image reference as a
one-line artifact; gitops-update downloads it via download-artifact@v4
with run-id from the workflow_run event.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:52:02 +02:00
kacerr af030c8255 Merge pull request 'fix(ci): separate git credentials from --git-repo URL to fix tea pr create' (#40) from fix/gitops-tea-url into main
Build and Push / build (push) Successful in 42s
Build and Push / build-go (push) Successful in 1m23s
Deploy to K8s / deploy (push) Successful in 10s
Reviewed-on: #40
0.38
2026-06-12 19:39:31 +02:00
kacerrandClaude Opus 4.8 ad127d36ea fix(ci): separate git credentials from --git-repo URL to fix tea pr create
Deploy to K8s / deploy (push) Successful in 12s
tea pr create matches the remote URL against the configured login URL to
auto-detect owner/repo. Embedding credentials in the URL (user:token@host)
breaks that match and produces "path segment [0] is empty". Store creds
via git credential helper instead and pass a clean URL to uh-cli.

Also adds set -x to the PR step for shell-level tracing in CI logs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:37:29 +02:00
kacerrandClaude Opus 4.8 29938d7a0c chore(changelog): log gitops-update workflow addition
Deploy to K8s / deploy (push) Successful in 8s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:32:20 +02:00
kacerr 1df1863725 Merge pull request 'feat(ci): gitops image-update PR workflow for home-kubernetes' (#39) from feat/gitops-pr-action into main
Deploy to K8s / deploy (push) Successful in 11s
Reviewed-on: #39
2026-06-12 19:31:51 +02:00
kacerrandClaude Opus 4.8 995abfacb2 feat(ci): add gitops-update workflow to open image-bump PR in home-kubernetes
Deploy to K8s / deploy (push) Successful in 12s
After a successful Go image build, uh-cli opens a PR against
kacerr/home-kubernetes that bumps the fuj-management Deployment
(namespace fuj) to the newly published image tag. Supports
workflow_run auto-trigger and workflow_dispatch with dry-run option.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:28:29 +02:00
kacerrandClaude Opus 4.8 f047150004 fix(tests): derive fee test expectations from constants, not hardcoded values
Deploy to K8s / deploy (push) Successful in 9s
Configured-month cases now read expected values from AdultFeeMonthlyRate /
JuniorFeeMonthlyRate via a mustRate helper that panics if a test month is
removed from the map. Fallback cases use AdultFeeDefault / JuniorFeeDefault.

This way the tests verify dispatch logic (0/1/2+ branching, map vs. fallback)
without breaking when rates are intentionally updated in the map.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 11:37:52 +02:00
kacerr 6f2994b8ad Merge pull request 'feat(display): limit /adults and /juniors to last N months by default' (#38) from feat/months-to-show into main
Deploy to K8s / deploy (push) Successful in 14s
Build and Push / build (push) Successful in 9s
Build and Push / build-go (push) Successful in 1m10s
Reviewed-on: #38
0.37
2026-06-08 09:31:46 +00:00
kacerrandClaude Opus 4.8 c2a381bb63 fix(display): default from-selector to last N months; keep all months selectable
Deploy to K8s / deploy (push) Successful in 12s
Instead of hiding older months entirely, show all months in the from/to
selectors but default the from-select to the last MONTHS_TO_SHOW months
on page load. The "All" button resets to full history as before.

Python: passes months_to_show to render_template, IIFE sets fromSelect.value.
Go: adds MonthsToShow to response structs, data-months-to-show attr in
templates, filters.js reads it and defaults fromSelect after hideFutureMonths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 11:28:40 +02:00
kacerrandClaude Opus 4.8 c0487e3af0 feat(display): limit /adults and /juniors to last N months by default
Deploy to K8s / deploy (push) Successful in 17s
Show only the last MONTHS_TO_SHOW months (default 5) in the fee table columns
so the page fits on screen without horizontal scrolling. Reconciliation still
runs over the full month history so balances, credits, and debts are unaffected.
Set MONTHS_TO_SHOW=0 to show all months. Implemented in both Python and Go.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 11:18:55 +02:00
kacerrandClaude Opus 4.8 37fc17cf9c chore(settings): accumulate Claude Code permission allowlist entries
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 11:11:36 +02:00
kacerrandClaude Opus 4.8 20b618685f fix(reconcile): handle '?' expected fee in fill-first allocation
Juniors with exactly 1 session get expected='?' (manual-review marker
from attendance.py). The fill-first allocation block summed and cast
expected values numerically without guarding against this, causing a
TypeError: unsupported operand type(s) for +: 'int' and 'str' on the
/juniors route whenever any matched payment landed on such a month.

Add _expected_amount() helper that coerces non-numeric markers to 0
(same convention the final-balance calculation at line 512 already used)
and apply it in the two failing spots plus the existing isinstance check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 11:10:41 +02:00
kacerrandClaude Sonnet 4.6 72e29b1882 chore(changelog): add entry for fee rate update 2026-05 through 2026-08
Build and Push / build (push) Successful in 11s
Build and Push / build-go (push) Successful in 1m24s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
0.36
2026-05-24 21:58:25 +02:00
kacerr 241fecfb2c Merge pull request 'feat: multi-account Fio sync + switch QR default to 2502035405/2010' (#37) from feat/multi-account-bank-sync into main
Deploy to K8s / deploy (push) Successful in 22s
Reviewed-on: #37
2026-05-24 19:57:52 +00:00
kacerrandClaude Sonnet 4.6 723591cbce feat(fees): update adult monthly rates for 2026-05 through 2026-08
Deploy to K8s / deploy (push) Successful in 40s
- 2026-05: 700 → 450 CZK
- 2026-06, 07, 08: 600 CZK (new months)

Changes are mirrored in both Python (scripts/attendance.py) and Go (go/internal/domain/fees/fees.go).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 21:56:41 +02:00
kacerrandClaude Opus 4.7 69af4c1e3b feat: multi-account Fio sync + switch QR default to 2502035405/2010
Deploy to K8s / deploy (push) Successful in 24s
Add second Fio account (CZ0820100000002502035405 / 2502035405/2010).
Both accounts are fetched on every sync run and combined before dedup,
so the payments sheet accumulates transactions from either account.
QR codes now default to the new account.

Go:
- config.go: hardcoded Accounts/LoadedAccount slice replaces scalar
  BankAccount + FioAPIToken; Config.BankAccount renamed QRAccount;
  per-account tokens via FIO_API_TOKEN_NEW / FIO_API_TOKEN_OLD
- banksync.SyncToSheets: accepts []fio.Client, loops to combine txns
- cmd/fuj/main.go: buildFioClients helper; both sync call sites updated
- html_handler + build_adults/juniors: use Config.QRAccount
- New TestSyncToSheets_MultiAccount covers cross-account dedup

Python:
- config.py: ACCOUNTS list + LOADED_ACCOUNTS (tokens from env)
- fio_utils.py: fetch_transactions_for (per-account) +
  fetch_transactions_all (loops all accounts)
- sync_fio_to_sheets.py: uses fetch_transactions_all

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 21:42:47 +02:00
kacerr 152908fec6 Merge pull request 'gitignore go/parity' (#36) from fix/fill-first-multi-month-allocation into main
Deploy to K8s / deploy (push) Successful in 34s
Reviewed-on: #36
2026-05-24 19:16:27 +00:00
kacerr fbc5a41d12 gitignore go/parity
Deploy to K8s / deploy (push) Successful in 22s
2026-05-24 21:15:38 +02:00
kacerr 7f801d27f5 Merge branch 'feat/go-m6-7-embed-verify'
Deploy to K8s / deploy (push) Successful in 15s
2026-05-24 21:13:15 +02:00
kacerr 10e2e9dc04 Merge pull request 'fix(reconcile): fill earliest month deficit first in multi-month allocations' (#35) from fix/fill-first-multi-month-allocation into main
Deploy to K8s / deploy (push) Successful in 13s
Build and Push / build (push) Successful in 6s
Build and Push / build-go (push) Successful in 52s
Reviewed-on: #35
0.35
2026-05-11 22:01:36 +00:00
kacerrandClaude Opus 4.7 8734089223 fix(reconcile): fill earliest month deficit first in multi-month allocations
Deploy to K8s / deploy (push) Successful in 9s
Replace proportional split with a fill-first loop that allocates
min(remaining, deficit) to each matched month in user-supplied order,
where deficit = expected - already_paid. Prior transactions' contributions
are now properly accounted for, so a second payment on overlapping months
fills only what's still owed instead of splitting proportionally by total
expected. Surplus after all deficits are covered goes to the credit bucket.

Fixes: Matyáš Thér 200+550 showing 566/183 instead of 500/250.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 23:59:36 +02:00
kacerrandClaude Opus 4.7 aaa876e593 fix(python): parse Fio 2-digit-year dates + add make sync-debug
Build and Push / build (push) Successful in 6s
Build and Push / build-go (push) Successful in 59s
Deploy to K8s / deploy (push) Successful in 8s
Fio's transparent page now serves recent rows as DD.MM.YY while older
rows stay DD.MM.YYYY. parse_czech_date only knew the 4-digit form so
every recent transfer was silently dropped — make sync-2026 reported
zero new transactions. Adds %d.%m.%y and %d/%m/%y to the format list,
mirroring the Go-side fix from 2026-05-07.

Also adds a Python analog of make go-sync-debug:
- --dry-run skips header write / append / sort and prints "would …" lines
- --print-fio-table prints aligned per-txn table with NEW/DUP status
- make sync-debug [DAYS=N] wrapper (default DAYS=30)
- always-on stderr diagnostics in fio_utils: which fetcher was chosen
  (with FIO_API_TOKEN-unset lag warning) + raw-vs-filtered counts, so
  this class of "scraper drops everything" bug surfaces immediately.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
0.34
2026-05-11 22:56:49 +02:00
kacerrandClaude Sonnet 4.6 d981392593 feat(go): M6.7 — single-binary embed verification
Deploy to K8s / deploy (push) Successful in 8s
Add TestEmbedCompleteness and TestStaticAssetsServed in
go/internal/web/assets_test.go. The completeness guard walks the
on-disk templates/ and static/ directories and asserts every file is
present in the corresponding embed.FS, catching forgotten files on
future additions. The static mux test hits /static/css/app.css and all
JS files through the same http.FileServerFS wiring used in server.go,
confirming assets are served from the embedded FS with correct
Content-Type and a 404 for unknown paths.

Standalone binary smoke test passed manually: binary copied to /tmp
(no adjacent templates/ or static/), assets served correctly.

Closes M6.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 15:24:47 +02:00
kacerrandClaude Opus 4.7 f25552eef2 chore: CHANGELOG + tick M6.6 (f6ba85b) and M6.6.1 (4276d7b) in progress tracker
Deploy to K8s / deploy (push) Successful in 6s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:56:57 +02:00
kacerr 4276d7b915 Merge pull request 'feat(go): M6.6.1 — QR payment popup modal on /adults and /juniors' (#33) from feat/go-m6-6-1-payment-qr-modal into main
Deploy to K8s / deploy (push) Successful in 9s
Reviewed-on: #33
2026-05-08 12:54:23 +00:00
kacerr f6ba85b18f Merge pull request 'feat(go): M6.6 — /qr, /sync-bank, /flush-cache, /version pages' (#32) from feat/go-m6-6-action-pages into main
Deploy to K8s / deploy (push) Has been cancelled
Reviewed-on: #32
2026-05-08 12:54:16 +00:00
kacerrandClaude Opus 4.7 919845518c feat(go): M6.6.1 — QR payment popup modal on /adults and /juniors
Deploy to K8s / deploy (push) Successful in 9s
Replace bare <a href=/qr> Pay buttons with <button data-*> elements that
open an in-page #qrModal (matching Python's showPayQR UX), driven by a
new payment-qr.js vanilla-JS IIFE module.  Remove the now-dead qrHref /
qrHrefAll template helpers from render.go.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:49:35 +02:00
kacerrandClaude Opus 4.7 fe935235e8 feat(go): M6.6 — /qr, /sync-bank, /flush-cache, /version pages
Deploy to K8s / deploy (push) Successful in 8s
- GET /qr: Czech QR Platba PNG; ports Python qr_code() exactly
  (account validation, amount clamping, * stripping, SPD format)
- GET /sync-bank: Fio sync → infer → cache flush with captured log
- GET+POST /flush-cache: form + action, shows deleted count
- GET /version: JSON alias of /api/version (Python parity)
- FlushCache() added to membership.Sources; wired through api.Handler
- web.ActionHandlers{BankSync} closure-based dep injection for sync
- New dep: github.com/skip2/go-qrcode
- TestQRBuildSPD (9 cases), TestServeQR, TestServeFlushCache{GET,POST},
  TestServeSync, TestServeVersion added

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:26:54 +02:00
kacerrandClaude Opus 4.7 e22ab8cc49 chore: CHANGELOG + tick M6.5 in progress tracker — SHA e53e238
Deploy to K8s / deploy (push) Successful in 7s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:19:19 +02:00
kacerr e53e238ca6 Merge pull request 'feat(go): M6.5 — member-detail modal JS module' (#31) from feat/go-m6-5-modal-js into main
Deploy to K8s / deploy (push) Successful in 11s
Reviewed-on: #31
2026-05-08 11:18:46 +00:00
kacerrandClaude Opus 4.7 309c26f209 feat(go): M6.5 — member-detail modal JS module for /adults and /juniors
Deploy to K8s / deploy (push) Successful in 8s
Adds static/js/member-detail.js: fetches /api/<page> once on page load,
caches the response, and renders a per-member detail modal on [i] row click.
Keyboard nav: Esc closes, ↑/↓ walk visible (filtered) rows. All modal CSS
was already in place from M6.1.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:14:41 +02:00
kacerrandClaude Opus 4.7 01573faced chore: CHANGELOG + tick M6.4 in progress tracker — SHA 689f1c0
Deploy to K8s / deploy (push) Successful in 10s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 12:48:42 +02:00
kacerr 689f1c01fd Merge pull request 'feat(go): M6.4 — Go-native /payments page (grouped-by-person ledger)' (#30) from feat/go-m6-4-payments-page into main
Deploy to K8s / deploy (push) Successful in 9s
Reviewed-on: #30
2026-05-08 10:48:04 +00:00
kacerrandClaude Opus 4.7 cb8a09b571 feat(go): M6.4 — Go-native /payments page (grouped-by-person ledger)
Deploy to K8s / deploy (push) Successful in 6s
- Extract AssemblePayments(ctx) from ServePayments in api/handler.go,
  mirroring the AssembleAdults/AssembleJuniors pattern
- Add PaymentsPageData view-model wrapper in render.go
- Rewire html_handler.go ServePayments to call AssemblePayments and
  render with PaymentsPageData
- Replace payments.tmpl placeholder with real grouped-by-person ledger:
  alphabetical member blocks, txn-table (Date/Amount/Purpose/Message),
  newest-first rows, Unmatched/Unknown bucket
- Append ledger CSS classes to app.css (.ledger-container, .member-block,
  .txn-table, .txn-date/amount/purpose/message, tr:hover)
- Add TestPaymentsPage markup test

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 12:29:32 +02:00
kacerrandClaude Opus 4.7 7f87e63b7c chore: tick M6.3 in progress tracker — SHA 9564103
Deploy to K8s / deploy (push) Successful in 7s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 12:19:13 +02:00
kacerr 95641036cc Merge pull request 'feat(go): M6.3 — Go-native /juniors page' (#29) from feat/go-m6-3-juniors-page into main
Deploy to K8s / deploy (push) Successful in 9s
Reviewed-on: #29
2026-05-08 10:18:40 +00:00
kacerrandClaude Opus 4.7 505d635c66 chore: CHANGELOG entry for M6.3 Go juniors page
Deploy to K8s / deploy (push) Failing after 11s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 11:26:08 +02:00