openxiangda 1.0.22 → 1.0.24
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 +28 -10
- package/lib/cli.js +271 -11
- package/lib/workspace-init.js +13 -0
- package/openxiangda-skills/SKILL.md +25 -10
- package/openxiangda-skills/references/architecture-patterns.md +44 -22
- package/openxiangda-skills/references/best-practices.md +163 -0
- package/openxiangda-skills/references/pages/workspace-structure.md +5 -3
- package/openxiangda-skills/references/workspace-state.md +6 -0
- package/openxiangda-skills/skills/openxiangda-app/SKILL.md +11 -7
- package/openxiangda-skills/skills/openxiangda-core/SKILL.md +22 -4
- package/openxiangda-skills/skills/openxiangda-form/SKILL.md +6 -1
- package/openxiangda-skills/skills/openxiangda-page/SKILL.md +7 -1
- package/openxiangda-skills/skills/openxiangda-permission-settings/SKILL.md +3 -0
- package/openxiangda-skills/skills/openxiangda-workflow-automation/SKILL.md +7 -0
- package/package.json +1 -1
- package/templates/sy-lowcode-app-workspace/examples/best-practices/README.md +32 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/catalog.json +61 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/decision-guide.md +44 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/design-style.md +30 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/module-structure.md +48 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/index.ts +2 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/permissions.test.ts +35 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/permissions.ts +24 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/types.ts +17 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/index.ts +4 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/permissions.test.ts +42 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/permissions.ts +23 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/state-machine.test.ts +63 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/state-machine.ts +73 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/ticket-query.test.ts +34 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/ticket-query.ts +73 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/types.ts +64 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/app-role/page.tsx +1 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/app-role/schema.ts +57 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/customer-profile/page.tsx +1 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/customer-profile/schema.ts +83 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/service-ticket/page.tsx +1 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/service-ticket/schema.ts +97 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/ticket-action-log/page.tsx +1 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/ticket-action-log/schema.ts +65 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/js-code-nodes/daily_ticket_digest/index.ts +44 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/js-code-nodes/sync_roles_to_platform/index.ts +33 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/App.tsx +7 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/WorkbenchPage.tsx +36 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/components/ConfigPanel.tsx +34 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/components/PreviewPanel.tsx +17 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/index.tsx +10 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/page.config.ts +9 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/reducer.ts +29 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/styles.css +24 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/App.tsx +7 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/MobilePortalShell.tsx +31 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/index.tsx +10 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/modules/MobileHome.tsx +13 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/page.config.ts +14 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/routes.ts +13 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/styles.css +11 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/App.tsx +7 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/PcPortalShell.tsx +35 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/components/PortalMetric.tsx +11 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/index.tsx +10 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/modules/HomeModule.tsx +25 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/modules/TicketsModule.tsx +14 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/page.config.ts +14 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/routes.ts +19 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/styles.css +35 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/App.tsx +7 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/TicketOpsPage.tsx +105 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/components/TicketActionTimeline.tsx +22 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/components/TicketDetailDrawer.tsx +41 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/components/TicketTableActions.tsx +55 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/index.tsx +10 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/page.config.ts +9 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/styles.css +35 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/automations/daily-ticket-digest/automation.json +25 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/automations/daily-ticket-digest/trigger.json +9 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/notifications/daily-ticket-digest.json +24 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/permissions/form-groups/service-ticket-college.json +21 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/permissions/roles.json +17 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/workflows/expense-approval-workflow.json +48 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/ConfirmAction.tsx +22 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/QueryState.tsx +37 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/StatusTag.tsx +20 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/hooks/useTicketOps.ts +96 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/services/role-governance.ts +48 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/services/service-ticket.ts +113 -0
- package/templates/sy-lowcode-app-workspace/package.json +1 -0
- package/templates/sy-lowcode-app-workspace/src/dev/App.tsx +11 -1
- package/templates/sy-lowcode-app-workspace/tsconfig.examples.json +24 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# OpenXiangda Best Practices
|
|
2
|
+
|
|
3
|
+
Use this reference before scaffolding a real app, a complex page, a data
|
|
4
|
+
management view, a portal shell, role governance, notification automation, or a
|
|
5
|
+
business lifecycle flow.
|
|
6
|
+
|
|
7
|
+
The workspace template includes examples under:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
examples/best-practices/
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
These examples are copied by `openxiangda workspace init`, but they are not
|
|
14
|
+
published by default. Copy only the selected pattern into `src/`, then adapt the
|
|
15
|
+
form codes, field names, permissions, and page route names.
|
|
16
|
+
|
|
17
|
+
## AI Development Flow
|
|
18
|
+
|
|
19
|
+
1. Choose the architecture before writing code:
|
|
20
|
+
- normal form
|
|
21
|
+
- custom form page
|
|
22
|
+
- data management page
|
|
23
|
+
- custom data management page
|
|
24
|
+
- app-shell PC portal
|
|
25
|
+
- app-shell mobile portal
|
|
26
|
+
- pure interactive workbench
|
|
27
|
+
- business status lifecycle
|
|
28
|
+
- real approval workflow
|
|
29
|
+
- automation / JS_CODE
|
|
30
|
+
- role governance / permissions
|
|
31
|
+
2. Read the matching files in `examples/best-practices/`.
|
|
32
|
+
3. Copy the smallest useful slice into `src/`.
|
|
33
|
+
4. Keep view code thin; put reusable business logic in `domain/` and platform
|
|
34
|
+
calls in `shared/services/`.
|
|
35
|
+
5. Run `pnpm examples:check` while changing examples, and `pnpm check` after
|
|
36
|
+
copying code into the app source.
|
|
37
|
+
|
|
38
|
+
## State Flow Is Not Workflow
|
|
39
|
+
|
|
40
|
+
Most business processes are status lifecycles, not approval workflows.
|
|
41
|
+
|
|
42
|
+
Use a normal form plus:
|
|
43
|
+
|
|
44
|
+
- a `status` field
|
|
45
|
+
- responsibility fields such as `ownerUserId`, `ownerDeptId`, `collegeId`,
|
|
46
|
+
`classId`
|
|
47
|
+
- an action log form
|
|
48
|
+
- a pure state machine in `domain/<feature>/state-machine.ts`
|
|
49
|
+
- a service method that changes status and writes the log in one path
|
|
50
|
+
- optional automation / JS_CODE for timed reminders or backend follow-up
|
|
51
|
+
|
|
52
|
+
Use workflow only when there are real approval tasks:
|
|
53
|
+
|
|
54
|
+
- approver assignment
|
|
55
|
+
- agree / reject / transfer / countersign behavior
|
|
56
|
+
- approval opinions
|
|
57
|
+
- node-level permissions
|
|
58
|
+
- process task records and audit requirements
|
|
59
|
+
- notification or JS_CODE nodes tied to approval nodes
|
|
60
|
+
|
|
61
|
+
Do not model ordinary "pending -> processing -> resolved -> closed" state
|
|
62
|
+
changes as workflow forms.
|
|
63
|
+
|
|
64
|
+
## Layering Rules
|
|
65
|
+
|
|
66
|
+
Use this dependency direction:
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
pages/forms -> shared -> domain
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- `domain/<feature>/`: pure TypeScript business types, state machine,
|
|
73
|
+
permission predicates, and query condition builders. No React, Ant Design,
|
|
74
|
+
runtime SDK, CSS, or platform IDs.
|
|
75
|
+
- `shared/services/<feature>.ts`: SDK/API access, paginated queries, status
|
|
76
|
+
updates, log writes, resource calls.
|
|
77
|
+
- `shared/hooks/<feature>/`: loading, refresh, submit pending, error handling,
|
|
78
|
+
optimistic or rollback behavior.
|
|
79
|
+
- `shared/components/`: reusable empty, loading, error, status tag,
|
|
80
|
+
confirmation, timeline, and list action components.
|
|
81
|
+
- `pages/<feature>/components/`: page-local reusable components.
|
|
82
|
+
- `pages/<feature>/styles.css`: page CSS namespace. Do not put all styling in
|
|
83
|
+
TSX.
|
|
84
|
+
- `pages/<feature>/index.tsx`: entry and composition only. Avoid large business
|
|
85
|
+
logic blocks here.
|
|
86
|
+
|
|
87
|
+
PC and mobile pages may have different layout/components, but must reuse the
|
|
88
|
+
same `domain/` and `shared/services/` when the business behavior is the same.
|
|
89
|
+
|
|
90
|
+
## Module Size Rules
|
|
91
|
+
|
|
92
|
+
- Avoid single-file pages. A page file over about 250 lines should be split.
|
|
93
|
+
- Move table columns, filter definitions, route configs, status configs, and
|
|
94
|
+
action visibility rules into separate files.
|
|
95
|
+
- Do not let page components assemble complex API payloads directly. Call a hook
|
|
96
|
+
or service.
|
|
97
|
+
- Keep shared modules independent from specific page folders.
|
|
98
|
+
- Keep domain functions unit-testable without a browser or platform runtime.
|
|
99
|
+
|
|
100
|
+
## Permission And Data Isolation
|
|
101
|
+
|
|
102
|
+
For apps with dynamic roles:
|
|
103
|
+
|
|
104
|
+
1. Create an app role maintenance form, such as `app-role`.
|
|
105
|
+
2. Use automation / JS_CODE to sync role records to platform roles.
|
|
106
|
+
3. Add redundant ownership fields to business forms, for example:
|
|
107
|
+
- `collegeId`
|
|
108
|
+
- `classId`
|
|
109
|
+
- `ownerDeptId`
|
|
110
|
+
- `ownerUserId`
|
|
111
|
+
- `roleCode`
|
|
112
|
+
4. Create page permission groups for entry visibility.
|
|
113
|
+
5. Create form permission groups with condition-based data permissions for real
|
|
114
|
+
data isolation.
|
|
115
|
+
|
|
116
|
+
Frontend button hiding is only user experience. It is not permission control.
|
|
117
|
+
Every sensitive action must still be protected by platform role/form permission
|
|
118
|
+
groups or backend-side JS_CODE checks.
|
|
119
|
+
|
|
120
|
+
## Query Performance
|
|
121
|
+
|
|
122
|
+
- Always use paginated APIs with `currentPage`, `pageSize`, sort, and structured
|
|
123
|
+
conditions.
|
|
124
|
+
- Do not fetch a huge page and filter in the browser.
|
|
125
|
+
- Do not default to `searchKeyWord`. It is broad and expensive.
|
|
126
|
+
- For multi-field fuzzy search, build `filterGroup` with `OR` across explicit
|
|
127
|
+
fields.
|
|
128
|
+
- Put query construction in `domain/<feature>/ticket-query.ts` or the service
|
|
129
|
+
layer, not inside JSX.
|
|
130
|
+
- Keep current table/list data visible during refresh and show local refresh
|
|
131
|
+
state to avoid flicker.
|
|
132
|
+
|
|
133
|
+
## Interaction Rules
|
|
134
|
+
|
|
135
|
+
- Every list/detail page needs loading, empty, error, refresh, and submit-pending
|
|
136
|
+
states.
|
|
137
|
+
- Destructive or state-changing actions need confirmation.
|
|
138
|
+
- Show processing feedback and success/failure feedback.
|
|
139
|
+
- On failure, refresh or rollback the affected row instead of leaving stale UI.
|
|
140
|
+
- Keep interaction styles consistent across PC and mobile, but do not force the
|
|
141
|
+
same layout component onto both viewports.
|
|
142
|
+
|
|
143
|
+
## Template Catalog
|
|
144
|
+
|
|
145
|
+
- `customer-profile`: standard form schema with validation, members,
|
|
146
|
+
departments, attachments, and child table.
|
|
147
|
+
- `service-ticket-lifecycle`: status lifecycle with ticket form, action-log
|
|
148
|
+
form, state machine, service layer, and operation log.
|
|
149
|
+
- `service-ticket-ops`: custom data management page based on
|
|
150
|
+
`DataManagementList`, split into page, components, hook, query builder, and
|
|
151
|
+
detail drawer.
|
|
152
|
+
- `role-governance`: role maintenance form, role sync JS_CODE, redundant
|
|
153
|
+
ownership fields, and permission-group resource examples.
|
|
154
|
+
- `pc-portal-shell`: app-shell PC portal with routes, modules, components, and
|
|
155
|
+
services.
|
|
156
|
+
- `mobile-portal-shell`: app-shell mobile portal with mobile-only components
|
|
157
|
+
reusing the same domain/service layer.
|
|
158
|
+
- `interactive-workbench`: pure interactive page with reducer, modular panels,
|
|
159
|
+
preview, loading/error, and batch operations.
|
|
160
|
+
- `expense-approval-workflow`: real approval workflow example; use only for
|
|
161
|
+
approval scenarios.
|
|
162
|
+
- `daily-ticket-digest`: automation / JS_CODE example for paginated overdue
|
|
163
|
+
query, notification, and log writing.
|
|
@@ -5,16 +5,18 @@ Form pages, workflow form pages, and custom code pages live in `sy-lowcode-app-w
|
|
|
5
5
|
Create a new workspace with:
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
openxiangda workspace init ./my-app-workspace
|
|
8
|
+
openxiangda workspace init ./my-app-workspace --profile <name> --app-name "应用名称"
|
|
9
9
|
cd ./my-app-workspace
|
|
10
10
|
pnpm install
|
|
11
|
-
openxiangda workspace bind --profile <name> --app-type APP_XXXX
|
|
12
11
|
```
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
Local workspace state is authoritative. If the current folder has no app binding, create a new app; do not search the platform for similar app names.
|
|
14
|
+
|
|
15
|
+
Bind an existing app only when the user explicitly provides `appType` or asks to reuse that app:
|
|
15
16
|
|
|
16
17
|
```bash
|
|
17
18
|
openxiangda workspace init ./my-app-workspace --profile <name> --app-type APP_XXXX
|
|
19
|
+
openxiangda workspace bind --profile <name> --app-type APP_XXXX
|
|
18
20
|
```
|
|
19
21
|
|
|
20
22
|
Typical code page layout:
|
|
@@ -31,6 +31,10 @@ Tokens never belong in the project. User tokens live in `~/.openxiangda/profiles
|
|
|
31
31
|
"menus": {},
|
|
32
32
|
"roles": {},
|
|
33
33
|
"connectors": {},
|
|
34
|
+
"notifications": {
|
|
35
|
+
"templates": {},
|
|
36
|
+
"typeConfigs": {}
|
|
37
|
+
},
|
|
34
38
|
"pagePermissionGroups": {},
|
|
35
39
|
"formPermissionGroups": {},
|
|
36
40
|
"formSettings": {}
|
|
@@ -44,6 +48,8 @@ Tokens never belong in the project. User tokens live in `~/.openxiangda/profiles
|
|
|
44
48
|
|
|
45
49
|
- Profile is the deployment boundary.
|
|
46
50
|
- `baseUrl` is the backend API base. On standard private deployments it is `<origin>/service`; management pages use `/platform`, and app runtime pages use `/view`.
|
|
51
|
+
- Local state is authoritative for app binding. If a workspace has no `appType` for the target profile, create a new app/workspace with `openxiangda workspace init <dir> --profile <name> --app-name "应用名称"`.
|
|
52
|
+
- Do not search platform apps or reuse similar names unless the user explicitly asks to reuse an existing app or provides an `appType`.
|
|
47
53
|
- Local resource keys are logical codes.
|
|
48
54
|
- Live IDs and lightweight runtime aliases are nested under the profile that produced them.
|
|
49
55
|
- Do not store business configuration or secrets in `.openxiangda/state.json`; store those in `src/resources/`.
|
|
@@ -19,16 +19,16 @@ openxiangda auth status --profile <name>
|
|
|
19
19
|
If the workspace is not bound:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
openxiangda app
|
|
23
|
-
|
|
22
|
+
openxiangda workspace init ./my-app-workspace --profile <name> --app-name "应用名称"
|
|
23
|
+
cd ./my-app-workspace
|
|
24
|
+
pnpm install
|
|
24
25
|
```
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
Bind to an existing app only when the user explicitly provides `appType` or asks to reuse an existing platform app:
|
|
27
28
|
|
|
28
29
|
```bash
|
|
29
30
|
openxiangda workspace init ./my-app-workspace --profile <name> --app-type APP_XXX
|
|
30
|
-
|
|
31
|
-
pnpm install
|
|
31
|
+
openxiangda workspace bind --profile <name> --app-type APP_XXX
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
For menu work:
|
|
@@ -39,7 +39,7 @@ openxiangda menu create main --name "主菜单" --type nav --profile <name>
|
|
|
39
39
|
openxiangda menu create customer-entry --name "客户信息" --type receipt --form-code customer --profile <name>
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
If the app
|
|
42
|
+
If the user explicitly asks to create an app without initializing a workspace:
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
45
|
openxiangda app create "应用名称" --profile <name>
|
|
@@ -50,9 +50,11 @@ openxiangda workspace bind --profile <name> --app-type APP_XXX
|
|
|
50
50
|
|
|
51
51
|
- Never ask for AK/SK.
|
|
52
52
|
- Always pass `--profile` for publish or cross-platform operations.
|
|
53
|
-
-
|
|
53
|
+
- Local `.openxiangda/state.json` is authoritative. If the user starts from a new empty directory or the workspace has no app binding, create a new app with `openxiangda workspace init <dir> --profile <name> --app-name "应用名称"`.
|
|
54
|
+
- Do not search platform apps or reuse similar app names unless the user explicitly asks to reuse an existing app or gives an `appType`.
|
|
54
55
|
- Store platform-specific IDs only in `.openxiangda/state.json`.
|
|
55
56
|
- Use logical local codes for forms, pages, workflows, automations, and menus.
|
|
57
|
+
- Before scaffolding a new business app, read `../../references/best-practices.md` and pick an architecture from the initialized `examples/best-practices/` catalog. Do not generate a large single-file app page when a template pattern already covers the scenario.
|
|
56
58
|
- Use `openxiangda app snapshot <APP_XXX> --profile <name> --json` before changing an existing app.
|
|
57
59
|
|
|
58
60
|
## Resource State
|
|
@@ -62,3 +64,5 @@ Read `../../references/workspace-state.md` when changing `.openxiangda/state.jso
|
|
|
62
64
|
Read `../../references/openxiangda-api.md` when exact endpoint fields are needed.
|
|
63
65
|
|
|
64
66
|
Read `../../references/architecture-patterns.md` to understand the overall app structure (how forms, pages, menus, workflows, and permissions compose into an app, and the recommended `src/forms` / `src/pages` layout) before scaffolding or restructuring an app workspace.
|
|
67
|
+
|
|
68
|
+
Read `../../references/best-practices.md` before implementing app-level patterns such as status lifecycles, role governance, PC/mobile portals, high-performance data management pages, workflow boundaries, and automation.
|
|
@@ -40,22 +40,35 @@ Use `--profile` for every destructive or publishing action. Treat the profile as
|
|
|
40
40
|
|
|
41
41
|
Run write commands sequentially in the same workspace because they update `.openxiangda/state.json`. Read-only commands such as list, pull, snapshot, and inspect may run in parallel.
|
|
42
42
|
|
|
43
|
+
## Updates
|
|
44
|
+
|
|
45
|
+
Use the official npm registry for OpenXiangda package updates because domestic mirrors may lag:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install -g openxiangda@latest --registry=https://registry.npmjs.org
|
|
49
|
+
openxiangda update check --json
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
At the start of substantial work, run `openxiangda update check --json`. If `updateAvailable` is true, run `openxiangda update install` before generating or publishing so the CLI and installed skills stay compatible. If the installed CLI does not support `update`, reinstall with the official registry command above, then run `openxiangda skill install --force`.
|
|
53
|
+
|
|
43
54
|
## Workspace State
|
|
44
55
|
|
|
45
56
|
Create a workspace when the current project does not already contain a `sy-lowcode-app-workspace`:
|
|
46
57
|
|
|
47
58
|
```bash
|
|
48
|
-
openxiangda workspace init ./my-app-workspace --profile dev --app-
|
|
59
|
+
openxiangda workspace init ./my-app-workspace --profile dev --app-name "测试应用"
|
|
49
60
|
cd ./my-app-workspace
|
|
50
61
|
pnpm install
|
|
51
62
|
openxiangda env --profile dev
|
|
52
63
|
```
|
|
53
64
|
|
|
54
|
-
If the
|
|
65
|
+
Local workspace state is authoritative. If `.openxiangda/state.json` already contains an app binding for the target profile, use it. If there is no local binding, create a new app with `workspace init --app-name`; do not search platform apps for similar names.
|
|
66
|
+
|
|
67
|
+
After workspace initialization, inspect `examples/best-practices/` before generating a real app. The examples are copied locally but are not published by default; copy only the selected pattern into `src/`.
|
|
68
|
+
|
|
69
|
+
If the workspace already exists and the user explicitly provides an existing app, bind each platform to its own app, then publish from `sy-lowcode-app-workspace`:
|
|
55
70
|
|
|
56
71
|
```bash
|
|
57
|
-
openxiangda app list --profile dev
|
|
58
|
-
openxiangda app create "测试应用" --profile dev
|
|
59
72
|
openxiangda workspace bind --profile dev --app-type APP_DEV
|
|
60
73
|
openxiangda workspace bind --profile prod --app-type APP_PROD
|
|
61
74
|
cd /path/to/sy-lowcode-app-workspace
|
|
@@ -96,6 +109,10 @@ Project state is stored in `.openxiangda/state.json`:
|
|
|
96
109
|
"menus": {},
|
|
97
110
|
"roles": {},
|
|
98
111
|
"connectors": {},
|
|
112
|
+
"notifications": {
|
|
113
|
+
"templates": {},
|
|
114
|
+
"typeConfigs": {}
|
|
115
|
+
},
|
|
99
116
|
"pagePermissionGroups": {},
|
|
100
117
|
"formPermissionGroups": {},
|
|
101
118
|
"formSettings": {}
|
|
@@ -145,3 +162,4 @@ The publish script is responsible for:
|
|
|
145
162
|
- `../../references/openxiangda-api.md` — exact endpoint contracts.
|
|
146
163
|
- `../../references/workspace-state.md` — `.openxiangda/state.json` shape and profile-scoped resource maps.
|
|
147
164
|
- `../../references/architecture-patterns.md` — overall architecture of an OpenXiangda app workspace (CRUD data flow, page/form layering, recommended directory organization). Read this when you need to understand how forms, pages, workflows, and platform state fit together end-to-end.
|
|
165
|
+
- `../../references/best-practices.md` — initialized best-practice templates and rules for modular pages, status lifecycles, role governance, data isolation, query performance, and workflow boundaries.
|
|
@@ -18,11 +18,13 @@ cd /path/to/sy-lowcode-app-workspace
|
|
|
18
18
|
If the workspace does not exist yet, create it before writing form source:
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
openxiangda workspace init ./my-app-workspace --profile <name> --app-
|
|
21
|
+
openxiangda workspace init ./my-app-workspace --profile <name> --app-name "应用名称"
|
|
22
22
|
cd ./my-app-workspace
|
|
23
23
|
pnpm install
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
Use `--app-type APP_XXX` only when the user explicitly provides an existing app to reuse.
|
|
27
|
+
|
|
26
28
|
Create or edit workspace source:
|
|
27
29
|
|
|
28
30
|
```text
|
|
@@ -61,10 +63,13 @@ Read these references only when writing or reviewing schema:
|
|
|
61
63
|
- `../../references/forms/layout-and-rules.md`
|
|
62
64
|
- `../../references/platform-data-model.md` — how each field type is persisted (JSONB, `{label, value}` for option fields, attachment shape). Consult before designing schema or wiring values.
|
|
63
65
|
- `../../references/component-guide.md` — when to pick platform form components vs. custom widgets, and the option-component rules.
|
|
66
|
+
- `../../references/best-practices.md` — status lifecycle fields, ownership redundancy, role-governance fields, and the boundary between normal forms and workflow forms.
|
|
64
67
|
|
|
65
68
|
## Rules
|
|
66
69
|
|
|
67
70
|
- Prefer deterministic `formCode` as local key; bind live `formUuid` under the active profile.
|
|
71
|
+
- For business lifecycles, model status with normal form fields (`status`, owner/responsibility fields, action-log relation fields) unless the scenario has real approval tasks. Do not create workflow forms for ordinary status transitions.
|
|
72
|
+
- For permission isolation, add redundant ownership fields such as `collegeId`, `classId`, `ownerDeptId`, and `ownerUserId` at schema time so form permission groups can use structured conditions later.
|
|
68
73
|
- For multi-platform publishing, create or bind the form separately for each profile.
|
|
69
74
|
- Do not copy `formUuid` from dev to prod unless the target platform explicitly already uses that ID.
|
|
70
75
|
- Keep `schema.ts` and `page.tsx` as the source for fields/layout/rules and presentation; generated build output is not the source of truth.
|
|
@@ -19,11 +19,13 @@ openxiangda workspace publish --profile <name>
|
|
|
19
19
|
If the workspace does not exist yet, initialize it first:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
openxiangda workspace init ./my-app-workspace --profile <name> --app-
|
|
22
|
+
openxiangda workspace init ./my-app-workspace --profile <name> --app-name "应用名称"
|
|
23
23
|
cd ./my-app-workspace
|
|
24
24
|
pnpm install
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
Use `--app-type APP_XXX` only when the user explicitly provides an existing app to reuse.
|
|
28
|
+
|
|
27
29
|
Direct publish is only for already built assets or targeted repair:
|
|
28
30
|
|
|
29
31
|
```bash
|
|
@@ -41,6 +43,7 @@ Read these references only when editing page code:
|
|
|
41
43
|
|
|
42
44
|
- `../../references/pages/workspace-structure.md`
|
|
43
45
|
- `../../references/pages/app-shell.md` — formal backend / PC portal / mobile portal entry pattern. Read before creating any user-facing main entry or admin console.
|
|
46
|
+
- `../../references/best-practices.md` — initialized examples for modular pages, status lifecycles, role governance, high-performance queries, portal shells, and interactive workbenches. Read before scaffolding complex pages or data management pages.
|
|
44
47
|
- `../../references/pages/page-sdk.md`
|
|
45
48
|
- `../../references/notifications.md` — notification resources and `sdk.notification` usage. Read before adding reminders, alerts, or message templates to a page.
|
|
46
49
|
- `../../references/pages/publish-flow.md`
|
|
@@ -53,6 +56,8 @@ Read these references only when editing page code:
|
|
|
53
56
|
|
|
54
57
|
- Keep `pageCode` stable and use it as the local logical key.
|
|
55
58
|
- Formal user-facing entries such as admin consoles, PC portals, and mobile portals must be app-shell code pages. Declare `entry: { mode: "app-shell", hidePlatformNav: true, defaultRoute: "<home-route>" }` in `page.config.ts`.
|
|
59
|
+
- Do not generate single-file large pages. Split complex code pages into `domain/`, `shared/services/`, `shared/hooks/`, shared/page-local `components/`, route/config files, and `styles.css` as described in `../../references/best-practices.md`.
|
|
60
|
+
- Keep view code thin. Page components call hooks/services; business rules, state transition rules, permission predicates, and query builders live outside TSX and are reusable by PC and mobile pages.
|
|
56
61
|
- Store live `pageId`, `routeKey`, and `legacyFormUuid` under the current profile only.
|
|
57
62
|
- Use `openxiangda/runtime` for platform data access instead of hardcoding backend URLs in page code.
|
|
58
63
|
- For reminders, alerts, and business messages, declare `src/resources/notifications/` first and call `sdk.notification`; do not hardcode notification API URLs.
|
|
@@ -64,6 +69,7 @@ Read these references only when editing page code:
|
|
|
64
69
|
- For prod, explicitly run with `--profile prod`; never rely on the current profile for release operations.
|
|
65
70
|
- Follow the style system in `../../references/style-system.md`: never hardcode colors, fonts, spacing, or radii — use the platform CSS variables and the page CSS namespace.
|
|
66
71
|
- For list / detail / CRUD pages, follow `../../references/architecture-patterns.md` (e.g. `DataManagementList`) before writing custom data-fetching loops.
|
|
72
|
+
- Query pages must use pagination with structured conditions. Do not fetch a large `pageSize` and filter in the browser; avoid default `searchKeyWord`, and build multi-field fuzzy search with explicit `filterGroup` + `OR`.
|
|
67
73
|
- Pick components per `../../references/component-guide.md`: prefer the platform component, fall back to Ant Design, and only build a custom component when neither fits.
|
|
68
74
|
- When a page misbehaves (lost styles, `options is undefined`, option labels showing raw values, etc.), consult `../../references/troubleshooting.md` before patching symptoms.
|
|
69
75
|
- For custom portal pages and business modals, do not temporarily embed a single `FormProvider` field component from the standard form runtime. If a standard component is required, navigate to a full standard form page or render a complete `StandardFormPage` inside a dedicated carrier route.
|
|
@@ -34,6 +34,8 @@ Use role codes in permission group JSON. Bind existing role IDs only inside the
|
|
|
34
34
|
openxiangda permission role-bind sales --role-id <id> --profile dev
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
For dynamic multi-role apps, do not hardcode role behavior only in page code. Create a role maintenance form, sync it to platform roles with automation / JS_CODE, and add redundant ownership fields to business forms (`collegeId`, `classId`, `ownerDeptId`, `ownerUserId`, `roleCode`). Use page permission groups for entry visibility and form permission groups with condition-based data permissions for real data isolation.
|
|
38
|
+
|
|
37
39
|
## Page Permission Groups
|
|
38
40
|
|
|
39
41
|
Page permission groups control menu/page visibility:
|
|
@@ -92,5 +94,6 @@ Do not store platform-specific public access IDs locally. The CLI resolves by `a
|
|
|
92
94
|
## References
|
|
93
95
|
|
|
94
96
|
- Permission model and examples: `../../references/permissions-settings.md`
|
|
97
|
+
- Dynamic role governance and data-isolation pattern: `../../references/best-practices.md`
|
|
95
98
|
- Profile-isolated IDs: `../../references/workspace-state.md`
|
|
96
99
|
- API fields: `../../references/openxiangda-api.md`
|
|
@@ -7,6 +7,12 @@ description: Build, validate, publish, enable, and inspect OpenXiangda workflow
|
|
|
7
7
|
|
|
8
8
|
Use this skill when the user asks for approval workflows, workflow forms, automation rules, scheduled jobs, form-event triggers, or process-triggered automation in OpenXiangda.
|
|
9
9
|
|
|
10
|
+
## Architecture Boundary
|
|
11
|
+
|
|
12
|
+
Most business lifecycle flows are not workflows. For ordinary status changes such as `pending -> processing -> resolved -> closed`, use a normal form, a `status` field, redundant responsibility fields, an action-log form, a domain state machine, a service method, and optional automation / JS_CODE.
|
|
13
|
+
|
|
14
|
+
Create workflow definitions only when the scenario has real approval semantics: approvers, approval tasks, agree/reject actions, approval opinions, node-level permissions, process records, or approval-node side effects.
|
|
15
|
+
|
|
10
16
|
## Required Context
|
|
11
17
|
|
|
12
18
|
Before any write:
|
|
@@ -101,6 +107,7 @@ Use `automation disable` before risky edits. Published automations create a draf
|
|
|
101
107
|
|
|
102
108
|
## References
|
|
103
109
|
|
|
110
|
+
- Best-practice architecture and status-flow boundary: `../../references/best-practices.md`
|
|
104
111
|
- Workflow v3 JSON: `../../references/workflow-v3.md`
|
|
105
112
|
- Automation v3 JSON and triggers: `../../references/automation-v3.md`
|
|
106
113
|
- Notification resources and runtime calls: `../../references/notifications.md`
|
package/package.json
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# OpenXiangda Best Practices
|
|
2
|
+
|
|
3
|
+
These examples are intentionally placed under `examples/best-practices/`.
|
|
4
|
+
They are copied by `workspace init`, but they are not scanned by
|
|
5
|
+
`lowcode-workspace build` or `openxiangda workspace publish`.
|
|
6
|
+
|
|
7
|
+
Copy the pieces you need into `src/`:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cp -R examples/best-practices/src/domain/service-ticket src/domain/
|
|
11
|
+
cp -R examples/best-practices/src/shared/services/service-ticket.ts src/shared/services/
|
|
12
|
+
cp -R examples/best-practices/src/pages/service-ticket-ops src/pages/
|
|
13
|
+
cp -R examples/best-practices/src/forms/service-ticket src/forms/
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Run `pnpm examples:check` after editing examples, and run the normal
|
|
17
|
+
`pnpm check` after copying code into `src/`.
|
|
18
|
+
|
|
19
|
+
## Core Rules
|
|
20
|
+
|
|
21
|
+
- Keep view code thin. Pages compose components, hooks, and services.
|
|
22
|
+
- Put business rules in `domain/`; keep it free of React, SDK, and UI imports.
|
|
23
|
+
- Put platform calls in `shared/services/`.
|
|
24
|
+
- Put reusable loading, empty, error, status, and confirmation UI in
|
|
25
|
+
`shared/components/`.
|
|
26
|
+
- Use state fields and operation logs for business lifecycle flows.
|
|
27
|
+
- Use workflow only for real approval tasks.
|
|
28
|
+
- Query with pagination and structured conditions. Avoid large page sizes,
|
|
29
|
+
client-side filtering, and broad `searchKeyWord` queries.
|
|
30
|
+
|
|
31
|
+
Read `decision-guide.md`, `module-structure.md`, and `design-style.md` before
|
|
32
|
+
using any template.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"publishedByDefault": false,
|
|
4
|
+
"copyInto": "src/",
|
|
5
|
+
"templates": [
|
|
6
|
+
{
|
|
7
|
+
"code": "customer-profile",
|
|
8
|
+
"type": "form",
|
|
9
|
+
"path": "src/forms/customer-profile",
|
|
10
|
+
"description": "Standard form schema covering field types, validation, users, departments, attachments, and subforms."
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"code": "service-ticket-lifecycle",
|
|
14
|
+
"type": "state-flow",
|
|
15
|
+
"path": "src/domain/service-ticket",
|
|
16
|
+
"description": "Lifecycle state machine with ticket and action-log forms. Does not use workflow."
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"code": "service-ticket-ops",
|
|
20
|
+
"type": "page",
|
|
21
|
+
"path": "src/pages/service-ticket-ops",
|
|
22
|
+
"description": "DataManagementList-based ops page with modular actions, drawer, timeline, hook, and service."
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"code": "role-governance",
|
|
26
|
+
"type": "permissions",
|
|
27
|
+
"path": "src/domain/role-governance",
|
|
28
|
+
"description": "Dynamic role maintenance, role sync, redundant ownership fields, and permission-group resource examples."
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"code": "pc-portal-shell",
|
|
32
|
+
"type": "app-shell-page",
|
|
33
|
+
"path": "src/pages/pc-portal-shell",
|
|
34
|
+
"description": "PC app-shell entry with routes, modules, shared domain usage, and no hardcoded view URLs."
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"code": "mobile-portal-shell",
|
|
38
|
+
"type": "app-shell-page",
|
|
39
|
+
"path": "src/pages/mobile-portal-shell",
|
|
40
|
+
"description": "Mobile app-shell entry sharing domain/service logic with the PC portal."
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"code": "interactive-workbench",
|
|
44
|
+
"type": "page",
|
|
45
|
+
"path": "src/pages/interactive-workbench",
|
|
46
|
+
"description": "Pure interaction workbench with reducer state, modular panels, and unified query states."
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"code": "expense-approval-workflow",
|
|
50
|
+
"type": "workflow",
|
|
51
|
+
"path": "src/resources/workflows/expense-approval-workflow.json",
|
|
52
|
+
"description": "True approval workflow example. Use only when approval tasks are required."
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"code": "daily-ticket-digest",
|
|
56
|
+
"type": "automation",
|
|
57
|
+
"path": "src/resources/automations/daily-ticket-digest",
|
|
58
|
+
"description": "Scheduled JS_CODE automation that queries paginated data and sends notification resources."
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Decision Guide
|
|
2
|
+
|
|
3
|
+
## Page And Data Shape
|
|
4
|
+
|
|
5
|
+
Use a form when you need a data table. Each form schema defines fields,
|
|
6
|
+
validation, storage shape, and generated platform data APIs.
|
|
7
|
+
|
|
8
|
+
Use a code page when you need a workbench, portal, dashboard, cross-form
|
|
9
|
+
composition, custom list actions, or complex interaction.
|
|
10
|
+
|
|
11
|
+
Use `DataManagementList` for list/search/export/batch-management pages. Extend
|
|
12
|
+
it with row actions, custom renderers, and drawers instead of rebuilding
|
|
13
|
+
pagination, export, and filters from scratch.
|
|
14
|
+
|
|
15
|
+
## State Flow Is Not Workflow
|
|
16
|
+
|
|
17
|
+
Most business "processes" are lifecycle state changes:
|
|
18
|
+
|
|
19
|
+
- work tickets: new -> accepted -> processing -> resolved -> closed
|
|
20
|
+
- orders: draft -> submitted -> paid -> fulfilled -> completed
|
|
21
|
+
- assets: available -> reserved -> in_use -> maintenance -> retired
|
|
22
|
+
|
|
23
|
+
Use a normal form with a `status` field, ownership fields, and an operation-log
|
|
24
|
+
form. Define allowed transitions in `domain/<feature>/state-machine.ts`, and
|
|
25
|
+
execute changes through a service method that updates state and writes logs.
|
|
26
|
+
|
|
27
|
+
Use workflow only when the platform must create approval tasks with approvers,
|
|
28
|
+
approval comments, agree/reject actions, copy nodes, node field permissions, and
|
|
29
|
+
approval history.
|
|
30
|
+
|
|
31
|
+
## Automation And JS_CODE
|
|
32
|
+
|
|
33
|
+
Use automation or workflow JS_CODE when logic must run on the backend after a
|
|
34
|
+
trigger: scheduled scans, cross-form synchronization, notification fan-out,
|
|
35
|
+
external HTTP calls, or platform role synchronization.
|
|
36
|
+
|
|
37
|
+
Frontend code must not be responsible for data isolation or background jobs.
|
|
38
|
+
|
|
39
|
+
## Permissions
|
|
40
|
+
|
|
41
|
+
For dynamic multi-role apps, create a business role table and synchronize it to
|
|
42
|
+
platform app roles. Add redundant ownership fields to business forms, such as
|
|
43
|
+
`collegeId`, `classId`, `ownerDeptId`, and `ownerUserId`. Use form permission
|
|
44
|
+
groups with condition-style data permissions to enforce data isolation.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Design Style
|
|
2
|
+
|
|
3
|
+
OpenXiangda business apps should feel like focused operational tools.
|
|
4
|
+
|
|
5
|
+
## Interaction Defaults
|
|
6
|
+
|
|
7
|
+
- Every async page has loading, refreshing, empty, error, and submit-pending
|
|
8
|
+
states.
|
|
9
|
+
- List refresh should keep existing rows visible and show a small refresh state.
|
|
10
|
+
- Mutating actions need confirmation, pending feedback, success feedback, and a
|
|
11
|
+
failure refresh or rollback path.
|
|
12
|
+
- Mobile actions should use a bottom action area, drawer, or action sheet; do
|
|
13
|
+
not copy a dense PC table toolbar to mobile.
|
|
14
|
+
|
|
15
|
+
## Layout Defaults
|
|
16
|
+
|
|
17
|
+
- Use dense but readable workbench layouts for admin and ops pages.
|
|
18
|
+
- Put high-value filters near the list, not in hidden configuration pages.
|
|
19
|
+
- Use status tags, responsibility fields, and latest action summaries for
|
|
20
|
+
lifecycle data.
|
|
21
|
+
- Do not build marketing-style hero pages for business tools.
|
|
22
|
+
|
|
23
|
+
## Styling Rules
|
|
24
|
+
|
|
25
|
+
- Use platform CSS variables, Tailwind semantic classes, Ant Design, and
|
|
26
|
+
antd-mobile.
|
|
27
|
+
- Keep page styles in `styles.css`; avoid large inline style objects.
|
|
28
|
+
- Keep reusable visual states in shared components: status tags, query states,
|
|
29
|
+
confirmation triggers, and operation timelines.
|
|
30
|
+
- Do not override private Ant Design class names.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Module Structure
|
|
2
|
+
|
|
3
|
+
Use this structure for substantial features:
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
src/
|
|
7
|
+
domain/<feature>/
|
|
8
|
+
types.ts
|
|
9
|
+
state-machine.ts
|
|
10
|
+
permissions.ts
|
|
11
|
+
query.ts
|
|
12
|
+
index.ts
|
|
13
|
+
shared/
|
|
14
|
+
services/<feature>.ts
|
|
15
|
+
hooks/use<Feature>.ts
|
|
16
|
+
components/
|
|
17
|
+
QueryState.tsx
|
|
18
|
+
StatusTag.tsx
|
|
19
|
+
pages/<feature>/
|
|
20
|
+
page.config.ts
|
|
21
|
+
index.tsx
|
|
22
|
+
App.tsx
|
|
23
|
+
styles.css
|
|
24
|
+
components/
|
|
25
|
+
forms/<feature>/
|
|
26
|
+
schema.ts
|
|
27
|
+
page.tsx
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Dependency Direction
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
pages -> shared/hooks -> shared/services -> domain
|
|
34
|
+
forms -> shared -> domain
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- `domain/` has no React, Ant Design, SDK, or page imports.
|
|
38
|
+
- `shared/` does not import from `pages/`.
|
|
39
|
+
- `pages/` compose modules and call hooks; they do not build complex query
|
|
40
|
+
payloads inline.
|
|
41
|
+
- PC and mobile views can have different components and styles, but they reuse
|
|
42
|
+
the same domain and service logic.
|
|
43
|
+
|
|
44
|
+
## File Size
|
|
45
|
+
|
|
46
|
+
Avoid large single-file pages. If a page grows beyond roughly 250 lines, split
|
|
47
|
+
table actions, drawers, timelines, query builders, hooks, and styles into
|
|
48
|
+
separate files.
|