@robsun/create-keystone-app 0.1.18 → 0.2.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 +4 -5
- package/bin/create-keystone-app.js +1 -80
- package/package.json +1 -1
- package/template/README.md +5 -13
- package/template/apps/server/config.example.yaml +0 -1
- package/template/apps/server/config.yaml +0 -1
- package/template/apps/server/internal/modules/example/api/handler/item_handler.go +162 -0
- package/template/apps/server/internal/modules/example/bootstrap/migrations/item.go +21 -0
- package/template/apps/server/internal/modules/example/bootstrap/seeds/item.go +33 -0
- package/template/apps/server/internal/modules/example/domain/models/item.go +30 -0
- package/template/apps/server/internal/modules/{demo → example}/domain/service/errors.go +1 -1
- package/template/apps/server/internal/modules/example/domain/service/item_service.go +110 -0
- package/template/apps/server/internal/modules/example/infra/repository/item_repository.go +49 -0
- package/template/apps/server/internal/modules/example/module.go +55 -17
- package/template/apps/server/internal/modules/manifest.go +1 -3
- package/template/apps/web/src/app.config.ts +1 -1
- package/template/apps/web/src/main.tsx +0 -1
- package/template/apps/web/src/modules/example/help/faq.md +23 -0
- package/template/apps/web/src/modules/example/help/items.md +26 -0
- package/template/apps/web/src/modules/example/help/overview.md +18 -4
- package/template/apps/web/src/modules/example/pages/ExampleItemsPage.tsx +227 -0
- package/template/apps/web/src/modules/example/routes.tsx +33 -10
- package/template/apps/web/src/modules/example/services/exampleItems.ts +32 -0
- package/template/apps/web/src/modules/example/types.ts +10 -0
- package/template/docs/CONVENTIONS.md +44 -0
- package/template/docs/GETTING_STARTED.md +54 -0
- package/template/package.json +1 -1
- package/template/scripts/check-modules.js +7 -1
- package/template/apps/server/internal/modules/demo/api/handler/task_handler.go +0 -152
- package/template/apps/server/internal/modules/demo/bootstrap/migrations/task.go +0 -21
- package/template/apps/server/internal/modules/demo/bootstrap/seeds/task.go +0 -33
- package/template/apps/server/internal/modules/demo/domain/models/task.go +0 -30
- package/template/apps/server/internal/modules/demo/domain/service/task_service.go +0 -95
- package/template/apps/server/internal/modules/demo/infra/repository/task_repository.go +0 -49
- package/template/apps/server/internal/modules/demo/module.go +0 -91
- package/template/apps/server/internal/modules/example/handlers.go +0 -19
- package/template/apps/web/src/modules/demo/help/overview.md +0 -12
- package/template/apps/web/src/modules/demo/index.ts +0 -7
- package/template/apps/web/src/modules/demo/pages/DemoTasksPage.tsx +0 -185
- package/template/apps/web/src/modules/demo/routes.tsx +0 -43
- package/template/apps/web/src/modules/demo/services/demoTasks.ts +0 -28
- package/template/apps/web/src/modules/demo/types.ts +0 -9
- package/template/apps/web/src/modules/example/pages/ExamplePage.tsx +0 -41
- package/template/apps/web/src/modules/example/services/api.ts +0 -8
|
@@ -41,7 +41,7 @@ function parseServerModules(content) {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
function formatList(items) {
|
|
44
|
-
return items.map((item) =>
|
|
44
|
+
return items.map((item) => ` - ${item}`).join('\n')
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
try {
|
|
@@ -60,6 +60,10 @@ try {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
console.error('Module configuration mismatch:')
|
|
63
|
+
console.error('\napps/web/src/app.config.ts modules.enabled:')
|
|
64
|
+
console.error(formatList(webModules))
|
|
65
|
+
console.error('\napps/server/config.yaml modules.enabled:')
|
|
66
|
+
console.error(formatList(serverModules))
|
|
63
67
|
if (missingInServer.length > 0) {
|
|
64
68
|
console.error('\nMissing in apps/server/config.yaml:')
|
|
65
69
|
console.error(formatList(missingInServer))
|
|
@@ -68,9 +72,11 @@ try {
|
|
|
68
72
|
console.error('\nMissing in apps/web/src/app.config.ts:')
|
|
69
73
|
console.error(formatList(missingInWeb))
|
|
70
74
|
}
|
|
75
|
+
console.error('\nFix: keep module names identical in both files and register modules in main.tsx/manifest.go.')
|
|
71
76
|
process.exit(1)
|
|
72
77
|
} catch (err) {
|
|
73
78
|
console.error('Failed to check modules:')
|
|
74
79
|
console.error(err instanceof Error ? err.message : String(err))
|
|
80
|
+
console.error('Hint: verify apps/web/src/app.config.ts and apps/server/config.yaml exist and are valid.')
|
|
75
81
|
process.exit(2)
|
|
76
82
|
}
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
package handler
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"errors"
|
|
5
|
-
|
|
6
|
-
"github.com/gin-gonic/gin"
|
|
7
|
-
|
|
8
|
-
hcommon "github.com/robsuncn/keystone/api/handler/common"
|
|
9
|
-
"github.com/robsuncn/keystone/api/response"
|
|
10
|
-
|
|
11
|
-
"__APP_NAME__/apps/server/internal/modules/demo/domain/models"
|
|
12
|
-
"__APP_NAME__/apps/server/internal/modules/demo/domain/service"
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
type TaskHandler struct {
|
|
16
|
-
tasks *service.TaskService
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
func NewTaskHandler(tasks *service.TaskService) *TaskHandler {
|
|
20
|
-
if tasks == nil {
|
|
21
|
-
return nil
|
|
22
|
-
}
|
|
23
|
-
return &TaskHandler{tasks: tasks}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
type taskInput struct {
|
|
27
|
-
Title string `json:"title"`
|
|
28
|
-
Status models.TaskStatus `json:"status"`
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const defaultTenantID uint = 1
|
|
32
|
-
|
|
33
|
-
func (h *TaskHandler) List(c *gin.Context) {
|
|
34
|
-
if h == nil || h.tasks == nil {
|
|
35
|
-
response.ServiceUnavailable(c, "demo tasks unavailable")
|
|
36
|
-
return
|
|
37
|
-
}
|
|
38
|
-
tenantID := resolveTenantID(c)
|
|
39
|
-
|
|
40
|
-
items, err := h.tasks.List(c.Request.Context(), tenantID)
|
|
41
|
-
if err != nil {
|
|
42
|
-
response.InternalError(c, "failed to load demo tasks")
|
|
43
|
-
return
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
response.Success(c, gin.H{"items": items})
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
func (h *TaskHandler) Create(c *gin.Context) {
|
|
50
|
-
if h == nil || h.tasks == nil {
|
|
51
|
-
response.ServiceUnavailable(c, "demo tasks unavailable")
|
|
52
|
-
return
|
|
53
|
-
}
|
|
54
|
-
tenantID := resolveTenantID(c)
|
|
55
|
-
|
|
56
|
-
var input taskInput
|
|
57
|
-
if err := c.ShouldBindJSON(&input); err != nil {
|
|
58
|
-
response.BadRequest(c, "invalid payload")
|
|
59
|
-
return
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
task, err := h.tasks.Create(c.Request.Context(), tenantID, service.TaskInput{
|
|
63
|
-
Title: input.Title,
|
|
64
|
-
Status: input.Status,
|
|
65
|
-
})
|
|
66
|
-
if err != nil {
|
|
67
|
-
switch {
|
|
68
|
-
case errors.Is(err, service.ErrTitleRequired):
|
|
69
|
-
response.BadRequest(c, "title is required")
|
|
70
|
-
case errors.Is(err, service.ErrStatusInvalid):
|
|
71
|
-
response.BadRequest(c, "invalid status")
|
|
72
|
-
default:
|
|
73
|
-
response.InternalError(c, "failed to create demo task")
|
|
74
|
-
}
|
|
75
|
-
return
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
response.Created(c, task)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
func (h *TaskHandler) Update(c *gin.Context) {
|
|
82
|
-
if h == nil || h.tasks == nil {
|
|
83
|
-
response.ServiceUnavailable(c, "demo tasks unavailable")
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
tenantID := resolveTenantID(c)
|
|
87
|
-
|
|
88
|
-
id, err := hcommon.ParseUintParam(c, "id")
|
|
89
|
-
if err != nil || id == 0 {
|
|
90
|
-
response.BadRequest(c, "invalid id")
|
|
91
|
-
return
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
var input taskInput
|
|
95
|
-
if err := c.ShouldBindJSON(&input); err != nil {
|
|
96
|
-
response.BadRequest(c, "invalid payload")
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
task, err := h.tasks.Update(c.Request.Context(), tenantID, id, service.TaskUpdateInput{
|
|
101
|
-
Title: input.Title,
|
|
102
|
-
Status: input.Status,
|
|
103
|
-
})
|
|
104
|
-
if err != nil {
|
|
105
|
-
switch {
|
|
106
|
-
case errors.Is(err, service.ErrTaskNotFound):
|
|
107
|
-
response.NotFound(c, "task not found")
|
|
108
|
-
case errors.Is(err, service.ErrStatusInvalid):
|
|
109
|
-
response.BadRequest(c, "invalid status")
|
|
110
|
-
default:
|
|
111
|
-
response.InternalError(c, "failed to update demo task")
|
|
112
|
-
}
|
|
113
|
-
return
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
response.SuccessWithMessage(c, "updated", task)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
func (h *TaskHandler) Delete(c *gin.Context) {
|
|
120
|
-
if h == nil || h.tasks == nil {
|
|
121
|
-
response.ServiceUnavailable(c, "demo tasks unavailable")
|
|
122
|
-
return
|
|
123
|
-
}
|
|
124
|
-
tenantID := resolveTenantID(c)
|
|
125
|
-
|
|
126
|
-
id, err := hcommon.ParseUintParam(c, "id")
|
|
127
|
-
if err != nil || id == 0 {
|
|
128
|
-
response.BadRequest(c, "invalid id")
|
|
129
|
-
return
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if err := h.tasks.Delete(c.Request.Context(), tenantID, id); err != nil {
|
|
133
|
-
if errors.Is(err, service.ErrTaskNotFound) {
|
|
134
|
-
response.NotFound(c, "task not found")
|
|
135
|
-
return
|
|
136
|
-
}
|
|
137
|
-
response.InternalError(c, "failed to delete demo task")
|
|
138
|
-
return
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
response.SuccessWithMessage(c, "deleted", gin.H{"id": id})
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
func resolveTenantID(c *gin.Context) uint {
|
|
145
|
-
if c == nil {
|
|
146
|
-
return defaultTenantID
|
|
147
|
-
}
|
|
148
|
-
if tenantID, ok := hcommon.GetTenantID(c); ok && tenantID > 0 {
|
|
149
|
-
return tenantID
|
|
150
|
-
}
|
|
151
|
-
return defaultTenantID
|
|
152
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
package migrations
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"fmt"
|
|
5
|
-
"log"
|
|
6
|
-
|
|
7
|
-
"gorm.io/gorm"
|
|
8
|
-
|
|
9
|
-
"__APP_NAME__/apps/server/internal/modules/demo/domain/models"
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
func Migrate(db *gorm.DB) error {
|
|
13
|
-
if db == nil {
|
|
14
|
-
return nil
|
|
15
|
-
}
|
|
16
|
-
log.Println("[demo] Running migrations...")
|
|
17
|
-
if err := db.AutoMigrate(&models.DemoTask{}); err != nil {
|
|
18
|
-
return fmt.Errorf("auto migrate demo_tasks: %w", err)
|
|
19
|
-
}
|
|
20
|
-
return nil
|
|
21
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
package seeds
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"log"
|
|
5
|
-
|
|
6
|
-
"gorm.io/gorm"
|
|
7
|
-
|
|
8
|
-
"__APP_NAME__/apps/server/internal/modules/demo/domain/models"
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
func Seed(db *gorm.DB) error {
|
|
12
|
-
if db == nil {
|
|
13
|
-
return nil
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
var count int64
|
|
17
|
-
if err := db.Model(&models.DemoTask{}).Count(&count).Error; err != nil {
|
|
18
|
-
return err
|
|
19
|
-
}
|
|
20
|
-
if count > 0 {
|
|
21
|
-
return nil
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
log.Println("[demo] Seeding initial data...")
|
|
25
|
-
tasks := []models.DemoTask{
|
|
26
|
-
{Title: "Set up project", Status: models.StatusTodo},
|
|
27
|
-
{Title: "Review UI states", Status: models.StatusDone},
|
|
28
|
-
}
|
|
29
|
-
for i := range tasks {
|
|
30
|
-
tasks[i].TenantID = 1
|
|
31
|
-
}
|
|
32
|
-
return db.Create(&tasks).Error
|
|
33
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
package models
|
|
2
|
-
|
|
3
|
-
import "github.com/robsuncn/keystone/domain/models"
|
|
4
|
-
|
|
5
|
-
type TaskStatus string
|
|
6
|
-
|
|
7
|
-
const (
|
|
8
|
-
StatusTodo TaskStatus = "todo"
|
|
9
|
-
StatusInProgress TaskStatus = "in_progress"
|
|
10
|
-
StatusDone TaskStatus = "done"
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
func (s TaskStatus) IsValid() bool {
|
|
14
|
-
switch s {
|
|
15
|
-
case StatusTodo, StatusInProgress, StatusDone:
|
|
16
|
-
return true
|
|
17
|
-
default:
|
|
18
|
-
return false
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
type DemoTask struct {
|
|
23
|
-
models.BaseModel
|
|
24
|
-
Title string `gorm:"size:200;not null" json:"title"`
|
|
25
|
-
Status TaskStatus `gorm:"size:20;not null;default:'todo'" json:"status"`
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
func (DemoTask) TableName() string {
|
|
29
|
-
return "demo_tasks"
|
|
30
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
package service
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"context"
|
|
5
|
-
"strings"
|
|
6
|
-
|
|
7
|
-
"__APP_NAME__/apps/server/internal/modules/demo/domain/models"
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
type TaskRepository interface {
|
|
11
|
-
List(ctx context.Context, tenantID uint) ([]models.DemoTask, error)
|
|
12
|
-
FindByID(tenantID, id uint) (*models.DemoTask, error)
|
|
13
|
-
Create(ctx context.Context, task *models.DemoTask) error
|
|
14
|
-
Update(ctx context.Context, task *models.DemoTask) error
|
|
15
|
-
Delete(ctx context.Context, task *models.DemoTask) error
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
type TaskService struct {
|
|
19
|
-
tasks TaskRepository
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
type TaskInput struct {
|
|
23
|
-
Title string
|
|
24
|
-
Status models.TaskStatus
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
type TaskUpdateInput struct {
|
|
28
|
-
Title string
|
|
29
|
-
Status models.TaskStatus
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
func NewTaskService(tasks TaskRepository) *TaskService {
|
|
33
|
-
return &TaskService{tasks: tasks}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
func (s *TaskService) List(ctx context.Context, tenantID uint) ([]models.DemoTask, error) {
|
|
37
|
-
return s.tasks.List(ctx, tenantID)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
func (s *TaskService) Create(ctx context.Context, tenantID uint, input TaskInput) (*models.DemoTask, error) {
|
|
41
|
-
title := strings.TrimSpace(input.Title)
|
|
42
|
-
if title == "" {
|
|
43
|
-
return nil, ErrTitleRequired
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
status := input.Status
|
|
47
|
-
if status == "" {
|
|
48
|
-
status = models.StatusTodo
|
|
49
|
-
}
|
|
50
|
-
if !status.IsValid() {
|
|
51
|
-
return nil, ErrStatusInvalid
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
task := &models.DemoTask{
|
|
55
|
-
Title: title,
|
|
56
|
-
Status: status,
|
|
57
|
-
}
|
|
58
|
-
task.TenantID = tenantID
|
|
59
|
-
|
|
60
|
-
if err := s.tasks.Create(ctx, task); err != nil {
|
|
61
|
-
return nil, err
|
|
62
|
-
}
|
|
63
|
-
return task, nil
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
func (s *TaskService) Update(ctx context.Context, tenantID, id uint, input TaskUpdateInput) (*models.DemoTask, error) {
|
|
67
|
-
task, err := s.tasks.FindByID(tenantID, id)
|
|
68
|
-
if err != nil {
|
|
69
|
-
return nil, err
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if title := strings.TrimSpace(input.Title); title != "" {
|
|
73
|
-
task.Title = title
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if input.Status != "" {
|
|
77
|
-
if !input.Status.IsValid() {
|
|
78
|
-
return nil, ErrStatusInvalid
|
|
79
|
-
}
|
|
80
|
-
task.Status = input.Status
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if err := s.tasks.Update(ctx, task); err != nil {
|
|
84
|
-
return nil, err
|
|
85
|
-
}
|
|
86
|
-
return task, nil
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
func (s *TaskService) Delete(ctx context.Context, tenantID, id uint) error {
|
|
90
|
-
task, err := s.tasks.FindByID(tenantID, id)
|
|
91
|
-
if err != nil {
|
|
92
|
-
return err
|
|
93
|
-
}
|
|
94
|
-
return s.tasks.Delete(ctx, task)
|
|
95
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
package repository
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"context"
|
|
5
|
-
"errors"
|
|
6
|
-
|
|
7
|
-
"gorm.io/gorm"
|
|
8
|
-
|
|
9
|
-
"__APP_NAME__/apps/server/internal/modules/demo/domain/models"
|
|
10
|
-
"__APP_NAME__/apps/server/internal/modules/demo/domain/service"
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
type TaskRepository struct {
|
|
14
|
-
db *gorm.DB
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
func NewTaskRepository(db *gorm.DB) *TaskRepository {
|
|
18
|
-
return &TaskRepository{db: db}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
func (r *TaskRepository) List(ctx context.Context, tenantID uint) ([]models.DemoTask, error) {
|
|
22
|
-
var tasks []models.DemoTask
|
|
23
|
-
err := r.db.WithContext(ctx).
|
|
24
|
-
Where("tenant_id = ?", tenantID).
|
|
25
|
-
Order("created_at desc").
|
|
26
|
-
Find(&tasks).Error
|
|
27
|
-
return tasks, err
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
func (r *TaskRepository) FindByID(tenantID, id uint) (*models.DemoTask, error) {
|
|
31
|
-
var task models.DemoTask
|
|
32
|
-
err := r.db.Where("tenant_id = ? AND id = ?", tenantID, id).First(&task).Error
|
|
33
|
-
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
34
|
-
return nil, service.ErrTaskNotFound
|
|
35
|
-
}
|
|
36
|
-
return &task, err
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
func (r *TaskRepository) Create(ctx context.Context, task *models.DemoTask) error {
|
|
40
|
-
return r.db.WithContext(ctx).Create(task).Error
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
func (r *TaskRepository) Update(ctx context.Context, task *models.DemoTask) error {
|
|
44
|
-
return r.db.WithContext(ctx).Save(task).Error
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
func (r *TaskRepository) Delete(ctx context.Context, task *models.DemoTask) error {
|
|
48
|
-
return r.db.WithContext(ctx).Delete(task).Error
|
|
49
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
package demo
|
|
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
|
-
demohandler "__APP_NAME__/apps/server/internal/modules/demo/api/handler"
|
|
11
|
-
demomigrations "__APP_NAME__/apps/server/internal/modules/demo/bootstrap/migrations"
|
|
12
|
-
demoseeds "__APP_NAME__/apps/server/internal/modules/demo/bootstrap/seeds"
|
|
13
|
-
demomodels "__APP_NAME__/apps/server/internal/modules/demo/domain/models"
|
|
14
|
-
demoservice "__APP_NAME__/apps/server/internal/modules/demo/domain/service"
|
|
15
|
-
demorepository "__APP_NAME__/apps/server/internal/modules/demo/infra/repository"
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
type Module struct {
|
|
19
|
-
tasks *demoservice.TaskService
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
func NewModule() *Module {
|
|
23
|
-
return &Module{}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
func (m *Module) Name() string {
|
|
27
|
-
return "demo"
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
func (m *Module) RegisterRoutes(rg *gin.RouterGroup) {
|
|
31
|
-
if rg == nil || m == nil {
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
handler := demohandler.NewTaskHandler(m.tasks)
|
|
35
|
-
if handler == nil {
|
|
36
|
-
return
|
|
37
|
-
}
|
|
38
|
-
group := rg.Group("/demo")
|
|
39
|
-
group.GET("/tasks", handler.List)
|
|
40
|
-
group.POST("/tasks", handler.Create)
|
|
41
|
-
group.PATCH("/tasks/:id", handler.Update)
|
|
42
|
-
group.DELETE("/tasks/:id", handler.Delete)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
func (m *Module) RegisterModels() []interface{} {
|
|
46
|
-
return []interface{}{&demomodels.DemoTask{}}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
func (m *Module) RegisterPermissions(reg *permissions.Registry) error {
|
|
50
|
-
if reg == nil {
|
|
51
|
-
return nil
|
|
52
|
-
}
|
|
53
|
-
if err := reg.CreateMenu("demo:task", "Demo Tasks", "demo", 10); err != nil {
|
|
54
|
-
return err
|
|
55
|
-
}
|
|
56
|
-
if err := reg.CreateAction("demo:task:view", "View Tasks", "demo", "demo:task"); err != nil {
|
|
57
|
-
return err
|
|
58
|
-
}
|
|
59
|
-
if err := reg.CreateAction("demo:task:manage", "Manage Tasks", "demo", "demo:task"); err != nil {
|
|
60
|
-
return err
|
|
61
|
-
}
|
|
62
|
-
return nil
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
func (m *Module) RegisterJobs(_ *jobs.Registry) error {
|
|
66
|
-
return nil
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
func (m *Module) Migrate(db *gorm.DB) error {
|
|
70
|
-
if db == nil {
|
|
71
|
-
return nil
|
|
72
|
-
}
|
|
73
|
-
m.ensureServices(db)
|
|
74
|
-
return demomigrations.Migrate(db)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
func (m *Module) Seed(db *gorm.DB) error {
|
|
78
|
-
if db == nil {
|
|
79
|
-
return nil
|
|
80
|
-
}
|
|
81
|
-
m.ensureServices(db)
|
|
82
|
-
return demoseeds.Seed(db)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
func (m *Module) ensureServices(db *gorm.DB) {
|
|
86
|
-
if m == nil || db == nil || m.tasks != nil {
|
|
87
|
-
return
|
|
88
|
-
}
|
|
89
|
-
repo := demorepository.NewTaskRepository(db)
|
|
90
|
-
m.tasks = demoservice.NewTaskService(repo)
|
|
91
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
package example
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"github.com/gin-gonic/gin"
|
|
5
|
-
|
|
6
|
-
"github.com/robsuncn/keystone/api/response"
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
type HelloResponse struct {
|
|
10
|
-
Message string `json:"message"`
|
|
11
|
-
Module string `json:"module"`
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
func handleHello(c *gin.Context) {
|
|
15
|
-
response.Success(c, HelloResponse{
|
|
16
|
-
Message: "Hello from Example module!",
|
|
17
|
-
Module: "example",
|
|
18
|
-
})
|
|
19
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
helpKey: "demo/tasks"
|
|
3
|
-
title: "Demo Tasks"
|
|
4
|
-
description: "Manage sample tasks in the scaffold."
|
|
5
|
-
category: "demo"
|
|
6
|
-
tags: ["demo", "tasks"]
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Demo Tasks
|
|
10
|
-
|
|
11
|
-
Use this module as a reference for list + create + update flows. Replace it
|
|
12
|
-
with real business logic when you build new modules.
|