Files
BountyBoard/DECISIONS.md
T
etalon 976f5238f8 feat: scaffold app skeleton with config, ULID, health endpoints, compose stack (phase 1)
- internal .env loader (real env wins) + strictly validated config struct
- ULID package: 48-bit ms timestamp + 80-bit crypto randomness, sortable
- HTTP server with recovery/request-id/trusted-proxy/access-log middleware
- /healthz, /readyz (pluggable checkers), /metricsz (counter registry)
- multi-stage Dockerfile (alpine, non-root) + compose with healthchecks,
  app bound to 127.0.0.1:8787, mongo unpublished, graceful 15s shutdown

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 18:10:30 +02:00

2.3 KiB

Decisions

Spec-silent choices, recorded as required by the build instructions.

Phase 1

  • Go toolchain 1.26.4 (latest stable; spec requires ≥ 1.22). Installed at /usr/local/go.
  • Module name bountyboard — no remote repository exists; a single-word module keeps import paths short (bountyboard/internal/...).
  • Package in internal/http is named httpx to avoid clashing with stdlib net/http inside its own files. The directory stays internal/http per spec §14; importers alias it (httpx "bountyboard/internal/http").
  • /readyz uses a pluggable checker registry (AddReadinessCheck): required checks (Mongo, Phase 2) gate readiness with 503; optional checks (atomizer / work performer, Phase 11) are reported as degraded but stay 200, matching §6's "non-fatal, reported".
  • Runtime image is alpine:3.21, not distroless — busybox wget enables the compose healthcheck without adding tooling, and ca-certificates is needed for outbound HTTPS to Jira/ADO/YouTrack. Non-root user.
  • Config validation is strict and fail-fast: CREDENTIALS_ENC_KEY is mandatory at startup (base64, exactly 32 bytes) and SESSION_SECRET must be ≥ 16 chars, even before the features using them land — a misconfigured deployment should die at boot, not at first use. All validation errors are reported together via errors.Join.
  • Trusted-proxy resolution walks X-Forwarded-For right-to-left, skipping addresses inside TRUSTED_PROXY_CIDRS; the first untrusted address is the client. A malformed entry stops the walk (everything left of it is attacker-controllable). If the whole chain is trusted, the leftmost entry is used. Headers are ignored entirely when the direct peer is untrusted.
  • ULID: canonical 48-bit ms timestamp + 80-bit crypto randomness, no intra-millisecond monotonicity (spec only needs sortability at ms resolution; randomness makes collisions negligible).
  • .env loader semantics: real environment variables win over .env values; unquoted values support trailing # comment; missing .env file is not an error (containers receive env via compose env_file).
  • Makefile seed/backup/restore are failing stubs until Phase 12 so the targets exist but cannot be mistaken for working.