Move to the layout REPO_POLICIES.md gives (closes #30)
check / check (push) Successful in 2m32s

The Go module moves from backend/ to the root (go.mod, go.sum,
.golangci.yml, cmd/, internal/), the page's source to web/, and nginx's
two files to configs/. backend/ is gone: its LICENSE and .dockerignore
are deleted, and its .gitignore entries, README and scripts are folded
into the root ones. script/build builds the server binary after the
frontend; script/run and script/clean move up from backend/script/;
make test, lint, fmt and fmt-check do what the backend's did. Vite's
root is web/ and it still builds into dist/. script/bootstrap no longer
installs gcc, which only the host Go tests needed.

Model: opus-5-5
This commit is contained in:
2026-10-14 08:56:45 +00:00
parent b1eefe0c29
commit 0f78f19a9d
68 changed files with 328 additions and 530 deletions
+2 -8
View File
@@ -17,7 +17,7 @@
# golangci-lint is not installed: make lint runs it in Docker, as make
# test runs the tests, and this script does not install Docker either.
#
# Unlike the org model: Go and gcc for backend/, a newer node for eslint.
# Unlike the org model: Go for the backend, a newer node for eslint.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
@@ -272,19 +272,13 @@ main() {
if missing make; then pkg_install gnumake make make make; fi
if missing git; then pkg_install git git git git; fi
# The race detector in backend/'s make test needs cgo, which Go turns
# on only when it finds its C compiler, gcc on Linux. apt and apk
# ship the C library headers apart from gcc.
if missing gcc; then
pkg_install gcc "gcc libc6-dev" gcc "gcc musl-dev"
fi
ensure_node
ensure_yarn
yarn install --frozen-lockfile
ensure_go
(cd "$ROOT/backend" && go mod download)
go mod download
if missing docker; then
echo "bootstrap: docker not found; make test and make lint, and so" >&2
+11 -2
View File
@@ -1,6 +1,7 @@
#!/bin/sh
# script/build: build the frontend for production into dist/. The Go
# backend is built by backend/script/build.
# script/build: build the frontend for production into dist/, then the
# static netwatch-server binary into the repo root, with its version
# stamped in.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
@@ -8,6 +9,14 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
main() {
cd "$ROOT"
yarn build
# VERSION comes from the environment. Unset or empty, it is git
# describe, or "dev" where there is no git or no repository history.
version="${VERSION:-$(git describe --always --dirty 2>/dev/null || echo dev)}"
CGO_ENABLED=0 go build -trimpath \
-ldflags "-s -w -X main.Version=$version" \
-o netwatch-server ./cmd/netwatch-server/
}
main "$@"
Executable
+13
View File
@@ -0,0 +1,13 @@
#!/bin/sh
# script/clean: remove what script/build writes: dist/ and the
# netwatch-server binary.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
main() {
cd "$ROOT"
rm -rf dist netwatch-server
}
main "$@"
+5 -3
View File
@@ -1,7 +1,9 @@
#!/bin/sh
# script/fmt: format the whole repo (writes): prettier over the
# JavaScript, CSS, HTML and Markdown, then gofmt over the Go backend.
# The org model formats only markdown; this repo also has JS and Go.
# JavaScript, CSS, HTML and Markdown, then gofmt over the Go sources in
# cmd/ and internal/; not over the whole root, as node_modules/ holds
# .go files of its own. The org model formats only markdown; this repo
# also has JS and Go.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
@@ -12,7 +14,7 @@ main() {
# ~/.local/bin, which the shell that called it may not have on PATH.
PATH="$HOME/.local/bin:$PATH"
"$ROOT/script/frontend-fmt"
"$ROOT/backend/script/fmt"
gofmt -l -w cmd internal
}
main "$@"
+6 -1
View File
@@ -12,7 +12,12 @@ main() {
# ~/.local/bin, which the shell that called it may not have on PATH.
PATH="$HOME/.local/bin:$PATH"
"$ROOT/script/frontend-fmt-check"
"$ROOT/backend/script/fmt-check"
unformatted="$(gofmt -l cmd internal)"
if [ -n "$unformatted" ]; then
echo "Go files not formatted:" >&2
echo "$unformatted" >&2
exit 1
fi
}
main "$@"
+4 -4
View File
@@ -1,9 +1,9 @@
#!/bin/sh
# script/frontend-fmt: format the JavaScript, CSS, HTML and Markdown,
# repo-wide (writes), the markdown in backend/ included. Those are the
# languages REPO_POLICIES.md gives prettier; the YAML is left alone, as
# backend/.golangci.yml must stay the org standard byte for byte.
# Prettier does not read Go; backend/script/fmt formats the Go sources.
# repo-wide (writes). Those are the languages REPO_POLICIES.md gives
# prettier; the YAML is left alone, as .golangci.yml must stay the org
# standard byte for byte. Prettier does not read Go; script/fmt runs
# gofmt over the Go sources.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
+10 -10
View File
@@ -2,11 +2,11 @@
# script/frontend-viewport-test: verify the responsive layout of the built
# frontend in a real browser engine.
#
# Builds dist/, serves it with the same nginx image and the same nginx.conf
# the shipping container uses, points a containerised headless Chrome at it
# over CDP, and asserts on computed layout at every viewport width derived
# from the app's own CSS. See test/viewport/README.md for what this covers
# and what it cannot.
# Builds dist/, serves it with the same nginx image and the same
# configs/nginx.conf the shipping container uses, points a containerised
# headless Chrome at it over CDP, and asserts on computed layout at every
# viewport width derived from the app's own CSS. See
# test/viewport/README.md for what this covers and what it cannot.
#
# Deliberately not part of script/check: it needs Docker and takes far
# longer than the 20s budget make test has to stay inside.
@@ -61,18 +61,18 @@ main() {
# host.
docker network create --internal "$NETWORK" > /dev/null
# nginx.conf is a template: the image renders it over its own
# configs/nginx.conf is a template: the image renders it over its own
# default.conf, with the same port and limit bin/entrypoint.sh uses.
# The empty file it includes trusts no proxy, as bin/entrypoint.sh
# writes it when TRUSTED_PROXIES is unset. nginx.conf also includes
# the security headers, so the page runs under the shipped policy.
# writes it when TRUSTED_PROXIES is unset. It also includes the
# security headers, so the page runs under the shipped policy.
docker run -d --rm --name "$SERVER" \
--network "$NETWORK" --network-alias netwatch \
-e PORT=8080 -e NGINX_ENVSUBST_FILTER='^PORT$' \
-v "$ROOT/dist:/usr/share/nginx/html:ro" \
-v "$ROOT/nginx.conf:/etc/nginx/templates/default.conf.template:ro" \
-v "$ROOT/configs/nginx.conf:/etc/nginx/templates/default.conf.template:ro" \
-v /dev/null:/etc/nginx/trusted-proxies.conf:ro \
-v "$ROOT/security-headers.conf:/etc/nginx/security-headers.conf:ro" \
-v "$ROOT/configs/security-headers.conf:/etc/nginx/security-headers.conf:ro" \
"$SERVER_IMAGE" > /dev/null
# The image's own entrypoint already exposes CDP on 9222 and passes
Executable
+14
View File
@@ -0,0 +1,14 @@
#!/bin/sh
# script/run: build with script/build, then run netwatch-server locally
# with its defaults: port 8080, reports stored in data/reports.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
main() {
cd "$ROOT"
"$ROOT/script/build"
exec ./netwatch-server "$@"
}
main "$@"
+3 -3
View File
@@ -1,12 +1,12 @@
#!/bin/sh
# script/tidy: run go mod tidy in backend/, which adds the modules the
# Go sources import, drops those they no longer do, and updates go.sum.
# script/tidy: run go mod tidy, which adds the modules the Go sources
# import, drops those they no longer do, and updates go.sum.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
main() {
cd "$ROOT/backend"
cd "$ROOT"
go mod tidy
}