@nakedev/go-scaffold 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,7 +28,7 @@ async function runCreateWizard(preset = {}) {
28
28
  }));
29
29
  const openapiDocs = preset.openapiDocs ??
30
30
  (await (0, interactive_1.confirm)({
31
- message: "Include hand-written OpenAPI docs (docs/openapi.yaml, whole docs/ tree served at /docs)?",
31
+ message: "Include hand-written OpenAPI docs (docs/openapi.yaml files only, never served over HTTP)?",
32
32
  default: true,
33
33
  }));
34
34
  const observability = preset.observability ??
@@ -49,8 +49,8 @@ function patchMainGoForObservability(mainGoPath, goModule, projectName) {
49
49
  }
50
50
  const newUseLine = `${USE_LINE.slice(0, -1)}, middleware.Metrics(), middleware.Tracing("${projectName}"))`;
51
51
  content = content.replace(USE_LINE, () => newUseLine);
52
- // Not gated on APP_ENV the way /docs is: production is exactly where you
53
- // want a scrape target, and Prometheus reaches it in-cluster. It is still
52
+ // Unlike docs/, which is never served at all: production is exactly where
53
+ // you want a scrape target, and Prometheus reaches it in-cluster. It is still
54
54
  // unauthenticated and does disclose your route list and traffic shape, so
55
55
  // block /metrics at the ingress rather than publishing it to the internet.
56
56
  const metricsRoute = 'r.GET("/metrics", gin.WrapH(promhttp.Handler()))';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nakedev/go-scaffold",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "description": "Scaffold Gin + GORM + Postgres Go backend projects with a consistent domain-module standard",
5
5
  "repository": {
6
6
  "type": "git",
@@ -166,15 +166,15 @@ TEST_DB_DSN=postgres://postgres:postgres@localhost:5432/{{dbName}}_test?sslmode=
166
166
 
167
167
  ## API spec
168
168
 
169
- `docs/openapi.yaml` is hand-written and served, along with every file it `$ref`s (`common/`, `health/`, per-domain folders), under `/docs` while the server runspoint a renderer (Scalar, Swagger UI, Redoc) or a client generator (Hey API) at `http://localhost:8080/docs/openapi.yaml`, or browse the tree at `http://localhost:8080/docs/`. Update the spec by hand whenever an endpoint/DTO changes.
169
+ `docs/openapi.yaml` is hand-written and split across sibling files (`common/`, `health/`, per-domain folders) via relative `$ref`. **The server never serves it** there is no `/docs` route, in any environment, so the API surface and `docs/architect/`'s internal notes stay off the wire. Update the spec by hand whenever an endpoint/DTO changes.
170
170
 
171
- Some tools don't resolve external `$ref`s when importing a local file — they read it as-is and see zero routes (Bruno's "Import Collection" does this; some Postman flows too). For those, bundle the spec into one fully-resolved file first:
171
+ To open it in a renderer (Scalar, Swagger UI, Redoc) or a client generator (Hey API), bundle it into one fully-resolved file and point the tool at that file. Bundling is also what importers that don't resolve external `$ref`s need — they read the index as-is and see zero routes (Bruno's "Import Collection" does this; some Postman flows too):
172
172
 
173
173
  ```bash
174
174
  make openapi-bundle # writes docs/openapi.bundled.yaml (gitignored — regenerate anytime)
175
175
  ```
176
176
 
177
- Import `docs/openapi.bundled.yaml` instead. Tools that resolve `$ref` over HTTP or when reading a URL (Scalar, Swagger UI, Redoc) don't need this point them at the live `/docs/openapi.yaml` URL above.
177
+ Then open `docs/openapi.bundled.yaml` — it needs no network and no running server.
178
178
  {{/if}}
179
179
 
180
180
  ## Adding a domain
@@ -89,23 +89,13 @@ func run() error {
89
89
  })
90
90
  // go-scaffold:extra-routes
91
91
  {{#if openapiDocs}}
92
- // hand-written spec at docs/openapi.yaml, split across sibling files (common/, health/,
93
- // <domain>/) via relative $ref serve the whole tree under one prefix so a client that
94
- // resolves $ref over HTTP (Scalar, Swagger UI, Redoc, Hey API pointed at a URL) can reach
95
- // them too; StaticFile on just the index file would 404 on every $ref it follows.
96
- //
97
- // gin.Dir(..., true) keeps directory listings on, which r.Static suppresses:
98
- // without them opening /docs/ in a browser answers 404 with a blank page,
99
- // which reads as "this is broken" rather than "ask for a file". The listing
100
- // costs nothing here — every file in the tree is already downloadable — and
101
- // it makes openapi.yaml discoverable without knowing its name up front.
102
- //
103
- // Not in production: this serves your whole API surface — every path,
104
- // parameter and schema — to anyone who asks. Publish the spec deliberately
105
- // (`make openapi-bundle`) rather than by leaving this on.
106
- if !cfg.IsProd() {
107
- r.StaticFS("/docs", gin.Dir("./docs", true))
108
- }
92
+ // ponytail: docs/ is deliberately NOT served over HTTP, in any environment.
93
+ // The whole treeevery path, parameter and schema, plus docs/architect/'s
94
+ // internal design notes used to be reachable at /docs outside production.
95
+ // Read the spec from the working copy instead: `make openapi-bundle` writes
96
+ // one fully-resolved docs/openapi.bundled.yaml for a renderer or client
97
+ // generator to open as a local file. Publish it deliberately if you want
98
+ // it public.
109
99
  {{/if}}
110
100
 
111
101
  api := r.Group("/{{apiPrefix}}")
@@ -104,9 +104,9 @@ insert, so it doesn't need `gen_random_uuid()`.
104
104
  ## 8. API Documentation
105
105
 
106
106
  **Decision:** Hand-written OpenAPI spec (`docs/openapi.yaml`), split by
107
- domain module, served under `/docs` (so relative `$ref`s to sibling files
108
- resolve over HTTP too the index alone isn't enough for a renderer like
109
- Scalar/Swagger UI/Redoc to follow them).
107
+ domain module, read from the working copy only the server serves no `/docs`
108
+ route in any environment. Renderers that follow relative `$ref`s get a
109
+ fully-resolved single file from `make openapi-bundle`.
110
110
  **Rationale:** Cheap while the endpoint count is low; switch to
111
111
  comment-generated (swaggo) if hand-updates start drifting.
112
112
  {{/if}}
@@ -22,7 +22,7 @@
22
22
  - PostgreSQL + GORM baseline: always enabled
23
23
  - Graceful shutdown, structured logging, `/livez` + `/readyz`: always enabled
24
24
  - Docker Compose (local Postgres): `{{#if docker}}enabled{{else}}disabled{{/if}}`
25
- - OpenAPI docs (`docs/openapi.yaml`, whole `docs/` tree served at `/docs`): `{{#if openapiDocs}}enabled{{else}}disabled{{/if}}`
25
+ - OpenAPI docs (`docs/openapi.yaml`, working-copy only never served over HTTP): `{{#if openapiDocs}}enabled{{else}}disabled{{/if}}`
26
26
  - Metrics + tracing (Prometheus `/metrics`, OpenTelemetry for Gin + GORM, `cmd/api` only): `{{#if observability}}enabled{{else}}disabled{{/if}}`
27
27
  - API route prefix: `{{#if apiPrefix}}/{{apiPrefix}}{{else}}(none){{/if}}`
28
28
  - CI (`.github/workflows/ci.yml` — build, vet, gofmt check, golangci-lint, `go test` with a real Postgres service): always enabled