openxiangda 1.0.135 → 1.0.136

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 (22) hide show
  1. package/lib/design-gates.js +40 -10
  2. package/openxiangda-skills/SKILL.md +7 -1
  3. package/openxiangda-skills/references/best-practices.md +32 -5
  4. package/openxiangda-skills/references/openxiangda-api.md +32 -6
  5. package/openxiangda-skills/references/permission-design-patterns.md +216 -0
  6. package/openxiangda-skills/references/permissions-settings.md +58 -0
  7. package/openxiangda-skills/references/resource-manifest-cheatsheet.md +32 -1
  8. package/openxiangda-skills/skills/openxiangda-architecture-design/SKILL.md +8 -0
  9. package/openxiangda-skills/skills/openxiangda-permission-settings/SKILL.md +38 -1
  10. package/package.json +1 -1
  11. package/templates/openxiangda-react-spa/.cursor/rules/openxiangda.mdc +7 -1
  12. package/templates/openxiangda-react-spa/.qoder/rules/openxiangda.md +7 -1
  13. package/templates/openxiangda-react-spa/AGENTS.md +6 -1
  14. package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda-resources.mdc +5 -1
  15. package/templates/sy-lowcode-app-workspace/.cursor/rules/openxiangda.mdc +6 -1
  16. package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda-resources.md +6 -0
  17. package/templates/sy-lowcode-app-workspace/.qoder/rules/openxiangda.md +6 -1
  18. package/templates/sy-lowcode-app-workspace/AGENTS.md +6 -1
  19. package/templates/sy-lowcode-app-workspace/examples/best-practices/README.md +3 -0
  20. package/templates/sy-lowcode-app-workspace/examples/best-practices/access-governance.md +239 -0
  21. package/templates/sy-lowcode-app-workspace/examples/best-practices/catalog.json +6 -0
  22. package/templates/sy-lowcode-app-workspace/examples/best-practices/decision-guide.md +25 -1
@@ -112,28 +112,51 @@ const DESIGN_GATE_TOPICS = [
112
112
  },
113
113
  {
114
114
  code: 'permissions',
115
- title: '角色 / 页面权限 / 表单数据范围',
116
- triggers: ['权限', '角色', '数据范围', '只看自己', '部门数据', '页面权限', '字段权限'],
115
+ title: '账号 / 角色 / 页面权限 / 表单数据范围',
116
+ triggers: ['权限', '角色', 'RBAC', '账号权限', '平台账号', '组织账号', '角色治理', '数据范围', '只看自己', '部门数据', '页面权限', '字段权限', '查询参数权限'],
117
117
  mustAsk: [
118
- '角色清单及成员来源:固定成员、组织部门、外部角色',
119
- '页面、菜单、公开路由分别开放给哪些角色',
120
- '每个表单的 submit/view/manage 操作和字段权限',
121
- '数据范围是全部、本人、部门、自定义条件还是公开 grant',
122
- '验收时需要模拟哪些角色和拒绝场景',
118
+ '权限模式选择:managed-platform-account、existing-platform-user-assignment、static-role-permission、query-param-context 中哪一种,为什么',
119
+ '账号来源是什么:应用创建平台账号/部门、选择已有平台用户、固定角色成员,还是仅使用低风险查询参数上下文',
120
+ '是否创建或维护平台账号/部门;如果是,哪些 App Function/organization SDK 负责创建、更新、重置密码和同步审计',
121
+ '角色成员如何维护:角色分配表、平台角色手工维护、静态 roles manifest、还是公开访问 externalRoleCodes',
122
+ '哪些角色可以设置应用角色、分配角色成员、给角色分配接口权限;这些角色是否需要 `app:role:manage`',
123
+ '哪些角色可以维护页面权限组、表单权限组、组织账号;是否需要 `app:page-permission-group:manage`、`app:form-permission-group:manage`、`app:organization:manage`',
124
+ '业务范围字段是什么,哪些可见字段需要派生隐藏 scalar key 供表单权限条件匹配',
125
+ '页面/菜单/路由、表单 submit/view/manage/fieldAccessPolicy/dataScope 的权限矩阵如何落到 resources',
126
+ '查询参数是否参与授权;如果参与,只能做上下文、筛选或 ticket 输入,敏感数据必须由 public-access grant、角色、表单权限组或 App Function 校验',
127
+ '验收时需要模拟哪些角色、账号状态、业务范围、查询参数篡改和拒绝场景',
123
128
  ],
124
129
  recommendedDefaults: [
125
- '角色写 src/resources/roles,页面组写 permissions/page-groups',
126
- '表单权限组写 permissions/form-groups,显式声明 dataScope/operations',
127
- '公开访问不要复用内部管理员权限组',
130
+ '正式后台优先选择 managed-platform-account;如果平台账号已存在,选择 existing-platform-user-assignment;固定内部门户选择 static-role-permission',
131
+ 'query-param-context 仅用于低风险页面上下文、筛选条件或公开 ticket 输入,不作为敏感数据授权依据',
132
+ '角色写 src/resources/roles,页面组写 permissions/page-groups,表单组写 permissions/form-groups,显式声明 dataScope/operations/fieldAccessPolicy',
133
+ '能管理角色或给别人分配角色的应用角色必须在 roles manifest 声明 apiPermissionCodes;至少包含 app:role:manage,按需加入 app:page-permission-group:manage、app:form-permission-group:manage、app:organization:manage',
134
+ '由校区管理员等委托管理员创建的新角色,如果还具备继续管理账号/角色/权限的能力,也必须同步声明并发布对应 apiPermissionCodes',
135
+ '账号治理闭环使用 organization_unit、system_account、role_assignment 等业务表,加 roles、page groups、form groups、sync App Functions 和 PermissionBoundary',
136
+ '平台账号创建、更新、重置密码只走 sdk.organization/ctx.organization;操作者必须具备 app:organization:manage',
137
+ '公开访问不要复用内部管理员权限组;公开数据仍需 public-access grants 与外部角色权限组双重覆盖',
128
138
  ],
129
139
  antiPatterns: [
140
+ '不能只做前端权限隐藏,必须有后端角色、表单权限组、public-access grant 或 App Function 校验',
141
+ '查询参数不能作为敏感授权依据,只能作为上下文、筛选或 ticket 输入',
130
142
  '只配菜单可见,不配后端数据权限',
131
143
  '为了省事授予全部数据再在前端过滤',
144
+ '在页面里硬编码角色、账号、部门或权限范围',
145
+ '只给用户挂业务角色但没有给该角色绑定角色设置接口权限,导致后续新增账号/角色时运行时报无权限',
146
+ '让普通管理员创建带管理能力的新角色,但没有同时发布新角色的 apiPermissionCodes',
147
+ '前端模拟权限通过、mock role、假账号、假 ID 或空数组兜底',
148
+ '直接绕过 SDK 调平台账号/组织写接口,或用旧 /user、/department 接口写账号',
132
149
  '公开角色和内部角色混用',
133
150
  ],
134
151
  acceptance: [
135
152
  'permission audit 输出无高危缺口',
153
+ '设计文档写明权限模式、账号来源、角色成员来源和权限矩阵',
154
+ '角色资源中声明了管理型角色的 apiPermissionCodes,并说明由谁首次授予',
136
155
  '内部角色允许项可用,未授权项拒绝',
156
+ '用非授权角色验证角色创建/成员分配/权限组维护会被拒绝,用授权角色验证可成功',
157
+ '敏感 App Function 包含服务端 role/scope checks,且不信任页面传入的 roleCodes',
158
+ '平台账号治理路径验证当前操作者拥有 app:organization:manage',
159
+ '查询参数篡改不会扩大敏感数据访问范围',
137
160
  '公开访问受 public-access grant 和权限组双重约束',
138
161
  ],
139
162
  },
@@ -236,6 +259,13 @@ const DESIGN_GATE_TOPIC_ALIASES = {
236
259
  permission: 'permissions',
237
260
  role: 'permissions',
238
261
  roles: 'permissions',
262
+ rbac: 'permissions',
263
+ 'role-governance': 'permissions',
264
+ 'account-permission': 'permissions',
265
+ 'organization-account': 'permissions',
266
+ 'org-account': 'permissions',
267
+ 'account-role': 'permissions',
268
+ 'query-param-permission': 'permissions',
239
269
  workflow: 'workflow-automation',
240
270
  automation: 'workflow-automation',
241
271
  function: 'workflow-automation',
@@ -29,7 +29,7 @@ OpenXiangda supports two workspace modes. Classic `sy-lowcode-app-workspace` pub
29
29
  | 自动化 / 定时任务 / 提交触发 / cron | `openxiangda-workflow-automation` | `openxiangda automation validate / create / publish / enable` |
30
30
  | App Function / function_call / 可复用后端逻辑 | `openxiangda-workflow-automation` | declare `src/resources/functions/<code>.json` + `src/functions/<code>/index.ts` |
31
31
  | 应用登录 / Auth SDK / 手机号验证码 / CAS / 钉钉免登 | `openxiangda-architecture-design` + `openxiangda-page` | design security gate first, then declare `src/resources/auth/<code>.json` and use `createAuthClient` / `LoginPage` |
32
- | 角色 / 权限组 / 字段权限 / 数据范围 | `openxiangda-permission-settings` | `openxiangda permission ...` / `openxiangda settings ...` |
32
+ | 账号权限 / 角色 / 权限组 / 字段权限 / 数据范围 / RBAC | `openxiangda-permission-settings` | `openxiangda design gates --topic permissions --json` → choose permission mode → `openxiangda permission ...` / `openxiangda settings ...` |
33
33
  | 平台部门 / 平台账号 / 重置密码 / 组织账号管理 | `openxiangda-architecture-design` + `openxiangda-page` | check `openxiangda organization capabilities --json`; use `sdk.organization` / `ctx.organization` only after `app:organization:manage` is granted |
34
34
  | 外部人员无需登录访问 / 公开报名 / 公开查询 / public page | `openxiangda-architecture-design` + `openxiangda-permission-settings` + `openxiangda-page` | 先确认公开范围、外部角色、ticket、grants;再声明 `routes` + `public-access`,并用 `OpenXiangdaProvider` + `OpenXiangdaPageProvider` + `PublicAccessGate` |
35
35
  | 看应用结构 / 快照 / 对比 / 诊断 / 排查 / 报错 | `openxiangda-inspect` | `openxiangda app snapshot <APP_XXX> --profile <name> --json` |
@@ -51,6 +51,7 @@ OpenXiangda supports two workspace modes. Classic `sy-lowcode-app-workspace` pub
51
51
  - ✅ For non-trivial app requirements, run the architecture design gate first: forms, fields, pages, permissions, data views, status/workflow, automation, notifications, and development tasks must be decided before coding.
52
52
  - ✅ For app login/auth requirements, run the auth security gate before coding: enabled methods, registration policy, identity matching keys, provider boundary, default roles, rate limits, audit fields, and third-party ownership must be confirmed.
53
53
  - ✅ For public/no-login access requirements, run the public access design gate before coding: public routes, external role codes, guest vs ticket, form/dataView/function/connector grants, backend permission groups, and visible loading/error fallback states must be confirmed. New React SPA apps use `/view/:appType/public/*`, `src/resources/routes/`, `src/resources/public-access/`, and `PublicAccessGate`; route children that use Page SDK hooks must be inside `OpenXiangdaProvider` + `OpenXiangdaPageProvider`.
54
+ - ✅ For account/role/permission/data-scope/query-param authorization requirements, run `openxiangda design gates --topic permissions --json` before coding. Pick one mode from `managed-platform-account`, `existing-platform-user-assignment`, `static-role-permission`, or `query-param-context`, write the permission matrix, and use roles/page-groups/form-groups/App Functions for real enforcement.
54
55
  - ✅ Public/no-login validation must inspect the JSON envelope, not only HTTP status. HTTP 200 with `code: "PUBLIC_GRANT_DENIED"` is a denied request; success requires `code` `200`, `"200"`, or compatible `0`, and no `success: false`.
55
56
  - ✅ Use first-class resource CLI commands for discovery, diagnosis, and small live fixes: `route`, `public-access`, `auth-config`, `function`, `connector`, `notification`, `organization`, `data-view`, `menu`, and `permission`. For multi-resource formal development, still prefer `src/resources/**` + `openxiangda resource validate|plan|publish`. If a direct CLI write is intentionally used, add `--write-manifest` when the repository should stay the source of truth.
56
57
  - ✅ For form-entry UX, pick components in this order: OpenXiangda platform form components → `antd` / `antd-mobile` wrappers → custom component only when neither exists.
@@ -69,6 +70,7 @@ OpenXiangda supports two workspace modes. Classic `sy-lowcode-app-workspace` pub
69
70
  - ❌ Implementing an architecture-class request before the user confirms the design. This includes creating files, mutating platform resources, publishing runtime, sending notifications, or calling live write/delete endpoints.
70
71
  - ❌ Running a full publish after editing one file. Default to `--changed --dry-run` → `--changed`, or targeted `--page` / `--form`.
71
72
  - ❌ Generating fake form instance IDs, mock rows, fallback schemas, or fallback display data to make a broken API path look successful.
73
+ - ❌ Treating query parameters, frontend button hiding, hardcoded roles, mock role context, or `PermissionBoundary` alone as sensitive authorization. Query parameters may provide context or ticket input only; sensitive data still needs public-access grants, platform roles, form permission groups, or App Function checks.
72
74
  - ❌ Storing tokens, AK, SK, or third-party API secrets in project files. Shared env (`APP_OSS_*`, feedback robot) goes to `~/.openxiangda/.env`.
73
75
  - ❌ Raw native HTML form controls in AI-authored workspace code (`<input>`, `<select>`, `<textarea>`, file inputs, hand-written pickers, hand-written upload controls). They are allowed only inside OpenXiangda SDK/platform component internals.
74
76
  - ❌ Using `?publicAccess=guest` or form `publicAccess` settings for new React SPA apps. Those are legacy `sy-lowcode-view` compatibility only.
@@ -161,6 +163,8 @@ When the user provides a root domain such as `https://yida.wisejob.cn/`, use it
161
163
  - For external APIs, create a connector manifest in `src/resources/connectors/` and call it from pages through `sdk.connector`; never put third-party API keys in page source.
162
164
  - For reusable backend logic shared by pages, automations, and workflows, create an App Function in `src/resources/functions/<functionCode>.json` plus `src/functions/<functionCode>/index.ts`. Call it from pages with `sdk.function.invoke`, from automation/workflow graphs with `function_call`, or from the runtime endpoint when the caller has app automation management permission. Current App Function MVP exposes controlled helpers such as `ctx.resources`, `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`, `ctx.dataView`, `ctx.connector`, `ctx.notification`, `ctx.organization`, and `ctx.platform.api`; it does not expose raw SQL or Redis. Runtime functions also receive trusted role context on `ctx.operator.roleCodes`, `ctx.operator.currentRoleCode`, `ctx.operator.hasFullAccess`, `ctx.currentUser`, and `ctx.permissions`; use these for server-side business authorization. Do not trust role codes sent in page input for sensitive actions. App Function form writes are trusted backend writes governed by declared `resources.forms` and function invocation authorization; do not grant normal users raw submit permission to internal forms just to let `ctx.form.createOne/updateOne/updateById` run.
163
165
  - For app-managed platform departments/accounts, use `sdk.organization.departments.*`, `sdk.organization.accounts.*`, `ctx.organization.departments.*`, or `ctx.organization.accounts.*`. The real current user/audit actor must hold `app:organization:manage` on the app; runtime service principals do not bypass this permission. Do not call legacy `/user` or `/department` write endpoints from apps. Do not include `password` in account updates; reset target accounts with `resetPassword`, and change the current user's password with `changeMyPassword({ oldPassword, newPassword })`.
166
+ - For account, role, data-scope, organization-account, RBAC, or query-param authorization designs, read `references/permission-design-patterns.md` and choose a permission mode before writing forms/pages/resources. Formal backends should use platform roles, page permission groups, form permission groups, public-access grants, and App Function role/scope checks; frontend hiding is display only.
167
+ - When a role such as 校区管理员 will create app roles, assign role members, grant role permissions, maintain permission groups, or manage organization accounts, its role manifest must declare the needed `apiPermissionCodes` such as `app:role:manage`, `app:page-permission-group:manage`, `app:form-permission-group:manage`, and `app:organization:manage`. If that administrator creates another administrator role, the new role must also declare its own `apiPermissionCodes`; permissions are not inherited from the creator.
164
168
  - For application login, declare auth resources in `src/resources/auth/<code>.json` and publish them with `openxiangda resource publish`. App Function auth providers may validate external credentials and return only an identity assertion; they must never issue tokens, set cookies, or write platform user/binding tables directly. The platform auth service decides create/bind/reject and issues tokens.
165
169
  - For external/no-login pages in React SPA apps, declare `src/resources/routes/<code>.json` and `src/resources/public-access/<code>.json`, put the page under `/view/:appType/public/*`, and use `PublicAccessGate` or `createPublicAccessClient`. The route tree must also include `OpenXiangdaPageProvider` inside `OpenXiangdaProvider` before any `usePageSdk()` / `usePageContext()` / `useDataSource()` call; otherwise pages throw `usePageSdkStore 必须在 PageProvider 内使用`. Always provide `fallback` and `errorFallback` for public routes so slow networks, missing tickets, or expired tickets do not render blank pages. Public guest access to forms, dataViews, functions, and connectors is denied unless policy `grants` explicitly names the resource; backend permission groups still apply.
166
170
  - When verifying public access, parse the response body and reject string business errors such as `PUBLIC_GRANT_DENIED` even if the HTTP status is 200. Do not use `response.ok` alone as the success condition.
@@ -208,6 +212,7 @@ Core CLI / state:
208
212
  - `references/data-views.md` — `src/resources/data-views` materialized/live data view resources, DSL, permissions, refresh, CLI commands, and runtime SDK usage.
209
213
  - `references/notifications.md` — `src/resources/notifications`, notification templates/type bindings, and `sdk.notification` / `ctx.notification`.
210
214
  - `references/best-practices.md` — initialized examples for modular pages, state lifecycles, role governance, permission isolation, high-performance queries, portal shells, workflow boundaries, and automation patterns.
215
+ - `references/permission-design-patterns.md` — account/role/permission design modes: managed platform account, existing user assignment, static role permission, query-param context, and the required resource/permission matrix.
211
216
 
212
217
  Form authoring:
213
218
 
@@ -226,6 +231,7 @@ Workflow / automation / permissions:
226
231
  - `references/workflow-v3.md` — workflow v3 definitions, JS_CODE nodes, App Function `function_call`, and trusted_node mode.
227
232
  - `references/automation-v3.md` — automation triggers, conditions, App Function `function_call`, and publishing.
228
233
  - `references/permissions-settings.md` — roles, page/form permission groups, settings.
234
+ - `references/permission-design-patterns.md` — required when designing accounts, roles, RBAC, organization-account governance, data scope, or query-param authorization.
229
235
 
230
236
  Platform domain knowledge (read these first when generating forms or pages so the output matches the live platform behavior):
231
237
 
@@ -27,7 +27,7 @@ form codes, field names, permissions, and page route names.
27
27
  - business status lifecycle
28
28
  - real approval workflow
29
29
  - automation / JS_CODE
30
- - role governance / permissions
30
+ - access governance / role governance / permissions
31
31
  - optional admin UI template:
32
32
  `glass-home-dashboard`, `mint-analytics-dashboard`,
33
33
  `ops-monitor-dashboard`, or `work-order-list-drawer`
@@ -104,10 +104,25 @@ same `domain/` and `shared/services/` when the business behavior is the same.
104
104
 
105
105
  ## Permission And Data Isolation
106
106
 
107
- For apps with dynamic roles:
108
-
109
- 1. Create an app role maintenance form, such as `app-role`.
110
- 2. Use automation / JS_CODE to sync role records to platform roles.
107
+ For account, role, RBAC, data-scope, or query-parameter authorization
108
+ requirements, read `permission-design-patterns.md` and choose one mode before
109
+ writing code:
110
+
111
+ - `managed-platform-account`: the app owns platform account/department lifecycle
112
+ and role synchronization.
113
+ - `existing-platform-user-assignment`: the app assigns existing platform users
114
+ to app roles and business scopes.
115
+ - `static-role-permission`: roles and permission groups are fixed resources.
116
+ - `query-param-context`: query parameters are context, filters, or ticket input
117
+ only; sensitive access still needs real authorization.
118
+
119
+ For apps with managed accounts or dynamic roles:
120
+
121
+ 1. Create the minimum governance forms required by the chosen mode:
122
+ `organization_unit`, `system_account`, `role_assignment`, or a smaller app
123
+ role maintenance form such as `app-role`.
124
+ 2. Use App Functions, automation, or JS_CODE to sync organization units,
125
+ platform accounts, and role records to platform departments/accounts/roles.
111
126
  3. Model visible scope fields with maintainable controls:
112
127
  - personnel and departments use platform personnel/department fields
113
128
  - enum scopes use `SelectField` / `RadioField` with `options`
@@ -126,11 +141,20 @@ For apps with dynamic roles:
126
141
  5. Create page permission groups for entry visibility.
127
142
  6. Create form permission groups with condition-based data permissions for real
128
143
  data isolation.
144
+ 7. For delegated administrators, add role API permissions in
145
+ `src/resources/roles/<code>.json` with `apiPermissionCodes`, for example
146
+ `app:role:manage`, `app:page-permission-group:manage`,
147
+ `app:form-permission-group:manage`, and `app:organization:manage`.
148
+ 8. Put sensitive writes behind App Functions with server-side role/scope checks.
129
149
 
130
150
  Frontend button hiding is only user experience. It is not permission control.
131
151
  Every sensitive action must still be protected by platform role/form permission
132
152
  groups or backend-side JS_CODE checks.
133
153
 
154
+ Query parameters are not permission control either. They may prefill context,
155
+ select filters, or carry a signed/expiring ticket, but tampering with a query
156
+ parameter must not expand sensitive data access.
157
+
134
158
  ## Form Copy And Field Visibility
135
159
 
136
160
  - Every visible form field should have a short, user-facing placeholder.
@@ -220,6 +244,9 @@ groups or backend-side JS_CODE checks.
220
244
  - `service-ticket-ops`: custom data management page based on
221
245
  `DataManagementList`, split into page, components, hook, query builder, and
222
246
  detail drawer.
247
+ - `access-governance`: account/role permission mode decision, organization,
248
+ account, role assignment, sync function, roles, page-group, and form-group
249
+ skeletons.
223
250
  - `role-governance`: role maintenance form, role sync JS_CODE, maintainable
224
251
  scope fields, hidden permission keys, and permission-group resource examples.
225
252
  - `pc-portal-shell`: app-shell PC portal with routes, modules, components, and
@@ -636,11 +636,13 @@ Requires Bearer token. Returns one execution record with raw `nodeExecutionLogs`
636
636
 
637
637
  ### GET `/apps/:appType/roles`
638
638
 
639
- Requires Bearer token. Lists app roles visible to the current user.
639
+ Requires Bearer token and app role management permission for role-setting
640
+ operations. Lists app roles visible to the current user.
640
641
 
641
642
  ### POST `/apps/:appType/roles`
642
643
 
643
- Requires Bearer token. Creates an app-scoped role.
644
+ Requires Bearer token with `app:role:manage` on the app. Creates an app-scoped
645
+ role.
644
646
 
645
647
  Body:
646
648
 
@@ -658,11 +660,13 @@ Requires Bearer token. Returns app role detail.
658
660
 
659
661
  ### PUT `/apps/:appType/roles/:roleId`
660
662
 
661
- Requires Bearer token. Updates app role metadata.
663
+ Requires Bearer token with `app:role:manage` on the app. Updates app role
664
+ metadata.
662
665
 
663
666
  ### DELETE `/apps/:appType/roles/:roleId`
664
667
 
665
- Requires Bearer token. Deletes a non-system app role.
668
+ Requires Bearer token with `app:role:manage` on the app. Deletes a non-system
669
+ app role.
666
670
 
667
671
  ### GET `/apps/:appType/roles/:roleId/users`
668
672
 
@@ -670,11 +674,33 @@ Requires Bearer token. Lists users under an app role.
670
674
 
671
675
  ### POST `/apps/:appType/roles/:roleId/users`
672
676
 
673
- Requires Bearer token. Adds users to an app role.
677
+ Requires Bearer token with `app:role:manage` on the app. Adds users to an app
678
+ role.
674
679
 
675
680
  ### DELETE `/apps/:appType/roles/:roleId/users/:userId`
676
681
 
677
- Requires Bearer token. Removes one user from an app role.
682
+ Requires Bearer token with `app:role:manage` on the app. Removes one user from
683
+ an app role.
684
+
685
+ When publishing role resources, OpenXiangda can also assign app-scoped API
686
+ permissions to the role:
687
+
688
+ ```json
689
+ {
690
+ "code": "campus_admin",
691
+ "name": "校区管理员",
692
+ "apiPermissionMode": "merge",
693
+ "apiPermissionCodes": [
694
+ "app:role:manage",
695
+ "app:page-permission-group:manage",
696
+ "app:form-permission-group:manage"
697
+ ]
698
+ }
699
+ ```
700
+
701
+ This is required when the role itself should create roles, assign role members,
702
+ or maintain permission groups. The first grant is normally done by a platform
703
+ administrator or an existing app role that already has `app:role:manage`.
678
704
 
679
705
  ### GET `/apps/:appType/page-permission-groups`
680
706
 
@@ -0,0 +1,216 @@
1
+ # Permission Design Patterns
2
+
3
+ Use this reference before implementing OpenXiangda requirements that mention
4
+ accounts, roles, permission groups, organization scope, data scope, or query
5
+ parameter based access.
6
+
7
+ The rule is simple: choose the permission mode first, then design forms,
8
+ resources, App Functions, pages, and publish order. Do not start by hiding
9
+ buttons in the frontend.
10
+
11
+ ## Mode Selection
12
+
13
+ ### `managed-platform-account`
14
+
15
+ The app owns account governance. Use this for formal admin systems, external
16
+ account lifecycle, school/company tenant management, or any workflow where the
17
+ app must create, update, disable, reset, or place platform accounts into
18
+ departments and roles.
19
+
20
+ Required design:
21
+
22
+ - `organization_unit` form: business organization tree, parent key, manager,
23
+ platform department ID, sync status, sync message, last synced time.
24
+ - `system_account` form: login name, display name, phone/email, organization
25
+ unit, enabled state, platform user ID, sync status, last synced time.
26
+ - `role_assignment` form: account, role codes, business scope fields, hidden
27
+ scalar scope keys, platform role member sync state.
28
+ - `src/resources/roles/*.json`: stable app role codes.
29
+ - `src/resources/permissions/page-groups/*.json`: menu, route, and page access.
30
+ - `src/resources/permissions/form-groups/*.json`: submit/view/manage, data
31
+ scope, operations, and `fieldAccessPolicy`.
32
+ - `apiPermissionCodes` on roles that are allowed to manage roles, role members,
33
+ permission groups, or organization accounts.
34
+ - Sync App Functions or trusted JS_CODE: sync organization units, accounts, and
35
+ role assignments to the platform.
36
+ - Page `PermissionBoundary` and runtime menus for display control only.
37
+ - Backend role/scope checks in App Functions for sensitive writes.
38
+
39
+ Platform account writes must use `sdk.organization.*` or `ctx.organization.*`.
40
+ The real current operator must have `app:organization:manage`. Do not call
41
+ legacy `/user` or `/department` write endpoints from app code.
42
+
43
+ ### `existing-platform-user-assignment`
44
+
45
+ The platform already has users and departments. The app only assigns existing
46
+ users to app roles and business scopes.
47
+
48
+ Required design:
49
+
50
+ - Role assignment form with `UserSelectField` / department fields for members.
51
+ - Business scope fields such as region, department, project, customer, class, or
52
+ college; derive hidden scalar keys with `valueSync` when permission
53
+ conditions need scalar matching.
54
+ - Role sync App Function or automation only updates app role members, not
55
+ account records.
56
+ - Roles, page groups, and form groups remain the backend enforcement layer.
57
+
58
+ Use this when HR/IT or the platform admin owns account lifecycle.
59
+
60
+ ### `static-role-permission`
61
+
62
+ Roles are fixed and membership is maintained by platform admins or resource
63
+ manifests. Use this for small internal apps, stable admin roles, and apps where
64
+ no in-app role maintenance screen is required.
65
+
66
+ Required design:
67
+
68
+ - `roles` resources.
69
+ - Page permission groups for menus/routes.
70
+ - Form permission groups for submit/view/manage/data scope/field access.
71
+ - Optional `PermissionBoundary` for UI display.
72
+
73
+ Do not create role/account governance forms just because a page has two static
74
+ roles.
75
+
76
+ ### `query-param-context`
77
+
78
+ Query parameters provide context only. Use this for low-risk links, prefilled
79
+ filters, external ticket input, public lookup keys, or deep links.
80
+
81
+ Allowed:
82
+
83
+ - select an initial tab, filter, date range, organization code, or public ticket
84
+ code
85
+ - prefill a form field before the user submits
86
+ - carry a signed/expiring ticket that is validated by public-access policy or an
87
+ App Function
88
+
89
+ Not allowed:
90
+
91
+ - granting sensitive data access only because `?role=admin` or `?dept=...` is
92
+ present
93
+ - deciding form data scope only in the frontend
94
+ - bypassing roles, form permission groups, public-access grants, or App
95
+ Function checks
96
+
97
+ If the page reads sensitive data, performs writes, or exposes internal records,
98
+ combine query parameters with real authorization: public-access grants, roles,
99
+ form permission groups, or server-side App Function checks.
100
+
101
+ ## Standard Resource Closure
102
+
103
+ A complete high-governance permission design usually has this closure:
104
+
105
+ ```text
106
+ organization_unit
107
+ -> system_account
108
+ -> role_assignment
109
+ -> src/resources/roles
110
+ -> permissions/page-groups
111
+ -> permissions/form-groups
112
+ -> sync App Functions / JS_CODE
113
+ -> PermissionBoundary for display
114
+ -> backend role/scope checks for sensitive writes
115
+ ```
116
+
117
+ Pages may show or hide navigation with `useAppMenus`, `useCanAccessRoute`, and
118
+ `PermissionBoundary`, but these are not the authority. Real authority is the
119
+ platform permission group, public-access grant, or App Function role/scope
120
+ check.
121
+
122
+ ## Role Setting Delegation
123
+
124
+ Setting application roles is itself permission controlled. A user can be a
125
+ business administrator in the app and still fail to create roles, assign role
126
+ members, or grant role permissions unless that user's current app role has the
127
+ matching API permission.
128
+
129
+ Use role `apiPermissionCodes` in `src/resources/roles/<code>.json` for delegated
130
+ administrators:
131
+
132
+ ```json
133
+ {
134
+ "code": "campus_admin",
135
+ "name": "校区管理员",
136
+ "description": "维护本校区账号、角色和权限",
137
+ "apiPermissionMode": "merge",
138
+ "apiPermissionCodes": [
139
+ "app:role:manage",
140
+ "app:page-permission-group:manage",
141
+ "app:form-permission-group:manage",
142
+ "app:organization:manage"
143
+ ]
144
+ }
145
+ ```
146
+
147
+ Platform behavior to design against:
148
+
149
+ - `app:role:manage` is required to create/update/delete app roles, assign app
150
+ roles to users, and assign app-scoped API permissions to roles.
151
+ - `app:page-permission-group:manage` is required to create/update/delete page
152
+ permission groups.
153
+ - `app:form-permission-group:manage` is required to create/update/delete form
154
+ permission groups.
155
+ - `app:organization:manage` is required for platform account/department writes.
156
+ - Platform roles still require platform-admin authority; delegated app admins
157
+ can only manage app-scoped roles and app-scoped API permissions.
158
+
159
+ When a platform administrator first grants a role such as `campus_admin`, that
160
+ role must include the API permissions needed for its future work. If
161
+ `campus_admin` later creates another role that also manages accounts, roles, or
162
+ permission groups, the new role must also be published with its own
163
+ `apiPermissionCodes`. Do not rely on inherited privilege from the creator.
164
+
165
+ `apiPermissionMode` defaults to `merge`. Use `replace` only when you explicitly
166
+ want the manifest to become the full API permission list for the role.
167
+ `openxiangda resource publish` fails if a declared permission code is missing
168
+ from the platform seed data, which is preferable to silently creating an
169
+ administrator role that cannot administer.
170
+
171
+ ## Design Matrix
172
+
173
+ Before implementation, write a matrix with at least these columns:
174
+
175
+ | Area | Decision |
176
+ | ---- | -------- |
177
+ | Permission mode | `managed-platform-account` / `existing-platform-user-assignment` / `static-role-permission` / `query-param-context` |
178
+ | Account source | app-created platform account / existing platform user / static member / public context |
179
+ | Role source | role assignment form / platform role admin / roles manifest / public external role |
180
+ | Role setting delegation | which roles need `apiPermissionCodes`, who grants them first, and whether delegation can continue |
181
+ | Business scope fields | visible fields and hidden scalar keys |
182
+ | Page access | menu codes, route codes, path patterns, role codes |
183
+ | Form access | submit/view/manage operations, data scope, field access policy |
184
+ | Backend checks | App Functions that validate role/scope and deny bad input |
185
+ | Query parameters | context only, ticket validation, tamper-deny test |
186
+ | Publish order | forms -> resources -> functions/runtime |
187
+
188
+ ## Anti-Patterns
189
+
190
+ - Query parameters as sensitive authorization.
191
+ - Frontend-only button hiding or route hiding.
192
+ - Hardcoded role strings scattered through pages.
193
+ - Delegated administrators without `app:role:manage` or required permission
194
+ group management API permissions.
195
+ - New roles created by delegated administrators without their own
196
+ `apiPermissionCodes` when they are expected to administer accounts or roles.
197
+ - Mock role context, fake account IDs, fake form instance IDs, or empty-array
198
+ fallback displays.
199
+ - Giving users all form data and filtering in the browser.
200
+ - Direct platform account API calls that bypass OpenXiangda organization SDK.
201
+ - Reusing public visitor roles as internal admin roles.
202
+
203
+ ## Acceptance
204
+
205
+ - `openxiangda design gates --topic permissions --json` was run and its open
206
+ questions are answered.
207
+ - Permission mode and matrix are recorded in SDD/design docs.
208
+ - Admin roles that can manage roles, members, permission groups, or accounts
209
+ declare `apiPermissionCodes`.
210
+ - `openxiangda permission audit --json` has no high-risk gaps.
211
+ - Allowed role paths and denied role paths are both tested.
212
+ - Query parameter tampering does not expand sensitive access.
213
+ - App Functions that mutate sensitive data verify `ctx.operator.roleCodes`,
214
+ `ctx.operator.currentRoleCode`, business scope, or explicit public ticket.
215
+ - Managed account flows verify `app:organization:manage` before account or
216
+ department writes.
@@ -2,6 +2,41 @@
2
2
 
3
3
  OpenXiangda permission APIs use ordinary user Bearer tokens. The effective permissions are the same as the current frontend user.
4
4
 
5
+ Before implementing account, role, RBAC, organization-account, data-scope, or
6
+ query-parameter authorization requirements, run:
7
+
8
+ ```bash
9
+ openxiangda design gates --topic permissions --json
10
+ ```
11
+
12
+ Then choose one permission mode from
13
+ `references/permission-design-patterns.md`:
14
+
15
+ - `managed-platform-account`: the app creates/maintains platform accounts,
16
+ departments, and role members.
17
+ - `existing-platform-user-assignment`: the app selects existing platform users
18
+ and assigns app roles/business scopes.
19
+ - `static-role-permission`: fixed roles and permission groups, no account
20
+ governance screens.
21
+ - `query-param-context`: query parameters are context, filters, or ticket input
22
+ only; they are not sensitive authorization.
23
+
24
+ Frontend hiding, `PermissionBoundary`, route guards, and query parameters are
25
+ display or context tools. Sensitive data access must be enforced by platform
26
+ roles, page permission groups, form permission groups, public-access grants, or
27
+ backend App Function role/scope checks.
28
+
29
+ Role management is permission controlled too. A role such as "校区管理员" that
30
+ will create app roles, assign role members, or grant role permissions must be
31
+ published with API permissions on the role resource. Use `apiPermissionCodes`
32
+ in `src/resources/roles/<code>.json`; otherwise the user may have the business
33
+ role but still fail when calling role-setting APIs.
34
+
35
+ For app-managed platform accounts or departments, use `sdk.organization.*` or
36
+ `ctx.organization.*`. The real current operator must have
37
+ `app:organization:manage`; do not bypass OpenXiangda with legacy user or
38
+ department write APIs.
39
+
5
40
  ## Role Codes
6
41
 
7
42
  Use stable local role codes:
@@ -16,6 +51,29 @@ Use stable local role codes:
16
51
 
17
52
  Role IDs are platform-specific. Store them only in `.openxiangda/state.json` under the active profile.
18
53
 
54
+ For delegated role administrators, include API permission codes on the role:
55
+
56
+ ```json
57
+ {
58
+ "code": "campus_admin",
59
+ "name": "校区管理员",
60
+ "description": "维护本校区账号、角色和权限",
61
+ "apiPermissionMode": "merge",
62
+ "apiPermissionCodes": [
63
+ "app:role:manage",
64
+ "app:page-permission-group:manage",
65
+ "app:form-permission-group:manage",
66
+ "app:organization:manage"
67
+ ]
68
+ }
69
+ ```
70
+
71
+ `app:role:manage` covers app role creation, role member assignment, and assigning
72
+ app-scoped API permissions to roles. Page/form permission group maintenance use
73
+ their own permission codes. If a delegated administrator creates another role
74
+ that should also administer accounts or roles, that new role also needs its own
75
+ `apiPermissionCodes`; permissions are not inherited from the creator.
76
+
19
77
  ## Page Permission Groups
20
78
 
21
79
  Page permission groups map role codes to visible menu targets. Form menus use their `FORM_...`
@@ -656,13 +656,44 @@ export default async function (ctx) {
656
656
 
657
657
  ## 8. Role — `src/resources/roles/<code>.json`
658
658
 
659
+ Before creating roles or permission groups for account/role/data-scope work,
660
+ run `openxiangda design gates --topic permissions --json` and choose a
661
+ permission mode: `managed-platform-account`,
662
+ `existing-platform-user-assignment`, `static-role-permission`, or
663
+ `query-param-context`. Query parameters and `PermissionBoundary` are never
664
+ sensitive authorization by themselves.
665
+
659
666
  ```json
660
667
  {
661
668
  "code": "sales",
662
- "name": "销售"
669
+ "name": "销售",
670
+ "description": "销售人员"
663
671
  }
664
672
  ```
665
673
 
674
+ Delegated admin roles that manage roles, role members, permission groups, or
675
+ organization accounts must also declare API permissions:
676
+
677
+ ```json
678
+ {
679
+ "code": "campus_admin",
680
+ "name": "校区管理员",
681
+ "description": "维护本校区账号、角色和权限",
682
+ "apiPermissionMode": "merge",
683
+ "apiPermissionCodes": [
684
+ "app:role:manage",
685
+ "app:page-permission-group:manage",
686
+ "app:form-permission-group:manage",
687
+ "app:organization:manage"
688
+ ]
689
+ }
690
+ ```
691
+
692
+ `apiPermissionMode` is `merge` by default. Use `replace` only when the manifest
693
+ should become the full API permission list for that role. Platform role setup
694
+ requires platform-admin authority; app roles can only receive app-scoped API
695
+ permission codes.
696
+
666
697
  ## 9. Page Permission Group — `src/resources/permissions/page-groups/<code>.json`
667
698
 
668
699
  ```json
@@ -21,6 +21,7 @@ Read these supporting references when the design touches the topic:
21
21
  - `references/architecture-patterns.md`
22
22
  - `references/data-views.md`
23
23
  - `references/permissions-settings.md`
24
+ - `references/permission-design-patterns.md`
24
25
  - `references/workflow-v3.md`
25
26
  - `references/automation-v3.md`
26
27
  - `references/notifications.md`
@@ -66,6 +67,8 @@ Once the user confirms, hand execution to the relevant implementation skill and
66
67
  - Do not default to `searchKeyWord` for broad fuzzy search. Prefer explicit searchable fields and structured `filterGroup` conditions.
67
68
  - Do not use workflow forms for ordinary business lifecycles. Use normal forms, status fields, state machines, responsibility fields, action logs, permissions, and automations. Use workflow only for real approval semantics.
68
69
  - Do not put sensitive authorization in page conditions only. Use page permission groups, form permission groups, backend data scope, and field access policy when data is sensitive.
70
+ - Do not design account/role/permission requirements without choosing a permission mode first: `managed-platform-account`, `existing-platform-user-assignment`, `static-role-permission`, or `query-param-context`.
71
+ - Do not treat query parameters as sensitive authorization. They may provide context, filters, or ticket input only; sensitive reads/writes still need public-access grants, roles, form permission groups, or App Function checks.
69
72
  - Do not put repeated multi-form joins or fixed dashboard metrics into page-side loops. Use Data View when the query is reusable and read-only; choose `live` or `materialized` deliberately.
70
73
  - Do not scatter reusable backend logic in pages or JS_CODE nodes. Use App Functions for logic shared by pages, automations, and workflows. Use JS_CODE V2 for node-local backend trigger logic.
71
74
  - Do not design raw native form controls for AI-authored workspace code. Use OpenXiangda platform form components first, then Ant Design / antd-mobile wrappers.
@@ -103,6 +106,9 @@ Resolve these before finalizing:
103
106
 
104
107
  - Data volume, pagination, searchable fields, sort fields, and expected indexes.
105
108
  - Role model, data sensitivity, backend-enforced data scope, and field visibility.
109
+ - Account source, role membership source, permission design mode, and whether platform accounts/departments are created by the app.
110
+ - Which roles can manage roles, assign role members, grant role API permissions, maintain permission groups, or manage organization accounts; list the required `apiPermissionCodes`.
111
+ - Permission matrix for pages/routes, form submit/view/manage, data scope, field access policy, backend App Function checks, and query parameter tamper-deny tests.
106
112
  - Which flows are status machines and which are real approvals.
107
113
  - Report freshness: real-time live view, materialized refresh cadence, or manual snapshot.
108
114
  - Whether dashboards and joins are bounded enough for Data View.
@@ -118,6 +124,8 @@ The final design must be decision-complete. Include:
118
124
  - Architecture overview and OpenXiangda resource map.
119
125
  - Form and field design with storage shape, hidden scope keys, searchable fields, and pagination strategy.
120
126
  - Permission design with page groups, form groups, data scope, and field access policy.
127
+ - Permission mode decision with account source, role assignment source, business scope fields, hidden scalar keys, query-parameter boundary, and backend role/scope checks.
128
+ - Delegated role-setting design: which administrator role is first granted by a platform/app admin, which `apiPermissionCodes` it receives, and whether roles it creates can further delegate management.
121
129
  - Page/menu/UX design, including PC/mobile and design mockup decisions.
122
130
  - Data access and Data View plan with `live` / `materialized`, refresh, indexes, and runtime SDK calls.
123
131
  - Status machine, workflow, automation, JS_CODE V2, and App Function plan.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: openxiangda-permission-settings
3
- description: Manage OpenXiangda app **roles** (角色), **page permission groups** (页面权限组 / 菜单可见), **form permission groups** (表单权限组 / 提交 / 查看 / 字段权限 / 数据范围 / 数据隔离), and **form settings** (表单设置 / 索引 / 数据管理页 / 公开访问 / public access / 分享) with profile-isolated IDs and ordinary user token permissions. Trigger on 角色 / role / 权限 / permission / 数据范围 / data scope / 字段权限 / field permission / 菜单可见 / menu visibility / 公开访问 / public access / 分享 / share, or any work touching `permission ...` / `settings ...` CLI commands or `src/resources/{roles,pagePermissionGroups,formPermissionGroups,formSettings}/`.
3
+ description: Manage OpenXiangda app **roles** (角色), **page permission groups** (页面权限组 / 菜单可见), **form permission groups** (表单权限组 / 提交 / 查看 / 字段权限 / 数据范围 / 数据隔离), account/role governance patterns, query-parameter authorization boundaries, and **form settings** (表单设置 / 索引 / 数据管理页 / 公开访问 / public access / 分享) with profile-isolated IDs and ordinary user token permissions. Trigger on 角色 / role / 权限 / permission / RBAC / 账号权限 / account permission / 组织账号 / organization account / 平台账号 / 数据范围 / data scope / 字段权限 / field permission / 菜单可见 / menu visibility / 公开访问 / public access / 分享 / share, or any work touching `permission ...` / `settings ...` CLI commands or `src/resources/{roles,pagePermissionGroups,formPermissionGroups,formSettings}/`.
4
4
  ---
5
5
 
6
6
  # OpenXiangda Permission And Settings
@@ -12,14 +12,25 @@ description: Manage OpenXiangda app **roles** (角色), **page permission groups
12
12
  - User wants to **gate form submit / view / edit / data scope / field permissions** (form permission groups).
13
13
  - User wants to **publish a form publicly** or change form runtime settings, indexes, data-management page config.
14
14
  - User asks about **dynamic role governance** (role maintenance form synced to platform via automation).
15
+ - User asks about **platform accounts, organization accounts, account-role assignment, RBAC, or query-parameter access**.
15
16
 
16
17
  ## DO / DO NOT
17
18
 
19
+ - ✅ Before account/role/permission design, run `openxiangda design gates --topic permissions --json` and choose one mode: `managed-platform-account`, `existing-platform-user-assignment`, `static-role-permission`, or `query-param-context`.
20
+ - ✅ Write a permission matrix before implementation: account source, role member source, page groups, form groups, data scope, field access policy, backend checks, query parameter boundary, and publish order.
18
21
  - ✅ Use logical role / group codes locally; live IDs go under the active profile in `.openxiangda/state.json`.
19
22
  - ✅ For dynamic multi-role apps, build a role maintenance form + automation/JS_CODE sync, not hardcoded role logic in page code.
20
23
  - ✅ For permission scope keys, derive hidden scalars (`collegeScopeKey`, `classScopeKey`, `ownerDeptScopeKey`, `ownerUserScopeKey`, `roleCode`) via `valueSync` from visible select/person/department fields.
21
24
  - ✅ Use page permission groups for entry visibility, form permission groups for real data isolation with condition-based data permissions.
25
+ - ✅ For app-managed platform accounts/departments, use `sdk.organization.*` / `ctx.organization.*` and require the current operator to have `app:organization:manage`.
26
+ - ✅ For delegated administrators such as 校区管理员, put role-setting API permissions in the role manifest with `apiPermissionCodes`; use `app:role:manage` for app role creation/member assignment/API-permission assignment, and add page/form/organization management permission codes only when needed.
27
+ - ✅ If a delegated administrator creates another role that can also manage accounts, roles, or permission groups, publish that new role with its own `apiPermissionCodes`.
22
28
  - ❌ Expose raw ID text fields to users for permission scopes.
29
+ - ❌ Treat query parameters as sensitive authorization. They may carry context, filters, or ticket input only.
30
+ - ❌ Treat `PermissionBoundary`, button hiding, route hiding, or frontend role checks as the authority for sensitive data.
31
+ - ❌ Hardcode role strings in pages without backing roles/page groups/form groups or App Function checks.
32
+ - ❌ Give a user a business admin role but forget to bind `app:role:manage`, then expect role creation or role-member assignment to work.
33
+ - ❌ Bypass OpenXiangda SDK and call platform account/organization write APIs directly.
23
34
  - ❌ Store platform-specific public-access IDs locally; CLI resolves by `appType + formUuid` per profile.
24
35
  - ❌ Reuse role / permission-group IDs across profiles.
25
36
  - ❌ Use AK/SK or legacy `/dingtalk-api/v1.0` — the logged-in user must have the matching app permission.
@@ -36,6 +47,24 @@ openxiangda workspace bind --profile dev --app-type APP_XXX
36
47
 
37
48
  The logged-in user must have the matching app permission. Do not use AK/SK or legacy `/dingtalk-api/v1.0`.
38
49
 
50
+ For design work, also run:
51
+
52
+ ```bash
53
+ openxiangda design gates --topic permissions --json
54
+ ```
55
+
56
+ Resolve the permission mode before writing resources:
57
+
58
+ - `managed-platform-account`: the app creates/maintains platform accounts,
59
+ departments, and role members.
60
+ - `existing-platform-user-assignment`: the app selects existing platform users
61
+ and assigns app roles/business scopes.
62
+ - `static-role-permission`: fixed app roles and permission groups, no in-app
63
+ account governance.
64
+ - `query-param-context`: query parameters are only context, filters, or ticket
65
+ input; sensitive authorization still comes from roles, grants, form groups,
66
+ or App Function checks.
67
+
39
68
  ## Roles
40
69
 
41
70
  Create app roles first:
@@ -53,6 +82,13 @@ openxiangda permission role-bind sales --role-id <id> --profile dev
53
82
 
54
83
  For dynamic multi-role apps, do not hardcode role behavior only in page code. Create a role maintenance form and sync it to platform roles with automation / JS_CODE. Visible scope fields should be maintainable controls: personnel/department fields for people and orgs, `SelectField` / `RadioField` for enums, and `SelectField` with `optionSource.type: "linkedForm"` for records maintained by other forms. When the source form can have many records, set `remoteSearch: true` and `searchFieldId` so typing in the dropdown triggers an SDK query instead of loading every record. If form permission groups need scalar matching, derive hidden keys such as `collegeScopeKey`, `classScopeKey`, `ownerDeptScopeKey`, `ownerUserScopeKey`, and `roleCode`; do not expose raw ID text fields to users. Use page permission groups for entry visibility and form permission groups with condition-based data permissions for real data isolation.
55
84
 
85
+ For managed platform account governance, use organization/account forms and sync
86
+ functions as a closed loop: organization units, system accounts, role
87
+ assignments, roles resources, page groups, form groups, sync App Functions, and
88
+ backend role/scope checks. Platform account writes must go through
89
+ `sdk.organization` or `ctx.organization`; the current operator must have
90
+ `app:organization:manage`.
91
+
56
92
  ## Page Permission Groups
57
93
 
58
94
  Page permission groups control menu/page visibility:
@@ -153,6 +189,7 @@ Do not store platform-specific public access IDs locally. The CLI resolves by `a
153
189
  ## References
154
190
 
155
191
  - Permission model and examples: `references/permissions-settings.md`
192
+ - Account/role design modes: `references/permission-design-patterns.md`
156
193
  - Dynamic role governance and data-isolation pattern: `references/best-practices.md`
157
194
  - Profile-isolated IDs: `references/workspace-state.md`
158
195
  - API fields: `references/openxiangda-api.md`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda",
3
- "version": "1.0.135",
3
+ "version": "1.0.136",
4
4
  "description": "OpenXiangda CLI, workspace build tools, runtime SDK, and form components.",
5
5
  "private": false,
6
6
  "bin": {
@@ -22,13 +22,19 @@ This is an OpenXiangda React SPA workspace. See [AGENTS.md](mdc:AGENTS.md) for f
22
22
  - Writes and deploys must pass `--profile <name>` explicitly.
23
23
  - Architecture-class work is plan-gated: run `openxiangda design gates --topic <code> --json` and wait for confirmation.
24
24
  - High-risk changes must start with `openxiangda sdd context --json`, use an approved change, and run `openxiangda sdd verify <change> --changed` before release.
25
+ - Account/role/permission/RBAC/organization-account/query-param authorization work must run `openxiangda design gates --topic permissions --json`, choose `managed-platform-account`, `existing-platform-user-assignment`, `static-role-permission`, or `query-param-context`, and write the permission matrix.
26
+ - Roles that create roles, assign members, grant API permissions, maintain permission groups, or manage organization accounts must declare `apiPermissionCodes`, such as `app:role:manage`, `app:page-permission-group:manage`, `app:form-permission-group:manage`, and `app:organization:manage`.
25
27
  - `src/resources/**` is the resource source of truth; use `validate -> plan -> publish`.
26
28
  - React routes live in `src/app/router.tsx`; frontend artifacts are deployed with `openxiangda runtime deploy`.
27
- - Backend permissions and public-access grants are authoritative.
29
+ - Backend permissions, public-access grants, and App Function role/scope checks are authoritative.
30
+ - Query parameters are context, filters, or ticket input only; they are not sensitive authorization.
28
31
 
29
32
  ## Never
30
33
 
31
34
  - Do not run `lowcode-workspace publish-all`, `pnpm publish:all`, or `pnpm openxiangda:publish` directly.
32
35
  - Do not deploy without `--profile`.
33
36
  - Do not use legacy `?publicAccess=guest`, `isRenderNav`, or workbench page parameters for new React SPA routes.
37
+ - Do not rely on frontend-only button hiding, query-param checks, hardcoded roles, mock permissions, fake account IDs, or `PermissionBoundary` alone for real authorization.
38
+ - Do not assign a business admin role without the role-setting API permissions needed for role/member management.
39
+ - Do not bypass `sdk.organization` / `ctx.organization` for platform account/department writes.
34
40
  - Do not commit tokens, AK/SK, or third-party secrets.
@@ -22,13 +22,19 @@ This is an OpenXiangda React SPA workspace. Read [AGENTS.md](AGENTS.md) for full
22
22
  - 发布和写平台资源必须显式传 `--profile <name>`。
23
23
  - 架构类需求先跑 `openxiangda design gates --topic <code> --json` 并等用户确认。
24
24
  - 高风险变更先跑 `openxiangda sdd context --json`,创建/继续 change,并在用户确认后 `openxiangda sdd approve <change>`;发布前 `openxiangda sdd verify <change> --changed`。
25
+ - 账号/角色/权限/RBAC/组织账号/查询参数授权需求先跑 `openxiangda design gates --topic permissions --json`,选择 `managed-platform-account` / `existing-platform-user-assignment` / `static-role-permission` / `query-param-context` 并输出权限矩阵。
26
+ - 角色能新增角色、分配成员、授接口权限、维护权限组或管理组织账号时,角色资源必须声明 `apiPermissionCodes`,例如 `app:role:manage`、`app:page-permission-group:manage`、`app:form-permission-group:manage`、`app:organization:manage`。
25
27
  - `src/resources/**` 是工程化资源来源,正式多资源变更走 `validate -> plan -> publish`。
26
28
  - React SPA 路由由 `src/app/router.tsx` 管理,前端包通过 `openxiangda runtime deploy` 发布。
27
- - 页面权限、表单权限、公开访问 grants 以后端资源为准;前端只做展示保护。
29
+ - 页面权限、表单权限、公开访问 grants、App Function 后端检查是授权依据;前端只做展示保护。
30
+ - 查询参数只能做上下文、筛选或 ticket 输入,不能作为敏感数据授权依据。
28
31
 
29
32
  ## Never
30
33
 
31
34
  - 不要直接运行 `lowcode-workspace publish-all`、`pnpm publish:all` 或 `pnpm openxiangda:publish`。
32
35
  - 不要省略 `--profile` 发布。
33
36
  - 不要使用旧 `?publicAccess=guest`、`isRenderNav` 或 workbench 参数模型开发新 React SPA。
37
+ - 不要只隐藏按钮、只判断 query 参数、硬编码角色、前端模拟权限、假账号/假 ID、或用 `PermissionBoundary` 代替真实授权。
38
+ - 不要给用户挂“管理员”业务角色但不给该角色绑定 `app:role:manage` 等角色设置接口权限。
39
+ - 不要绕过 `sdk.organization` / `ctx.organization` 直接写平台账号/部门。
34
40
  - 不要把 token、AK、SK、第三方密钥写入项目文件。
@@ -6,12 +6,17 @@
6
6
 
7
7
  - 架构类需求默认只规划、不实现。新应用、复杂页面、登录注册、公开访问、权限数据范围、流程自动化、连接器/通知等需求,先运行 `openxiangda doctor --json` 和 `openxiangda design gates --topic <code> --json`,输出设计并等用户确认;确认前只允许读取、快照、dry-run、提问和写设计文档,不允许改源码、写平台、发布或发送通知。
8
8
  - 高风险变更必须挂到 SDD change。修改 `src/forms/**`、`src/pages/**`、`src/resources/**`、`src/functions/**`、`src/automations/**`、`src/workflows/**`、`src/js-code-nodes/**`、`src/runtime/**` 或 `app-workspace.config.ts` 前,先运行 `openxiangda sdd context --json`,没有合适 change 就 `openxiangda sdd propose <change>`,等用户确认后运行 `openxiangda sdd approve <change>` 再实现。发布前运行 `openxiangda sdd verify <change> --changed`、`openxiangda workspace check --changed`、`openxiangda resource plan --profile <name>`。
9
+ - 账号、角色、权限、数据范围、组织账号、RBAC、查询参数授权需求必须先运行 `openxiangda design gates --topic permissions --json`,选择 `managed-platform-account` / `existing-platform-user-assignment` / `static-role-permission` / `query-param-context`,输出权限矩阵后再实现。
10
+ - 应用角色如果要创建角色、分配角色成员、给角色授接口权限、维护页面/表单权限组或管理组织账号,必须在角色资源声明 `apiPermissionCodes`,例如 `app:role:manage`、`app:page-permission-group:manage`、`app:form-permission-group:manage`、`app:organization:manage`。
9
11
  - 默认用户界面保持克制:左侧应用导航、顶部账号信息、首页内容区域。
10
12
  - 不在默认可见页面展示 SDK、Runtime、Cookie、Proxy、Playwright、AI 验证、调试上下文、构建号等开发语言。
11
13
  - 使用 React Router 管理路由,路由定义在 `src/app/router.tsx`。
12
14
  - 使用 Tailwind CSS 表达样式,不依赖平台 theme tokens。
13
15
  - 菜单和首页文案优先改 `src/app/navigation.ts`、`src/app/starter-content.ts` 与 `src/pages/admin/AdminDashboardPage.tsx`。
14
16
  - 页面、表单、字段、数据范围、流程动作、文件、连接器权限以后端接口为准;前端只做展示保护和清晰状态页。
17
+ - 查询参数只能作为上下文、筛选或 ticket 输入,不能作为敏感数据授权依据;敏感读写必须由 public-access grants、平台角色、页面/表单权限组或 App Function 后端校验保护。
18
+ - 应用管理平台账号/部门时,必须走 `sdk.organization` / `ctx.organization`,并要求当前操作者具备 `app:organization:manage`。
19
+ - 只给用户分配“管理员”业务角色不等于授权其设置角色;缺少 `app:role:manage` 时角色创建、成员分配和角色接口权限授予会被后端拒绝。
15
20
  - 本地开发通过 Vite `/service` 代理远端平台,保持 HttpOnly Cookie 同域访问。
16
21
  - 新公开访问页使用 `/view/:appType/public/*`、`src/resources/routes/`、`src/resources/public-access/` 和 `PublicAccessGate`。不要使用旧 `?publicAccess=guest`。
17
22
 
@@ -78,7 +83,7 @@ React SPA 页面需要声明菜单 code、route code 和 path pattern。默认
78
83
  import { PermissionBoundary, useAppMenus, useRuntimeBootstrap } from "openxiangda/runtime/react";
79
84
  ```
80
85
 
81
- `PermissionBoundary` 只能做展示保护,不能替代后端权限。后端返回 401 时跳登录,403 时展示无权限状态。
86
+ `PermissionBoundary` 只能做展示保护,不能替代后端权限。不要硬编码角色、前端模拟权限、只判断 query 参数或用空数组兜底伪装成功。后端返回 401 时跳登录,403 时展示无权限状态。
82
87
 
83
88
  公开页面需要同时声明 route 和 public access policy:
84
89
 
@@ -25,4 +25,8 @@ See `references/resource-manifest-cheatsheet.md` for copy-paste skeletons.
25
25
 
26
26
  Commands: `openxiangda resource validate|plan|publish|pull --profile <name>`.
27
27
 
28
- Forbidden: `formUuid` / `pageId` / `workflowId` 等平台 ID 写进 manifest;把 API key / token / secret / authorization 写进 manifest;data view 用作单表 CRUD / linkedForm / 写回 / 强实时;page 源里 hardcode 通知或 connector URL。
28
+ Before editing `roles`, `permissions/page-groups`, or `permissions/form-groups` for account/role/data-scope/RBAC/query-param authorization work, run `openxiangda design gates --topic permissions --json`, choose the permission mode, and write the permission matrix.
29
+
30
+ If a `roles/<code>.json` role can create roles, assign members, grant API permissions, maintain permission groups, or manage organization accounts, it must declare `apiPermissionCodes`; a business role name alone does not grant backend API permission.
31
+
32
+ Forbidden: 把 `formUuid` / `pageId` / `workflowId` 等平台 ID 写进 manifest;把 API key / token / secret / authorization 写进 manifest;data view 用作单表 CRUD / linkedForm / 写回 / 强实时;只靠 query 参数、前端隐藏按钮、硬编码角色、mock 权限或 `PermissionBoundary` 作为敏感授权;管理型角色缺少 `app:role:manage` / `app:page-permission-group:manage` / `app:form-permission-group:manage` / `app:organization:manage`;page 源里 hardcode 通知或 connector URL。
@@ -18,7 +18,7 @@ This is a `sy-lowcode-app-workspace` managed by the `openxiangda` CLI. See [AGEN
18
18
  | edit code page / portal / dashboard / 代码页 | `openxiangda-page` | edit `src/pages/<code>/` → `workspace publish --page <code>` |
19
19
  | approval workflow / 审批流程 / JS_CODE | `openxiangda-workflow-automation` | `openxiangda workflow ...` |
20
20
  | automation / cron / 自动化 / 定时 | `openxiangda-workflow-automation` | `openxiangda automation ...` |
21
- | role / permission / 公开访问 | `openxiangda-permission-settings` | `openxiangda permission ...` / `openxiangda settings ...` |
21
+ | account / role / permission / data scope / query-param authorization | `openxiangda-permission-settings` | run `openxiangda design gates --topic permissions --json` first, then `openxiangda permission ...` / `openxiangda settings ...` |
22
22
  | diagnose / snapshot / 排查 / 报错 | `openxiangda-inspect` | `openxiangda app snapshot APP_XXX --profile <name> --json` |
23
23
  | login / token / switch profile | `openxiangda-core` | `openxiangda env --profile <name>` / `openxiangda auth status` |
24
24
 
@@ -26,6 +26,8 @@ This is a `sy-lowcode-app-workspace` managed by the `openxiangda` CLI. See [AGEN
26
26
 
27
27
  - For routine edits, default to incremental publish: `workspace publish --profile <name> --changed --dry-run` then `--changed` or targeted `--page <code>` / `--form <code>`.
28
28
  - High-risk changes must use SDD first: `openxiangda sdd context --json` -> `openxiangda sdd propose <change>` -> user confirmation -> `openxiangda sdd approve <change>`; before release run `openxiangda sdd verify <change> --changed`.
29
+ - Account/role/permission/RBAC/organization-account/query-param authorization work must choose a mode first: `managed-platform-account`, `existing-platform-user-assignment`, `static-role-permission`, or `query-param-context`, then write the permission matrix.
30
+ - Roles that create roles, assign members, grant API permissions, maintain permission groups, or manage organization accounts must declare `apiPermissionCodes` in `src/resources/roles/<code>.json`, such as `app:role:manage`, `app:page-permission-group:manage`, `app:form-permission-group:manage`, and `app:organization:manage`.
29
31
  - Confirm current profile before any write: `openxiangda env --profile <name>`.
30
32
  - `.openxiangda/state.json` is the authoritative profile → appType → resource-ID map; CLI maintains it, do not hand-edit.
31
33
  - User tokens live in `~/.openxiangda/profiles.json`; shared env in `~/.openxiangda/.env`.
@@ -41,6 +43,9 @@ This is a `sy-lowcode-app-workspace` managed by the `openxiangda` CLI. See [AGEN
41
43
  - ❌ Search the platform for similar app names when `.openxiangda/state.json` has no binding.
42
44
  - ❌ Copy `formUuid` / `pageId` / `workflowId` / `automationId` across profiles.
43
45
  - ❌ Run a full publish for a single-file edit.
46
+ - ❌ Frontend-only button hiding, query-param checks, hardcoded roles, mock permissions, fake account IDs, or `PermissionBoundary` alone as real authorization.
47
+ - ❌ Business admin roles without `app:role:manage` or required role-setting API permissions when they are expected to manage roles or members.
48
+ - ❌ Direct platform account/department writes that bypass `sdk.organization` / `ctx.organization`.
44
49
  - ❌ Use `openxiangda form create` / `form publish` / `page publish` as the normal page generation path.
45
50
  - ❌ Store tokens / AK / SK / third-party secrets in project files.
46
51
  - ❌ `npm publish` — this workspace is `"private": true`, not an npm package.
@@ -12,6 +12,10 @@ You are editing engineering-managed resource manifests under `src/resources/`. *
12
12
 
13
13
  `references/resource-manifest-cheatsheet.md`(installed at `~/.qoder/skills/openxiangda/references/resource-manifest-cheatsheet.md`)— connector / data-view / notification / workflow / automation / JS_CODE / role / page-group / form-group / settings / menu 骨架。
14
14
 
15
+ 编辑 `roles`、`permissions/page-groups`、`permissions/form-groups` 前,如果需求涉及账号、角色、数据范围、组织账号、RBAC 或查询参数授权,先运行 `openxiangda design gates --topic permissions --json`,选择权限模式并输出权限矩阵。
16
+
17
+ 如果 `roles/<code>.json` 代表的角色需要新增角色、分配成员、授接口权限、维护权限组或管理组织账号,必须声明 `apiPermissionCodes`;只写业务角色名不会获得这些后端接口权限。
18
+
15
19
  ## 文件夹与对应 skill
16
20
 
17
21
  | 路径 | 用途 | 主导 skill |
@@ -42,5 +46,7 @@ openxiangda resource pull --profile <name> # 平台 → 本地
42
46
  - ❌ 把 `formUuid` / `pageId` / `workflowId` 等平台 ID 直接写进 manifest(CLI 解析逻辑 code)。
43
47
  - ❌ 把 API key / token / secret / password / authorization / headers / credential 写进 manifest(平台后台配置)。
44
48
  - ❌ data view 用作单表 CRUD、`linkedForm` 下拉、写回、强实时数据源。
49
+ - ❌ 只靠 query 参数、前端隐藏按钮、硬编码角色、mock 权限或 `PermissionBoundary` 作为敏感授权。
50
+ - ❌ 管理型角色缺少 `app:role:manage`、`app:page-permission-group:manage`、`app:form-permission-group:manage` 或 `app:organization:manage`。
45
51
  - ❌ 在 page 源里 hardcode `/api/notification-config/*` 或 `/connectors/actions/invoke`(用 `sdk.notification` / `sdk.connector`)。
46
52
  - ❌ 同时在 manifest 与平台后台编辑同一个资源(漂移源)。
@@ -18,7 +18,7 @@ This is a `sy-lowcode-app-workspace` managed by the `openxiangda` CLI. Read [AGE
18
18
  | 改代码页 / portal / dashboard | `openxiangda-page` | 编辑 `src/pages/<code>/` → `workspace publish --page <code>` |
19
19
  | 审批流程 / workflow / JS_CODE | `openxiangda-workflow-automation` | `openxiangda workflow ...` |
20
20
  | 自动化 / 定时 / 提交触发 | `openxiangda-workflow-automation` | `openxiangda automation ...` |
21
- | 角色 / 权限 / 公开访问 | `openxiangda-permission-settings` | `openxiangda permission ...` / `openxiangda settings ...` |
21
+ | 账号 / 角色 / 权限 / 数据范围 / 查询参数授权 | `openxiangda-permission-settings` | `openxiangda design gates --topic permissions --json`,再 `openxiangda permission ...` / `openxiangda settings ...` |
22
22
  | 排查 / 快照 / 对比 / 报错 | `openxiangda-inspect` | `openxiangda app snapshot APP_XXX --profile <name> --json` |
23
23
  | 登录 / token / 切平台 | `openxiangda-core` | `openxiangda env --profile <name>` / `openxiangda auth status` |
24
24
 
@@ -26,6 +26,8 @@ This is a `sy-lowcode-app-workspace` managed by the `openxiangda` CLI. Read [AGE
26
26
 
27
27
  - 单文件改动默认增量发布:先 `workspace publish --profile <name> --changed --dry-run`,再 `--changed` 或 `--page <code>` / `--form <code>`。
28
28
  - 高风险变更先走 SDD:`openxiangda sdd context --json` → `openxiangda sdd propose <change>` → 用户确认 → `openxiangda sdd approve <change>`;发布前 `openxiangda sdd verify <change> --changed`。
29
+ - 账号/角色/权限/RBAC/组织账号/查询参数授权需求先选权限模式:`managed-platform-account` / `existing-platform-user-assignment` / `static-role-permission` / `query-param-context`,并输出权限矩阵。
30
+ - 角色能新增角色、分配成员、授接口权限、维护权限组或管理组织账号时,`src/resources/roles/<code>.json` 必须声明 `apiPermissionCodes`,例如 `app:role:manage`、`app:page-permission-group:manage`、`app:form-permission-group:manage`、`app:organization:manage`。
29
31
  - 任何写操作前确认当前 profile:`openxiangda env --profile <name>`。
30
32
  - `.openxiangda/state.json` 是 profile 到 appType / 资源 ID 的权威映射,由 CLI 维护,不要手改。
31
33
  - 用户 token 在 `~/.openxiangda/profiles.json`;共享 env 在 `~/.openxiangda/.env`。
@@ -41,6 +43,9 @@ This is a `sy-lowcode-app-workspace` managed by the `openxiangda` CLI. Read [AGE
41
43
  - ❌ 在没有本地 `.openxiangda/state.json` 绑定时,去平台搜索同名应用"复用"。
42
44
  - ❌ 把 `formUuid` / `pageId` / `workflowId` / `automationId` 从 dev 复制到 prod。
43
45
  - ❌ 改一处就全量发布。
46
+ - ❌ 只隐藏按钮、只判断 query 参数、硬编码角色、前端模拟权限、假账号/假 ID、或用 `PermissionBoundary` 代替真实授权。
47
+ - ❌ 给用户挂“管理员”业务角色但不给该角色绑定 `app:role:manage` 等角色设置接口权限。
48
+ - ❌ 绕过 `sdk.organization` / `ctx.organization` 直接写平台账号/部门。
44
49
  - ❌ `openxiangda form create` / `form publish` / `page publish` 当作页面生成方式(仅底层修复)。
45
50
  - ❌ 把 token / AK / SK / 第三方密钥写进项目文件。
46
51
  - ❌ `npm publish` — 本工作区 `"private": true`,不发 npm 包。
@@ -25,7 +25,7 @@
25
25
  | 创建 / 改自定义代码页、portal、看板 | `openxiangda-page` | 编辑 `src/pages/<code>/` → `workspace publish --page <code>` |
26
26
  | 审批流程 / 流程节点 / JS_CODE | `openxiangda-workflow-automation` | `openxiangda workflow validate / create / publish` |
27
27
  | 自动化 / 定时任务 / 提交触发 / cron | `openxiangda-workflow-automation` | `openxiangda automation validate / create / publish / enable` |
28
- | 角色 / 权限组 / 字段权限 / 公开访问 | `openxiangda-permission-settings` | `openxiangda permission ...` / `openxiangda settings ...` |
28
+ | 账号 / 角色 / 权限组 / 字段权限 / 数据范围 / 查询参数授权 | `openxiangda-permission-settings` | `openxiangda design gates --topic permissions --json`,再 `openxiangda permission ...` / `openxiangda settings ...` |
29
29
  | 查应用结构 / 快照 / 对比 / 排查 / 报错 | `openxiangda-inspect` | `openxiangda app snapshot <APP_XXX> --profile <name> --json` |
30
30
  | 登录 / 切平台 / token / whoami | `openxiangda-core` | `openxiangda env --profile <name>` / `openxiangda auth status` |
31
31
  | 多表只读联表查询 / 报表数据源 | `openxiangda-form`(data view) | 在 `src/resources/data-views/<code>.json` 声明 → `resource publish` |
@@ -37,6 +37,8 @@
37
37
  - ✅ 先 preflight:`openxiangda env --profile <name>` + `openxiangda auth status --profile <name>` + `openxiangda update check --json`。
38
38
  - ✅ 架构类需求先 plan gate:`openxiangda doctor --profile <name> --json` + `openxiangda design gates --topic <code> --json`,用户确认后再实现。
39
39
  - ✅ 高风险变更先 SDD gate:`openxiangda sdd context --json` → `openxiangda sdd propose <change>` → 用户确认 → `openxiangda sdd approve <change>`。
40
+ - ✅ 涉及账号、角色、权限、数据范围、组织账号、RBAC、查询参数授权时,先跑 `openxiangda design gates --topic permissions --json`,选择 `managed-platform-account` / `existing-platform-user-assignment` / `static-role-permission` / `query-param-context`,并输出权限矩阵后再改资源。
41
+ - ✅ 某个应用角色如果要创建角色、分配角色成员、给角色授接口权限、维护页面/表单权限组或管理组织账号,必须在 `src/resources/roles/<code>.json` 声明 `apiPermissionCodes`,例如 `app:role:manage`、`app:page-permission-group:manage`、`app:form-permission-group:manage`、`app:organization:manage`。
40
42
  - ✅ 单文件改动默认增量发布:`workspace publish --profile <name> --changed --dry-run` → `--changed` / `--page` / `--form`。
41
43
  - ✅ 用户 token 在 `~/.openxiangda/profiles.json`;项目 state 在 `.openxiangda/state.json`(只存 ID)。
42
44
  - ✅ 共享环境(`APP_OSS_*`、反馈机器人等)在 `~/.openxiangda/.env`,项目 `.env` 仅做 per-workspace override。
@@ -54,6 +56,9 @@
54
56
  - ❌ 把 `openxiangda form create` / `form publish` / `page publish` 当作日常页面生成方式。它们仅作底层修复 / 诊断。
55
57
  - ❌ 改一个文件就 `workspace publish` 全量。
56
58
  - ❌ 用户确认架构设计前就实现、写平台资源、发布、部署或发送通知。
59
+ - ❌ 只隐藏按钮、只判断 query 参数、硬编码角色、前端模拟权限、假账号/假 ID、或用 `PermissionBoundary` 代替真实授权。敏感数据必须由角色、页面/表单权限组、public-access grants 或 App Function 后端校验保护。
60
+ - ❌ 只给用户分配“管理员”业务角色,却不给该角色绑定 `app:role:manage` 等角色设置接口权限,然后期望他能新增账号、角色或权限组。
61
+ - ❌ 直接绕过 SDK 调平台账号/组织写接口;应用管理平台账号/部门必须使用 `sdk.organization` / `ctx.organization`,且当前操作者具备 `app:organization:manage`。
57
62
  - ❌ 把 token、AK、SK、第三方密钥写进项目文件。
58
63
  - ❌ `npm publish` —— 这个工作区是 `"private": true` 的应用工作区,不是要发到 npm 的 package。
59
64
  - ❌ 在 AI 生成的 `src/forms/**` / `src/pages/**` 里直接写原生 `<input>` / `<select>` / `<textarea>` / `<input type="file">`、手写 picker、手写 uploader、手写人员/部门选择器。原生控件只允许出现在 OpenXiangda SDK / 平台组件内部。
@@ -27,6 +27,9 @@ Run `pnpm examples:check` after editing examples, and run the normal
27
27
  `shared/components/`.
28
28
  - Use state fields and operation logs for business lifecycle flows.
29
29
  - Use workflow only for real approval tasks.
30
+ - For account, role, data scope, organization-account, RBAC, or query-param
31
+ authorization work, run `openxiangda design gates --topic permissions --json`
32
+ and choose an access governance mode before copying examples.
30
33
  - Query with pagination and structured conditions. Avoid large page sizes,
31
34
  client-side filtering, and broad `searchKeyWord` queries.
32
35
  - For admin UI, choose one optional default from `glass-home-dashboard`,
@@ -0,0 +1,239 @@
1
+ # Access Governance Pattern
2
+
3
+ This example is a generic account and permission governance skeleton. Copy only
4
+ the parts required by the selected permission mode. Do not publish this example
5
+ directly without changing codes, names, roles, and data scopes.
6
+
7
+ Start with:
8
+
9
+ ```bash
10
+ openxiangda design gates --topic permissions --json
11
+ ```
12
+
13
+ Choose one mode:
14
+
15
+ - `managed-platform-account`: app creates/maintains platform departments,
16
+ accounts, and role members.
17
+ - `existing-platform-user-assignment`: app assigns existing platform users to
18
+ app roles and business scopes.
19
+ - `static-role-permission`: fixed roles and permission groups only.
20
+ - `query-param-context`: query parameters are only context, filters, or ticket
21
+ input; they do not grant sensitive data access.
22
+
23
+ ## Resource Closure
24
+
25
+ ```text
26
+ src/forms/organization_unit/schema.ts
27
+ src/forms/system_account/schema.ts
28
+ src/forms/role_assignment/schema.ts
29
+ src/functions/sync_access_governance/index.ts
30
+ src/resources/roles/access-roles.json
31
+ src/resources/permissions/page-groups/access-admin-pages.json
32
+ src/resources/permissions/form-groups/role_assignment/access-admin.json
33
+ ```
34
+
35
+ ## Form Skeletons
36
+
37
+ `organization_unit` stores business organization units and the platform
38
+ department sync result:
39
+
40
+ ```ts
41
+ export const organizationUnitFields = [
42
+ { fieldId: "unitName", label: "组织名称", componentName: "TextField", placeholder: "请输入组织名称" },
43
+ { fieldId: "unitCode", label: "组织编码", componentName: "TextField", placeholder: "请输入稳定组织编码" },
44
+ { fieldId: "parentUnit", label: "上级组织", componentName: "SelectField", placeholder: "请选择上级组织", options: [] },
45
+ { fieldId: "manager", label: "负责人", componentName: "UserSelectField", placeholder: "请选择负责人" },
46
+ { fieldId: "platformDeptId", label: "平台部门ID", componentName: "TextField", behavior: "HIDDEN" },
47
+ {
48
+ fieldId: "syncStatus",
49
+ label: "同步状态",
50
+ componentName: "SelectField",
51
+ behavior: "HIDDEN",
52
+ options: [
53
+ { label: "待同步", value: "pending" },
54
+ { label: "已同步", value: "synced" },
55
+ { label: "同步失败", value: "failed" },
56
+ ],
57
+ },
58
+ { fieldId: "syncMessage", label: "同步说明", componentName: "TextAreaField", behavior: "HIDDEN" },
59
+ { fieldId: "lastSyncedAt", label: "最后同步时间", componentName: "DateField", behavior: "HIDDEN" },
60
+ ];
61
+ ```
62
+
63
+ `system_account` stores the app-owned account record and the platform user sync
64
+ result:
65
+
66
+ ```ts
67
+ export const systemAccountFields = [
68
+ { fieldId: "displayName", label: "姓名", componentName: "TextField", placeholder: "请输入姓名" },
69
+ { fieldId: "loginName", label: "登录名", componentName: "TextField", placeholder: "请输入登录名" },
70
+ { fieldId: "phone", label: "手机号", componentName: "TextField", placeholder: "请输入手机号" },
71
+ { fieldId: "unitCode", label: "所属组织", componentName: "SelectField", placeholder: "请选择所属组织", options: [] },
72
+ {
73
+ fieldId: "enabled",
74
+ label: "账号状态",
75
+ componentName: "RadioField",
76
+ placeholder: "请选择账号状态",
77
+ options: [
78
+ { label: "启用", value: "enabled" },
79
+ { label: "停用", value: "disabled" },
80
+ ],
81
+ },
82
+ { fieldId: "platformUserId", label: "平台用户ID", componentName: "TextField", behavior: "HIDDEN" },
83
+ { fieldId: "platformDeptId", label: "平台部门ID", componentName: "TextField", behavior: "HIDDEN" },
84
+ {
85
+ fieldId: "syncStatus",
86
+ label: "同步状态",
87
+ componentName: "SelectField",
88
+ behavior: "HIDDEN",
89
+ options: [
90
+ { label: "待同步", value: "pending" },
91
+ { label: "已同步", value: "synced" },
92
+ { label: "同步失败", value: "failed" },
93
+ ],
94
+ },
95
+ { fieldId: "lastSyncedAt", label: "最后同步时间", componentName: "DateField", behavior: "HIDDEN" },
96
+ ];
97
+ ```
98
+
99
+ `role_assignment` maps accounts or existing platform users to roles and business
100
+ scope keys:
101
+
102
+ ```ts
103
+ export const roleAssignmentFields = [
104
+ { fieldId: "account", label: "账号", componentName: "SelectField", placeholder: "请选择账号", options: [] },
105
+ { fieldId: "platformUser", label: "平台用户", componentName: "UserSelectField", placeholder: "请选择平台用户" },
106
+ {
107
+ fieldId: "roleCodes",
108
+ label: "角色",
109
+ componentName: "CheckboxField",
110
+ placeholder: "请选择角色",
111
+ options: [
112
+ { label: "权限管理员", value: "access_admin" },
113
+ { label: "范围内经办人", value: "scope_operator" },
114
+ ],
115
+ },
116
+ { fieldId: "businessUnit", label: "业务组织", componentName: "SelectField", placeholder: "请选择业务组织", options: [] },
117
+ { fieldId: "businessScopeKey", label: "业务范围键", componentName: "TextField", behavior: "HIDDEN" },
118
+ {
119
+ fieldId: "syncStatus",
120
+ label: "同步状态",
121
+ componentName: "SelectField",
122
+ behavior: "HIDDEN",
123
+ options: [
124
+ { label: "待同步", value: "pending" },
125
+ { label: "已同步", value: "synced" },
126
+ { label: "同步失败", value: "failed" },
127
+ ],
128
+ },
129
+ { fieldId: "syncMessage", label: "同步说明", componentName: "TextAreaField", behavior: "HIDDEN" },
130
+ ];
131
+ ```
132
+
133
+ ## Sync App Function Skeleton
134
+
135
+ ```ts
136
+ export default async function syncAccessGovernance(ctx, input) {
137
+ const roleCodes = ctx.operator?.roleCodes || [];
138
+ if (!roleCodes.includes("access_admin") && !ctx.operator?.hasFullAccess) {
139
+ throw new Error("ACCESS_DENIED");
140
+ }
141
+
142
+ if (input.action === "syncAccount") {
143
+ if (!ctx.organization?.accounts) throw new Error("ORGANIZATION_API_UNAVAILABLE");
144
+ // Current operator must have app:organization:manage.
145
+ return ctx.organization.accounts.create({
146
+ name: input.displayName,
147
+ loginName: input.loginName,
148
+ phone: input.phone,
149
+ departmentId: input.platformDeptId,
150
+ });
151
+ }
152
+
153
+ if (input.action === "syncRoleMembers") {
154
+ // Read role_assignment records, resolve platformUserId values, and update
155
+ // app role members through the platform role API exposed by OpenXiangda.
156
+ return { ok: true };
157
+ }
158
+
159
+ throw new Error("UNKNOWN_ACTION");
160
+ }
161
+ ```
162
+
163
+ ## Role Resource
164
+
165
+ ```json
166
+ [
167
+ {
168
+ "code": "access_admin",
169
+ "name": "权限管理员",
170
+ "description": "维护组织、账号、角色和权限资源",
171
+ "apiPermissionMode": "merge",
172
+ "apiPermissionCodes": [
173
+ "app:role:manage",
174
+ "app:page-permission-group:manage",
175
+ "app:form-permission-group:manage",
176
+ "app:organization:manage"
177
+ ]
178
+ },
179
+ {
180
+ "code": "scope_operator",
181
+ "name": "范围内经办人",
182
+ "description": "只能访问授权业务范围内的数据"
183
+ }
184
+ ]
185
+ ```
186
+
187
+ The initial grant of `access_admin` is normally done by a platform administrator
188
+ or an existing app administrator. If `access_admin` creates another role that
189
+ also manages accounts, roles, or permission groups, publish that new role with
190
+ its own `apiPermissionCodes`; management power is not inherited from the
191
+ creator.
192
+
193
+ ## Page Permission Group
194
+
195
+ ```json
196
+ {
197
+ "code": "access_admin_pages",
198
+ "name": "权限管理员页面",
199
+ "roles": ["access_admin"],
200
+ "menuCodes": ["access_governance"],
201
+ "routeCodes": ["access.governance"],
202
+ "pathPatterns": ["/view/:appType/admin/access/*"]
203
+ }
204
+ ```
205
+
206
+ ## Form Permission Group
207
+
208
+ ```json
209
+ {
210
+ "code": "role_assignment_admin",
211
+ "formCode": "role_assignment",
212
+ "name": "角色分配管理员",
213
+ "type": "view",
214
+ "roles": ["access_admin"],
215
+ "operations": ["view", "edit", "delete"],
216
+ "dataScope": [{ "type": "all" }],
217
+ "fieldAccessPolicy": {
218
+ "defaultAccess": "edit",
219
+ "fields": [
220
+ { "fieldId": "syncMessage", "access": "readonly" }
221
+ ]
222
+ }
223
+ }
224
+ ```
225
+
226
+ For `scope_operator`, use condition data permission against hidden scalar keys,
227
+ for example `businessScopeKey = ${CURRENT_USER_SCOPE}`. Do not fetch all rows
228
+ and filter them in the page.
229
+
230
+ ## Acceptance
231
+
232
+ - Permission mode and matrix are written in the SDD change or design document.
233
+ - `openxiangda permission audit --json` has no high-risk gaps.
234
+ - Allowed and denied role paths are both tested.
235
+ - Query parameter tampering does not expand sensitive access.
236
+ - Managed account writes are executed only by a user with
237
+ `app:organization:manage`.
238
+ - Roles that create roles, assign members, or maintain permission groups include
239
+ `apiPermissionCodes` such as `app:role:manage`.
@@ -53,6 +53,12 @@
53
53
  "path": "src/pages/service-ticket-ops",
54
54
  "description": "DataManagementList-based ops page with modular actions, drawer, timeline, hook, and service."
55
55
  },
56
+ {
57
+ "code": "access-governance",
58
+ "type": "permissions",
59
+ "path": "access-governance.md",
60
+ "description": "Generic account/role permission mode decision with organization, account, role assignment, sync function, role resource, page group, and form group skeletons."
61
+ },
56
62
  {
57
63
  "code": "role-governance",
58
64
  "type": "permissions",
@@ -59,6 +59,21 @@ Frontend code must not be responsible for data isolation or background jobs.
59
59
 
60
60
  ## Permissions
61
61
 
62
+ Run `openxiangda design gates --topic permissions --json` before implementing
63
+ account, role, RBAC, organization-account, data-scope, or query-param
64
+ authorization requirements.
65
+
66
+ Choose one pattern:
67
+
68
+ - `managed-platform-account`: app creates and maintains platform departments,
69
+ accounts, and role members. Start from `access-governance.md`.
70
+ - `existing-platform-user-assignment`: app selects existing platform users and
71
+ assigns roles/business scopes. Use a role assignment form with
72
+ `UserSelectField`.
73
+ - `static-role-permission`: fixed roles and permission groups only.
74
+ - `query-param-context`: query parameters are context, filters, or ticket input
75
+ only; they cannot grant sensitive access.
76
+
62
77
  For dynamic multi-role apps, create a business role table and synchronize it to
63
78
  platform app roles. User-facing scope fields should be maintainable controls:
64
79
  personnel/department fields for people and orgs, enum fields for fixed option
@@ -67,4 +82,13 @@ customers, and other records maintained by forms. Use `remoteSearch: true` when
67
82
  the source form can have many records. If the platform permission condition
68
83
  needs a scalar value, derive a hidden scope key such as `collegeScopeKey` or
69
84
  `ownerDeptScopeKey`. Use form permission groups with condition-style data
70
- permissions to enforce data isolation.
85
+ permissions and App Function role/scope checks to enforce data isolation.
86
+
87
+ When an app role is expected to create roles, assign role members, grant role
88
+ API permissions, maintain permission groups, or manage organization accounts,
89
+ declare the matching `apiPermissionCodes` on that role. `app:role:manage` is
90
+ required for app role creation and member assignment; page/form permission group
91
+ maintenance and organization account management use their own permission codes.
92
+
93
+ Frontend hiding and query parameters are not authorization. They must not be the
94
+ only barrier for sensitive data or write actions.