Files
fuj-management/go/internal/web/api/juniors.go
Jan Novak f253e3fcb1
All checks were successful
Deploy to K8s / deploy (push) Successful in 7s
feat(go): M5.1 — hand-author /api/* wire types + JSON Schemas
Add internal/web/api package with Go structs for every /api/X route:
AdultsResponse, JuniorsResponse, PaymentsResponse, VersionResponse.
All fields carry explicit json: tags matching the Python view-model keys.

Key design choices:
- member_data / month_labels / raw_payments are nested objects (not
  the pre-serialised JSON strings used in Jinja templates)
- Expected{Value int; Unknown bool} with custom MarshalJSON emits int
  or the string "?" for junior single-attendance months
- RawTransaction covers the full 11-column payments sheet row

schemagen_test.go reflects all four response types via
github.com/invopop/jsonschema and golden-compares against committed
schemas in tests/fixtures/api-schema/. The JSONSchema() method on
Expected lives in the test file so the prod binary has no jsonschema
dependency.

Closes M5.1 in docs/plans/2026-05-03-2349-go-backend-rewrite-progress.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 17:36:46 +02:00

42 lines
2.1 KiB
Go

package api
// JuniorsMonthData is the reconciled ledger for one junior member in one month.
// expected and original_expected may be the "?" sentinel (single-attendance month
// requiring manual review); they are carried via the Expected type.
type JuniorsMonthData struct {
Expected Expected `json:"expected"`
OriginalExpected Expected `json:"original_expected"`
AttendanceCount int `json:"attendance_count"`
Exception *ExceptionData `json:"exception"`
Paid float64 `json:"paid"`
Transactions []MemberTxEntry `json:"transactions"`
}
// JuniorsMemberData is the reconciled ledger for one junior member.
type JuniorsMemberData struct {
Tier string `json:"tier"`
Months map[string]JuniorsMonthData `json:"months"`
OtherTransactions []MemberOtherEntry `json:"other_transactions"`
TotalBalance int `json:"total_balance"`
}
// JuniorsResponse is the JSON contract for GET /api/juniors.
// Same outer shape as AdultsResponse; differs in that member_data carries
// Expected (int or "?") for expected/original_expected fields.
type JuniorsResponse struct {
Months []string `json:"months"`
RawMonths []string `json:"raw_months"`
Results []MemberRow `json:"results"`
Totals []TotalCell `json:"totals"`
MemberData map[string]JuniorsMemberData `json:"member_data"`
MonthLabels map[string]string `json:"month_labels"`
RawPayments map[string][]RawTransaction `json:"raw_payments"`
Credits []Credit `json:"credits"`
Debts []Credit `json:"debts"`
Unmatched []RawTransaction `json:"unmatched"`
AttendanceURL string `json:"attendance_url"`
PaymentsURL string `json:"payments_url"`
BankAccount string `json:"bank_account"`
CurrentMonth string `json:"current_month"`
}