@robsun/create-keystone-app 0.1.13 → 0.1.15

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 (55) hide show
  1. package/README.md +19 -10
  2. package/bin/create-keystone-app.js +199 -60
  3. package/package.json +1 -1
  4. package/template/.husky/pre-commit +4 -0
  5. package/template/.lintstagedrc.json +5 -0
  6. package/template/.prettierrc +9 -0
  7. package/template/README.md +45 -23
  8. package/template/apps/server/.air.toml +44 -0
  9. package/template/apps/server/README.md +27 -0
  10. package/template/apps/server/cmd/server/main.go +213 -0
  11. package/template/apps/server/config.yaml +51 -0
  12. package/template/apps/server/docs/docs.go +34 -0
  13. package/template/apps/server/go.mod +13 -0
  14. package/template/apps/server/go.sum +72 -0
  15. package/template/apps/server/internal/app/routes/module_routes.go +16 -0
  16. package/template/apps/server/internal/app/routes/routes.go +226 -0
  17. package/template/apps/server/internal/app/startup/startup.go +74 -0
  18. package/template/apps/server/internal/frontend/dist/.gitkeep +1 -0
  19. package/template/apps/server/internal/frontend/embed.go +28 -0
  20. package/template/apps/server/internal/frontend/handler.go +122 -0
  21. package/template/apps/server/internal/{demo/demo.go → modules/demo/handlers.go} +4 -1
  22. package/template/apps/server/internal/modules/demo/module.go +55 -0
  23. package/template/apps/server/internal/modules/manifest.go +11 -0
  24. package/template/apps/server/internal/modules/registry.go +145 -0
  25. package/template/apps/web/.env.example +3 -0
  26. package/template/apps/web/README.md +29 -0
  27. package/template/apps/web/eslint.config.js +35 -0
  28. package/template/apps/web/package.json +27 -10
  29. package/template/apps/web/postcss.config.js +6 -0
  30. package/template/apps/web/src/index.css +3 -0
  31. package/template/apps/web/src/main.tsx +1 -0
  32. package/template/apps/web/src/modules/demo/help/overview.md +12 -0
  33. package/template/apps/web/src/modules/demo/routes.tsx +2 -0
  34. package/template/apps/web/tailwind.config.js +18 -0
  35. package/template/apps/web/tests/setup.ts +37 -0
  36. package/template/apps/web/tsconfig.app.json +3 -3
  37. package/template/apps/web/vite.config.ts +28 -2
  38. package/template/docker-compose.yml +45 -0
  39. package/template/docs/CODE_STYLE.md +34 -0
  40. package/template/docs/CONVENTIONS.md +62 -88
  41. package/template/package.json +15 -3
  42. package/template/scripts/build.bat +133 -0
  43. package/template/scripts/build.js +25 -0
  44. package/template/scripts/build.sh +99 -0
  45. package/template/scripts/clean.bat +35 -0
  46. package/template/scripts/clean.js +25 -0
  47. package/template/scripts/clean.sh +34 -0
  48. package/template/scripts/dev.bat +82 -0
  49. package/template/scripts/dev.js +25 -0
  50. package/template/scripts/dev.sh +88 -0
  51. package/template/scripts/test.bat +86 -0
  52. package/template/scripts/test.js +25 -0
  53. package/template/scripts/test.sh +86 -0
  54. package/template/apps/server/main.go +0 -28
  55. /package/template/{config.yaml → apps/server/config.example.yaml} +0 -0
@@ -0,0 +1,29 @@
1
+ # Web Shell
2
+
3
+ ## 定位
4
+ - 负责渲染平台 UI,业务模块统一放在 `src/modules/*`。
5
+ - 平台核心能力由 `@robsun/keystone-web-core` 提供。
6
+
7
+ ## 入口
8
+ - `src/main.tsx`:应用入口。
9
+ - `src/app.config.ts`:品牌与模块启用配置。
10
+ - `src/modules/<module>/index.ts`:模块注册入口。
11
+ - `apps/web/.env.example`:前端环境变量模板(Vite 读取)。
12
+
13
+ ## 新建模块
14
+ 1) 创建目录:`src/modules/<module>`。
15
+ 2) 在 `index.ts` 调用 `registerModule` 注册路由。
16
+ 3) 在 `routes.tsx` 配置菜单、权限、帮助文档。
17
+ 4) 在 `app.config.ts` 的 `modules.enabled` 启用模块。
18
+
19
+ ## 帮助文档
20
+ - 放在 `src/modules/<module>/help/**`。
21
+ - `helpKey` 与路由 `handle.helpKey` 保持一致。
22
+
23
+ ## 常用命令
24
+ - 开发:`pnpm web:dev`
25
+ - Lint:`pnpm -C apps/web lint`
26
+ - 测试:`pnpm -C apps/web test`
27
+
28
+ ## 嵌入式构建
29
+ - `pnpm build` 会将产物写入 `apps/server/internal/frontend/dist`。
@@ -0,0 +1,35 @@
1
+ import js from '@eslint/js'
2
+ import globals from 'globals'
3
+ import reactHooks from 'eslint-plugin-react-hooks'
4
+ import reactRefresh from 'eslint-plugin-react-refresh'
5
+ import tseslint from 'typescript-eslint'
6
+ import { defineConfig, globalIgnores } from 'eslint/config'
7
+
8
+ export default defineConfig([
9
+ globalIgnores([
10
+ 'dist',
11
+ 'build',
12
+ '*.min.js',
13
+ 'coverage',
14
+ 'node_modules',
15
+ '.turbo',
16
+ '.pnpm-store',
17
+ 'apps/server/tmp',
18
+ 'data',
19
+ '*.log',
20
+ '.env*',
21
+ ]),
22
+ {
23
+ files: ['**/*.{ts,tsx}'],
24
+ extends: [
25
+ js.configs.recommended,
26
+ tseslint.configs.recommended,
27
+ reactHooks.configs.flat.recommended,
28
+ reactRefresh.configs.vite,
29
+ ],
30
+ languageOptions: {
31
+ ecmaVersion: 2020,
32
+ globals: globals.browser,
33
+ },
34
+ },
35
+ ])
@@ -6,28 +6,45 @@
6
6
  "scripts": {
7
7
  "dev": "vite",
8
8
  "build": "vite build",
9
- "preview": "vite preview"
9
+ "build:strict": "tsc -b && vite build",
10
+ "lint": "eslint .",
11
+ "preview": "vite preview",
12
+ "lint:fix": "eslint . --fix",
13
+ "format": "prettier --write \"src/**/*.{ts,tsx}\"",
14
+ "format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
15
+ "typecheck": "tsc --noEmit",
16
+ "test": "vitest"
10
17
  },
11
18
  "dependencies": {
12
19
  "@ant-design/icons": "^6.1.0",
13
20
  "@robsun/keystone-web-core": "0.1.7",
14
21
  "antd": "^6.0.1",
15
- "cookie": "^1.1.1",
16
22
  "dayjs": "^1.11.19",
17
- "debug": "^4.4.3",
18
- "extend": "^3.0.2",
19
23
  "react": "^19.2.0",
20
24
  "react-dom": "^19.2.0",
21
- "react-router": "^7.10.1",
22
- "react-router-dom": "^7.10.1",
23
- "style-to-js": "^1.1.21"
25
+ "react-router-dom": "^7.10.1"
24
26
  },
25
27
  "devDependencies": {
28
+ "@eslint/js": "^9.39.1",
29
+ "@tailwindcss/postcss": "^4.1.17",
30
+ "@testing-library/jest-dom": "^6.6.3",
31
+ "@testing-library/react": "^16.2.0",
32
+ "@testing-library/user-event": "^14.6.1",
26
33
  "@types/node": "^24.10.1",
27
34
  "@types/react": "^19.2.5",
28
35
  "@types/react-dom": "^19.2.3",
36
+ "@vitejs/plugin-react": "^5.1.1",
37
+ "autoprefixer": "^10.4.22",
38
+ "eslint": "^9.39.1",
39
+ "eslint-plugin-react-hooks": "^7.0.1",
40
+ "eslint-plugin-react-refresh": "^0.4.24",
41
+ "globals": "^16.5.0",
42
+ "jsdom": "^24.1.0",
43
+ "postcss": "^8.5.6",
44
+ "tailwindcss": "^4.1.17",
29
45
  "typescript": "~5.9.3",
30
- "vite": "^7.2.4"
46
+ "typescript-eslint": "^8.46.4",
47
+ "vite": "^7.2.4",
48
+ "vitest": "^2.1.4"
31
49
  }
32
- }
33
-
50
+ }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ plugins: {
3
+ '@tailwindcss/postcss': {},
4
+ autoprefixer: {},
5
+ },
6
+ }
@@ -0,0 +1,3 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
@@ -4,6 +4,7 @@ import dayjs from 'dayjs'
4
4
  import { KeystoneApp, getKeystoneConfig, setKeystoneConfig } from '@robsun/keystone-web-core'
5
5
  import { appConfig } from './app.config'
6
6
  import '@robsun/keystone-web-core/styles/keystone.css'
7
+ import './index.css'
7
8
  import './modules/demo'
8
9
 
9
10
  setKeystoneConfig(appConfig)
@@ -0,0 +1,12 @@
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.
@@ -33,6 +33,8 @@ export const demoRoutes: RouteObject[] = [
33
33
  handle: {
34
34
  menu: { label: 'Demo Tasks', icon: <AppstoreOutlined /> },
35
35
  breadcrumb: 'Demo Tasks',
36
+ permission: 'demo:task:view',
37
+ helpKey: 'demo/tasks',
36
38
  },
37
39
  },
38
40
  ].map((route) => ({
@@ -0,0 +1,18 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
4
+ corePlugins: {
5
+ preflight: false,
6
+ },
7
+ theme: {
8
+ extend: {
9
+ colors: {
10
+ primary: '#1890ff',
11
+ success: '#52c41a',
12
+ warning: '#faad14',
13
+ error: '#ff4d4f',
14
+ },
15
+ },
16
+ },
17
+ plugins: [],
18
+ }
@@ -0,0 +1,37 @@
1
+ import '@testing-library/jest-dom'
2
+ import { vi } from 'vitest'
3
+
4
+ window.matchMedia = vi.fn().mockImplementation((query: string) => ({
5
+ matches: false,
6
+ media: query,
7
+ onchange: null,
8
+ addListener: vi.fn(),
9
+ removeListener: vi.fn(),
10
+ addEventListener: vi.fn(),
11
+ removeEventListener: vi.fn(),
12
+ dispatchEvent: vi.fn(),
13
+ }))
14
+
15
+ if (!('ResizeObserver' in window)) {
16
+ class ResizeObserver {
17
+ observe() {}
18
+ unobserve() {}
19
+ disconnect() {}
20
+ }
21
+ // @ts-expect-error test shim
22
+ window.ResizeObserver = ResizeObserver
23
+ }
24
+
25
+ const originalGetComputedStyle = window.getComputedStyle
26
+ window.getComputedStyle = (elt: Element) => {
27
+ const style = originalGetComputedStyle
28
+ ? originalGetComputedStyle(elt)
29
+ : ({} as CSSStyleDeclaration)
30
+ return {
31
+ ...style,
32
+ getPropertyValue: (prop: string) =>
33
+ style?.getPropertyValue ? style.getPropertyValue(prop) : '',
34
+ } as CSSStyleDeclaration
35
+ }
36
+
37
+ export {}
@@ -5,7 +5,7 @@
5
5
  "useDefineForClassFields": true,
6
6
  "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
7
  "module": "ESNext",
8
- "types": ["vite/client"],
8
+ "types": ["vite/client", "vitest/globals", "@testing-library/jest-dom"],
9
9
  "skipLibCheck": true,
10
10
  "moduleResolution": "bundler",
11
11
  "allowImportingTsExtensions": true,
@@ -19,5 +19,5 @@
19
19
  "noFallthroughCasesInSwitch": true,
20
20
  "noUncheckedSideEffectImports": true
21
21
  },
22
- "include": ["src"]
23
- }
22
+ "include": ["src", "tests"]
23
+ }
@@ -1,6 +1,14 @@
1
+ /// <reference types="vitest" />
1
2
  import { createKeystoneViteConfig } from '@robsun/keystone-web-core/vite'
3
+ import path from 'path'
2
4
 
3
5
  export default createKeystoneViteConfig({
6
+ helpDir: path.resolve(__dirname, './src/modules'),
7
+ resolve: {
8
+ alias: {
9
+ '@app': path.resolve(__dirname, './src'),
10
+ },
11
+ },
4
12
  server: {
5
13
  port: 3000,
6
14
  proxy: {
@@ -10,5 +18,23 @@ export default createKeystoneViteConfig({
10
18
  },
11
19
  },
12
20
  },
13
- })
14
-
21
+ build: {
22
+ outDir: path.resolve(__dirname, '../server/internal/frontend/dist'),
23
+ emptyOutDir: false,
24
+ sourcemap: true,
25
+ rollupOptions: {
26
+ output: {
27
+ manualChunks: {
28
+ vendor: ['react', 'react-dom'],
29
+ },
30
+ },
31
+ },
32
+ },
33
+ test: {
34
+ globals: true,
35
+ environment: 'jsdom',
36
+ setupFiles: './tests/setup.ts',
37
+ include: ['tests/**/*.{test,spec}.{ts,tsx}'],
38
+ exclude: ['**/node_modules/**', 'tests/e2e/**'],
39
+ },
40
+ })
@@ -0,0 +1,45 @@
1
+ version: '3.8'
2
+
3
+ services:
4
+ postgres:
5
+ image: postgres:17
6
+ container_name: keystone-postgres
7
+ restart: unless-stopped
8
+ ports:
9
+ - '5432:5432'
10
+ environment:
11
+ POSTGRES_DB: keystone
12
+ POSTGRES_USER: keystone
13
+ POSTGRES_PASSWORD: keystone
14
+ volumes:
15
+ - pgdata:/var/lib/postgresql/data
16
+ healthcheck:
17
+ test: ['CMD-SHELL', 'pg_isready -U keystone -d keystone']
18
+ interval: 10s
19
+ timeout: 5s
20
+ retries: 5
21
+
22
+ # Redis (optional, uncomment when needed)
23
+ # redis:
24
+ # image: redis:7-alpine
25
+ # container_name: keystone-redis
26
+ # restart: unless-stopped
27
+ # ports:
28
+ # - '6379:6379'
29
+ # volumes:
30
+ # - redisdata:/data
31
+ # healthcheck:
32
+ # test: ['CMD', 'redis-cli', 'ping']
33
+ # interval: 10s
34
+ # timeout: 5s
35
+ # retries: 5
36
+
37
+ volumes:
38
+ pgdata:
39
+ driver: local
40
+ # redisdata:
41
+ # driver: local
42
+
43
+ networks:
44
+ default:
45
+ name: keystone-network
@@ -0,0 +1,34 @@
1
+ # 编码规范
2
+
3
+ ## 总体原则
4
+ - 依赖自动格式化工具,不做手工对齐。
5
+ - 代码优先可读性,遵循项目约定的目录与命名规则。
6
+ - Web 端使用 ESLint + Prettier;Go 端使用 gofmt。
7
+
8
+ ## TypeScript / React
9
+ - 组件名用 `PascalCase`,hooks 用 `useXxx`。
10
+ - 变量/函数用 `camelCase`,常量用 `UPPER_SNAKE_CASE`。
11
+ - 模块目录固定在 `apps/web/src/modules/<module>`。
12
+ - 路由/菜单/权限统一写在 `routes.tsx` 的 `handle` 元信息里。
13
+ - API 请求集中在 `services/`,类型定义放在 `types.ts`。
14
+ - 使用 Prettier 默认风格(2 空格、单引号、无分号)。
15
+
16
+ ## CSS / UI
17
+ - 全局样式入口:`apps/web/src/index.css`。
18
+ - 组件级样式靠近组件放置,避免跨模块引用。
19
+
20
+ ## Go
21
+ - 文件名用 `snake_case.go`,package 名小写。
22
+ - 统一使用 `gofmt` 格式化代码。
23
+ - 错误处理使用 `fmt.Errorf("...: %w", err)` 包裹。
24
+ - 新模块放在 `apps/server/internal/modules/<module>`,实现 `Module` 接口。
25
+
26
+ ## 常用命令
27
+ ```bash
28
+ # Web 端格式化与检查
29
+ pnpm format
30
+ pnpm -C apps/web lint
31
+
32
+ # Go 端格式化
33
+ gofmt -w apps/server
34
+ ```
@@ -1,33 +1,43 @@
1
- # Keystone App Conventions
2
-
3
- ## Goals
4
- - Keep modules predictable across web and server.
5
- - Keep routing, menus, permissions, and help content in one place.
6
- - Follow the tradeflow app patterns for structure and naming.
7
-
8
- ## Project Layout
9
- - `apps/web/`: React + Vite app.
10
- - `apps/server/`: Go API app.
11
- - `apps/web/src/app.config.ts`: web runtime config (modules, branding, approval).
12
- - `config.yaml`: server runtime config (modules, database, queue, storage).
13
-
14
- ## Frontend Module Rules
15
- - Each business module lives in `apps/web/src/modules/<module>`.
16
- - `index.ts` must register the module:
17
- - `registerModule({ name, routes, i18n })`.
18
- - `routes.tsx` owns menu/breadcrumb/permission metadata via `handle`.
19
- - Pages go in `pages/`, shared UI in `components/`, API calls in `services/`, types in `types.ts`, shared state in `stores/`.
20
- - Lazy-load page components and wrap with `Suspense`.
21
-
22
- Example module entry:
1
+ # Keystone App Conventions
2
+
3
+ ## 目标
4
+ - Web/Server 模块结构统一,便于复用与维护。
5
+ - 路由、菜单、权限、帮助文档集中管理。
6
+ - 约定优于配置,降低上手成本。
7
+ 编码规范请参考 `docs/CODE_STYLE.md`。
8
+
9
+ ## 项目结构
10
+ - `apps/web/`:React + Vite 壳与业务模块。
11
+ - `apps/server/`:Go 服务端(`cmd/server` 启动,`internal/app` 编排)。
12
+ - `apps/server/internal/modules/`:后端模块注册与实现。
13
+ - `apps/server/internal/frontend/`:嵌入式前端输出目录(`dist/`)。
14
+ - `scripts/`:跨平台 dev/build/test/clean。
15
+ - `apps/server/config.yaml`:服务端配置(支持环境变量覆盖,`docker-compose.yml` 提供依赖)。
16
+ 提示:更细节的入口说明见 `apps/web/README.md` `apps/server/README.md`。
17
+
18
+ ## 开发流程
19
+ - `pnpm dev`:执行 `scripts/dev.*`,检查环境并启动 Air + Vite。
20
+ - `apps/server/.air.toml`:后端热重载配置。
21
+ - `pnpm server:dev` 仅启动后端;`pnpm web:dev` 仅启动前端。
22
+
23
+ ## 配置与环境
24
+ - `apps/server/config.yaml` 为默认配置;`apps/server/config.example.yaml` 用作模板。
25
+ - `apps/server/config.yaml` 供 `go run`/Air 使用。
26
+ - 前端环境变量参考 `apps/web/.env.example`(Vite 会读取)。
27
+ - 后端环境变量需通过 Shell/工具注入(服务端不读取 `.env`)。
28
+ - 本地数据库默认 SQLite:`apps/server/data/keystone-local.db`。
29
+ - 本地存储目录:`apps/server/storage/`(当 `storage.driver=local`)。
30
+
31
+ ## 前端模块规范
32
+ - 模块目录:`apps/web/src/modules/<module>`。
33
+ - 在 `index.ts` 注册模块:
23
34
  ```ts
24
35
  import { registerModule } from '@robsun/keystone-web-core'
25
36
  import { orderRoutes } from './routes'
26
37
 
27
38
  registerModule({ name: 'orders', routes: orderRoutes })
28
39
  ```
29
-
30
- Example route meta:
40
+ - 在 `routes.tsx` 配置菜单/权限/帮助:
31
41
  ```tsx
32
42
  {
33
43
  path: 'orders',
@@ -40,62 +50,15 @@ Example route meta:
40
50
  },
41
51
  }
42
52
  ```
53
+ - 页面放 `pages/`,组件放 `components/`,API 放 `services/`。
43
54
 
44
- ## Permissions and Menu Rules
45
- - Permission format: `domain:resource:action` (wildcards allowed, e.g. `inventory:*:*`).
46
- - Menus are derived from `handle.menu`. If a route should not appear, omit `handle.menu`.
47
- - Breadcrumbs are derived from `handle.breadcrumb`.
48
- - Use `handle.menu.order` to control menu ordering when needed.
49
-
50
- ## Help Docs
51
- - Store help markdown under `apps/web/src/modules/<module>/help/**`.
52
- - Use frontmatter keys: `helpKey`, `title`, `description`, `category`, `tags`, `relatedKeys`.
53
- - Route `handle.helpKey` must match the markdown `helpKey`.
54
- - Enable app help by pointing Vite to your help folder (`helpDir` in `vite.config.ts`).
55
-
56
- Frontmatter example:
57
- ```md
58
- ---
59
- helpKey: "inventory/warehouses"
60
- title: "Warehouse Management"
61
- description: "Manage warehouses and locations."
62
- category: "inventory"
63
- tags: ["warehouse", "location"]
64
- relatedKeys: ["inventory/stock"]
65
- ---
66
- ```
67
-
68
- ## API and Services
69
- - Use `api` from `@robsun/keystone-web-core` for HTTP.
70
- - If your API base path changes, call `setApiBaseUrl` once at startup.
71
- - Keep API calls in `services/*.ts`, return typed data, and let pages handle UI state.
72
- - For paginated endpoints, map `page`/`page_size` (server) to `page`/`pageSize` (web).
73
-
74
- Example service:
75
- ```ts
76
- import { api, type ApiResponse, type PaginatedData } from '@robsun/keystone-web-core'
77
-
78
- export async function listItems(page = 1, pageSize = 20) {
79
- const { data } = await api.get<ApiResponse<PaginatedData<Item>>>('/items', {
80
- params: { page, page_size: pageSize },
81
- })
82
- return data.data
83
- }
84
- ```
85
-
86
- ## State
87
- - Use local state for single pages.
88
- - Use zustand stores for shared state or cross-page flows.
89
- - Store shape should include `loading`, `error`, `filters`, and a `fetch` method.
90
-
91
- ## Naming
92
- - Page components: `*Page.tsx` (e.g. `InventoryListPage.tsx`).
93
- - API modules: `services/api.ts` or `services/<feature>.ts`.
94
- - Store modules: `stores/*Store.ts` or `stores/use*Store.ts`.
95
- - Domain types: `types.ts` (export interfaces and enums).
55
+ ## Help 文档
56
+ - 文档放在 `apps/web/src/modules/<module>/help/**`。
57
+ - `helpKey` 与路由 `handle.helpKey` 保持一致。
58
+ - Vite 已配置 `helpDir` 扫描 `src/modules`。
96
59
 
97
- ## Backend Module Rules
98
- For production modules, mirror this layout:
60
+ ## 后端模块规范
61
+ 推荐结构:
99
62
  ```
100
63
  apps/server/internal/modules/<module>/
101
64
  module.go
@@ -107,7 +70,7 @@ apps/server/internal/modules/<module>/
107
70
  bootstrap/seeds/
108
71
  ```
109
72
 
110
- Module interface (simplified):
73
+ 模块接口:
111
74
  ```go
112
75
  type Module interface {
113
76
  Name() string
@@ -120,15 +83,26 @@ type Module interface {
120
83
  }
121
84
  ```
122
85
 
123
- Register modules and enable them via `config.yaml` (`modules.enabled`).
124
- Keep the enabled list aligned with `app.config.ts`.
86
+ ## 模块注册与启用
87
+ - `apps/server/internal/modules/manifest.go` 注册模块。
88
+ - 在 `apps/server/config.yaml` 的 `modules.enabled` 启用模块。
89
+ - Web 端 `app.config.ts` 保持同名启用列表。
90
+
91
+ ## 迁移 / 种子 / 权限
92
+ - `startup.InitializeDatabase` 统一执行:核心迁移 + 模块迁移 + 种子 + 权限注册。
93
+ - 模块权限通过 `RegisterPermissions` 注入。
94
+
95
+ ## 任务与队列
96
+ - Worker 在 `cmd/server/main.go` 启动。
97
+ - 模块通过 `RegisterJobs` 注册任务处理器。
98
+ - 队列配置在 `apps/server/config.yaml` 的 `queue` 部分。
125
99
 
126
- ## Routing and Responses (Server)
127
- - Mount API under `/api/v1`.
128
- - Use auth, rbac, and tenant guards consistently across module routes.
129
- - Use `github.com/robsuncn/keystone/api/response` helpers for JSON responses.
100
+ ## 嵌入式前端
101
+ - Vite `build.outDir` 指向 `apps/server/internal/frontend/dist`。
102
+ - Go 通过 `//go:embed` 嵌入前端产物。
103
+ - 保留 `apps/server/internal/frontend/dist/.gitkeep`,避免 embed 找不到目录。
130
104
 
131
105
  ## Testing
132
- - Web: `apps/web/tests/{unit,component,e2e,perf}` with `*.test.ts(x)`.
133
- - Server: `apps/server/tests/{unit,integration,e2e,fixtures}` with `*_test.go`.
134
- - Run `go test ./...` for server changes; add a web test runner when needed.
106
+ - Web:`pnpm -C apps/web test`(Vitest)。
107
+ - Server:`go -C apps/server test ./...`。
108
+ - 全量:`pnpm test`。
@@ -3,9 +3,21 @@
3
3
  "private": true,
4
4
  "version": "0.1.0",
5
5
  "scripts": {
6
- "dev": "pnpm -C apps/web dev",
6
+ "dev": "node scripts/dev.js",
7
+ "build": "node scripts/build.js",
8
+ "build:web": "pnpm --filter web build",
9
+ "test": "node scripts/test.js",
10
+ "lint": "pnpm --filter web lint",
11
+ "format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md,yml,yaml}\"",
12
+ "clean": "node scripts/clean.js",
7
13
  "web:dev": "pnpm -C apps/web dev",
8
- "server:dev": "go -C apps/server run ."
14
+ "server:dev": "go -C apps/server run ./cmd/server",
15
+ "prepare": "husky"
16
+ },
17
+ "devDependencies": {
18
+ "husky": "^9.1.7",
19
+ "lint-staged": "^16.2.7",
20
+ "prettier": "^3.7.4"
9
21
  },
10
22
  "packageManager": "pnpm@9.15.0"
11
- }
23
+ }