Vendor pinned prettier/format toolchain from prompts scaffold (closes #203)
Check / check (pull_request) Successful in 3m15s

script/fmt ran unpinned npx prettier with an inline --tab-width and no config, so formatting was not reproducible. This vendors the canonical format toolchain from the prompts scaffold: .prettierrc (tabWidth 4, proseWrap always), package.json and yarn.lock pinning prettier 3.8.1, and a script/bootstrap that installs node/yarn from a hash-verified nvm archive. script/fmt now reads the config over static/js and markdown; gofmt/goimports unchanged. .prettierignore keeps the *.min.js rule protecting the vendored alpine.min.js. Existing markdown was reflowed to house style.

Disclosure: make check does not gate prettier; the linter's pre-existing gomodguard deprecation warning is unrelated and left as-is.

Model: opus-4-8 (implementation and review)
This commit is contained in:
2026-09-22 18:43:58 +00:00
committed by sneak
parent 6026e3923d
commit 1d769834de
9 changed files with 277 additions and 136 deletions
+37 -31
View File
@@ -1,6 +1,8 @@
# Go HTTP Server Conventions
This document defines the architectural patterns, design decisions, and conventions for building Go HTTP servers. All new projects must follow these standards.
This document defines the architectural patterns, design decisions, and
conventions for building Go HTTP servers. All new projects must follow these
standards.
## Table of Contents
@@ -25,18 +27,18 @@ This document defines the architectural patterns, design decisions, and conventi
These libraries are **mandatory** for all new projects:
| Purpose | Library | Import Path |
|---------|---------|-------------|
| Dependency Injection | Uber fx | `go.uber.org/fx` |
| HTTP Router | go-chi | `github.com/go-chi/chi` |
| Logging | slog (stdlib) | `log/slog` |
| Configuration | Viper | `github.com/spf13/viper` |
| Environment Loading | godotenv | `github.com/joho/godotenv/autoload` |
| CORS | go-chi/cors | `github.com/go-chi/cors` |
| Error Reporting | Sentry | `github.com/getsentry/sentry-go` |
| Metrics | Prometheus | `github.com/prometheus/client_golang` |
| Metrics Middleware | go-http-metrics | `github.com/slok/go-http-metrics` |
| Basic Auth | basicauth-go | `github.com/99designs/basicauth-go` |
| Purpose | Library | Import Path |
| -------------------- | --------------- | ------------------------------------- |
| Dependency Injection | Uber fx | `go.uber.org/fx` |
| HTTP Router | go-chi | `github.com/go-chi/chi` |
| Logging | slog (stdlib) | `log/slog` |
| Configuration | Viper | `github.com/spf13/viper` |
| Environment Loading | godotenv | `github.com/joho/godotenv/autoload` |
| CORS | go-chi/cors | `github.com/go-chi/cors` |
| Error Reporting | Sentry | `github.com/getsentry/sentry-go` |
| Metrics | Prometheus | `github.com/prometheus/client_golang` |
| Metrics Middleware | go-http-metrics | `github.com/slok/go-http-metrics` |
| Basic Auth | basicauth-go | `github.com/99designs/basicauth-go` |
---
@@ -85,7 +87,8 @@ project-root/
### Key Principles
- **`cmd/{appname}/`**: Only the entry point. Minimal logic, just bootstrapping.
- **`internal/`**: All application packages. Not importable by external projects.
- **`internal/`**: All application packages. Not importable by external
projects.
- **One package per concern**: config, database, handlers, middleware, etc.
- **Flat handler files**: One file per handler or logical group of handlers.
@@ -190,7 +193,8 @@ Providers are resolved automatically by fx, but conceptually follow this order:
2. `logger.New` - Logger (depends on Globals)
3. `config.New` - Configuration (depends on Globals, Logger)
4. `database.New` - Database (depends on Logger, Config)
5. `healthcheck.New` - Health check (depends on Globals, Config, Logger, Database)
5. `healthcheck.New` - Health check (depends on Globals, Config, Logger,
Database)
6. `middleware.New` - Middleware (depends on Logger, Globals, Config)
7. `handlers.New` - Handlers (depends on Logger, Globals, Database, Healthcheck)
8. `server.New` - Server (depends on all above)
@@ -453,7 +457,8 @@ func New(lc fx.Lifecycle, params HandlersParams) (*Handlers, error) {
### Closure-Based Handler Pattern
All handlers return `http.HandlerFunc` using the closure pattern. This allows initialization logic to run once when the handler is created:
All handlers return `http.HandlerFunc` using the closure pattern. This allows
initialization logic to run once when the handler is created:
```go
// internal/handlers/index.go
@@ -510,7 +515,8 @@ func (s *Handlers) decodeJSON(w http.ResponseWriter, r *http.Request, v interfac
### Handler Naming Convention
- `HandleIndex()` - Main page
- `HandleLoginGET()` / `HandleLoginPOST()` - Form handlers with HTTP method suffix
- `HandleLoginGET()` / `HandleLoginPOST()` - Form handlers with HTTP method
suffix
- `HandleNow()` - API endpoints
- `HandleHealthCheck()` - System endpoints
@@ -733,7 +739,8 @@ func New(lc fx.Lifecycle, params ConfigParams) (*Config, error) {
1. **Environment variables** (highest priority via `AutomaticEnv()`)
2. **`.env` file** (loaded via `godotenv/autoload` import)
3. **Config files**: `/etc/{appname}/{appname}.yaml`, `~/.config/{appname}/{appname}.yaml`
3. **Config files**: `/etc/{appname}/{appname}.yaml`,
`~/.config/{appname}/{appname}.yaml`
4. **Defaults** (lowest priority)
### Environment Loading
@@ -1005,6 +1012,7 @@ var Static embed.FS
```
Directory structure:
```
static/
├── static.go
@@ -1045,15 +1053,13 @@ Templates use Go's template composition:
```html
<!-- index.html -->
{{ template "htmlheader.html" . }}
{{ template "navbar.html" . }}
{{ template "htmlheader.html" . }} {{ template "navbar.html" . }}
<main>
<!-- Page content -->
</main>
{{ template "pagefooter.html" . }}
{{ template "htmlfooter.html" . }}
{{ template "pagefooter.html" . }} {{ template "htmlfooter.html" . }}
```
### Static Asset References
@@ -1214,12 +1220,12 @@ if viper.GetString("METRICS_USERNAME") != "" {
### Environment Variables Summary
| Variable | Description | Default |
|----------|-------------|---------|
| `PORT` | HTTP listen port | 8080 |
| `DEBUG` | Enable debug logging | false |
| `DBURL` | Database connection URL | "" |
| `SENTRY_DSN` | Sentry DSN for error reporting | "" |
| `MAINTENANCE_MODE` | Enable maintenance mode | false |
| `METRICS_USERNAME` | Basic auth username for /metrics | "" |
| `METRICS_PASSWORD` | Basic auth password for /metrics | "" |
| Variable | Description | Default |
| ------------------ | -------------------------------- | ------- |
| `PORT` | HTTP listen port | 8080 |
| `DEBUG` | Enable debug logging | false |
| `DBURL` | Database connection URL | "" |
| `SENTRY_DSN` | Sentry DSN for error reporting | "" |
| `MAINTENANCE_MODE` | Enable maintenance mode | false |
| `METRICS_USERNAME` | Basic auth username for /metrics | "" |
| `METRICS_PASSWORD` | Basic auth password for /metrics | "" |