@nakedev/go-scaffold 0.4.0 → 0.4.3

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.
Files changed (118) hide show
  1. package/README.md +288 -50
  2. package/dist/commands/auth.js +53 -22
  3. package/dist/commands/config.js +50 -0
  4. package/dist/commands/create.js +32 -2
  5. package/dist/commands/generate.js +25 -2
  6. package/dist/commands/method.js +22 -7
  7. package/dist/commands/migration.js +2 -2
  8. package/dist/commands/observability.js +3 -3
  9. package/dist/commands/rbac.js +3 -3
  10. package/dist/commands/undo.js +5 -0
  11. package/dist/commands/worker.js +1 -1
  12. package/dist/index.js +186 -59
  13. package/dist/prompts/auth-wizard.js +40 -6
  14. package/dist/prompts/create-wizard.js +42 -1
  15. package/dist/prompts/generate-wizard.js +89 -9
  16. package/dist/templates/auth-manifest.js +31 -1
  17. package/dist/templates/create-manifest.js +4 -0
  18. package/dist/templates/module-manifest.js +37 -1
  19. package/dist/templates/rbac-manifest.js +1 -0
  20. package/dist/types.js +6 -0
  21. package/dist/utils/auth-patcher.js +115 -24
  22. package/dist/utils/config.js +147 -3
  23. package/dist/utils/main-patcher.js +29 -27
  24. package/dist/utils/marker-patch.js +7 -1
  25. package/dist/utils/method-patcher.js +261 -81
  26. package/dist/utils/module-profile.js +32 -0
  27. package/dist/utils/platform-patcher.js +29 -7
  28. package/dist/utils/rbac-patcher.js +97 -75
  29. package/package.json +7 -2
  30. package/templates/add/auth/cmd/seed/main.go.hbs +13 -3
  31. package/templates/add/auth/docs/login.yaml.hbs +11 -1
  32. package/templates/add/auth/docs/mfa-verify.yaml.hbs +19 -0
  33. package/templates/add/auth/docs/provider-exchange.yaml.hbs +40 -0
  34. package/templates/add/auth/docs/provider-login.yaml.hbs +31 -0
  35. package/templates/add/auth/docs/refresh.yaml.hbs +7 -0
  36. package/templates/add/auth/docs/register.yaml.hbs +7 -0
  37. package/templates/add/auth/docs/reset-password.yaml.hbs +1 -1
  38. package/templates/add/auth/docs/schemas.yaml.hbs +59 -1
  39. package/templates/add/auth/docs/users-me-mfa-confirm.yaml.hbs +19 -0
  40. package/templates/add/auth/docs/users-me-mfa-disable.yaml.hbs +15 -0
  41. package/templates/add/auth/docs/users-me-mfa-setup.yaml.hbs +14 -0
  42. package/templates/add/auth/docs/users-me-mfa.yaml.hbs +12 -0
  43. package/templates/add/auth/internal/app/user/application/oauth.go.hbs +132 -0
  44. package/templates/add/auth/internal/app/user/application/recovery.go.hbs +113 -0
  45. package/templates/add/auth/internal/app/user/browser_policy.go.hbs +98 -0
  46. package/templates/add/auth/internal/app/user/composition.go.hbs +165 -0
  47. package/templates/add/auth/internal/app/user/contracts.go.hbs +88 -0
  48. package/templates/add/auth/internal/app/user/dto.go.hbs +57 -0
  49. package/templates/add/auth/internal/app/user/errors.go.hbs +25 -0
  50. package/templates/add/auth/internal/app/user/external_login.go.hbs +208 -0
  51. package/templates/add/auth/internal/app/user/handler.go.hbs +60 -203
  52. package/templates/add/auth/internal/app/user/handler_local.go.hbs +75 -0
  53. package/templates/add/auth/internal/app/user/handler_mfa.go.hbs +83 -0
  54. package/templates/add/auth/internal/app/user/handler_oauth.go.hbs +70 -0
  55. package/templates/add/auth/internal/app/user/handler_recovery.go.hbs +49 -0
  56. package/templates/add/auth/internal/app/user/handler_test.go.hbs +290 -0
  57. package/templates/add/auth/internal/app/user/handler_user.go.hbs +41 -0
  58. package/templates/add/auth/internal/app/user/jwt.go.hbs +6 -59
  59. package/templates/add/auth/internal/app/user/local_auth.go.hbs +98 -0
  60. package/templates/add/auth/internal/app/user/mfa_service.go.hbs +450 -0
  61. package/templates/add/auth/internal/app/user/mfa_service_test.go.hbs +199 -0
  62. package/templates/add/auth/internal/app/user/mfa_store.go.hbs +127 -0
  63. package/templates/add/auth/internal/app/user/mfa_store_test.go.hbs +174 -0
  64. package/templates/add/auth/internal/app/user/model/authtoken.go.hbs +8 -2
  65. package/templates/add/auth/internal/app/user/model/identity.go.hbs +4 -3
  66. package/templates/add/auth/internal/app/user/model/mfa_challenge.go.hbs +17 -0
  67. package/templates/add/auth/internal/app/user/model/mfa_enrollment.go.hbs +20 -0
  68. package/templates/add/auth/internal/app/user/model/mfa_recovery_code.go.hbs +17 -0
  69. package/templates/add/auth/internal/app/user/model/user.go.hbs +3 -2
  70. package/templates/add/auth/internal/app/user/provider_test.go.hbs +286 -0
  71. package/templates/add/auth/internal/app/user/recovery_service.go.hbs +114 -0
  72. package/templates/add/auth/internal/app/user/repository.go.hbs +2 -0
  73. package/templates/add/auth/internal/app/user/service.go.hbs +82 -478
  74. package/templates/add/auth/internal/app/user/service_test.go.hbs +601 -45
  75. package/templates/add/auth/internal/app/user/session_cookie.go.hbs +33 -0
  76. package/templates/add/auth/internal/app/user/sessions.go.hbs +99 -0
  77. package/templates/add/auth/internal/app/user/tokenstore.go.hbs +42 -14
  78. package/templates/add/auth/internal/app/user/tokenstore_pg.go.hbs +105 -40
  79. package/templates/add/auth/internal/app/user/tokenstore_pg_test.go.hbs +96 -0
  80. package/templates/add/auth/internal/app/user/tokenstore_recovery.go.hbs +58 -0
  81. package/templates/add/auth/internal/app/user/tokenstore_redis.go.hbs +144 -70
  82. package/templates/add/auth/internal/app/user/tokenstore_redis_test.go.hbs +185 -0
  83. package/templates/add/auth/internal/app/user/user_query.go.hbs +65 -0
  84. package/templates/add/auth/internal/platform/authprovider/google/google.go.hbs +389 -0
  85. package/templates/add/auth/internal/platform/authprovider/google/google_test.go.hbs +312 -0
  86. package/templates/add/auth/migrations/create_auth_tokens.up.sql.hbs +9 -4
  87. package/templates/add/auth/migrations/create_identities.up.sql.hbs +1 -1
  88. package/templates/add/auth/migrations/create_mfa.down.sql.hbs +3 -0
  89. package/templates/add/auth/migrations/create_mfa.up.sql.hbs +29 -0
  90. package/templates/add/auth/migrations/create_users.up.sql.hbs +2 -2
  91. package/templates/add/rbac/internal/app/role/composition.go.hbs +35 -0
  92. package/templates/add/rbac/internal/app/role/service.go.hbs +12 -12
  93. package/templates/create/base/.claude/skills/go-scaffold/SKILL.md.hbs +340 -121
  94. package/templates/create/base/.env.example.hbs +0 -1
  95. package/templates/create/base/AGENTS.md.hbs +255 -67
  96. package/templates/create/base/Makefile.hbs +2 -1
  97. package/templates/create/base/README.md.hbs +42 -14
  98. package/templates/create/base/cmd/api/wiring.go.hbs +11 -8
  99. package/templates/create/base/internal/platform/database/database.go.hbs +3 -3
  100. package/templates/create/base/internal/shared/apperror/apperror.go.hbs +15 -2
  101. package/templates/create/base/internal/shared/config/config.go.hbs +0 -8
  102. package/templates/create/base/internal/shared/middleware/cors_test.go.hbs +40 -0
  103. package/templates/create/base/internal/shared/middleware/error.go.hbs +15 -5
  104. package/templates/create/features/docs/architecture.md.hbs +35 -13
  105. package/templates/create/features/docs/patterns.md.hbs +40 -21
  106. package/templates/create/features/docs/techstack.md.hbs +2 -2
  107. package/templates/generate/module/commands.go.hbs +95 -0
  108. package/templates/generate/module/composition.go.hbs +23 -0
  109. package/templates/generate/module/cqrs_test.go.hbs +7 -0
  110. package/templates/generate/module/handler.go.hbs +50 -5
  111. package/templates/generate/module/minimal/commands.go.hbs +34 -0
  112. package/templates/generate/module/minimal/handler.go.hbs +34 -0
  113. package/templates/generate/module/minimal/queries.go.hbs +45 -0
  114. package/templates/generate/module/minimal/service.go.hbs +27 -1
  115. package/templates/generate/module/queries.go.hbs +62 -0
  116. package/templates/generate/module/service.go.hbs +61 -5
  117. package/templates/add/auth/docs/google-callback.yaml.hbs +0 -22
  118. package/templates/add/auth/docs/google-login.yaml.hbs +0 -7
@@ -1,5 +1,30 @@
1
1
  package {{pkg}}
2
2
 
3
+ {{#if cqrs}}
4
+ // repository is the complete data dependency retained for the compatibility
5
+ // facade below. CQRS handlers consume the narrower command/query ports.
6
+ type repository interface {
7
+ commandRepository
8
+ queryRepository
9
+ // go-scaffold:repository-interface
10
+ }
11
+
12
+ // Service is a compatibility facade. New code should depend on
13
+ // commandService or queryService directly.
14
+ type Service struct {
15
+ commands commandService
16
+ queries queryService
17
+ }
18
+
19
+ func NewService(repo repository) *Service {
20
+ return &Service{
21
+ commands: NewCommandHandler(repo),
22
+ queries: NewQueryHandler(repo),
23
+ }
24
+ }
25
+
26
+ // go-scaffold:service-methods
27
+ {{else}}
3
28
  import (
4
29
  "context"
5
30
  "errors"
@@ -39,7 +64,8 @@ func wrapFindErr(err error) error {
39
64
  if errors.Is(err, gorm.ErrRecordNotFound) {
40
65
  return errNotFound()
41
66
  }
42
- return apperror.NewInternal()
67
+ return apperror.NewInternal(err)
43
68
  }
44
69
 
45
70
  // go-scaffold:service-methods
71
+ {{/if}}
@@ -0,0 +1,62 @@
1
+ package {{pkg}}
2
+
3
+ import (
4
+ "context"
5
+ "errors"
6
+
7
+ "{{goModule}}/internal/app/{{modulePath}}/model"
8
+ "{{goModule}}/internal/shared/apperror"
9
+
10
+ "github.com/google/uuid"
11
+ "gorm.io/gorm"
12
+ )
13
+
14
+ // queryRepository is the outbound port for read-only use cases. A separate
15
+ // port makes it possible to replace this with a projection/read model later
16
+ // without changing command handlers.
17
+ type queryRepository interface {
18
+ FindAll(ctx context.Context, limit, offset int) ([]model.{{pascalName}}, error)
19
+ FindByID(ctx context.Context, id uuid.UUID) (*model.{{pascalName}}, error)
20
+ // go-scaffold:query-repository-interface
21
+ }
22
+
23
+ // queryService is the inbound application port consumed by read endpoints.
24
+ type queryService interface {
25
+ List(context.Context, int, int) ([]model.{{pascalName}}, error)
26
+ Get(context.Context, uuid.UUID) (*model.{{pascalName}}, error)
27
+ // go-scaffold:query-interface
28
+ }
29
+
30
+ // QueryHandler owns read-only use cases for {{pkg}}.
31
+ type QueryHandler struct {
32
+ repo queryRepository
33
+ }
34
+
35
+ func NewQueryHandler(repo queryRepository) *QueryHandler {
36
+ return &QueryHandler{repo: repo}
37
+ }
38
+
39
+ func (h *QueryHandler) List(ctx context.Context, limit, offset int) ([]model.{{pascalName}}, error) {
40
+ items, err := h.repo.FindAll(ctx, limit, offset)
41
+ if err != nil {
42
+ return nil, apperror.NewInternal(err)
43
+ }
44
+ return items, nil
45
+ }
46
+
47
+ func (h *QueryHandler) Get(ctx context.Context, id uuid.UUID) (*model.{{pascalName}}, error) {
48
+ m, err := h.repo.FindByID(ctx, id)
49
+ if err != nil {
50
+ return nil, wrapFindErr(err)
51
+ }
52
+ return m, nil
53
+ }
54
+
55
+ func wrapFindErr(err error) error {
56
+ if errors.Is(err, gorm.ErrRecordNotFound) {
57
+ return errNotFound()
58
+ }
59
+ return apperror.NewInternal(err)
60
+ }
61
+
62
+ // go-scaffold:query-methods
@@ -1,5 +1,60 @@
1
1
  package {{pkg}}
2
2
 
3
+ {{#if cqrs}}
4
+ import (
5
+ "context"
6
+
7
+ "{{goModule}}/internal/app/{{modulePath}}/model"
8
+
9
+ "github.com/google/uuid"
10
+ )
11
+
12
+ // repository is the complete data dependency retained for the compatibility
13
+ // facade below. The actual CQRS handlers consume the narrower
14
+ // commandRepository/queryRepository ports declared in commands.go/queries.go.
15
+ type repository interface {
16
+ commandRepository
17
+ queryRepository
18
+ // go-scaffold:repository-interface
19
+ }
20
+
21
+ // Service is a compatibility facade for callers that still want one feature
22
+ // service. New code should depend on commandService or queryService instead,
23
+ // so the read and write paths remain independently replaceable.
24
+ type Service struct {
25
+ commands commandService
26
+ queries queryService
27
+ }
28
+
29
+ func NewService(repo repository) *Service {
30
+ return &Service{
31
+ commands: NewCommandHandler(repo),
32
+ queries: NewQueryHandler(repo),
33
+ }
34
+ }
35
+
36
+ func (s *Service) Create(ctx context.Context, in createInput) (*model.{{pascalName}}, error) {
37
+ return s.commands.Create(ctx, in)
38
+ }
39
+
40
+ func (s *Service) List(ctx context.Context, limit, offset int) ([]model.{{pascalName}}, error) {
41
+ return s.queries.List(ctx, limit, offset)
42
+ }
43
+
44
+ func (s *Service) Get(ctx context.Context, id uuid.UUID) (*model.{{pascalName}}, error) {
45
+ return s.queries.Get(ctx, id)
46
+ }
47
+
48
+ func (s *Service) Update(ctx context.Context, id uuid.UUID, in updateInput) (*model.{{pascalName}}, error) {
49
+ return s.commands.Update(ctx, id, in)
50
+ }
51
+
52
+ func (s *Service) Delete(ctx context.Context, id uuid.UUID) error {
53
+ return s.commands.Delete(ctx, id)
54
+ }
55
+
56
+ // go-scaffold:service-methods
57
+ {{else}}
3
58
  import (
4
59
  "context"
5
60
  "errors"
@@ -41,7 +96,7 @@ func (s *Service) Create(ctx context.Context, in createInput) (*model.{{pascalNa
41
96
  if dberr.IsDuplicate(err) {
42
97
  return nil, errConflict()
43
98
  }
44
- return nil, apperror.NewInternal()
99
+ return nil, apperror.NewInternal(err)
45
100
  }
46
101
  return m, nil
47
102
  }
@@ -49,7 +104,7 @@ func (s *Service) Create(ctx context.Context, in createInput) (*model.{{pascalNa
49
104
  func (s *Service) List(ctx context.Context, limit, offset int) ([]model.{{pascalName}}, error) {
50
105
  items, err := s.repo.FindAll(ctx, limit, offset)
51
106
  if err != nil {
52
- return nil, apperror.NewInternal()
107
+ return nil, apperror.NewInternal(err)
53
108
  }
54
109
  return items, nil
55
110
  }
@@ -79,7 +134,7 @@ func (s *Service) Update(ctx context.Context, id uuid.UUID, in updateInput) (*mo
79
134
  if dberr.IsDuplicate(err) {
80
135
  return nil, errConflict()
81
136
  }
82
- return nil, apperror.NewInternal()
137
+ return nil, apperror.NewInternal(err)
83
138
  }
84
139
  return m, nil
85
140
  }
@@ -93,7 +148,7 @@ func (s *Service) Delete(ctx context.Context, id uuid.UUID) error {
93
148
  if dberr.IsForeignKey(err) {
94
149
  return errHasReferences()
95
150
  }
96
- return apperror.NewInternal()
151
+ return apperror.NewInternal(err)
97
152
  }
98
153
  return nil
99
154
  }
@@ -102,7 +157,8 @@ func wrapFindErr(err error) error {
102
157
  if errors.Is(err, gorm.ErrRecordNotFound) {
103
158
  return errNotFound()
104
159
  }
105
- return apperror.NewInternal()
160
+ return apperror.NewInternal(err)
106
161
  }
107
162
 
108
163
  // go-scaffold:service-methods
164
+ {{/if}}
@@ -1,22 +0,0 @@
1
- get:
2
- summary: Google OAuth callback
3
- description: Redirect target Google sends the browser back to after consent — not called directly by API clients.
4
- operationId: googleCallback
5
- tags: [auth]
6
- security: []
7
- parameters:
8
- - name: code
9
- in: query
10
- required: true
11
- schema: { type: string }
12
- - name: state
13
- in: query
14
- required: true
15
- schema: { type: string }
16
- responses:
17
- "200":
18
- description: ok, refresh_token set as an httpOnly cookie
19
- content:
20
- application/json:
21
- schema: { $ref: './schemas.yaml#/AuthResponse' }
22
- "401": { $ref: '../common/responses.yaml#/UnauthorizedError' }
@@ -1,7 +0,0 @@
1
- get:
2
- summary: Start the Google OAuth login flow
3
- operationId: googleLogin
4
- tags: [auth]
5
- security: []
6
- responses:
7
- "302": { description: redirect to Google's consent screen }