@robsun/create-keystone-app 0.2.15 → 0.4.1

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 (96) hide show
  1. package/README.md +46 -44
  2. package/dist/create-keystone-app.js +347 -10
  3. package/dist/create-module.js +1217 -1187
  4. package/package.json +1 -1
  5. package/template/.claude/skills/keystone-implement/SKILL.md +113 -0
  6. package/template/.claude/skills/keystone-implement/references/CHECKLIST.md +91 -0
  7. package/template/.claude/skills/keystone-implement/references/PATTERNS.md +1088 -0
  8. package/template/.claude/skills/keystone-implement/references/SCHEMA.md +135 -0
  9. package/template/.claude/skills/keystone-implement/references/TESTING.md +231 -0
  10. package/template/.claude/skills/keystone-requirements/SKILL.md +296 -0
  11. package/template/.claude/skills/keystone-requirements/references/CONFIRM_TEMPLATE.md +170 -0
  12. package/template/.claude/skills/keystone-requirements/references/SCHEMA.md +135 -0
  13. package/template/.eslintrc.js +3 -0
  14. package/template/.github/workflows/ci.yml +30 -0
  15. package/template/.github/workflows/release.yml +32 -0
  16. package/template/.golangci.yml +11 -0
  17. package/template/README.md +82 -81
  18. package/template/apps/server/README.md +8 -0
  19. package/template/apps/server/cmd/server/main.go +27 -185
  20. package/template/apps/server/config.example.yaml +31 -1
  21. package/template/apps/server/config.yaml +31 -1
  22. package/template/apps/server/go.mod +61 -19
  23. package/template/apps/server/go.sum +185 -32
  24. package/template/apps/server/internal/frontend/embed.go +3 -8
  25. package/template/apps/server/internal/modules/example/README.md +18 -0
  26. package/template/apps/server/internal/modules/example/api/handler/handler_test.go +9 -0
  27. package/template/apps/server/internal/modules/example/api/handler/item_handler.go +468 -165
  28. package/template/apps/server/internal/modules/example/bootstrap/seeds/item.go +217 -8
  29. package/template/apps/server/internal/modules/example/domain/models/item.go +40 -7
  30. package/template/apps/server/internal/modules/example/domain/service/approval_callback.go +68 -0
  31. package/template/apps/server/internal/modules/example/domain/service/approval_schema.go +41 -0
  32. package/template/apps/server/internal/modules/example/domain/service/errors.go +20 -22
  33. package/template/apps/server/internal/modules/example/domain/service/item_service.go +267 -7
  34. package/template/apps/server/internal/modules/example/domain/service/item_service_test.go +281 -0
  35. package/template/apps/server/internal/modules/example/i18n/keys.go +32 -20
  36. package/template/apps/server/internal/modules/example/i18n/locales/en-US.json +30 -18
  37. package/template/apps/server/internal/modules/example/i18n/locales/zh-CN.json +30 -18
  38. package/template/apps/server/internal/modules/example/infra/exporter/item_exporter.go +119 -0
  39. package/template/apps/server/internal/modules/example/infra/importer/item_importer.go +77 -0
  40. package/template/apps/server/internal/modules/example/infra/repository/item_repository.go +99 -49
  41. package/template/apps/server/internal/modules/example/module.go +171 -97
  42. package/template/apps/server/internal/modules/example/tests/integration_test.go +7 -0
  43. package/template/apps/server/internal/modules/manifest.go +7 -7
  44. package/template/apps/web/README.md +4 -2
  45. package/template/apps/web/package.json +1 -1
  46. package/template/apps/web/src/app.config.ts +8 -6
  47. package/template/apps/web/src/index.css +7 -3
  48. package/template/apps/web/src/main.tsx +2 -5
  49. package/template/apps/web/src/modules/example/help/en-US/faq.md +27 -0
  50. package/template/apps/web/src/modules/example/help/en-US/items.md +30 -0
  51. package/template/apps/web/src/modules/example/help/en-US/overview.md +31 -0
  52. package/template/apps/web/src/modules/example/help/zh-CN/faq.md +27 -0
  53. package/template/apps/web/src/modules/example/help/zh-CN/items.md +31 -0
  54. package/template/apps/web/src/modules/example/help/zh-CN/overview.md +32 -0
  55. package/template/apps/web/src/modules/example/locales/en-US/example.json +99 -32
  56. package/template/apps/web/src/modules/example/locales/zh-CN/example.json +85 -18
  57. package/template/apps/web/src/modules/example/pages/ExampleItemsPage.tsx +840 -237
  58. package/template/apps/web/src/modules/example/services/exampleItems.ts +79 -8
  59. package/template/apps/web/src/modules/example/types.ts +14 -1
  60. package/template/apps/web/src/modules/index.ts +1 -0
  61. package/template/apps/web/vite.config.ts +9 -3
  62. package/template/docs/CONVENTIONS.md +17 -17
  63. package/template/package.json +4 -5
  64. package/template/pnpm-lock.yaml +76 -5
  65. package/template/scripts/build.bat +15 -3
  66. package/template/scripts/build.sh +9 -3
  67. package/template/scripts/check-help.js +249 -0
  68. package/template/scripts/compress-assets.js +89 -0
  69. package/template/scripts/test.bat +23 -0
  70. package/template/scripts/test.sh +16 -0
  71. package/template/.claude/skills/keystone-dev/SKILL.md +0 -90
  72. package/template/.claude/skills/keystone-dev/references/ADVANCED_PATTERNS.md +0 -716
  73. package/template/.claude/skills/keystone-dev/references/APPROVAL.md +0 -121
  74. package/template/.claude/skills/keystone-dev/references/CAPABILITIES.md +0 -261
  75. package/template/.claude/skills/keystone-dev/references/CHECKLIST.md +0 -285
  76. package/template/.claude/skills/keystone-dev/references/GOTCHAS.md +0 -390
  77. package/template/.claude/skills/keystone-dev/references/PATTERNS.md +0 -605
  78. package/template/.claude/skills/keystone-dev/references/TEMPLATES.md +0 -2710
  79. package/template/.claude/skills/keystone-dev/references/TESTING.md +0 -44
  80. package/template/.codex/skills/keystone-dev/SKILL.md +0 -90
  81. package/template/.codex/skills/keystone-dev/references/ADVANCED_PATTERNS.md +0 -716
  82. package/template/.codex/skills/keystone-dev/references/APPROVAL.md +0 -121
  83. package/template/.codex/skills/keystone-dev/references/CAPABILITIES.md +0 -261
  84. package/template/.codex/skills/keystone-dev/references/CHECKLIST.md +0 -285
  85. package/template/.codex/skills/keystone-dev/references/GOTCHAS.md +0 -390
  86. package/template/.codex/skills/keystone-dev/references/PATTERNS.md +0 -605
  87. package/template/.codex/skills/keystone-dev/references/TEMPLATES.md +0 -2710
  88. package/template/.codex/skills/keystone-dev/references/TESTING.md +0 -44
  89. package/template/apps/server/internal/app/routes/module_routes.go +0 -16
  90. package/template/apps/server/internal/app/routes/routes.go +0 -226
  91. package/template/apps/server/internal/app/startup/startup.go +0 -74
  92. package/template/apps/server/internal/frontend/handler.go +0 -122
  93. package/template/apps/server/internal/modules/registry.go +0 -145
  94. package/template/apps/web/src/modules/example/help/faq.md +0 -23
  95. package/template/apps/web/src/modules/example/help/items.md +0 -26
  96. package/template/apps/web/src/modules/example/help/overview.md +0 -25
@@ -1,97 +1,171 @@
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
+ approvalRepo "github.com/robsuncn/keystone/domain/approval/repository"
8
+ approvalSvc "github.com/robsuncn/keystone/domain/approval/service"
9
+ "github.com/robsuncn/keystone/domain/permissions"
10
+ "github.com/robsuncn/keystone/domain/service"
11
+ "github.com/robsuncn/keystone/infra/exporter"
12
+ "github.com/robsuncn/keystone/infra/importer"
13
+ "github.com/robsuncn/keystone/infra/repository"
14
+ "github.com/robsuncn/keystone/infra/scheduler"
15
+
16
+ examplehandler "__APP_NAME__/apps/server/internal/modules/example/api/handler"
17
+ examplemigrations "__APP_NAME__/apps/server/internal/modules/example/bootstrap/migrations"
18
+ exampleseeds "__APP_NAME__/apps/server/internal/modules/example/bootstrap/seeds"
19
+ examplemodels "__APP_NAME__/apps/server/internal/modules/example/domain/models"
20
+ exampleservice "__APP_NAME__/apps/server/internal/modules/example/domain/service"
21
+ examplei18n "__APP_NAME__/apps/server/internal/modules/example/i18n"
22
+ exampleexporter "__APP_NAME__/apps/server/internal/modules/example/infra/exporter"
23
+ exampleimporter "__APP_NAME__/apps/server/internal/modules/example/infra/importer"
24
+ examplerepository "__APP_NAME__/apps/server/internal/modules/example/infra/repository"
25
+ servermodules "github.com/robsuncn/keystone/server/modules"
26
+ )
27
+
28
+ type Module struct {
29
+ db *gorm.DB
30
+ items *exampleservice.ItemService
31
+ }
32
+
33
+ func NewModule() *Module {
34
+ return &Module{}
35
+ }
36
+
37
+ func (m *Module) Name() string {
38
+ return "example"
39
+ }
40
+
41
+ func (m *Module) RegisterRoutes(rg *gin.RouterGroup, deps servermodules.RouteDeps) {
42
+ if rg == nil || m == nil {
43
+ return
44
+ }
45
+ handler := examplehandler.NewItemHandler(m.items)
46
+ if handler == nil {
47
+ return
48
+ }
49
+ middlewares := make([]gin.HandlerFunc, 0, 1+len(deps.TenantGuards))
50
+ if deps.Auth != nil {
51
+ middlewares = append(middlewares, deps.Auth)
52
+ }
53
+ if len(deps.TenantGuards) > 0 {
54
+ middlewares = append(middlewares, deps.TenantGuards...)
55
+ }
56
+
57
+ group := rg.Group("/example", middlewares...)
58
+ viewGuard := permissionGuard(deps.RBAC, "example:item:view")
59
+ manageGuard := permissionGuard(deps.RBAC, "example:item:manage")
60
+
61
+ group.GET("/items", viewGuard, handler.List)
62
+ group.GET("/items/export/pdf", viewGuard, handler.ExportPDF)
63
+ group.GET("/items/import-template", manageGuard, handler.DownloadImportTemplate)
64
+ group.GET("/items/:id", viewGuard, handler.Get)
65
+ group.POST("/items", manageGuard, handler.Create)
66
+ group.PATCH("/items/:id", manageGuard, handler.Update)
67
+ group.DELETE("/items/:id", manageGuard, handler.Delete)
68
+ group.POST("/items/:id/submit", manageGuard, handler.Submit)
69
+ group.POST("/items/:id/cancel", manageGuard, handler.Cancel)
70
+ }
71
+
72
+ func (m *Module) RegisterModels() []interface{} {
73
+ return []interface{}{&examplemodels.ExampleItem{}}
74
+ }
75
+
76
+ func (m *Module) RegisterPermissions(reg *permissions.Registry) error {
77
+ if reg == nil {
78
+ return nil
79
+ }
80
+ // Use NameKey for i18n support
81
+ if err := reg.CreateMenuI18n("example:item", "Example Items", "permission.example.item", "example", 10); err != nil {
82
+ return err
83
+ }
84
+ if err := reg.CreateActionI18n("example:item:view", "View Items", "permission.example.item.view", "example", "example:item"); err != nil {
85
+ return err
86
+ }
87
+ if err := reg.CreateActionI18n("example:item:manage", "Manage Items", "permission.example.item.manage", "example", "example:item"); err != nil {
88
+ return err
89
+ }
90
+ return nil
91
+ }
92
+
93
+ func (m *Module) RegisterI18n() error {
94
+ return examplei18n.RegisterLocales()
95
+ }
96
+
97
+ func (m *Module) RegisterTasks(_ *scheduler.Registry) error {
98
+ return nil
99
+ }
100
+
101
+ func (m *Module) RegisterImporters(reg *importer.Service) error {
102
+ if reg == nil {
103
+ return nil
104
+ }
105
+ if m.items == nil && m.db != nil {
106
+ m.ensureServices(m.db)
107
+ }
108
+ return exampleimporter.RegisterItemImporter(reg, m.items)
109
+ }
110
+
111
+ func (m *Module) RegisterExporters(reg *exporter.Service) error {
112
+ if reg == nil {
113
+ return nil
114
+ }
115
+ if m.items == nil && m.db != nil {
116
+ m.ensureServices(m.db)
117
+ }
118
+ return exampleexporter.RegisterItemExporter(reg, m.items)
119
+ }
120
+
121
+ func (m *Module) Migrate(db *gorm.DB) error {
122
+ if db == nil {
123
+ return nil
124
+ }
125
+ m.ensureServices(db)
126
+ return examplemigrations.Migrate(db)
127
+ }
128
+
129
+ func (m *Module) Seed(db *gorm.DB) error {
130
+ if db == nil {
131
+ return nil
132
+ }
133
+ m.ensureServices(db)
134
+ return exampleseeds.Seed(db)
135
+ }
136
+
137
+ func (m *Module) ensureServices(db *gorm.DB) {
138
+ if m == nil || db == nil || m.items != nil {
139
+ return
140
+ }
141
+ m.db = db
142
+ repo := examplerepository.NewItemRepository(db)
143
+
144
+ permRepo := repository.NewPermissionRepository(db)
145
+ userRepo := repository.NewUserRepository(db)
146
+ permSvc := service.NewPermissionService(permRepo, userRepo)
147
+
148
+ flowRepo := approvalRepo.NewFlowRepository(db)
149
+ nodeRepo := approvalRepo.NewNodeRepository(db)
150
+ instanceRepo := approvalRepo.NewInstanceRepository(db)
151
+ recordRepo := approvalRepo.NewRecordRepository(db)
152
+ approvalService := approvalSvc.NewService(db, instanceRepo, flowRepo, nodeRepo, recordRepo, userRepo, permSvc, approvalSvc.DefaultCallbackRegistry)
153
+ flowMatcher := approvalSvc.NewFlowMatcher(flowRepo)
154
+
155
+ notificationRepo := repository.NewNotificationRepository(db)
156
+ notificationSvc := service.NewNotificationService(db, notificationRepo)
157
+
158
+ callback := exampleservice.NewApprovalCallback(repo, notificationSvc)
159
+ approvalSvc.DefaultCallbackRegistry.Register(string(exampleservice.ApprovalBusinessType), callback)
160
+
161
+ m.items = exampleservice.NewItemService(repo, approvalService, flowMatcher, notificationSvc)
162
+ }
163
+
164
+ func permissionGuard(rbac servermodules.PermissionGuard, code string) gin.HandlerFunc {
165
+ if rbac == nil {
166
+ return func(c *gin.Context) {
167
+ c.Next()
168
+ }
169
+ }
170
+ return rbac.Require(code)
171
+ }
@@ -0,0 +1,7 @@
1
+ package tests
2
+
3
+ import "testing"
4
+
5
+ func TestExampleIntegration(t *testing.T) {
6
+ t.Skip("integration test template")
7
+ }
@@ -1,11 +1,11 @@
1
1
  package modules
2
2
 
3
- import (
4
- example "__APP_NAME__/apps/server/internal/modules/example"
5
- )
3
+ import servermodules "github.com/robsuncn/keystone/server/modules"
6
4
 
7
- // RegisterAll wires the module registry for this app.
8
- func RegisterAll() {
9
- Clear()
10
- Register(example.NewModule())
5
+ // Register wires application modules into the shared registry.
6
+ func Register(registry *servermodules.Registry) {
7
+ if registry == nil {
8
+ return
9
+ }
10
+ registry.Register(servermodules.NewCoreModule())
11
11
  }
@@ -8,20 +8,22 @@
8
8
  - `src/main.tsx`:应用入口。
9
9
  - `src/app.config.ts`:品牌与模块启用配置。
10
10
  - `src/modules/<module>/index.ts`:模块注册入口。
11
+ - `src/modules/index.ts`:应用模块聚合入口。
11
12
  - `apps/web/.env.example`:前端环境变量模板(Vite 读取)。
12
13
 
13
14
  ## 新建模块
14
15
  1) 创建目录:`src/modules/<module>`。
15
16
  2) 在 `index.ts` 调用 `registerModule` 注册路由。
16
17
  3) 在 `routes.tsx` 配置菜单、权限、帮助文档。
17
- 4) 在 `app.config.ts` 的 `modules.enabled` 启用模块。
18
+ 4) 在 `src/modules/index.ts` 引入模块。
19
+ 5) 在 `app.config.ts` 的 `modules.enabled` 启用模块。
18
20
 
19
21
  ## 帮助文档
20
22
  - 放在 `src/modules/<module>/help/**`。
21
23
  - `helpKey` 与路由 `handle.helpKey` 保持一致。
22
24
 
23
25
  ## 常用命令
24
- - 开发:`pnpm web:dev`
26
+ - 开发:`pnpm dev`(前后端一起)/ `pnpm -C apps/web dev`(仅前端)
25
27
  - Lint:`pnpm -C apps/web lint`
26
28
  - 测试:`pnpm -C apps/web test`
27
29
 
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@ant-design/icons": "^6.1.0",
20
- "@robsun/keystone-web-core": "^0.3.0",
20
+ "@robsun/keystone-web-core": "^0.5.0",
21
21
  "antd": "^6.0.1",
22
22
  "dayjs": "^1.11.19",
23
23
  "i18next": "^24.2.3",
@@ -7,12 +7,14 @@ export const appConfig: Partial<KeystoneWebConfig> = {
7
7
  appName: 'Keystone',
8
8
  platformName: 'Keystone Platform',
9
9
  },
10
- modules: {
11
- enabled: ['keystone', 'example'],
12
- },
13
- approval: {
14
- businessTypes: [{ value: 'general', label: 'General Flow' }],
15
- },
10
+ modules: {
11
+ enabled: ['keystone'],
12
+ },
13
+ approval: {
14
+ businessTypes: [
15
+ { value: 'general', label: 'General Flow' },
16
+ ],
17
+ },
16
18
  ui: {
17
19
  i18n: {
18
20
  enabled: true,
@@ -1,3 +1,7 @@
1
- @tailwind base;
2
- @tailwind components;
3
- @tailwind utilities;
1
+ /*
2
+ * Tailwind 样式由 @robsun/keystone-web-core/styles/keystone.css 提供
3
+ * 如需添加自定义 Tailwind 工具类,使用 Tailwind v4 语法:
4
+ * @import 'tailwindcss/utilities';
5
+ */
6
+
7
+ /* 应用级别的自定义样式可以放在这里 */
@@ -1,15 +1,12 @@
1
1
  import { StrictMode } from 'react'
2
2
  import { createRoot } from 'react-dom/client'
3
- import dayjs from 'dayjs'
4
- import { KeystoneApp, getKeystoneConfig, setKeystoneConfig } from '@robsun/keystone-web-core'
3
+ import { KeystoneApp, setKeystoneConfig } from '@robsun/keystone-web-core'
5
4
  import { appConfig } from './app.config'
6
5
  import '@robsun/keystone-web-core/styles/keystone.css'
7
6
  import './index.css'
8
- import './modules/example'
7
+ import './modules'
9
8
 
10
9
  setKeystoneConfig(appConfig)
11
- const dayjsLocale = getKeystoneConfig().ui?.locale?.dayjs ?? 'en'
12
- dayjs.locale(dayjsLocale)
13
10
 
14
11
  createRoot(document.getElementById('root')!).render(
15
12
  <StrictMode>
@@ -0,0 +1,27 @@
1
+ ---
2
+ helpKey: "example/faq"
3
+ title: "Example Module FAQ"
4
+ description: "Common questions for the Example module."
5
+ category: "example"
6
+ tags: ["example", "faq"]
7
+ ---
8
+
9
+ # FAQ
10
+
11
+ ## Why is the list empty?
12
+ - Confirm migrations and seed data have run (first launch runs them automatically).
13
+ - Check the current user has the `example:item:view` permission.
14
+ - Ensure `example` is enabled in `modules.enabled`.
15
+
16
+ ## Why does approval submission fail?
17
+ - Confirm an approval flow exists and is enabled (a sample flow is created by default).
18
+ - Check the current user is logged in and has submit permissions.
19
+ - Status must be `draft` / `rejected` / `cancelled`.
20
+
21
+ ## Why can I not edit or delete?
22
+ - `pending` status cannot be edited or deleted.
23
+ - Approved records are read-only.
24
+
25
+ ## What if import fails?
26
+ - Ensure import fields include `title`.
27
+ - Category must be `general` / `operations` / `finance` / `growth`.
@@ -0,0 +1,30 @@
1
+ ---
2
+ helpKey: "example/items"
3
+ title: "Example Items"
4
+ description: "Manage example items with CRUD, approval, import/export, and attachments."
5
+ category: "example"
6
+ tags: ["example", "items", "approval", "import", "export"]
7
+ ---
8
+
9
+ # Example Items
10
+ This page demonstrates the full lifecycle of example items, including creation, approval, import/export, and attachments.
11
+
12
+ ## Field reference
13
+ - **Title**: required, item title.
14
+ - **Description**: optional, item description.
15
+ - **Category**: business category used for filters and approval conditions.
16
+ - **Amount**: amount used for approval conditions and export.
17
+ - **Status**: `draft` / `pending` / `approved` / `rejected` / `cancelled`.
18
+ - **Attachment**: uploaded file stored in the file service.
19
+
20
+ ## Approval workflow
21
+ - After submission, status becomes `pending` and is approved by the admin role.
22
+ - Cancellation is supported; status becomes `cancelled` after cancel.
23
+
24
+ ## Import/Export
25
+ - Import fields: `title`, `description`, `category`, `amount`, `status`.
26
+ - Export includes ID, amount, approval status, and other fields.
27
+
28
+ ## Permissions
29
+ - `example:item:view`: view list and details.
30
+ - `example:item:manage`: create, edit, delete, submit/cancel approval.
@@ -0,0 +1,31 @@
1
+ ---
2
+ helpKey: "example/overview"
3
+ title: "Example Module Overview"
4
+ description: "Overview of the Example module and the platform integrations it demonstrates."
5
+ category: "example"
6
+ tags: ["example", "items", "approval", "import", "export", "file"]
7
+ ---
8
+
9
+ # Example Module
10
+ The Example module demonstrates how a business module integrates platform capabilities and serves as a reference template for new module development.
11
+
12
+ ## Capabilities covered
13
+ - CRUD with pagination and filters
14
+ - RBAC permissions and menu registration
15
+ - Approval workflow (submit, cancel, approval records)
16
+ - Import/Export (Excel)
17
+ - File upload and attachment storage
18
+ - Notifications
19
+ - i18n and Help docs
20
+
21
+ ## Key paths
22
+ - Frontend: `apps/web/src/modules/example/`
23
+ - Backend: `apps/server/internal/modules/example/`
24
+
25
+ ## Related APIs
26
+ - `GET /api/v1/example/items`
27
+ - `POST /api/v1/example/items`
28
+ - `PATCH /api/v1/example/items/:id`
29
+ - `DELETE /api/v1/example/items/:id`
30
+ - `POST /api/v1/example/items/:id/submit`
31
+ - `POST /api/v1/example/items/:id/cancel`
@@ -0,0 +1,27 @@
1
+ ---
2
+ helpKey: "example/faq"
3
+ title: "Example Module FAQ"
4
+ description: "Common questions for the Example module."
5
+ category: "example"
6
+ tags: ["example", "faq"]
7
+ ---
8
+
9
+ # FAQ
10
+
11
+ ## 为什么列表为空?
12
+ - 确认已执行迁移与种子数据(首次启动会自动执行)。
13
+ - 检查当前用户是否有 `example:item:view` 权限。
14
+ - 确认 `modules.enabled` 中已启用 `example`。
15
+
16
+ ## 为什么提交审批失败?
17
+ - 确认审批流程已创建并启用(默认会创建示例流程)。
18
+ - 检查当前用户是否已登录且具备提交权限。
19
+ - 状态需为 `draft` / `rejected` / `cancelled`。
20
+
21
+ ## 为什么无法编辑或删除?
22
+ - `pending` 状态下禁止编辑或删除。
23
+ - 已审批通过的记录仅可查看。
24
+
25
+ ## 导入失败怎么办?
26
+ - 检查导入字段是否包含 `title`。
27
+ - 类别需为 `general` / `operations` / `finance` / `growth`。
@@ -0,0 +1,31 @@
1
+ ---
2
+ helpKey: "example/items"
3
+ title: "Example Items"
4
+ description: "Manage example items with CRUD, approval, import/export, and attachments."
5
+ category: "example"
6
+ tags: ["example", "items", "approval", "import", "export"]
7
+ ---
8
+
9
+ # Example Items
10
+
11
+ 本页展示示例事项的完整流程,覆盖创建、审批、导入/导出与附件。
12
+
13
+ ## 字段说明
14
+ - **Title**:必填,事项标题。
15
+ - **Description**:可选,事项描述。
16
+ - **Category**:业务分类,用于筛选与审批条件。
17
+ - **Amount**:金额,用于审批条件与导出。
18
+ - **Status**:`draft` / `pending` / `approved` / `rejected` / `cancelled`。
19
+ - **Attachment**:上传文件,存储在文件服务中。
20
+
21
+ ## 审批流程
22
+ - 提交后进入 `pending` 状态,由管理员角色审批。
23
+ - 支持撤销审批,撤销后状态为 `cancelled`。
24
+
25
+ ## 导入/导出
26
+ - 导入字段:`title`, `description`, `category`, `amount`, `status`。
27
+ - 导出包含编号、金额、审批状态等字段。
28
+
29
+ ## 权限
30
+ - `example:item:view`:查看列表和详情。
31
+ - `example:item:manage`:新建、编辑、删除、提交/撤销审批。
@@ -0,0 +1,32 @@
1
+ ---
2
+ helpKey: "example/overview"
3
+ title: "Example Module Overview"
4
+ description: "Overview of the Example module and the platform integrations it demonstrates."
5
+ category: "example"
6
+ tags: ["example", "items", "approval", "import", "export", "file"]
7
+ ---
8
+
9
+ # Example Module
10
+
11
+ Example 模块用于演示业务模块如何接入平台能力,适合作为新模块开发的参考模板。
12
+
13
+ ## 覆盖能力
14
+ - CRUD + 分页检索与筛选
15
+ - RBAC 权限与菜单注册
16
+ - 审批流程(提交、撤销、审批记录)
17
+ - 导入/导出(Excel)
18
+ - 文件上传与附件存储
19
+ - 通知消息
20
+ - i18n 与 Help 文档
21
+
22
+ ## 关键路径
23
+ - 前端:`apps/web/src/modules/example/`
24
+ - 后端:`apps/server/internal/modules/example/`
25
+
26
+ ## 相关 API
27
+ - `GET /api/v1/example/items`
28
+ - `POST /api/v1/example/items`
29
+ - `PATCH /api/v1/example/items/:id`
30
+ - `DELETE /api/v1/example/items/:id`
31
+ - `POST /api/v1/example/items/:id/submit`
32
+ - `POST /api/v1/example/items/:id/cancel`