@nakedev/go-scaffold 0.4.0 → 0.5.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.
- package/README.md +598 -306
- package/dist/commands/auth.js +65 -23
- package/dist/commands/check.js +281 -0
- package/dist/commands/config.js +50 -0
- package/dist/commands/create.js +33 -2
- package/dist/commands/generate.js +29 -3
- package/dist/commands/method.js +74 -63
- package/dist/commands/migration.js +2 -2
- package/dist/commands/observability.js +4 -53
- package/dist/commands/rbac.js +21 -10
- package/dist/commands/undo.js +11 -3
- package/dist/commands/worker.js +15 -5
- package/dist/index.js +198 -59
- package/dist/prompts/auth-wizard.js +40 -6
- package/dist/prompts/create-wizard.js +42 -1
- package/dist/prompts/generate-wizard.js +89 -9
- package/dist/templates/auth-manifest.js +50 -19
- package/dist/templates/create-manifest.js +8 -0
- package/dist/templates/module-manifest.js +84 -26
- package/dist/templates/rbac-manifest.js +16 -11
- package/dist/templates/worker-manifest.js +4 -1
- package/dist/types.js +8 -0
- package/dist/utils/auth-patcher.js +124 -33
- package/dist/utils/config.js +167 -4
- package/dist/utils/docs-patcher.js +68 -0
- package/dist/utils/hexagonal-method-patcher.js +334 -0
- package/dist/utils/main-patcher.js +32 -30
- package/dist/utils/marker-patch.js +7 -1
- package/dist/utils/module-location.js +17 -11
- package/dist/utils/module-profile.js +32 -0
- package/dist/utils/platform-patcher.js +56 -7
- package/dist/utils/rbac-patcher.js +89 -210
- package/package.json +7 -2
- package/templates/add/auth/cmd/seed/main.go.hbs +15 -3
- package/templates/add/auth/docs/login.yaml.hbs +11 -1
- package/templates/add/auth/docs/mfa-verify.yaml.hbs +19 -0
- package/templates/add/auth/docs/provider-exchange.yaml.hbs +40 -0
- package/templates/add/auth/docs/provider-login.yaml.hbs +31 -0
- package/templates/add/auth/docs/refresh.yaml.hbs +7 -0
- package/templates/add/auth/docs/register.yaml.hbs +7 -0
- package/templates/add/auth/docs/reset-password.yaml.hbs +1 -1
- package/templates/add/auth/docs/schemas.yaml.hbs +59 -1
- package/templates/add/auth/docs/users-me-mfa-confirm.yaml.hbs +19 -0
- package/templates/add/auth/docs/users-me-mfa-disable.yaml.hbs +15 -0
- package/templates/add/auth/docs/users-me-mfa-setup.yaml.hbs +14 -0
- package/templates/add/auth/docs/users-me-mfa.yaml.hbs +12 -0
- package/templates/add/auth/internal/app/user/adapters/inbound/http/browser_policy.go.hbs +98 -0
- package/templates/add/auth/internal/app/user/adapters/inbound/http/dto.go.hbs +159 -0
- package/templates/add/auth/internal/app/user/adapters/inbound/http/handler.go.hbs +228 -0
- package/templates/add/auth/internal/app/user/adapters/inbound/http/handler_local.go.hbs +76 -0
- package/templates/add/auth/internal/app/user/adapters/inbound/http/handler_mfa.go.hbs +83 -0
- package/templates/add/auth/internal/app/user/adapters/inbound/http/handler_oauth.go.hbs +70 -0
- package/templates/add/auth/internal/app/user/adapters/inbound/http/handler_recovery.go.hbs +49 -0
- package/templates/add/auth/internal/app/user/adapters/inbound/http/handler_test.go.hbs +311 -0
- package/templates/add/auth/internal/app/user/adapters/inbound/http/handler_user.go.hbs +41 -0
- package/templates/add/auth/internal/app/user/adapters/inbound/http/session_cookie.go.hbs +35 -0
- package/templates/add/auth/internal/app/user/adapters/outbound/password/bcrypt.go.hbs +35 -0
- package/templates/add/auth/internal/app/user/adapters/outbound/password/bcrypt_test.go.hbs +20 -0
- package/templates/add/auth/internal/app/user/adapters/outbound/postgres/mfa_store.go.hbs +129 -0
- package/templates/add/auth/internal/app/user/adapters/outbound/postgres/mfa_store_test.go.hbs +174 -0
- package/templates/add/auth/internal/app/user/adapters/outbound/postgres/model.go.hbs +84 -0
- package/templates/add/auth/internal/app/user/adapters/outbound/postgres/repository.go.hbs +211 -0
- package/templates/add/auth/internal/app/user/{repository_test.go.hbs → adapters/outbound/postgres/repository_test.go.hbs} +18 -19
- package/templates/add/auth/internal/app/user/adapters/outbound/postgres/tokenstore_pg.go.hbs +213 -0
- package/templates/add/auth/internal/app/user/adapters/outbound/postgres/tokenstore_pg_test.go.hbs +103 -0
- package/templates/add/auth/internal/app/user/adapters/outbound/postgres/tokenstore_recovery.go.hbs +84 -0
- package/templates/add/auth/internal/app/user/adapters/outbound/redis/tokenstore.go.hbs +228 -0
- package/templates/add/auth/internal/app/user/adapters/outbound/redis/tokenstore_test.go.hbs +196 -0
- package/templates/add/auth/internal/app/user/application/contracts.go.hbs +52 -0
- package/templates/add/auth/internal/app/user/application/dto.go.hbs +75 -0
- package/templates/add/auth/internal/app/user/application/errors.go.hbs +62 -0
- package/templates/add/auth/internal/app/user/application/external_login.go.hbs +198 -0
- package/templates/add/auth/internal/app/user/application/jwt.go.hbs +58 -0
- package/templates/add/auth/internal/app/user/application/local_auth.go.hbs +96 -0
- package/templates/add/auth/internal/app/user/application/mfa_service.go.hbs +449 -0
- package/templates/add/auth/internal/app/user/application/mfa_service_test.go.hbs +200 -0
- package/templates/add/auth/internal/app/user/application/oauth.go.hbs +132 -0
- package/templates/add/auth/internal/app/user/application/provider_test.go.hbs +285 -0
- package/templates/add/auth/internal/app/user/application/recovery.go.hbs +82 -0
- package/templates/add/auth/internal/app/user/application/recovery_service.go.hbs +112 -0
- package/templates/add/auth/internal/app/user/application/service.go.hbs +145 -0
- package/templates/add/auth/internal/app/user/application/service_test.go.hbs +891 -0
- package/templates/add/auth/internal/app/user/application/sessions.go.hbs +99 -0
- package/templates/add/auth/internal/app/user/application/tokenstore_ports.go.hbs +14 -0
- package/templates/add/auth/internal/app/user/application/user_query.go.hbs +65 -0
- package/templates/add/auth/internal/app/user/composition.go.hbs +168 -0
- package/templates/add/auth/internal/app/user/domain/entity.go.hbs +41 -0
- package/templates/add/auth/internal/app/user/domain/errors.go.hbs +32 -0
- package/templates/add/auth/internal/app/user/ports/password.go.hbs +9 -0
- package/templates/add/auth/internal/app/user/ports/repository.go.hbs +90 -0
- package/templates/add/auth/internal/platform/authprovider/google/google.go.hbs +389 -0
- package/templates/add/auth/internal/platform/authprovider/google/google_test.go.hbs +312 -0
- package/templates/add/auth/migrations/create_auth_tokens.up.sql.hbs +10 -5
- package/templates/add/auth/migrations/create_identities.up.sql.hbs +1 -1
- package/templates/add/auth/migrations/create_login_throttle.up.sql.hbs +1 -1
- package/templates/add/auth/migrations/create_mfa.down.sql.hbs +3 -0
- package/templates/add/auth/migrations/create_mfa.up.sql.hbs +29 -0
- package/templates/add/auth/migrations/create_users.up.sql.hbs +4 -3
- package/templates/add/rbac/internal/app/role/adapters/inbound/http/handler.go.hbs +142 -0
- package/templates/add/rbac/internal/app/role/adapters/inbound/http/handler_test.go.hbs +19 -0
- package/templates/add/rbac/internal/app/role/adapters/outbound/postgres/model.go.hbs +48 -0
- package/templates/add/rbac/internal/app/role/adapters/outbound/postgres/repository.go.hbs +127 -0
- package/templates/add/rbac/internal/app/role/{repository_test.go.hbs → adapters/outbound/postgres/repository_test.go.hbs} +8 -8
- package/templates/add/rbac/internal/app/role/application/dto.go.hbs +47 -0
- package/templates/add/rbac/internal/app/role/application/errors.go.hbs +19 -0
- package/templates/add/rbac/internal/app/role/application/service.go.hbs +157 -0
- package/templates/add/rbac/internal/app/role/{service_test.go.hbs → application/service_test.go.hbs} +26 -19
- package/templates/add/rbac/internal/app/role/composition.go.hbs +48 -0
- package/templates/add/rbac/internal/app/role/domain/entity.go.hbs +23 -0
- package/templates/add/rbac/internal/app/role/domain/errors.go.hbs +26 -0
- package/templates/add/rbac/internal/app/role/ports/repository.go.hbs +25 -0
- package/templates/add/rbac/migrations/add_roles.down.sql.hbs +3 -11
- package/templates/add/rbac/migrations/add_roles.up.sql.hbs +17 -6
- package/templates/add/worker/internal/platform/queue/river_test.go.hbs +84 -0
- package/templates/create/base/.claude/skills/go-scaffold/SKILL.md.hbs +358 -121
- package/templates/create/base/.env.example.hbs +0 -1
- package/templates/create/base/.golangci.yml.hbs +2 -2
- package/templates/create/base/AGENTS.md.hbs +279 -67
- package/templates/create/base/Makefile.hbs +2 -1
- package/templates/create/base/README.md.hbs +115 -32
- package/templates/create/base/cmd/api/wiring.go.hbs +13 -9
- package/templates/create/base/internal/composition/doc.go.hbs +7 -0
- package/templates/create/base/internal/platform/database/database.go.hbs +3 -3
- package/templates/create/base/internal/shared/apperror/apperror.go.hbs +15 -2
- package/templates/create/base/internal/shared/config/config.go.hbs +0 -8
- package/templates/create/base/internal/shared/middleware/cors_test.go.hbs +40 -0
- package/templates/create/base/internal/shared/middleware/error.go.hbs +15 -5
- package/templates/create/features/docs/architecture.md.hbs +92 -32
- package/templates/create/features/docs/patterns.md.hbs +137 -91
- package/templates/create/features/docs/techstack.md.hbs +18 -3
- package/templates/generate/module/hexagonal/adapters/inbound/http/dto.go.hbs +45 -0
- package/templates/generate/module/hexagonal/adapters/inbound/http/dto.minimal.go.hbs +28 -0
- package/templates/generate/module/hexagonal/adapters/inbound/http/handler.go.hbs +182 -0
- package/templates/generate/module/hexagonal/adapters/inbound/http/handler.minimal.go.hbs +83 -0
- package/templates/generate/module/hexagonal/adapters/inbound/http/handler_crud_test.go.hbs +18 -0
- package/templates/generate/module/hexagonal/adapters/inbound/http/handler_test.go.hbs +30 -0
- package/templates/generate/module/hexagonal/adapters/outbound/postgres/model.go.hbs +37 -0
- package/templates/generate/module/hexagonal/adapters/outbound/postgres/repository.go.hbs +95 -0
- package/templates/generate/module/{repository_test.go.hbs → hexagonal/adapters/outbound/postgres/repository_test.go.hbs} +8 -8
- package/templates/generate/module/hexagonal/application/commands.crud.go.hbs +54 -0
- package/templates/generate/module/hexagonal/application/commands.go.hbs +25 -0
- package/templates/generate/module/hexagonal/application/cqrs_test.go.hbs +66 -0
- package/templates/generate/module/hexagonal/application/dto.go.hbs +35 -0
- package/templates/generate/module/hexagonal/application/dto.minimal.go.hbs +25 -0
- package/templates/generate/module/hexagonal/application/queries.crud.go.hbs +33 -0
- package/templates/generate/module/hexagonal/application/queries.go.hbs +25 -0
- package/templates/generate/module/hexagonal/application/service.crud.go.hbs +73 -0
- package/templates/generate/module/hexagonal/application/service.go.hbs +29 -0
- package/templates/generate/module/hexagonal/application/service_test.go.hbs +62 -0
- package/templates/generate/module/hexagonal/composition.go.hbs +27 -0
- package/templates/generate/module/hexagonal/domain/entity.go.hbs +20 -0
- package/templates/generate/module/hexagonal/domain/errors.go.hbs +11 -0
- package/templates/generate/module/hexagonal/ports/repository.go.hbs +38 -0
- package/templates/generate/module/migration.up.sql.hbs +1 -1
- package/dist/utils/method-patcher.js +0 -357
- package/templates/add/auth/docs/google-callback.yaml.hbs +0 -22
- package/templates/add/auth/docs/google-login.yaml.hbs +0 -7
- package/templates/add/auth/internal/app/user/dto.go.hbs +0 -77
- package/templates/add/auth/internal/app/user/errors.go.hbs +0 -43
- package/templates/add/auth/internal/app/user/handler.go.hbs +0 -276
- package/templates/add/auth/internal/app/user/jwt.go.hbs +0 -108
- package/templates/add/auth/internal/app/user/model/authtoken.go.hbs +0 -39
- package/templates/add/auth/internal/app/user/model/identity.go.hbs +0 -31
- package/templates/add/auth/internal/app/user/model/loginthrottle.go.hbs +0 -26
- package/templates/add/auth/internal/app/user/model/user.go.hbs +0 -30
- package/templates/add/auth/internal/app/user/repository.go.hbs +0 -137
- package/templates/add/auth/internal/app/user/service.go.hbs +0 -531
- package/templates/add/auth/internal/app/user/service_test.go.hbs +0 -316
- package/templates/add/auth/internal/app/user/tokenstore.go.hbs +0 -30
- package/templates/add/auth/internal/app/user/tokenstore_pg.go.hbs +0 -144
- package/templates/add/auth/internal/app/user/tokenstore_redis.go.hbs +0 -147
- package/templates/add/rbac/internal/app/role/dto.go.hbs +0 -45
- package/templates/add/rbac/internal/app/role/errors.go.hbs +0 -39
- package/templates/add/rbac/internal/app/role/handler.go.hbs +0 -104
- package/templates/add/rbac/internal/app/role/model/permission.go.hbs +0 -12
- package/templates/add/rbac/internal/app/role/model/role.go.hbs +0 -22
- package/templates/add/rbac/internal/app/role/model/role_permission.go.hbs +0 -11
- package/templates/add/rbac/internal/app/role/repository.go.hbs +0 -97
- package/templates/add/rbac/internal/app/role/service.go.hbs +0 -217
- package/templates/generate/module/dto.go.hbs +0 -36
- package/templates/generate/module/errors.go.hbs +0 -33
- package/templates/generate/module/handler.go.hbs +0 -134
- package/templates/generate/module/handler_test.go.hbs +0 -174
- package/templates/generate/module/minimal/dto.go.hbs +0 -28
- package/templates/generate/module/minimal/handler.go.hbs +0 -48
- package/templates/generate/module/minimal/handler_test.go.hbs +0 -10
- package/templates/generate/module/minimal/service.go.hbs +0 -45
- package/templates/generate/module/minimal/service_test.go.hbs +0 -77
- package/templates/generate/module/model/model.go.hbs +0 -36
- package/templates/generate/module/repository.go.hbs +0 -103
- package/templates/generate/module/service.go.hbs +0 -108
- package/templates/generate/module/service_test.go.hbs +0 -161
package/README.md
CHANGED
|
@@ -1,397 +1,689 @@
|
|
|
1
1
|
# @nakedev/go-scaffold
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
@nakedev/go-scaffold is an npm CLI for creating Gin + GORM + PostgreSQL Go
|
|
4
|
+
backend projects and extending them with consistent domain modules, endpoints,
|
|
5
|
+
migrations, authentication, background jobs, RBAC, and observability.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
each time — the CLI does that, and every module it generates follows the
|
|
10
|
-
same shape as the last one.
|
|
7
|
+
The normal workflow is simple: install the CLI with npm, run the wizard, then
|
|
8
|
+
run the same CLI from the generated project whenever the backend grows.
|
|
11
9
|
|
|
12
|
-
## Install
|
|
10
|
+
## Install with npm
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
npm install -g @nakedev/go-scaffold
|
|
16
|
-
```
|
|
12
|
+
Install the CLI globally when you expect to use it repeatedly:
|
|
17
13
|
|
|
18
|
-
|
|
14
|
+
~~~bash
|
|
15
|
+
npm install --global @nakedev/go-scaffold
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
go-scaffold --version
|
|
18
|
+
go-scaffold --help
|
|
19
|
+
~~~
|
|
20
|
+
|
|
21
|
+
npx is also supported when you do not want a global installation:
|
|
22
|
+
|
|
23
|
+
~~~bash
|
|
21
24
|
npx @nakedev/go-scaffold create my-api
|
|
22
|
-
|
|
25
|
+
npx @nakedev/go-scaffold --help
|
|
26
|
+
~~~
|
|
27
|
+
|
|
28
|
+
### Requirements
|
|
23
29
|
|
|
24
|
-
|
|
30
|
+
- Node.js >=22.13 to run the CLI. npm and npx are included with Node.js.
|
|
31
|
+
- Go >=1.25 to build and run the generated project.
|
|
32
|
+
- PostgreSQL to run the application. Docker is optional; create can generate
|
|
33
|
+
a Docker Compose PostgreSQL service for local development.
|
|
34
|
+
|
|
35
|
+
The CLI itself only needs Node.js. Go and PostgreSQL are needed after a project
|
|
36
|
+
has been generated.
|
|
37
|
+
|
|
38
|
+
## Developing the CLI
|
|
39
|
+
|
|
40
|
+
This repository is the source for the CLI and its generated-project contract.
|
|
41
|
+
Keep command logic in `src/`, emitted files in `templates/`, and behavior
|
|
42
|
+
covered by `tests/`. Generated-project `AGENTS.md`, Claude skill guidance, and
|
|
43
|
+
`docs/architect/` files are template outputs; update the template and a
|
|
44
|
+
regression test when their contract changes.
|
|
25
45
|
|
|
26
46
|
```bash
|
|
27
|
-
pnpm install
|
|
47
|
+
pnpm install --frozen-lockfile
|
|
28
48
|
pnpm run build
|
|
49
|
+
pnpm run verify
|
|
29
50
|
node bin/go-scaffold.js create my-api --defaults
|
|
30
51
|
```
|
|
31
52
|
|
|
32
|
-
`
|
|
33
|
-
|
|
34
|
-
|
|
53
|
+
`pnpm run verify` is the required local gate: it builds the TypeScript CLI,
|
|
54
|
+
runs unit and integration tests, and runs the generated-project smoke suite.
|
|
55
|
+
The smoke suite needs the Go toolchain, PostgreSQL/migrate, and golangci-lint;
|
|
56
|
+
do not treat an unavailable external check as a passing generated-project
|
|
57
|
+
check. See [`AGENTS.md`](AGENTS.md) for the source/template/test workflow.
|
|
35
58
|
|
|
36
|
-
|
|
59
|
+
### Release contract
|
|
60
|
+
|
|
61
|
+
`package.json` is the version source. Releases are published by
|
|
62
|
+
[`.github/workflows/release.yml`](.github/workflows/release.yml) only from a
|
|
63
|
+
clean, matching annotated `vX.Y.Z` tag. Before pushing a release tag, verify
|
|
64
|
+
the exact commit with:
|
|
37
65
|
|
|
38
66
|
```bash
|
|
67
|
+
pnpm run release:check -- v0.5.0
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The release workflow runs the full verification gate before npm publish and
|
|
71
|
+
GitHub Release creation.
|
|
72
|
+
|
|
73
|
+
## Quick start
|
|
74
|
+
|
|
75
|
+
~~~bash
|
|
76
|
+
npm install --global @nakedev/go-scaffold
|
|
39
77
|
go-scaffold create my-api
|
|
78
|
+
|
|
40
79
|
cd my-api
|
|
41
|
-
|
|
42
|
-
make
|
|
80
|
+
cp .env.example .env # optional: edit local settings
|
|
81
|
+
make docker-up # only when create included Docker + PostgreSQL
|
|
82
|
+
make db-create
|
|
43
83
|
go mod tidy
|
|
44
84
|
make run
|
|
45
|
-
|
|
85
|
+
~~~
|
|
46
86
|
|
|
47
|
-
|
|
87
|
+
The default create wizard includes Docker and OpenAPI files. If you choose
|
|
88
|
+
--no-docker, start PostgreSQL separately before running make db-create.
|
|
48
89
|
|
|
49
|
-
|
|
90
|
+
Add a first domain from the generated project directory:
|
|
91
|
+
|
|
92
|
+
~~~bash
|
|
50
93
|
go-scaffold generate module orders
|
|
51
94
|
go-scaffold generate method orders approve --type patch
|
|
52
|
-
|
|
95
|
+
~~~
|
|
53
96
|
|
|
54
|
-
|
|
97
|
+
The generated project starts with shared infrastructure and no business
|
|
98
|
+
domains. generate module adds the domain; generate method adds endpoints one
|
|
99
|
+
at a time.
|
|
55
100
|
|
|
56
|
-
|
|
57
|
-
`-y/--yes` skips that (and `--defaults` implies it) for CI and scripts.
|
|
58
|
-
Running `go-scaffold` with no arguments picks the command from a menu.
|
|
101
|
+
## How the wizard works
|
|
59
102
|
|
|
103
|
+
You can use the CLI interactively or provide answers as arguments and flags.
|
|
60
104
|
|
|
61
|
-
###
|
|
105
|
+
### Start with the top-level wizard
|
|
62
106
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
go-scaffold
|
|
67
|
-
|
|
107
|
+
Running the CLI without a command opens a menu:
|
|
108
|
+
|
|
109
|
+
~~~bash
|
|
110
|
+
go-scaffold
|
|
111
|
+
~~~
|
|
112
|
+
|
|
113
|
+
From a generated project directory, the menu offers:
|
|
68
114
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
115
|
+
1. Create a new project
|
|
116
|
+
2. Generate a module, method, or migration
|
|
117
|
+
3. Configure defaults for future modules
|
|
118
|
+
4. Add auth, worker, RBAC, or observability
|
|
119
|
+
5. Undo a generated module
|
|
120
|
+
|
|
121
|
+
When run outside a generated project, only create can run, so the CLI goes
|
|
122
|
+
straight to the project-creation flow.
|
|
123
|
+
|
|
124
|
+
You can also open a more focused wizard:
|
|
125
|
+
|
|
126
|
+
~~~bash
|
|
127
|
+
go-scaffold generate # choose module, method, or migration
|
|
128
|
+
go-scaffold add # choose worker, auth, RBAC, or observability
|
|
129
|
+
go-scaffold undo # choose a generated module and confirm
|
|
130
|
+
~~~
|
|
131
|
+
|
|
132
|
+
### Answer only what is missing
|
|
133
|
+
|
|
134
|
+
The command is the first choice, followed by only the questions that still need
|
|
135
|
+
an answer. A value passed as a flag is not asked again.
|
|
136
|
+
|
|
137
|
+
For example:
|
|
138
|
+
|
|
139
|
+
~~~text
|
|
140
|
+
go-scaffold create my-api
|
|
141
|
+
1. Docker + PostgreSQL?
|
|
142
|
+
2. OpenAPI files?
|
|
143
|
+
3. Metrics + tracing?
|
|
144
|
+
4. API route prefix?
|
|
145
|
+
5. Default module profile: Lean / CRUD / CQRS / Advanced?
|
|
146
|
+
6. Create project with these settings?
|
|
147
|
+
|
|
148
|
+
cd my-api
|
|
149
|
+
go-scaffold generate module orders
|
|
150
|
+
1. Module profile: Lean / CRUD / CQRS / Advanced?
|
|
151
|
+
2. Require an access token? # only when auth is installed
|
|
152
|
+
3. Permission code? # only when auth + RBAC are installed
|
|
153
|
+
~~~
|
|
154
|
+
|
|
155
|
+
Advanced is the wizard option that exposes the two lower-level module choices
|
|
156
|
+
separately: module surface and application boundary.
|
|
157
|
+
|
|
158
|
+
### Non-interactive usage
|
|
159
|
+
|
|
160
|
+
Use flags for scripts and CI. --defaults skips the optional wizard questions
|
|
161
|
+
where the command supports it. A project name is still required for scripted
|
|
162
|
+
create usage.
|
|
163
|
+
|
|
164
|
+
~~~bash
|
|
165
|
+
go-scaffold create my-api --defaults
|
|
166
|
+
go-scaffold generate module orders --defaults
|
|
167
|
+
go-scaffold add worker --defaults
|
|
168
|
+
go-scaffold add auth --defaults
|
|
169
|
+
~~~
|
|
170
|
+
|
|
171
|
+
Important behavior:
|
|
172
|
+
|
|
173
|
+
- In a terminal, omitted values open the relevant wizard.
|
|
174
|
+
- Without an interactive terminal, omitted values cause an error before files
|
|
175
|
+
are written. Pass the missing flags or use --defaults.
|
|
176
|
+
- --yes / -y skips an add or undo confirmation. It does not necessarily answer
|
|
177
|
+
every other wizard question; pass the choice flags too.
|
|
178
|
+
- Every add command shows a summary and asks for confirmation unless --yes or
|
|
179
|
+
--defaults is used.
|
|
180
|
+
- Run any command with --help to see its current options.
|
|
181
|
+
|
|
182
|
+
## Command overview
|
|
183
|
+
|
|
184
|
+
| Command | Purpose | Alias |
|
|
185
|
+
|---|---|---|
|
|
186
|
+
| create [name] | Create a new Go backend project | c |
|
|
187
|
+
| check | Validate hexagonal layout, layer dependencies, and service/CQRS contract | — |
|
|
188
|
+
| generate | Open the module/method/migration wizard | g |
|
|
189
|
+
| generate module [name] | Add a domain module | g m |
|
|
190
|
+
| generate method [module] [name] | Add one endpoint to an existing module | g me |
|
|
191
|
+
| generate migration [name] | Create a timestamped SQL migration pair | g mig |
|
|
192
|
+
| config | Set defaults for future modules | — |
|
|
193
|
+
| config show | Print the resolved project configuration | — |
|
|
194
|
+
| config validate | Validate configuration without changing files | — |
|
|
195
|
+
| add | Open the infrastructure-feature wizard | — |
|
|
196
|
+
| add worker | Add background jobs, mail, and cmd/worker | — |
|
|
197
|
+
| add auth | Add email/password and provider authentication | — |
|
|
198
|
+
| add rbac | Add roles, permissions, and authorization middleware | — |
|
|
199
|
+
| add observability | Add Prometheus metrics and OpenTelemetry tracing | — |
|
|
200
|
+
| undo module [name] | Remove a generated module and its wiring | undo m |
|
|
201
|
+
|
|
202
|
+
All commands except create are intended to run from the generated project
|
|
203
|
+
directory.
|
|
204
|
+
|
|
205
|
+
## create [name] — create a project
|
|
206
|
+
|
|
207
|
+
~~~bash
|
|
208
|
+
go-scaffold create my-api # interactive wizard
|
|
209
|
+
go-scaffold create my-api --defaults # use documented defaults
|
|
210
|
+
go-scaffold create my-api --defaults --no-docker
|
|
211
|
+
go-scaffold create my-api --api-prefix v1
|
|
212
|
+
go-scaffold c my-api
|
|
213
|
+
~~~
|
|
214
|
+
|
|
215
|
+
If [name] is omitted, the wizard asks for it. With a simple name, it becomes
|
|
216
|
+
both the project directory and the Go module path in the generated go.mod. A
|
|
217
|
+
full Go module path is also accepted; in that case the project directory uses
|
|
218
|
+
the path's final segment.
|
|
219
|
+
|
|
220
|
+
### Creation options
|
|
74
221
|
|
|
75
222
|
| Option | Effect |
|
|
76
223
|
|---|---|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
about Docker and never scaffolds it.
|
|
86
|
-
The prefix is a single project-wide choice made once at `create` time —
|
|
87
|
-
there's no per-domain versioning (a domain that needs a real breaking change
|
|
88
|
-
gets a new domain package or a new DTO field, not a duplicated model pointed
|
|
89
|
-
at the same table under a different URL — see "Why no per-domain versioning"
|
|
90
|
-
below).
|
|
91
|
-
|
|
92
|
-
**Config file** — every `create` writes `go-scaffold.config.json` to the
|
|
93
|
-
project root; `generate` reads it back (or auto-detects from `go.mod` /
|
|
94
|
-
directory layout if missing).
|
|
95
|
-
|
|
96
|
-
### `generate module <name>` (alias `m`) — add a domain module
|
|
224
|
+
| --defaults | Skip settings prompts; use Docker and OpenAPI, no API prefix, and Lean defaults for future modules |
|
|
225
|
+
| --no-docker | Do not create docker-compose.yml or a local PostgreSQL service |
|
|
226
|
+
| --no-openapi-docs | Do not create docs/openapi.yaml or OpenAPI files for generated features/modules |
|
|
227
|
+
| --observability | Include Prometheus /metrics and OpenTelemetry tracing at creation time |
|
|
228
|
+
| --api-prefix <prefix> | Put every API route under a prefix such as v1 or api/v1 |
|
|
229
|
+
| --module-profile <lean\|crud\|cqrs> | Set the default profile for future generate module commands |
|
|
230
|
+
| --module-surface <minimal\|crud> | Legacy way to set the future module surface; prefer --module-profile |
|
|
231
|
+
| --application-style <service\|cqrs> | Legacy way to set the future application boundary; prefer --module-profile |
|
|
97
232
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
go-scaffold generate module orders --full # opt-in CRUD skeleton, no prompt
|
|
101
|
-
go-scaffold generate module orders --defaults # safe minimal module, no prompt (CI/scripting)
|
|
102
|
-
```
|
|
233
|
+
The route prefix is a project-wide choice. For example, --api-prefix v1 puts a
|
|
234
|
+
module route under /v1/orders.
|
|
103
235
|
|
|
104
|
-
|
|
105
|
-
documented defaults (minimal, no auth) and asks nothing.
|
|
236
|
+
### What create generates
|
|
106
237
|
|
|
107
|
-
|
|
238
|
+
create produces a runnable base skeleton, not a business domain. It includes
|
|
239
|
+
the API entrypoint, shared packages, database connection, migrations folder,
|
|
240
|
+
development commands, and architecture documentation. Add domains later with
|
|
241
|
+
generate module.
|
|
108
242
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
├── dto.go # request/response structs (empty stubs — add real fields yourself)
|
|
113
|
-
├── errors.go # ORDER_NOT_FOUND / ORDER_CONFLICT / ORDER_HAS_REFERENCES / ORDER_STALE
|
|
114
|
-
├── repository.go # GORM data access
|
|
115
|
-
├── service.go # business logic + repository interface (mockable)
|
|
116
|
-
├── handler.go # Gin routes, registered under the project's API prefix
|
|
117
|
-
├── service_test.go # unit test, function-backed repository stub
|
|
118
|
-
├── handler_test.go # HTTP unit test, service stub, no DB
|
|
119
|
-
└── repository_test.go # Postgres integration test against migrated schema
|
|
120
|
-
```
|
|
243
|
+
Every project also gets go-scaffold.config.json. It stores the project defaults,
|
|
244
|
+
installed features, API prefix, and the resolved profile of each module so later
|
|
245
|
+
CLI commands can continue from the same choices.
|
|
121
246
|
|
|
122
|
-
|
|
123
|
-
method` always has a full data-access surface to call), but `dto`/`service`/
|
|
124
|
-
`handler` start empty — no default CRUD, no routes, just the plumbing
|
|
125
|
-
(`Register()`, the `repository` interface, `wrapFindErr`) that `generate
|
|
126
|
-
method` patches into. Use it when a domain doesn't need the full REST
|
|
127
|
-
surface, or you'd rather add endpoints one at a time.
|
|
247
|
+
## Module profiles
|
|
128
248
|
|
|
129
|
-
|
|
249
|
+
The module wizard presents a useful profile before exposing lower-level
|
|
250
|
+
architecture choices:
|
|
130
251
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
same schema for `AUTO_MIGRATE=false`/production
|
|
252
|
+
| Profile | Generated shape | Use it when |
|
|
253
|
+
|---|---|---|
|
|
254
|
+
| lean | Minimal surface + one service | The domain should start small and gain endpoints as requirements become real |
|
|
255
|
+
| crud | CRUD surface + one service | The domain needs list/get/create/update/delete starter endpoints |
|
|
256
|
+
| cqrs | Minimal surface + command/query handlers | Reads and writes have different application concerns |
|
|
257
|
+
| Advanced | Choose surface and application style separately | You need a custom combination, such as CRUD + CQRS |
|
|
138
258
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
259
|
+
minimal means no default CRUD endpoints are invented. CQRS separates the
|
|
260
|
+
command and query application paths inside the same modular monolith; it does
|
|
261
|
+
not add a second database, broker, or event-sourcing system.
|
|
142
262
|
|
|
143
|
-
|
|
263
|
+
The generated code is DDD-shaped: each domain has a package boundary,
|
|
264
|
+
repository port, application boundary, delivery adapter, and shared error
|
|
265
|
+
conventions. The CLI does not invent your aggregates, fields, value objects,
|
|
266
|
+
events, or business invariants.
|
|
144
267
|
|
|
145
|
-
|
|
268
|
+
## generate module [name] — add a domain
|
|
269
|
+
|
|
270
|
+
~~~bash
|
|
271
|
+
go-scaffold generate module orders # profile wizard
|
|
272
|
+
go-scaffold generate module orders --profile lean
|
|
273
|
+
go-scaffold generate module orders --profile crud
|
|
274
|
+
go-scaffold generate module orders --profile cqrs
|
|
275
|
+
go-scaffold generate module orders --defaults # use project defaults
|
|
276
|
+
go-scaffold g m orders --profile crud
|
|
277
|
+
~~~
|
|
278
|
+
|
|
279
|
+
When no name is supplied, the wizard asks for a singular module name such as
|
|
280
|
+
order or product. The package name is normalised for Go, while routes and
|
|
281
|
+
tables use plural names such as orders and order_items.
|
|
282
|
+
|
|
283
|
+
### Module options
|
|
284
|
+
|
|
285
|
+
| Option | Effect |
|
|
286
|
+
|---|---|
|
|
287
|
+
| --profile <lean\|crud\|cqrs> | Select a named profile without opening the profile question |
|
|
288
|
+
| --full | Legacy alias for the CRUD surface |
|
|
289
|
+
| --cqrs | Legacy axis flag for command/query handlers; combine with --full for CRUD + CQRS |
|
|
290
|
+
| --auth | Require a valid access token for this module's routes; needs add auth |
|
|
291
|
+
| --permission <code> | Also require an RBAC permission such as orders:manage; needs add rbac and --auth |
|
|
292
|
+
| --defaults | Use the project's recorded module defaults, skip prompts, and keep the module public |
|
|
293
|
+
|
|
294
|
+
--profile cannot be combined with the legacy --full or --cqrs flags. With
|
|
295
|
+
--defaults, a fresh project generates the Lean shape. If the project has auth
|
|
296
|
+
installed, the module remains public unless --auth is explicitly passed.
|
|
297
|
+
|
|
298
|
+
### Module output
|
|
299
|
+
|
|
300
|
+
For orders, the module package is internal/app/order/:
|
|
301
|
+
|
|
302
|
+
~~~text
|
|
303
|
+
internal/app/order/
|
|
304
|
+
├── domain/
|
|
305
|
+
│ ├── entity.go # business state and invariants
|
|
306
|
+
│ └── errors.go # domain error sentinels
|
|
307
|
+
├── ports/
|
|
308
|
+
│ └── repository.go # consumer-owned persistence ports
|
|
309
|
+
├── application/
|
|
310
|
+
│ ├── dto.go # use-case inputs and response mapping
|
|
311
|
+
│ ├── service.go # service-style application boundary
|
|
312
|
+
│ └── service_test.go # application unit tests
|
|
313
|
+
├── adapters/
|
|
314
|
+
│ ├── inbound/http/
|
|
315
|
+
│ │ ├── handler.go # Gin delivery adapter
|
|
316
|
+
│ │ └── handler_test.go # HTTP adapter tests
|
|
317
|
+
│ └── outbound/postgres/
|
|
318
|
+
│ ├── model.go # persistence model + mapping
|
|
319
|
+
│ ├── repository.go # GORM adapter
|
|
320
|
+
│ └── repository_test.go # PostgreSQL integration tests
|
|
321
|
+
└── composition.go # feature-local object graph
|
|
322
|
+
~~~
|
|
323
|
+
|
|
324
|
+
CRUD modules contain the starter list/get/create/update/delete methods. Lean
|
|
325
|
+
modules keep the endpoint surface small so it can be extended with
|
|
326
|
+
generate method.
|
|
327
|
+
|
|
328
|
+
CQRS modules additionally contain:
|
|
329
|
+
|
|
330
|
+
~~~text
|
|
331
|
+
internal/app/order/
|
|
332
|
+
└── application/
|
|
333
|
+
├── commands.go # command port + state-changing handlers
|
|
334
|
+
├── queries.go # query port + read-only handlers
|
|
335
|
+
└── cqrs_test.go # command/query boundary tests
|
|
336
|
+
~~~
|
|
337
|
+
|
|
338
|
+
`application/service.go` OR `application/commands.go` plus
|
|
339
|
+
`application/queries.go` is mutually exclusive inside one module. Service and
|
|
340
|
+
CQRS can coexist across modules in the same modular monolith. The root package
|
|
341
|
+
contains only `composition.go`; inbound and outbound adapters are the
|
|
342
|
+
framework/database edges.
|
|
343
|
+
|
|
344
|
+
Both shapes register the module in cmd/api/wiring.go, create a module-owned
|
|
345
|
+
PostgreSQL schema such as order_svc, append a timestamped create migration, and
|
|
346
|
+
record the resolved module profile in go-scaffold.config.json.
|
|
347
|
+
|
|
348
|
+
The CLI creates the structural TODOs, not your domain rules. Add real model and
|
|
349
|
+
DTO fields, implement business behavior, and review the generated migration
|
|
350
|
+
before applying it.
|
|
351
|
+
|
|
352
|
+
## generate method [module] [name] — add one endpoint
|
|
353
|
+
|
|
354
|
+
~~~bash
|
|
146
355
|
go-scaffold generate method orders approve --type patch
|
|
147
356
|
go-scaffold generate method orders findByStatus --type get --get-mode one --field status
|
|
148
357
|
go-scaffold g me orders findOverdue --type get --get-mode all
|
|
149
|
-
|
|
358
|
+
~~~
|
|
359
|
+
|
|
360
|
+
If the module, method name, or endpoint details are omitted, the wizard asks
|
|
361
|
+
for them. The module selector lists modules that exist on disk, so the command
|
|
362
|
+
does not require memorising the normalised Go package name.
|
|
150
363
|
|
|
151
|
-
|
|
152
|
-
same marker-comment approach as `main.go` — never a whole new module. Never
|
|
153
|
-
overwrites a method with the same name; picks a different one or errors.
|
|
364
|
+
### Method options
|
|
154
365
|
|
|
155
366
|
| Option | Effect |
|
|
156
367
|
|---|---|
|
|
157
|
-
|
|
|
158
|
-
|
|
|
159
|
-
|
|
|
368
|
+
| --type <get\|post\|put\|patch\|delete> | HTTP verb |
|
|
369
|
+
| --get-mode <all\|one> | For GET only: list endpoint or single-record lookup |
|
|
370
|
+
| --field <name> | For get --get-mode one: lookup column such as email, status, or slug; id is reserved |
|
|
371
|
+
|
|
372
|
+
The generated route and code depend on the method type:
|
|
160
373
|
|
|
161
|
-
|
|
|
374
|
+
| Input | Route shape | Result |
|
|
162
375
|
|---|---|---|
|
|
163
|
-
|
|
|
164
|
-
|
|
|
165
|
-
|
|
|
166
|
-
|
|
|
167
|
-
|
|
|
376
|
+
| get --get-mode all | GET /<plural>/<method> | Uses the module's list query; add real filtering yourself |
|
|
377
|
+
| get --get-mode one --field <field> | GET /<plural>/<field>/:<field> | Adds a FindBy<Field> query and a column/index migration |
|
|
378
|
+
| post | POST /<plural>/<method> | Adds a request body DTO and a TODO service method |
|
|
379
|
+
| put / patch | <VERB> /<plural>/:id/<method> | Loads by ID and leaves the update behavior as a TODO |
|
|
380
|
+
| delete | DELETE /<plural>/:id/<method> | Adds a delete endpoint stub |
|
|
168
381
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
382
|
+
For CQRS modules, GET methods are added to application/queries.go; other
|
|
383
|
+
methods are added to application/commands.go. Service modules use
|
|
384
|
+
application/service.go. Existing method names are never overwritten.
|
|
172
385
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
386
|
+
The generated business logic is deliberately a compiling TODO and returns a
|
|
387
|
+
clean not-implemented response until you implement it. If OpenAPI files were
|
|
388
|
+
enabled, a method document is also added under docs/<plural>/methods/ and
|
|
389
|
+
linked from docs/openapi.yaml.
|
|
176
390
|
|
|
177
|
-
|
|
178
|
-
after it writes. If the project was fine beforehand and the generated code
|
|
179
|
-
doesn't compile, it stops with the compiler output instead of leaving you to
|
|
180
|
-
find it later:
|
|
391
|
+
## generate migration [name] — reserve a migration pair
|
|
181
392
|
|
|
182
|
-
|
|
183
|
-
|
|
393
|
+
~~~bash
|
|
394
|
+
go-scaffold generate migration add_status_to_orders
|
|
395
|
+
go-scaffold g mig add_status_to_orders
|
|
396
|
+
~~~
|
|
184
397
|
|
|
185
|
-
|
|
186
|
-
since it was scaffolded, so the templates this CLI emits no longer match it.
|
|
398
|
+
This creates:
|
|
187
399
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
400
|
+
~~~text
|
|
401
|
+
migrations/<timestamp>_add_status_to_orders.up.sql
|
|
402
|
+
migrations/<timestamp>_add_status_to_orders.down.sql
|
|
403
|
+
~~~
|
|
191
404
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
project away from what this CLI's templates expect. `create` records its own
|
|
195
|
-
version in `go-scaffold.config.json` so the message can name both sides. A
|
|
196
|
-
project that was *already* broken (mid-refactor, or `go mod tidy` not run yet)
|
|
197
|
-
is left alone — only a passed-before/broken-after transition is reported. No Go
|
|
198
|
-
on `PATH` means the check is skipped.
|
|
405
|
+
Both files contain TODO comments. The CLI reserves the timestamp and filename;
|
|
406
|
+
you write the SQL and then apply it with:
|
|
199
407
|
|
|
200
|
-
|
|
408
|
+
~~~bash
|
|
409
|
+
make migrate-up
|
|
410
|
+
~~~
|
|
201
411
|
|
|
202
|
-
|
|
203
|
-
go-scaffold generate migration add_status_to_orders
|
|
204
|
-
```
|
|
412
|
+
## config — configure future module defaults
|
|
205
413
|
|
|
206
|
-
|
|
207
|
-
stubs. The CLI reserves the names; you own the SQL and should apply it with
|
|
208
|
-
`make migrate-up` (or `migrate -path migrations -database "$DB_DSN" up`).
|
|
414
|
+
Run this from the generated project directory:
|
|
209
415
|
|
|
210
|
-
|
|
416
|
+
~~~bash
|
|
417
|
+
go-scaffold config # profile wizard
|
|
418
|
+
go-scaffold config show # print JSON; no wizard
|
|
419
|
+
go-scaffold config validate # validate; no file changes
|
|
420
|
+
~~~
|
|
211
421
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
go-scaffold add worker --queue postgres # River (default)
|
|
215
|
-
go-scaffold add worker --queue redis # Asynq
|
|
216
|
-
go-scaffold add worker --defaults # no prompt, Postgres
|
|
217
|
-
```
|
|
422
|
+
config changes defaults for future modules only. Existing modules keep their
|
|
423
|
+
recorded surface and application style.
|
|
218
424
|
|
|
219
|
-
|
|
220
|
-
async email delivery, and `cmd/worker`.
|
|
425
|
+
## add — add optional project features
|
|
221
426
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
| Needed by `add auth` | no | no — `add auth --store` decides that separately |
|
|
226
|
-
| Enqueue joins your DB transaction | yes | **no** — needs an outbox |
|
|
227
|
-
| Throughput | thousands/sec | tens of thousands/sec |
|
|
228
|
-
| Inspect pending jobs | plain SQL | asynqmon |
|
|
229
|
-
|
|
230
|
-
The default is Postgres because a job enqueued inside `tx.Do` is then only
|
|
231
|
-
delivered if that transaction commits — no more welcome emails for signups
|
|
232
|
-
that rolled back. Run `make river-migrate` once per database to create
|
|
233
|
-
River's tables, then `make worker`.
|
|
234
|
-
|
|
235
|
-
Application code only ever sees `queue.Job`, `queue.Enqueuer` and
|
|
236
|
-
`queue.Handler` — no backend package appears outside its own adapter file, so
|
|
237
|
-
switching later means writing one adapter, not touching every module that
|
|
238
|
-
enqueues something.
|
|
239
|
-
|
|
240
|
-
```go
|
|
241
|
-
type WelcomeEmail struct{ To string `json:"to"` }
|
|
242
|
-
func (WelcomeEmail) Kind() string { return "email:welcome" }
|
|
243
|
-
|
|
244
|
-
// cmd/api — the job is discarded with the transaction if this fails
|
|
245
|
-
tx.Do(ctx, db, func(ctx context.Context) error {
|
|
246
|
-
if err := repo.Create(ctx, u); err != nil { return err }
|
|
247
|
-
return jobs.Enqueue(ctx, WelcomeEmail{To: u.Email}, nil)
|
|
248
|
-
})
|
|
249
|
-
```
|
|
427
|
+
Running go-scaffold add opens a feature wizard. It shows features already
|
|
428
|
+
installed as unavailable and explains that RBAC requires auth. Direct feature
|
|
429
|
+
commands are useful for scripts and explicit usage.
|
|
250
430
|
|
|
251
|
-
|
|
431
|
+
After an incremental feature is added, the CLI refreshes the generated
|
|
432
|
+
README and architect docs to reflect the resolved configuration. It only does
|
|
433
|
+
so when each file still matches the version it would have generated; edited
|
|
434
|
+
docs are preserved and reported for manual maintenance.
|
|
252
435
|
|
|
253
|
-
|
|
254
|
-
go-scaffold add auth # asks where tokens should live, then confirms
|
|
255
|
-
go-scaffold add auth --store postgres # tokens in Postgres, no extra service
|
|
256
|
-
go-scaffold add auth --store redis # tokens in Redis, exact across replicas
|
|
257
|
-
go-scaffold add auth --defaults # Postgres, no prompt at all (CI/scripting)
|
|
258
|
-
```
|
|
436
|
+
### add worker — background jobs and mail
|
|
259
437
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
438
|
+
~~~bash
|
|
439
|
+
go-scaffold add worker # queue wizard + confirmation
|
|
440
|
+
go-scaffold add worker --queue postgres # River in PostgreSQL
|
|
441
|
+
go-scaffold add worker --queue redis # Asynq in Redis
|
|
442
|
+
go-scaffold add worker --defaults # PostgreSQL/River, no prompts
|
|
443
|
+
go-scaffold add worker --queue redis --yes # skip confirmation
|
|
444
|
+
~~~
|
|
265
445
|
|
|
266
|
-
|
|
267
|
-
is sent inline, and `add worker` later moves it onto the queue for you — the
|
|
268
|
-
two endpoints that send mail block on SMTP until you do.
|
|
446
|
+
The command adds internal/platform/queue, mail delivery, and cmd/worker.
|
|
269
447
|
|
|
270
|
-
|
|
|
448
|
+
| Queue option | Storage | Operational note |
|
|
271
449
|
|---|---|---|
|
|
272
|
-
|
|
|
273
|
-
|
|
|
450
|
+
| postgres (River) | Project PostgreSQL database | No extra service; enqueueing can join the database transaction |
|
|
451
|
+
| redis (Asynq) | Redis | Run Redis separately; enqueueing cannot join a PostgreSQL transaction |
|
|
274
452
|
|
|
275
|
-
|
|
276
|
-
"I want this exact across replicas" is one decision. With `postgres` the per-IP
|
|
277
|
-
budget is per-replica; the failed-login lockout is in Postgres either way, since
|
|
278
|
-
that one can't be approximate.
|
|
453
|
+
For River:
|
|
279
454
|
|
|
280
|
-
|
|
455
|
+
~~~bash
|
|
456
|
+
make river-migrate
|
|
457
|
+
make river-migrate-test # before required real-store tests
|
|
458
|
+
make worker
|
|
459
|
+
~~~
|
|
281
460
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
go-scaffold generate module secrets --auth --permission secret:manage
|
|
285
|
-
```
|
|
461
|
+
For Redis, start Redis first and then run make worker. make dev runs the API and
|
|
462
|
+
worker together after worker support has been added.
|
|
286
463
|
|
|
287
|
-
|
|
288
|
-
middleware, and role assignment. Its migration seeds the default roles and
|
|
289
|
-
permissions, so apply it with `migrate up`: AutoMigrate creates tables but does
|
|
290
|
-
not run SQL seed statements.
|
|
464
|
+
### add auth — email/password and provider auth
|
|
291
465
|
|
|
292
|
-
|
|
466
|
+
~~~bash
|
|
467
|
+
go-scaffold add auth # store + browser topology wizard
|
|
468
|
+
go-scaffold add auth --store postgres # no extra service
|
|
469
|
+
go-scaffold add auth --store redis # Redis for shared refresh state
|
|
470
|
+
go-scaffold add auth --browser-topology same-origin
|
|
471
|
+
go-scaffold add auth --browser-topology same-site
|
|
472
|
+
go-scaffold add auth --browser-topology cross-site
|
|
473
|
+
go-scaffold add auth --defaults # Postgres + same-site defaults
|
|
474
|
+
~~~
|
|
293
475
|
|
|
294
|
-
|
|
295
|
-
go-scaffold add observability # on an existing project
|
|
296
|
-
go-scaffold create my-api --defaults --observability # or at creation time
|
|
297
|
-
```
|
|
476
|
+
Auth adds:
|
|
298
477
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
478
|
+
- JWT access tokens and refresh-token rotation with reuse detection
|
|
479
|
+
- registration, login, logout, refresh, password reset, and email verification
|
|
480
|
+
- generic provider OAuth routes, with Google as the first adapter
|
|
481
|
+
- failed-login lockout and user-session management
|
|
482
|
+
- MFA endpoints and configuration hooks
|
|
483
|
+
- internal/app/user, auth middleware, cmd/seed, migrations, and OpenAPI
|
|
484
|
+
documents when OpenAPI is enabled
|
|
305
485
|
|
|
306
|
-
|
|
486
|
+
The --store choice controls refresh-token storage and rate-limit counters:
|
|
307
487
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
488
|
+
| --store | Refresh/recovery token storage | Extra service |
|
|
489
|
+
|---|---|---|
|
|
490
|
+
| postgres (default) | PostgreSQL; rate-limit counters are in-process | None |
|
|
491
|
+
| redis | Refresh state and rate-limit counters in Redis; recovery remains in PostgreSQL | Redis |
|
|
312
492
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
493
|
+
--browser-topology describes how a browser frontend and API are deployed:
|
|
494
|
+
|
|
495
|
+
| Topology | Typical setup |
|
|
496
|
+
|---|---|
|
|
497
|
+
| same-origin | Same scheme, host, and port |
|
|
498
|
+
| same-site (default) | Different origin on the same site, such as localhost:3000 and localhost:8080 |
|
|
499
|
+
| cross-site | Different sites; use HTTPS, SameSite=None, secure cookies, and exact CORS origins |
|
|
500
|
+
|
|
501
|
+
After adding auth:
|
|
502
|
+
|
|
503
|
+
~~~bash
|
|
504
|
+
go mod tidy
|
|
505
|
+
make migrate-up
|
|
506
|
+
SEED_ADMIN_EMAIL=admin@example.com SEED_ADMIN_PASSWORD='change-me' make seed
|
|
507
|
+
~~~
|
|
508
|
+
|
|
509
|
+
Without add worker, verification and password-reset mail is sent inline. If a
|
|
510
|
+
worker is already installed, those jobs use the queue instead.
|
|
511
|
+
|
|
512
|
+
### add rbac — roles and permissions
|
|
513
|
+
|
|
514
|
+
~~~bash
|
|
515
|
+
go-scaffold add rbac
|
|
516
|
+
go-scaffold add rbac --yes
|
|
517
|
+
go-scaffold generate module secrets --profile lean --auth --permission secret:manage
|
|
518
|
+
~~~
|
|
519
|
+
|
|
520
|
+
RBAC requires add auth first. It adds:
|
|
521
|
+
|
|
522
|
+
- role and permission administration
|
|
523
|
+
- cached authorization middleware
|
|
524
|
+
- role assignment endpoints
|
|
525
|
+
- the internal/app/role module and its migration
|
|
526
|
+
|
|
527
|
+
Apply the migration before using the seeded roles and permissions:
|
|
528
|
+
|
|
529
|
+
~~~bash
|
|
530
|
+
make migrate-up
|
|
531
|
+
SEED_ADMIN_EMAIL=admin@example.com SEED_ADMIN_PASSWORD='change-me' make seed
|
|
532
|
+
~~~
|
|
533
|
+
|
|
534
|
+
### add observability — metrics and tracing
|
|
535
|
+
|
|
536
|
+
~~~bash
|
|
537
|
+
go-scaffold add observability
|
|
538
|
+
go-scaffold add observability --yes
|
|
539
|
+
go-scaffold create my-api --defaults --observability
|
|
540
|
+
~~~
|
|
541
|
+
|
|
542
|
+
This adds Prometheus GET /metrics and OpenTelemetry tracing for Gin and GORM.
|
|
543
|
+
Run go mod tidy after adding it. Metrics work immediately; set
|
|
544
|
+
OTEL_EXPORTER_OTLP_ENDPOINT when you want to export traces.
|
|
545
|
+
|
|
546
|
+
create --observability and create followed by add observability produce the same
|
|
547
|
+
feature configuration.
|
|
548
|
+
|
|
549
|
+
## undo module [name] — remove a generated module
|
|
550
|
+
|
|
551
|
+
~~~bash
|
|
552
|
+
go-scaffold undo module orders # asks for confirmation
|
|
553
|
+
go-scaffold undo m orders --yes # skip confirmation
|
|
554
|
+
go-scaffold undo # choose the module in a wizard
|
|
555
|
+
~~~
|
|
556
|
+
|
|
557
|
+
undo module removes the module package, its generated OpenAPI folder, owned
|
|
558
|
+
migrations, configuration entry, and wiring from cmd/api/wiring.go. It does not
|
|
559
|
+
drop a database table.
|
|
560
|
+
|
|
561
|
+
The command is intentionally conservative: it refuses when the module's
|
|
562
|
+
migrations may already have been shared or applied, or when another module
|
|
563
|
+
still depends on it. Use an explicit hand-written migration to retire a domain
|
|
564
|
+
that is already in use.
|
|
565
|
+
|
|
566
|
+
## Generated project structure
|
|
567
|
+
|
|
568
|
+
After go-scaffold create my-api, the important runtime structure is:
|
|
569
|
+
|
|
570
|
+
~~~text
|
|
571
|
+
my-api/
|
|
572
|
+
├── cmd/
|
|
573
|
+
│ └── api/
|
|
574
|
+
│ ├── main.go # process entrypoint and shutdown
|
|
575
|
+
│ └── wiring.go # infrastructure and module composition
|
|
576
|
+
├── internal/
|
|
577
|
+
│ ├── platform/
|
|
578
|
+
│ │ └── database/ # GORM connection and pool
|
|
579
|
+
│ ├── shared/
|
|
580
|
+
│ │ ├── config/ # environment configuration
|
|
581
|
+
│ │ ├── apperror/ # consistent application errors
|
|
582
|
+
│ │ ├── dberr/ # database error classification
|
|
583
|
+
│ │ ├── httpx/ # HTTP parsing and binding helpers
|
|
584
|
+
│ │ ├── id/ # UUID generation
|
|
585
|
+
│ │ ├── middleware/ # request ID, logging, errors, CORS
|
|
586
|
+
│ │ ├── pagination/ # pagination parsing and responses
|
|
587
|
+
│ │ └── tx/ # transaction context helpers
|
|
588
|
+
│ └── app/ # empty until generate module is used
|
|
589
|
+
├── migrations/ # embedded, versioned SQL migrations
|
|
590
|
+
├── docs/
|
|
591
|
+
│ ├── architect/ # architecture, patterns, tech stack
|
|
592
|
+
│ └── openapi.yaml # optional API index and referenced files
|
|
593
|
+
├── go-scaffold.config.json # CLI defaults, features, and module choices
|
|
594
|
+
├── go.mod
|
|
595
|
+
├── Makefile
|
|
596
|
+
├── .env.example
|
|
597
|
+
├── Dockerfile
|
|
598
|
+
└── docker-compose.yml # optional, when Docker was selected
|
|
599
|
+
~~~
|
|
600
|
+
|
|
601
|
+
Optional commands add these areas:
|
|
602
|
+
|
|
603
|
+
~~~text
|
|
604
|
+
add worker -> internal/platform/{queue,mail}/ and cmd/worker/
|
|
605
|
+
add auth -> internal/app/user/, auth middleware, and cmd/seed/
|
|
606
|
+
add rbac -> internal/app/role/ and authorization middleware
|
|
607
|
+
add observability -> internal/platform/telemetry/ and metrics/tracing middleware
|
|
608
|
+
~~~
|
|
609
|
+
|
|
610
|
+
After generate module orders, the domain sits behind its own package boundary:
|
|
611
|
+
|
|
612
|
+
~~~text
|
|
613
|
+
internal/app/order/
|
|
614
|
+
├── domain/ # entities, invariants, and domain errors
|
|
615
|
+
├── ports/ # consumer-owned application dependencies
|
|
616
|
+
├── application/ # service OR commands + queries, plus DTOs/tests
|
|
617
|
+
├── adapters/inbound/http/ # Gin delivery adapter and tests
|
|
618
|
+
├── adapters/outbound/postgres/ # persistence model, adapter, and tests
|
|
619
|
+
└── composition.go # module-local dependency wiring
|
|
620
|
+
~~~
|
|
621
|
+
|
|
622
|
+
The generated service and CQRS styles are exclusive within a module: a
|
|
623
|
+
service module has `application/service.go`; a CQRS module has
|
|
624
|
+
`application/commands.go` and `application/queries.go` and no service facade.
|
|
625
|
+
Different modules may choose different styles. `go-scaffold check` enforces the
|
|
626
|
+
physical layout and dependency direction.
|
|
627
|
+
|
|
628
|
+
The module name orders produces the Go package order, REST collection /orders,
|
|
629
|
+
plural table names such as order_items, and a module-owned schema such as
|
|
630
|
+
order_svc.
|
|
383
631
|
|
|
384
|
-
##
|
|
632
|
+
## Useful commands after scaffolding
|
|
385
633
|
|
|
386
|
-
|
|
387
|
-
`templates/create/base/go.mod.hbs`, which is the source of truth.
|
|
634
|
+
Run these from the generated project directory:
|
|
388
635
|
|
|
389
|
-
|
|
|
636
|
+
| Command | Purpose |
|
|
390
637
|
|---|---|
|
|
391
|
-
|
|
|
392
|
-
|
|
|
393
|
-
|
|
|
394
|
-
|
|
|
638
|
+
| make docker-up | Start the generated local PostgreSQL service |
|
|
639
|
+
| make docker-down | Stop the generated local services |
|
|
640
|
+
| make db-create | Create the project database; safe to run again |
|
|
641
|
+
| make run | Run cmd/api |
|
|
642
|
+
| make river-migrate | Apply River's own schema when the worker uses Postgres/River |
|
|
643
|
+
| make river-migrate-test | Apply River's own schema to TEST_DB_DSN for worker integration tests |
|
|
644
|
+
| make build | Build cmd/api into bin/api |
|
|
645
|
+
| make test | Run Go tests |
|
|
646
|
+
| make fmt | Format Go code |
|
|
647
|
+
| make vet | Run go vet ./... |
|
|
648
|
+
| make tidy | Run go mod tidy |
|
|
649
|
+
| make migrate-up | Apply migrations from migrations/ |
|
|
650
|
+
| make migrate-down | Roll back one migration |
|
|
651
|
+
| make migrate-verify | Check that migrations can roll forward and back |
|
|
652
|
+
| make openapi-bundle | Bundle OpenAPI $ref files when OpenAPI is enabled |
|
|
653
|
+
|
|
654
|
+
make run, make test, and migration targets load .env when it exists. Copy
|
|
655
|
+
.env.example to .env and adjust DB_DSN, PORT, CORS, mail, auth, or telemetry
|
|
656
|
+
settings as needed.
|
|
657
|
+
|
|
658
|
+
## What to edit after generation
|
|
659
|
+
|
|
660
|
+
The CLI gives you a compiling structure and explicit TODOs. Your application
|
|
661
|
+
still owns:
|
|
662
|
+
|
|
663
|
+
- domain fields and invariants in `domain/entity.go`
|
|
664
|
+
- request/use-case and response fields in `application/dto.go`
|
|
665
|
+
- persistence fields and mapping in `adapters/outbound/postgres/model.go`
|
|
666
|
+
- business rules in `application/service.go` or command/query handlers
|
|
667
|
+
- SQL bodies in generated migration files
|
|
668
|
+
- OpenAPI schemas and method descriptions
|
|
669
|
+
- tests for the behavior you add
|
|
670
|
+
|
|
671
|
+
Use go-scaffold generate method for the repetitive endpoint shape, then fill in
|
|
672
|
+
the generated TODO before treating the endpoint as production behavior.
|
|
673
|
+
|
|
674
|
+
## Architecture and migration note
|
|
675
|
+
|
|
676
|
+
Schema version 2 is the canonical hexagonal split layout. Every generated
|
|
677
|
+
feature, including auth and RBAC, uses `domain/`, `application/`, `ports/`,
|
|
678
|
+
`adapters/`, and a feature-local `composition.go`; one canonical implementation
|
|
679
|
+
tree is generated. Projects with the old schema 1 manifest are
|
|
680
|
+
rejected with a migration hint instead of silently generating a conflicting
|
|
681
|
+
architecture.
|
|
682
|
+
|
|
683
|
+
The generated tree has no `compat/` directory and no feature-level `model/`
|
|
684
|
+
directory. The word “compatibility” below refers only to CLI command aliases:
|
|
685
|
+
the hidden `remove module` alias remains supported for old scripts, while new
|
|
686
|
+
commands should use `go-scaffold undo module`.
|
|
395
687
|
|
|
396
688
|
## License
|
|
397
689
|
|