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>
This commit is contained in:
2026-10-08 11:33:57 +02:00
co-authored by Claude Opus 5.5
parent 96c14f0b22
commit 022facc957
82 changed files with 223 additions and 144 deletions
+9 -9
View File
@@ -18,20 +18,20 @@ import (
"time"
)
// Attendance CSV column indices (mirrors COL_* in scripts/attendance.py)
// Attendance CSV column indices (mirrors COL_* in legacy/scripts/attendance.py)
const (
colName = 0
colTier = 1
firstDateCol = 3
)
// AdultMergedMonths mirrors ADULT_MERGED_MONTHS in scripts/attendance.py.
// AdultMergedMonths mirrors ADULT_MERGED_MONTHS in legacy/scripts/attendance.py.
// Source month → target month (source attendance accumulated into target).
var AdultMergedMonths = map[string]string{
"2025-09": "2025-10",
}
// JuniorMergedMonths mirrors JUNIOR_MERGED_MONTHS in scripts/attendance.py.
// JuniorMergedMonths mirrors JUNIOR_MERGED_MONTHS in legacy/scripts/attendance.py.
var JuniorMergedMonths = map[string]string{
"2025-12": "2026-01",
"2025-09": "2025-10",
@@ -127,11 +127,11 @@ func (s *realSources) LoadExceptions(ctx context.Context) (map[reconcile.Excepti
}
// ---------------------------------------------------------------------------
// Attendance CSV parsing (ports scripts/attendance.py)
// Attendance CSV parsing (ports legacy/scripts/attendance.py)
// ---------------------------------------------------------------------------
// parseDates returns (columnIndex, YYYY-MM) pairs for all date columns.
// Ports scripts/attendance.py parse_dates + strftime("%Y-%m").
// Ports legacy/scripts/attendance.py parse_dates + strftime("%Y-%m").
func parseDates(header []string) []struct {
col int
month string
@@ -200,7 +200,7 @@ func countTrue(row []string, cols []int) int {
// parseAdultRows converts raw CSV rows to []reconcile.Member.
// Includes all tiers; fee is 0 for non-A tiers (reconcile filters downstream).
// Ports scripts/attendance.py get_members_with_fees.
// Ports legacy/scripts/attendance.py get_members_with_fees.
func parseAdultRows(rows [][]string) ([]reconcile.Member, []string, error) {
if len(rows) < 2 {
return nil, nil, nil
@@ -246,7 +246,7 @@ func parseAdultRows(rows [][]string) ([]reconcile.Member, []string, error) {
// parseJuniorRows builds junior members by merging tier-J rows from the adult tab
// with the junior sheet, then calling CalculateJuniorFee.
// Ports scripts/attendance.py get_junior_members_with_fees.
// Ports legacy/scripts/attendance.py get_junior_members_with_fees.
func parseJuniorRows(adultRows, juniorRows [][]string) ([]reconcile.Member, []string, error) {
if len(adultRows) < 2 || len(juniorRows) < 2 {
return nil, nil, nil
@@ -362,7 +362,7 @@ func parseJuniorRows(adultRows, juniorRows [][]string) ([]reconcile.Member, []st
}
// ---------------------------------------------------------------------------
// Payments sheet row parsing (ports scripts/match_payments.py fetch_sheet_data)
// Payments sheet row parsing (ports legacy/scripts/match_payments.py fetch_sheet_data)
// ---------------------------------------------------------------------------
func parseTransactionRows(rows [][]any) ([]reconcile.Transaction, error) {
@@ -466,7 +466,7 @@ func parseFloat(v any) float64 {
}
// ---------------------------------------------------------------------------
// Exceptions tab parsing (ports scripts/match_payments.py fetch_exceptions)
// Exceptions tab parsing (ports legacy/scripts/match_payments.py fetch_exceptions)
// ---------------------------------------------------------------------------
func parseExceptionRows(rows [][]any) map[reconcile.ExceptionKey]reconcile.Exception {