feat(go): IO layer behind interfaces (M4) #13

Merged
kacerr merged 4 commits from feat/m4-io-layer into main 2026-05-07 10:48:54 +02:00
Owner

Summary

  • io/attendance: CSV-over-public-URL client + Fake for adult/junior tabs (no auth needed for public sheets)
  • io/drive: Drive v3 modifiedTime-only client + Fake
  • io/sheets: Sheets v4 client (GetValues, AppendValues, BatchUpdateValues, WriteHeader, SortByDateColumn) + Fake with call-capture for assertions
  • io/cache: Drive-modifiedTime-gated FileCache; two TTL knobs (file-mtime guard + in-memory debounce); atomic writes via os.Rename; generic Get[T]; Python-compatible JSON format; Flush()
  • io/fio: Client interface with apiClient (REST JSON) and transparentClient (HTML scraper via x/net/html); Fake; fixtures in testdata/
  • membership/sources: NewSources wires all IO into LoadAdults, LoadJuniors, LoadTransactions, LoadExceptions; Czech month/merged-month parsing
  • banksync: SyncToSheets (SHA-256 Sync ID dedup, optional sort) + InferPayments ([?] review prefix, dry-run) — all tested with fakes
  • cmd/fuj: sync and infer subcommands wired to real clients; fees and reconcile now use real NewSources

Test plan

  • make go-test — all packages green (race detector on)
  • make go-lint — golangci-lint v1.64.8 clean (gofumpt extra-rules, errcheck, staticcheck, unused)
  • Smoke test: fuj fees, fuj reconcile, fuj sync --dry-run, fuj infer --dry-run against real credentials (manual, post-merge)

🤖 Generated with Claude Code

## Summary - **io/attendance**: CSV-over-public-URL client + `Fake` for adult/junior tabs (no auth needed for public sheets) - **io/drive**: Drive v3 `modifiedTime`-only client + `Fake` - **io/sheets**: Sheets v4 client (`GetValues`, `AppendValues`, `BatchUpdateValues`, `WriteHeader`, `SortByDateColumn`) + `Fake` with call-capture for assertions - **io/cache**: Drive-modifiedTime-gated `FileCache`; two TTL knobs (file-mtime guard + in-memory debounce); atomic writes via `os.Rename`; generic `Get[T]`; Python-compatible JSON format; `Flush()` - **io/fio**: `Client` interface with `apiClient` (REST JSON) and `transparentClient` (HTML scraper via `x/net/html`); `Fake`; fixtures in `testdata/` - **membership/sources**: `NewSources` wires all IO into `LoadAdults`, `LoadJuniors`, `LoadTransactions`, `LoadExceptions`; Czech month/merged-month parsing - **banksync**: `SyncToSheets` (SHA-256 Sync ID dedup, optional sort) + `InferPayments` (`[?]` review prefix, dry-run) — all tested with fakes - **cmd/fuj**: `sync` and `infer` subcommands wired to real clients; `fees` and `reconcile` now use real `NewSources` ## Test plan - [x] `make go-test` — all packages green (race detector on) - [x] `make go-lint` — golangci-lint v1.64.8 clean (gofumpt extra-rules, errcheck, staticcheck, unused) - [ ] Smoke test: `fuj fees`, `fuj reconcile`, `fuj sync --dry-run`, `fuj infer --dry-run` against real credentials (manual, post-merge) 🤖 Generated with [Claude Code](https://claude.ai/claude-code)
kacerr added 1 commit 2026-05-07 01:06:22 +02:00
feat(go): IO layer behind interfaces (M4)
All checks were successful
Deploy to K8s / deploy (push) Successful in 11s
6465e2a221
- io/attendance: CSV-over-public-URL client + Fake for adult/junior tabs
- io/drive: Drive v3 modifiedTime client + Fake
- io/sheets: Sheets v4 client (GetValues/AppendValues/BatchUpdateValues/
  WriteHeader/SortByDateColumn) + Fake with call-capture
- io/cache: Drive-modifiedTime-gated FileCache; two TTL knobs; atomic
  writes; generic Get[T]; Python-compatible JSON format; Flush()
- io/fio: Client interface backed by Fio REST API (apiClient) and HTML
  scraper (transparentClient); Fake; testdata fixtures
- membership/sources: NewSources wires attendance CSV + Sheets + cache
  into LoadAdults/LoadJuniors/LoadTransactions/LoadExceptions; Czech
  month parsing + merged-month maps
- banksync: SyncToSheets (SHA-256 dedup, optional sort) and
  InferPayments ([?] review prefix, dry-run) — tested with fakes
- cmd/fuj: sync and infer subcommands wired; fees and reconcile use
  real NewSources; go.mod gains google.golang.org/api + x/net
- gofumpt extra-rules applied across all packages; lint clean

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
kacerr added 1 commit 2026-05-07 10:34:00 +02:00
feat(go): add --dry-run to fuj sync
All checks were successful
Deploy to K8s / deploy (push) Successful in 18s
36a28a40d2
Mirror fuj infer's read-only mode: SyncOpts.DryRun skips WriteHeader,
AppendValues, and SortByDateColumn, printing one "Dry run: would …"
line per planned operation instead. ID-dedup still runs so the output
reflects exactly what the next real sync would write.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
kacerr added 1 commit 2026-05-07 10:36:23 +02:00
fix(go/fio): nil http client panic in fio.New
All checks were successful
Deploy to K8s / deploy (push) Successful in 10s
8275db1a63
When token is empty, New falls back to transparentClient with the
caller-supplied hc. main.go passes nil, so the first Do() call panicked.
Default to http.DefaultClient when hc is nil.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
kacerr added 1 commit 2026-05-07 10:47:56 +02:00
fix(go/fio): nested-table early exit + non-padded date parsing
All checks were successful
Deploy to K8s / deploy (push) Successful in 9s
fcb83691f5
extractSecondTableRows tracked a boolean inTarget flag and exited on
the first </table> token while inside the target. Any nested <table>
(e.g. pagination markup in the real Fio page) would cause an early
return before reading any data rows, explaining the 0-transaction report.
Fixed by tracking targetDepth instead: depth increments on every <table>
inside the target and we only return when it reaches 0 again.

parseCzechDate also only tried zero-padded layouts ("02.01.2006").
The real Fio transparent page emits non-padded dates ("7.5.2026");
added "2.1.2006" and "2/1/2006" as the preferred layouts.

Also adds a dry-run diagnostic line ("fetched N transaction(s) from Fio")
so the fetch vs dedup split is visible without reading logs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
kacerr merged commit f0a0f79475 into main 2026-05-07 10:48:54 +02:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: kacerr/fuj-management#13