diff --git a/backend/.editorconfig b/.editorconfig similarity index 100% rename from backend/.editorconfig rename to .editorconfig diff --git a/.gitignore b/.gitignore index 9451024..ee4128a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,27 @@ -node_modules/ -dist/ +# OS .DS_Store +Thumbs.db + +# Editors +*.swp +*.swo +*~ +*.bak +.idea/ +.vscode/ +*.sublime-* + +# Node +node_modules/ + +# Environment / secrets +.env +.env.* +*.pem +*.key + +# Build output +dist/ + +# Logs *.log diff --git a/Dockerfile.backend b/Dockerfile.backend index d97bbbd..e06a617 100644 --- a/Dockerfile.backend +++ b/Dockerfile.backend @@ -1,25 +1,50 @@ +# Lint stage — fast feedback on formatting and lint issues. The +# golangci/golangci-lint image ships Go, gofmt, make and the linter, so +# nothing is installed here. +# golangci/golangci-lint:v2.7.2 (2026-08-09) +FROM golangci/golangci-lint@sha256:5d6d5c70a61f1356adfd9dd6316ce286799fefc9d743421356ff1b00842368ba AS lint + +WORKDIR /src +COPY backend/go.mod backend/go.sum ./ +RUN go mod download +COPY backend/ . +RUN make fmt-check +RUN make lint + +# Build stage # golang:1.25-alpine (2026-02-27) FROM golang:1.25-alpine@sha256:f6751d823c26342f9506c03797d2527668d095b0a15f1862cddb4d927a7a4ced AS builder -RUN apk add --no-cache git make gcc musl-dev +RUN apk add --no-cache make -# golangci-lint v2.7.2 (2026-02-27) -RUN CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@9f61b0f53f80672872fced07b6874397c3ed197b +WORKDIR /src + +# Force BuildKit to run the lint stage before proceeding. BuildKit runs +# stages in parallel by default; without this no-op copy a lint failure +# would not gate compilation. +COPY --from=lint /src/go.sum /dev/null -WORKDIR /repo/backend COPY backend/go.mod backend/go.sum ./ RUN go mod download -COPY .git /repo/.git COPY backend/ . -RUN make check -RUN make build +RUN make test +# The build is driven through the Makefile so there is exactly one +# definition of the build command; it expands to +# CGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X main.Version=... -X main.Buildarch=..." +# VERSION is handed over in the environment rather than as a make +# variable so it still reaches the build if the target is ever turned +# into a shim around a script. +ARG VERSION=dev +RUN VERSION="${VERSION}" make build + +# Runtime stage # alpine:3.23 (2026-02-27) FROM alpine:3.23@sha256:25109184c71bdad752c8312a8623239686a9a2071e8825f20acb8f2198c3f659 RUN apk add --no-cache ca-certificates -COPY --from=builder /repo/backend/netwatch-server /usr/local/bin/netwatch-server +COPY --from=builder /src/netwatch-server /usr/local/bin/netwatch-server EXPOSE 8080 ENTRYPOINT ["netwatch-server"] diff --git a/TODO.md b/TODO.md index 587c805..1da8930 100644 --- a/TODO.md +++ b/TODO.md @@ -22,6 +22,23 @@ files, so merging it also closes most compliance gaps. # Completed Steps +- 2026-08-10: every interactive control now meets the 44x44 CSS px minimum tap + target (`.pin-btn`, `#interval-select`, the debug-log label and, on narrow + viewports, `#pause-btn`). The pin button's hit area grows via matching + negative margins, so its layout footprint and row density are unchanged +- 2026-08-10: per-host status line wraps below the 768px breakpoint instead of + forcing horizontal page scroll at 320px +- 2026-08-09: `Dockerfile.backend` reworked to the mandated Go multistage + lint-stage pattern: separate `lint` stage on the hash-pinned + `golangci/golangci-lint` image, `COPY --from=lint` stage dependency, + `CGO_ENABLED=0` static build driven by `ARG VERSION`, and no more `COPY .git` +- 2026-08-09: dotfile compliance — lifted `backend/.editorconfig` to the repo + root so `root = true` covers the frontend too, and replaced `.gitignore` with + the org model (OS, editor, node, and environment/secrets sections) plus this + repo's `dist/` and `*.log`. `.env`, `.env.*`, `*.pem`, and `*.key` are now + ignored repo-wide, not just under `backend/`. Excluding `.git` from + `.dockerignore` stays deferred: both images read git metadata at build time + (`COPY .git` in `Dockerfile.backend`, `git rev-parse` in `vite.config.js`) - 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints, Makefile shims, README Entrypoints section - 2026-02-27: backend with buffered zstd-compressed report storage; CI workflow diff --git a/backend/Makefile b/backend/Makefile index 38cebcf..4660353 100644 --- a/backend/Makefile +++ b/backend/Makefile @@ -1,25 +1,22 @@ -UNAME_S := $(shell uname -s) -VERSION := $(shell git describe --always --dirty) +# VERSION is overridable (the Dockerfile passes its ARG VERSION in) and +# degrades to "dev" when git is unavailable or there is no .git — the +# build must not depend on the repository history being in the build +# context. +VERSION ?= $(shell { git describe --always --dirty; } 2>/dev/null || echo dev) BUILDARCH := $(shell uname -m) BINARY := netwatch-server +GOLDFLAGS += -s -w GOLDFLAGS += -X main.Version=$(VERSION) GOLDFLAGS += -X main.Buildarch=$(BUILDARCH) -ifeq ($(UNAME_S),Darwin) - GOFLAGS := -ldflags "$(GOLDFLAGS)" -else - GOFLAGS = -ldflags "-linkmode external -extldflags -static $(GOLDFLAGS)" -endif - .PHONY: all build test lint fmt fmt-check check docker hooks run clean all: build -build: ./$(BINARY) - -./$(BINARY): $(shell find . -name '*.go' -type f) go.mod go.sum - go build -o $@ $(GOFLAGS) ./cmd/netwatch-server/ +build: + CGO_ENABLED=0 go build -trimpath -ldflags "$(GOLDFLAGS)" \ + -o ./$(BINARY) ./cmd/netwatch-server/ test: timeout 30 go test ./... diff --git a/src/main.js b/src/main.js index 3ab6bb8..135d36a 100644 --- a/src/main.js +++ b/src/main.js @@ -537,6 +537,12 @@ class SparklineRenderer { // --- UI Renderer ------------------------------------------------------------- +// The per-host status line must stay wrappable: its populated content is +// wider than the host column at a 320px viewport, and `whitespace-nowrap` +// here overflows the element and forces the whole document to scroll +// horizontally. +const STATUS_TEXT_CLASS = "status-text text-xs text-right col-span-2 mt-5"; + function hostRowHTML(host, index, showPin = true) { const pinColor = host.pinned ? "text-blue-500" @@ -562,7 +568,7 @@ function hostRowHTML(host, index, showPin = true) { --- ${host.url} -
-