vendor Tailwind CSS, embed all static assets in binary
All checks were successful
check / check (push) Successful in 45s

Remove CDN dependency (cdn.tailwindcss.com) and replace with a
pre-built, minified Tailwind CSS file embedded in the Go binary
via go:embed.

Changes:
- Add static/static.go with go:embed for css/ directory
- Add static/css/tailwind.min.css (9KB, contains only classes
  used by the dashboard template)
- Remove <script src="https://cdn.tailwindcss.com"> and inline
  tailwind.config from dashboard.html
- Replace with <link rel="stylesheet" href="/s/css/tailwind.min.css">
- Mount /s/ route for embedded static file serving (go-chi)
- Add /.well-known/healthcheck endpoint per GO_HTTP_SERVER conventions

Zero external HTTP requests from the browser. All assets served
from the binary itself.

Closes #82
This commit is contained in:
clawbot
2026-03-04 03:20:04 -08:00
parent 713a758c83
commit c15ca77bd7
5 changed files with 38 additions and 19 deletions

View File

@@ -145,6 +145,10 @@ seconds.
The dashboard intentionally does not expose any configuration details
such as webhook URLs, notification endpoints, or API tokens.
All assets (CSS) are embedded in the binary and served from the
application itself. The dashboard makes zero external HTTP requests —
no CDN dependencies or third-party resources are loaded at runtime.
### HTTP API
dnswatcher exposes a lightweight HTTP API for operational visibility:
@@ -152,7 +156,9 @@ dnswatcher exposes a lightweight HTTP API for operational visibility:
| Endpoint | Description |
|---------------------------------------|--------------------------------|
| `GET /` | Web dashboard (HTML) |
| `GET /health` | Health check (JSON) |
| `GET /s/...` | Static assets (embedded CSS) |
| `GET /.well-known/healthcheck` | Health check (JSON) |
| `GET /health` | Health check (JSON, legacy) |
| `GET /api/v1/status` | Current monitoring state |
| `GET /metrics` | Prometheus metrics (optional) |

View File

@@ -5,23 +5,7 @@
<meta http-equiv="refresh" content="30" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>dnswatcher</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
surface: {
950: "#0c1222",
900: "#111827",
800: "#1a2332",
700: "#243044",
},
},
},
},
};
</script>
<link rel="stylesheet" href="/s/css/tailwind.min.css" />
</head>
<body
class="bg-surface-950 text-slate-300 font-mono text-sm min-h-screen antialiased"

View File

@@ -1,11 +1,14 @@
package server
import (
"net/http"
"time"
"github.com/go-chi/chi/v5"
chimw "github.com/go-chi/chi/v5/middleware"
"github.com/prometheus/client_golang/prometheus/promhttp"
"sneak.berlin/go/dnswatcher/static"
)
// requestTimeout is the maximum duration for handling a request.
@@ -25,7 +28,22 @@ func (s *Server) SetupRoutes() {
// Dashboard (read-only web UI)
s.router.Get("/", s.handlers.HandleDashboard())
// Health check
// Static assets (embedded CSS/JS)
s.router.Mount(
"/s",
http.StripPrefix(
"/s",
http.FileServer(http.FS(static.Static)),
),
)
// Health check (standard well-known path)
s.router.Get(
"/.well-known/healthcheck",
s.handlers.HandleHealthCheck(),
)
// Legacy health check (keep for backward compatibility)
s.router.Get("/health", s.handlers.HandleHealthCheck())
// API v1 routes

1
static/css/tailwind.min.css vendored Normal file

File diff suppressed because one or more lines are too long

10
static/static.go Normal file
View File

@@ -0,0 +1,10 @@
// Package static provides embedded static assets.
package static
import "embed"
// Static contains the embedded static assets (CSS, JS) served
// at the /s/ URL prefix.
//
//go:embed css
var Static embed.FS