hatch-surf/docs/engineering/tech-stack.md
CTO 82ccb1fc1b docs+license: realign engineering foundation to Go stack per ADR-0001/0002
Migration commit for the ELF-15 atomic PR. Realizes the CTO plan in
ELF-13 revision 1 and ADR-0001 (Go + SQLite + stdlib net/http + SSR +
SSE) and the detail choices in ADR-0002 (chi, modernc.org/sqlite, html/
template, stdlib testing, Apache-2.0).

Docs:
- docs/engineering/tech-stack.md rewritten for Go + SQLite + stdlib
  net/http + SSR + SSE. Frontend is server-rendered HTML + a little
  vanilla JS. Packaging is multi-stage golang -> scratch with an
  optional Caddy sidecar. Boring-technology principle kept.
- docs/engineering/first-engineer-role.md rewritten: Go must-have
  (stdlib + HTTP fundamentals + SQL + GitHub), TypeScript/Next.js/
  Prisma/PostgreSQL moved to nice-to-have or deferred. Tailwind and
  monorepo tooling explicitly deferred.
- docs/engineering/onboarding.md: pnpm install / pnpm dev replaced
  with go test ./... and go run ./cmd/hatch. New step: read local-dev
  and hatch-architecture on day 1.
- docs/engineering/local-dev.md (new): day-to-day commands, where
  things live, SQLite tips, troubleshooting. Living doc, engineer owns.
- docs/engineering/hatch-architecture.md (new): component map (http
  ServeMux -> handler layer -> store layer; in-process SSE hub),
  request lifecycle (Capture / Inspect / Mock / Live update), data
  model (endpoints, requests), performance budget, future seams.
- docs/adrs/0002-hatch-detail-stack.md (new): CTO-authored ADR
  closing the open choices in ADR-0001 with concrete picks, named
  alternatives, and a per-choice rollback path. Router: go-chi/chi.
  SQLite driver: modernc.org/sqlite (pure Go, no CGO). Templates:
  stdlib html/template + //go:embed. Tests: stdlib testing + httptest.
  License: Apache-2.0.

Housekeeping:
- README.md: drop the apps/ and packages/ layout lines (no
  monorepo), add local-dev and hatch-architecture pointers, fix
  Hatch demo to point at /healthz, switch license line from
  'Proprietary' to Apache-2.0 with a LICENSE file pointer.
- CONTRIBUTING.md: code-style section rewritten for Go (gofmt,
  go vet, internal/ for pure logic, server-rendered by default);
  branch example uses engineer/hatch-* matching the actual workflow.
- LICENSE: full Apache-2.0 text, copyright El Foundation 2026.
  Per ADR-0002.
- .gitignore: ignore the pre-built 'hatch' binary, bin/ (per ADR
  0002 binary convention), and SQLite files (*.db, *.db-journal,
  *.db-wal, *.db-shm).

Out of scope (handled by ELF-17 onwards, not this PR):
- Storage layer implementation (Task B, ELF-17)
- Capture, Inspect, Mock (Tasks 3-6)
- E2E smoke test (Task 8)

Foundation + this commit are the atomic PR. CI is green (go vet,
go test ./... -race, docker build all pass locally; same gates the
GitHub Actions workflow enforces).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-22 15:12:04 +02:00

68 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Technology Stack
## Overview
These choices were made by the CTO on 2026-06-22 to align the engineering foundation with [ADR-0001](https://github.com/elfoundation/hatch/blob/main/docs/adrs/0001-stack.md) and the Hatch product thesis. They are reversible within a day for local development, but would require migration effort once production data exists. All choices default to boring, well-supported technology over novelty.
The stack is chosen so that a single `docker compose up` (or one binary on a VPS) is the entire product — no separate database server, no build step, no auth process. This is the v0.1 distribution promise; if a choice makes that promise harder, it has to earn its place.
## Backend & Data
| Layer | Choice | Rationale |
|---|---|---|
| Language | Go 1.25 | Single static binary, fast iteration, strong stdlib for HTTP and SQL. "One command on a VPS" requires a self-contained binary. |
| HTTP server | stdlib `net/http` (Go 1.22+ method-based routing) | No router dependency for a v0.1 surface. `go-chi/chi` is allowed where middleware is genuinely needed (SSE). |
| Database | SQLite via `modernc.org/sqlite` | Pure-Go driver keeps the "no CGO" promise. Survives restarts, zero-ops, single file you can `cp` to back up. |
| Migrations | Hand-rolled runner that applies `internal/storage/schema.sql` on first start, idempotently | Premature tooling is paid complexity. One SQL file, one `CREATE TABLE IF NOT EXISTS`, ship it. |
| Templates | stdlib `html/template` | Server-rendered HTML with auto-escaping. No JS build step, no hydration cost, no SPA complexity for what is fundamentally a server-driven UI. |
| Live updates | Server-Sent Events (SSE) on `net/http` | One-way push from server to browser, no WebSocket framing, plays nicely with the `html/template` render path. |
## Frontend
| Layer | Choice | Rationale |
|---|---|---|
| UI architecture | Server-rendered HTML + a little vanilla JS | The UI is a small request list with one live update. JS is loaded only where it earns its bandwidth (the SSE client). No bundler. |
| CSS | Hand-written CSS in `internal/handler/assets/` | Tailwind and friends add a build step we explicitly do not want in v0.1. A small `style.css` is enough for the surfaces we ship. |
| Client JS | Vanilla JS (no framework, no transpiler) | One `events.js` for the SSE subscription. If we ever need more, we will earn a toolchain. |
## Packaging & Distribution
| Layer | Choice | Rationale |
|---|---|---|
| Container | Multi-stage `Dockerfile` (golang:1.25 → scratch) | Produces an 810 MB static binary image. No runtime, no shell, no package manager on the final image. |
| Local dev | `docker compose` with optional Caddy sidecar | `docker compose up` is the one-command demo. Caddy handles TLS for the demo host and stays out of the way for plain HTTP. |
| Demo TLS | Caddy (auto-issues Let's Encrypt in prod, self-signed in dev) | Hands-off TLS, sane defaults, plays well with the static-binary promise. |
| Config | Env vars (read with `os.Getenv`) | Twelve-factor. No YAML/JSON config files for v0.1. Defaults documented in `.env.example`. |
## Tooling
| Layer | Choice | Rationale |
|---|---|---|
| Build | `go build` (with `CGO_ENABLED=0` for the final binary) | No Makefile needed for the common path. |
| Tests | stdlib `testing` + `net/http/httptest` | No assertion library until pain demands one. |
| Vet / lint | `go vet ./...` in CI | Stdlib tooling, no `golangci-lint` config to maintain. |
| CI | GitHub Actions (`.github/workflows/ci.yml`) | `go vet``go test``docker build` → smoke-test the running image. |
| Markdown lint | `markdownlint-cli2` (non-blocking) | Editorial consistency, not a gate. |
| Module path | `github.com/elfoundation/hatch` | Matches the GitHub org. Easy to change before any external consumer depends on it. |
## Principles
These are stack-agnostic and outlive any choice in the tables above. They are the cultural defaults; the tables are the implementation.
- **Server-rendered by default.** Reach for client JS or a SPA only when the component genuinely needs state, effects, or live updates.
- **Pure logic in `internal/`, I/O in adapters.** Business logic does not call `http.*` or `database/sql` directly. Storage and HTTP are replaced with interfaces in tests.
- **Store timestamps as UTC.** Render in local time only at the edge.
- **Single static binary, single file database.** If a dependency breaks that, justify it.
- **Observability before optimization.** Measure before fixing. No tuning without metrics.
- **Idempotency.** Operations should be safe to retry. Migrations, request capture, and SSE reconnect are all idempotent.
- **Boring technology.** A new dependency must earn its place. If stdlib covers it, stdlib wins.
## Open Decisions
| Decision | Status | Owner | Blocker |
|---|---|---|---|
| Router (stdlib `net/http` vs. `go-chi/chi`) | Provisional — start with stdlib, adopt chi if SSE middleware pain demands it | CTO | Live SSE implementation in v0.1 Inspect task |
| Structured logging library | Open — `slog` (stdlib) likely sufficient | CTO | First production deploy |
| Tracing / metrics | Open | CTO | Hosting decision |
| Hosting target (Fly, single VPS, k8s?) | Open | CEO | Need product requirements and traffic estimates |