Files
fuj-management/go/cmd/fuj/main.go
Jan Novak cf0f176d3f feat: Go rewrite M1 — skeleton, tooling, and hello server
Stand up the Go project alongside the Python backend so both run
independently during migration. `make web-go` builds and serves on :8080;
`make web-py` (alias: `make web`) keeps the Python side on :5001.

- go/: new module `fuj-management/go` (Go 1.26)
  - cmd/fuj: stdlib-flag dispatcher; `server` + `version` work,
    fees/reconcile/sync/infer stubbed for M2/M4
  - internal/config: env loader mirroring scripts/config.py
  - internal/logging: slog setup, level taken from config
  - internal/web: net/http ServeMux + request-timer middleware
  - build/Dockerfile: golang:1.26 → alpine:3 multi-stage image
  - .golangci.yml: govet, staticcheck, errcheck, gofumpt, unused
- Makefile: web→web-py alias; go-build/go-test/go-run/go-lint/web-go
- CI: parallel build-go job in .gitea/workflows/build.yaml (<tag>-go image)
- docs/plans/: M1 kickoff plan + progress tracker (M1 complete)
- .claude/settings.json: gofumpt + golangci-lint permissions

Gate: make go-build ✓  make go-lint ✓  make go-test ✓  curl :8080 ✓

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

85 lines
1.8 KiB
Go

package main
import (
"flag"
"fmt"
"fuj-management/go/internal/config"
"fuj-management/go/internal/logging"
"fuj-management/go/internal/web"
"os"
)
// Injected at build time via -ldflags "-X main.version=... -X main.commit=... -X main.buildDate=..."
var (
version = "dev"
commit = "unknown"
buildDate = "unknown"
)
func main() {
if len(os.Args) < 2 {
usage()
os.Exit(2)
}
cmd, args := os.Args[1], os.Args[2:]
switch cmd {
case "server":
serverCmd(args)
case "version":
versionCmd()
case "fees", "reconcile", "sync", "infer":
fmt.Fprintf(os.Stderr, "fuj %s: not implemented yet (lands in M2/M4)\n", cmd)
os.Exit(2)
case "-h", "--help", "help":
usage()
default:
fmt.Fprintf(os.Stderr, "fuj: unknown command %q\n\n", cmd)
usage()
os.Exit(2)
}
}
func serverCmd(args []string) {
fs := flag.NewFlagSet("server", flag.ExitOnError)
addr := fs.String("addr", "", "listen address (default from SERVER_ADDR env or :8080)")
fs.Usage = func() {
fmt.Fprintln(os.Stderr, "usage: fuj server [--addr :8080]")
fs.PrintDefaults()
}
if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
cfg := config.Load()
if *addr != "" {
cfg.ServerAddr = *addr
}
logger := logging.New(cfg.LogLevel)
build := web.BuildInfo{Version: version, Commit: commit, BuildDate: buildDate}
if err := web.Run(logger, cfg.ServerAddr, build); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func versionCmd() {
fmt.Printf("fuj %s (%s) built %s\n", version, commit, buildDate)
}
func usage() {
fmt.Fprintln(os.Stderr, `usage: fuj <command> [flags]
Commands:
server Start HTTP server (default :8080)
version Print version information
fees Calculate monthly fees [M2]
reconcile Show balance report [M2]
sync Sync Fio transactions [M4]
infer Infer payment details [M4]`)
}