@robsun/create-keystone-app 0.2.11 → 0.2.13

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.
@@ -4,7 +4,7 @@ go 1.24.3
4
4
 
5
5
  require (
6
6
  github.com/gin-gonic/gin v1.11.0
7
- github.com/robsuncn/keystone v0.2.0
7
+ github.com/robsuncn/keystone v0.2.1
8
8
  github.com/swaggo/files v1.0.1
9
9
  github.com/swaggo/gin-swagger v1.6.0
10
10
  github.com/swaggo/swag v1.16.2
@@ -146,8 +146,8 @@ github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7
146
146
  github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
147
147
  github.com/richardlehane/msoleps v1.0.4 h1:WuESlvhX3gH2IHcd8UqyCuFY5yiq/GR/yqaSM/9/g00=
148
148
  github.com/richardlehane/msoleps v1.0.4/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
149
- github.com/robsuncn/keystone v0.2.0 h1:6h+u0fTYi33Uj6vsCHnj31LFX/CaWNXissdfUbpzomE=
150
- github.com/robsuncn/keystone v0.2.0/go.mod h1:qIpuWlWXmuwy+lEuyMDLy5FLzjRWki/oJ3nGO5jyIFc=
149
+ github.com/robsuncn/keystone v0.2.1 h1:hFaSdhrGawevwRIOZzcXHF6q2tGymzapdSWr2SzHgU4=
150
+ github.com/robsuncn/keystone v0.2.1/go.mod h1:qIpuWlWXmuwy+lEuyMDLy5FLzjRWki/oJ3nGO5jyIFc=
151
151
  github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
152
152
  github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
153
153
  github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
@@ -1,165 +1,165 @@
1
- package handler
2
-
3
- import (
4
- "errors"
5
-
6
- "github.com/gin-gonic/gin"
7
- hcommon "github.com/robsuncn/keystone/api/handler/common"
8
- "github.com/robsuncn/keystone/api/response"
9
- "github.com/robsuncn/keystone/infra/i18n"
10
-
11
- examplei18n "__APP_NAME__/apps/server/internal/modules/example/i18n"
12
- "__APP_NAME__/apps/server/internal/modules/example/domain/models"
13
- "__APP_NAME__/apps/server/internal/modules/example/domain/service"
14
- )
15
-
16
- type ItemHandler struct {
17
- items *service.ItemService
18
- }
19
-
20
- func NewItemHandler(items *service.ItemService) *ItemHandler {
21
- if items == nil {
22
- return nil
23
- }
24
- return &ItemHandler{items: items}
25
- }
26
-
27
- type itemInput struct {
28
- Title string `json:"title"`
29
- Description string `json:"description"`
30
- Status models.ItemStatus `json:"status"`
31
- }
32
-
33
- type itemUpdateInput struct {
34
- Title *string `json:"title"`
35
- Description *string `json:"description"`
36
- Status *models.ItemStatus `json:"status"`
37
- }
38
-
39
- const defaultTenantID uint = 1
40
-
41
- func (h *ItemHandler) List(c *gin.Context) {
42
- if h == nil || h.items == nil {
43
- response.ServiceUnavailableI18n(c, examplei18n.MsgServiceUnavailable)
44
- return
45
- }
46
- tenantID := resolveTenantID(c)
47
-
48
- items, err := h.items.List(c.Request.Context(), tenantID)
49
- if err != nil {
50
- response.InternalErrorI18n(c, examplei18n.MsgItemLoadFailed)
51
- return
52
- }
53
-
54
- response.Success(c, gin.H{"items": items})
55
- }
56
-
57
- func (h *ItemHandler) Create(c *gin.Context) {
58
- if h == nil || h.items == nil {
59
- response.ServiceUnavailableI18n(c, examplei18n.MsgServiceUnavailable)
60
- return
61
- }
62
- tenantID := resolveTenantID(c)
63
-
64
- var input itemInput
65
- if err := c.ShouldBindJSON(&input); err != nil {
66
- response.BadRequestI18n(c, examplei18n.MsgInvalidPayload)
67
- return
68
- }
69
-
70
- item, err := h.items.Create(c.Request.Context(), tenantID, service.ItemInput{
71
- Title: input.Title,
72
- Description: input.Description,
73
- Status: input.Status,
74
- })
75
- if err != nil {
76
- var i18nErr *i18n.I18nError
77
- if errors.As(err, &i18nErr) {
78
- response.BadRequestI18n(c, i18nErr.Key)
79
- return
80
- }
81
- response.InternalErrorI18n(c, examplei18n.MsgItemCreateFailed)
82
- return
83
- }
84
-
85
- response.CreatedI18n(c, examplei18n.MsgItemCreated, item)
86
- }
87
-
88
- func (h *ItemHandler) Update(c *gin.Context) {
89
- if h == nil || h.items == nil {
90
- response.ServiceUnavailableI18n(c, examplei18n.MsgServiceUnavailable)
91
- return
92
- }
93
- tenantID := resolveTenantID(c)
94
-
95
- id, err := hcommon.ParseUintParam(c, "id")
96
- if err != nil || id == 0 {
97
- response.BadRequestI18n(c, examplei18n.MsgInvalidID)
98
- return
99
- }
100
-
101
- var input itemUpdateInput
102
- if err := c.ShouldBindJSON(&input); err != nil {
103
- response.BadRequestI18n(c, examplei18n.MsgInvalidPayload)
104
- return
105
- }
106
-
107
- item, err := h.items.Update(c.Request.Context(), tenantID, id, service.ItemUpdateInput{
108
- Title: input.Title,
109
- Description: input.Description,
110
- Status: input.Status,
111
- })
112
- if err != nil {
113
- var i18nErr *i18n.I18nError
114
- if errors.As(err, &i18nErr) {
115
- if i18nErr.Key == examplei18n.MsgItemNotFound {
116
- response.NotFoundI18n(c, i18nErr.Key)
117
- } else {
118
- response.BadRequestI18n(c, i18nErr.Key)
119
- }
120
- return
121
- }
122
- response.InternalErrorI18n(c, examplei18n.MsgItemUpdateFailed)
123
- return
124
- }
125
-
126
- response.SuccessI18n(c, examplei18n.MsgItemUpdated, item)
127
- }
128
-
129
- func (h *ItemHandler) Delete(c *gin.Context) {
130
- if h == nil || h.items == nil {
131
- response.ServiceUnavailableI18n(c, examplei18n.MsgServiceUnavailable)
132
- return
133
- }
134
- tenantID := resolveTenantID(c)
135
-
136
- id, err := hcommon.ParseUintParam(c, "id")
137
- if err != nil || id == 0 {
138
- response.BadRequestI18n(c, examplei18n.MsgInvalidID)
139
- return
140
- }
141
-
142
- if err := h.items.Delete(c.Request.Context(), tenantID, id); err != nil {
143
- var i18nErr *i18n.I18nError
144
- if errors.As(err, &i18nErr) {
145
- if i18nErr.Key == examplei18n.MsgItemNotFound {
146
- response.NotFoundI18n(c, i18nErr.Key)
147
- return
148
- }
149
- }
150
- response.InternalErrorI18n(c, examplei18n.MsgItemDeleteFailed)
151
- return
152
- }
153
-
154
- response.SuccessI18n(c, examplei18n.MsgItemDeleted, gin.H{"id": id})
155
- }
156
-
157
- func resolveTenantID(c *gin.Context) uint {
158
- if c == nil {
159
- return defaultTenantID
160
- }
161
- if tenantID, ok := hcommon.GetTenantID(c); ok && tenantID > 0 {
162
- return tenantID
163
- }
164
- return defaultTenantID
165
- }
1
+ package handler
2
+
3
+ import (
4
+ "errors"
5
+
6
+ "github.com/gin-gonic/gin"
7
+ hcommon "github.com/robsuncn/keystone/api/handler/common"
8
+ "github.com/robsuncn/keystone/api/response"
9
+ "github.com/robsuncn/keystone/infra/i18n"
10
+
11
+ examplei18n "__APP_NAME__/apps/server/internal/modules/example/i18n"
12
+ "__APP_NAME__/apps/server/internal/modules/example/domain/models"
13
+ "__APP_NAME__/apps/server/internal/modules/example/domain/service"
14
+ )
15
+
16
+ type ItemHandler struct {
17
+ items *service.ItemService
18
+ }
19
+
20
+ func NewItemHandler(items *service.ItemService) *ItemHandler {
21
+ if items == nil {
22
+ return nil
23
+ }
24
+ return &ItemHandler{items: items}
25
+ }
26
+
27
+ type itemInput struct {
28
+ Title string `json:"title"`
29
+ Description string `json:"description"`
30
+ Status models.ItemStatus `json:"status"`
31
+ }
32
+
33
+ type itemUpdateInput struct {
34
+ Title *string `json:"title"`
35
+ Description *string `json:"description"`
36
+ Status *models.ItemStatus `json:"status"`
37
+ }
38
+
39
+ const defaultTenantID uint = 1
40
+
41
+ func (h *ItemHandler) List(c *gin.Context) {
42
+ if h == nil || h.items == nil {
43
+ response.ServiceUnavailableI18n(c, examplei18n.MsgServiceUnavailable)
44
+ return
45
+ }
46
+ tenantID := resolveTenantID(c)
47
+
48
+ items, err := h.items.List(c.Request.Context(), tenantID)
49
+ if err != nil {
50
+ response.InternalErrorI18n(c, examplei18n.MsgItemLoadFailed)
51
+ return
52
+ }
53
+
54
+ response.Success(c, gin.H{"items": items})
55
+ }
56
+
57
+ func (h *ItemHandler) Create(c *gin.Context) {
58
+ if h == nil || h.items == nil {
59
+ response.ServiceUnavailableI18n(c, examplei18n.MsgServiceUnavailable)
60
+ return
61
+ }
62
+ tenantID := resolveTenantID(c)
63
+
64
+ var input itemInput
65
+ if err := c.ShouldBindJSON(&input); err != nil {
66
+ response.BadRequestI18n(c, examplei18n.MsgInvalidPayload)
67
+ return
68
+ }
69
+
70
+ item, err := h.items.Create(c.Request.Context(), tenantID, service.ItemInput{
71
+ Title: input.Title,
72
+ Description: input.Description,
73
+ Status: input.Status,
74
+ })
75
+ if err != nil {
76
+ var i18nErr *i18n.I18nError
77
+ if errors.As(err, &i18nErr) {
78
+ response.BadRequestI18n(c, i18nErr.Key)
79
+ return
80
+ }
81
+ response.InternalErrorI18n(c, examplei18n.MsgItemCreateFailed)
82
+ return
83
+ }
84
+
85
+ response.CreatedI18n(c, examplei18n.MsgItemCreated, item)
86
+ }
87
+
88
+ func (h *ItemHandler) Update(c *gin.Context) {
89
+ if h == nil || h.items == nil {
90
+ response.ServiceUnavailableI18n(c, examplei18n.MsgServiceUnavailable)
91
+ return
92
+ }
93
+ tenantID := resolveTenantID(c)
94
+
95
+ id, err := hcommon.ParseUintParam(c, "id")
96
+ if err != nil || id == 0 {
97
+ response.BadRequestI18n(c, examplei18n.MsgInvalidID)
98
+ return
99
+ }
100
+
101
+ var input itemUpdateInput
102
+ if err := c.ShouldBindJSON(&input); err != nil {
103
+ response.BadRequestI18n(c, examplei18n.MsgInvalidPayload)
104
+ return
105
+ }
106
+
107
+ item, err := h.items.Update(c.Request.Context(), tenantID, id, service.ItemUpdateInput{
108
+ Title: input.Title,
109
+ Description: input.Description,
110
+ Status: input.Status,
111
+ })
112
+ if err != nil {
113
+ var i18nErr *i18n.I18nError
114
+ if errors.As(err, &i18nErr) {
115
+ if i18nErr.Key == examplei18n.MsgItemNotFound {
116
+ response.NotFoundI18n(c, i18nErr.Key)
117
+ } else {
118
+ response.BadRequestI18n(c, i18nErr.Key)
119
+ }
120
+ return
121
+ }
122
+ response.InternalErrorI18n(c, examplei18n.MsgItemUpdateFailed)
123
+ return
124
+ }
125
+
126
+ response.SuccessI18n(c, examplei18n.MsgItemUpdated, item)
127
+ }
128
+
129
+ func (h *ItemHandler) Delete(c *gin.Context) {
130
+ if h == nil || h.items == nil {
131
+ response.ServiceUnavailableI18n(c, examplei18n.MsgServiceUnavailable)
132
+ return
133
+ }
134
+ tenantID := resolveTenantID(c)
135
+
136
+ id, err := hcommon.ParseUintParam(c, "id")
137
+ if err != nil || id == 0 {
138
+ response.BadRequestI18n(c, examplei18n.MsgInvalidID)
139
+ return
140
+ }
141
+
142
+ if err := h.items.Delete(c.Request.Context(), tenantID, id); err != nil {
143
+ var i18nErr *i18n.I18nError
144
+ if errors.As(err, &i18nErr) {
145
+ if i18nErr.Key == examplei18n.MsgItemNotFound {
146
+ response.NotFoundI18n(c, i18nErr.Key)
147
+ return
148
+ }
149
+ }
150
+ response.InternalErrorI18n(c, examplei18n.MsgItemDeleteFailed)
151
+ return
152
+ }
153
+
154
+ response.SuccessI18n(c, examplei18n.MsgItemDeleted, gin.H{"id": id})
155
+ }
156
+
157
+ func resolveTenantID(c *gin.Context) uint {
158
+ if c == nil {
159
+ return defaultTenantID
160
+ }
161
+ if tenantID, ok := hcommon.GetTenantID(c); ok && tenantID > 0 {
162
+ return tenantID
163
+ }
164
+ return defaultTenantID
165
+ }
@@ -1,22 +1,22 @@
1
- package service
2
-
3
- import "errors"
4
-
5
- var (
6
- ErrItemNotFound = errors.New("item not found")
7
- ErrTitleRequired = errors.New("title is required")
8
- ErrStatusInvalid = errors.New("status is invalid")
9
- )
10
-
11
- // I18n version (uncomment when using keystone with i18n support):
12
- //
13
- // import (
14
- // "github.com/robsuncn/keystone/infra/i18n"
15
- // examplei18n "your-app/apps/server/internal/modules/example/i18n"
16
- // )
17
- //
18
- // var (
19
- // ErrItemNotFound = &i18n.I18nError{Key: examplei18n.MsgItemNotFound}
20
- // ErrTitleRequired = &i18n.I18nError{Key: examplei18n.MsgTitleRequired}
21
- // ErrStatusInvalid = &i18n.I18nError{Key: examplei18n.MsgStatusInvalid}
22
- // )
1
+ package service
2
+
3
+ import "errors"
4
+
5
+ var (
6
+ ErrItemNotFound = errors.New("item not found")
7
+ ErrTitleRequired = errors.New("title is required")
8
+ ErrStatusInvalid = errors.New("status is invalid")
9
+ )
10
+
11
+ // I18n version (uncomment when using keystone with i18n support):
12
+ //
13
+ // import (
14
+ // "github.com/robsuncn/keystone/infra/i18n"
15
+ // examplei18n "your-app/apps/server/internal/modules/example/i18n"
16
+ // )
17
+ //
18
+ // var (
19
+ // ErrItemNotFound = &i18n.I18nError{Key: examplei18n.MsgItemNotFound}
20
+ // ErrTitleRequired = &i18n.I18nError{Key: examplei18n.MsgTitleRequired}
21
+ // ErrStatusInvalid = &i18n.I18nError{Key: examplei18n.MsgStatusInvalid}
22
+ // )
@@ -1,97 +1,97 @@
1
- package example
2
-
3
- import (
4
- "github.com/gin-gonic/gin"
5
- "gorm.io/gorm"
6
-
7
- "github.com/robsuncn/keystone/domain/permissions"
8
- "github.com/robsuncn/keystone/infra/jobs"
9
-
10
- examplehandler "__APP_NAME__/apps/server/internal/modules/example/api/handler"
11
- examplemigrations "__APP_NAME__/apps/server/internal/modules/example/bootstrap/migrations"
12
- exampleseeds "__APP_NAME__/apps/server/internal/modules/example/bootstrap/seeds"
13
- examplemodels "__APP_NAME__/apps/server/internal/modules/example/domain/models"
14
- exampleservice "__APP_NAME__/apps/server/internal/modules/example/domain/service"
15
- examplei18n "__APP_NAME__/apps/server/internal/modules/example/i18n"
16
- examplerepository "__APP_NAME__/apps/server/internal/modules/example/infra/repository"
17
- )
18
-
19
- type Module struct {
20
- items *exampleservice.ItemService
21
- }
22
-
23
- func NewModule() *Module {
24
- return &Module{}
25
- }
26
-
27
- func (m *Module) Name() string {
28
- return "example"
29
- }
30
-
31
- func (m *Module) RegisterRoutes(rg *gin.RouterGroup) {
32
- if rg == nil || m == nil {
33
- return
34
- }
35
- handler := examplehandler.NewItemHandler(m.items)
36
- if handler == nil {
37
- return
38
- }
39
- group := rg.Group("/example")
40
- group.GET("/items", handler.List)
41
- group.POST("/items", handler.Create)
42
- group.PATCH("/items/:id", handler.Update)
43
- group.DELETE("/items/:id", handler.Delete)
44
- }
45
-
46
- func (m *Module) RegisterModels() []interface{} {
47
- return []interface{}{&examplemodels.ExampleItem{}}
48
- }
49
-
50
- func (m *Module) RegisterPermissions(reg *permissions.Registry) error {
51
- if reg == nil {
52
- return nil
53
- }
54
- // Use NameKey for i18n support
55
- if err := reg.CreateMenuI18n("example:item", "Example Items", "permission.example.item", "example", 10); err != nil {
56
- return err
57
- }
58
- if err := reg.CreateActionI18n("example:item:view", "View Items", "permission.example.item.view", "example", "example:item"); err != nil {
59
- return err
60
- }
61
- if err := reg.CreateActionI18n("example:item:manage", "Manage Items", "permission.example.item.manage", "example", "example:item"); err != nil {
62
- return err
63
- }
64
- return nil
65
- }
66
-
67
- func (m *Module) RegisterI18n() error {
68
- return examplei18n.RegisterLocales()
69
- }
70
-
71
- func (m *Module) RegisterJobs(_ *jobs.Registry) error {
72
- return nil
73
- }
74
-
75
- func (m *Module) Migrate(db *gorm.DB) error {
76
- if db == nil {
77
- return nil
78
- }
79
- m.ensureServices(db)
80
- return examplemigrations.Migrate(db)
81
- }
82
-
83
- func (m *Module) Seed(db *gorm.DB) error {
84
- if db == nil {
85
- return nil
86
- }
87
- m.ensureServices(db)
88
- return exampleseeds.Seed(db)
89
- }
90
-
91
- func (m *Module) ensureServices(db *gorm.DB) {
92
- if m == nil || db == nil || m.items != nil {
93
- return
94
- }
95
- repo := examplerepository.NewItemRepository(db)
96
- m.items = exampleservice.NewItemService(repo)
97
- }
1
+ package example
2
+
3
+ import (
4
+ "github.com/gin-gonic/gin"
5
+ "gorm.io/gorm"
6
+
7
+ "github.com/robsuncn/keystone/domain/permissions"
8
+ "github.com/robsuncn/keystone/infra/jobs"
9
+
10
+ examplehandler "__APP_NAME__/apps/server/internal/modules/example/api/handler"
11
+ examplemigrations "__APP_NAME__/apps/server/internal/modules/example/bootstrap/migrations"
12
+ exampleseeds "__APP_NAME__/apps/server/internal/modules/example/bootstrap/seeds"
13
+ examplemodels "__APP_NAME__/apps/server/internal/modules/example/domain/models"
14
+ exampleservice "__APP_NAME__/apps/server/internal/modules/example/domain/service"
15
+ examplei18n "__APP_NAME__/apps/server/internal/modules/example/i18n"
16
+ examplerepository "__APP_NAME__/apps/server/internal/modules/example/infra/repository"
17
+ )
18
+
19
+ type Module struct {
20
+ items *exampleservice.ItemService
21
+ }
22
+
23
+ func NewModule() *Module {
24
+ return &Module{}
25
+ }
26
+
27
+ func (m *Module) Name() string {
28
+ return "example"
29
+ }
30
+
31
+ func (m *Module) RegisterRoutes(rg *gin.RouterGroup) {
32
+ if rg == nil || m == nil {
33
+ return
34
+ }
35
+ handler := examplehandler.NewItemHandler(m.items)
36
+ if handler == nil {
37
+ return
38
+ }
39
+ group := rg.Group("/example")
40
+ group.GET("/items", handler.List)
41
+ group.POST("/items", handler.Create)
42
+ group.PATCH("/items/:id", handler.Update)
43
+ group.DELETE("/items/:id", handler.Delete)
44
+ }
45
+
46
+ func (m *Module) RegisterModels() []interface{} {
47
+ return []interface{}{&examplemodels.ExampleItem{}}
48
+ }
49
+
50
+ func (m *Module) RegisterPermissions(reg *permissions.Registry) error {
51
+ if reg == nil {
52
+ return nil
53
+ }
54
+ // Use NameKey for i18n support
55
+ if err := reg.CreateMenuI18n("example:item", "Example Items", "permission.example.item", "example", 10); err != nil {
56
+ return err
57
+ }
58
+ if err := reg.CreateActionI18n("example:item:view", "View Items", "permission.example.item.view", "example", "example:item"); err != nil {
59
+ return err
60
+ }
61
+ if err := reg.CreateActionI18n("example:item:manage", "Manage Items", "permission.example.item.manage", "example", "example:item"); err != nil {
62
+ return err
63
+ }
64
+ return nil
65
+ }
66
+
67
+ func (m *Module) RegisterI18n() error {
68
+ return examplei18n.RegisterLocales()
69
+ }
70
+
71
+ func (m *Module) RegisterJobs(_ *jobs.Registry) error {
72
+ return nil
73
+ }
74
+
75
+ func (m *Module) Migrate(db *gorm.DB) error {
76
+ if db == nil {
77
+ return nil
78
+ }
79
+ m.ensureServices(db)
80
+ return examplemigrations.Migrate(db)
81
+ }
82
+
83
+ func (m *Module) Seed(db *gorm.DB) error {
84
+ if db == nil {
85
+ return nil
86
+ }
87
+ m.ensureServices(db)
88
+ return exampleseeds.Seed(db)
89
+ }
90
+
91
+ func (m *Module) ensureServices(db *gorm.DB) {
92
+ if m == nil || db == nil || m.items != nil {
93
+ return
94
+ }
95
+ repo := examplerepository.NewItemRepository(db)
96
+ m.items = exampleservice.NewItemService(repo)
97
+ }