openxiangda-skill-kit 2.0.0-alpha.64 → 2.0.0-alpha.66

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda-skill-kit",
3
- "version": "2.0.0-alpha.64",
3
+ "version": "2.0.0-alpha.66",
4
4
  "description": "Validation and deterministic packaging for OpenXiangda 2.0 AI skills.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -17,7 +17,7 @@
17
17
  "README.md"
18
18
  ],
19
19
  "dependencies": {
20
- "openxiangda-devkit-core": "2.0.0-alpha.46"
20
+ "openxiangda-devkit-core": "2.0.0-alpha.48"
21
21
  },
22
22
  "devDependencies": {
23
23
  "tsx": "4.23.12",
@@ -5,9 +5,9 @@ description: Use when building, inspecting, validating, or delivering a complete
5
5
 
6
6
  # OpenXiangda 2.0
7
7
 
8
- Use the generated React, NestJS and Data API workspace as one application. Before a workspace exists, invoke the exact 2.0 package published with this Skill: `pnpm dlx openxiangda-cli@2.0.0-alpha.79`. Inside an application use only its locked CLI through `pnpm openxiangda`; never invoke a bare global `openxiangda`, because that executable may belong to 1.x.
8
+ Use the generated React, NestJS and Data API workspace as one application. Before a workspace exists, invoke the exact 2.0 package published with this Skill: `pnpm dlx openxiangda-cli@2.0.0-alpha.81`. Inside an application use only its locked CLI through `pnpm openxiangda`; never invoke a bare global `openxiangda`, because that executable may belong to 1.x.
9
9
 
10
- Start with `pnpm dlx openxiangda-cli@2.0.0-alpha.79 login`, then `pnpm dlx openxiangda-cli@2.0.0-alpha.79 create <directory>`. Run `pnpm openxiangda dev` for the local feedback loop and `pnpm openxiangda check` before delivery. Moving tags such as `latest` and `alpha` are forbidden for bootstrap because package-manager metadata and dlx caches can resolve an older toolchain.
10
+ Start with `pnpm dlx openxiangda-cli@2.0.0-alpha.81 login`, then `pnpm dlx openxiangda-cli@2.0.0-alpha.81 create <directory>`. Run `pnpm openxiangda dev` for the local feedback loop and `pnpm openxiangda check` before delivery. Moving tags such as `latest` and `alpha` are forbidden for bootstrap because package-manager metadata and dlx caches can resolve an older toolchain.
11
11
 
12
12
  For an AI-native development client, start the workspace MCP through the same
13
13
  pinned executable with `pnpm exec openxiangda --mcp-stdio --cwd <workspace>`.
@@ -19,11 +19,19 @@ path.
19
19
 
20
20
  Keep ordinary CRUD on the platform Data API. Use NestJS only for real business actions. Page and field guards improve the interface; the platform remains authoritative for rows, fields and actions.
21
21
 
22
+ For every CRUD application, read [Data and authorization](references/data-authz.md)
23
+ before editing the manifest. Declare each resource through only `code`, `name`,
24
+ `fields` and optional list/layout/data-policy settings. Each field declares its
25
+ type, label, required state, Surface flags, reference/file metadata and access
26
+ once. `schema`, `surface`, resource `capabilities`, resource `fieldPolicies` and
27
+ `platform/data` modules are forbidden application source.
28
+
22
29
  Deploy test data first with `pnpm openxiangda deploy`. Inspect it with `pnpm openxiangda status` and `pnpm openxiangda logs`. Select production explicitly only after the same tested version succeeds. Use `pnpm openxiangda rollback --to <app-version-id>` when a verified prior version must be restored.
23
30
 
24
31
  OpenXiangda 2.0 has no compatibility surface. Do not add Umi, ProComponents, RoleSession, Function CRUD, underscore resource codes, `fieldPolicies.write`, legacy Skill routing, package aliases or migration branches. Replace a wrong alpha contract directly.
25
32
 
26
- Read only the reference needed for the current change:
33
+ Read only the reference needed for the current change, except that CRUD work
34
+ always reads Data and authorization as required above:
27
35
 
28
36
  - [Architecture](references/architecture.md)
29
37
  - [Workspace agent contract](references/workspace.md)
@@ -53,6 +53,12 @@ Backend routes are private to the application unless their operation declaration
53
53
  }
54
54
  ```
55
55
 
56
+ Every custom operation capability is declared once in
57
+ `authz.capabilities` with `kind: 'backend'`, then referenced by the operation
58
+ and granted to every role allowed to call it. A capability string written only
59
+ on an operation or role is invalid. Resource CRUD capabilities remain generated
60
+ and must not be copied into this catalog.
61
+
56
62
  Generated CRUD and custom actions use the same platform Catalog, current-user authorization, Preview/Confirm boundary and idempotent execution path. Do not create an application-owned MCP server, preview store, AI role or database client.
57
63
 
58
64
  For visitor duplicates, meeting-time conflicts, and course capacity, use
@@ -62,6 +68,33 @@ calculate replacement counters in application code. Course selection is a
62
68
  locked `record-assert` plus a bounded `increment`; replay must reach the
63
69
  platform idempotency receipt even after the course becomes full.
64
70
 
71
+ The visitor helper has one exact command shape. `duplicateMatch` is the actual
72
+ field-to-submitted-value object used for equality matching; it is never a list
73
+ of field names:
74
+
75
+ ```ts
76
+ return this.operations.createVisitorReservation({
77
+ reservationResourceCode: 'visitor-reservations',
78
+ duplicateMatch: {
79
+ visitorIdentityNumber: body.visitorIdentityNumber,
80
+ visitDate: body.visitDate,
81
+ startTime: body.startTime,
82
+ },
83
+ data: {
84
+ visitorIdentityNumber: body.visitorIdentityNumber,
85
+ visitDate: body.visitDate,
86
+ startTime: body.startTime,
87
+ status: body.status,
88
+ },
89
+ idempotencyKey: body.idempotencyKey,
90
+ activeStatusField: 'status',
91
+ activeStatusValues: ['pending', 'approved'],
92
+ });
93
+ ```
94
+
95
+ Use only declared field codes in `duplicateMatch`. Its values and `data` come
96
+ from the same immutable request body.
97
+
65
98
  An idempotency key and the complete command payload are one immutable pair.
66
99
  Never put `new Date()`, `Date.now()`, `randomUUID()` or another changing value
67
100
  inside a controller while constructing the transaction. If a business time is
@@ -1,7 +1,93 @@
1
1
  # OpenXiangda 2.0 Data and Authorization
2
2
 
3
- Declare stable capabilities and application roles. Express row access with platform-enforced predicates such as unrestricted school access, college field matching and current-user membership in an instrument manager array.
3
+ Declare a resource and every field exactly once in `openxiangda.config.ts`.
4
+ Do not write `schemaVersion`, `appCode`, `schema`, `capabilities`, `surface` or
5
+ resource-level `fieldPolicies`; those are compiler projections, not application
6
+ source. Do not create `platform/data` modules.
4
7
 
5
- Declare restricted field access separately for read, create and update. There is no shared `write` field and no fallback. A resource create capability owns unrestricted fields; generated update access is denied until the field declares update capabilities. Capability arrays are all-of. Frontend filtering is presentation only. Run `pnpm openxiangda check` after every policy change.
8
+ ```ts
9
+ import {
10
+ currentUserDataPolicy,
11
+ defineOpenXiangdaApp,
12
+ resourceCapabilityCodes,
13
+ } from 'openxiangda-devkit-core';
6
14
 
7
- One resource field owns storage and selector semantics together. A single `directory-user` reference uses `type: 'string'`; a single `directory-department` or same-application `resource` reference uses `type: 'uuid'`; every reference with `multiple: true` uses `type: 'json'`. Resource references must target a declared resource and a `string` or `text` label field. File limits belong only on `type: 'file'`. Never save labels or copied directory objects. Any role that reads or edits directory-backed fields must explicitly include `app:<app-code>:directory:read`.
15
+ const APP_CODE = 'visitor-center';
16
+ const reservations = resourceCapabilityCodes(APP_CODE, 'visitor-reservations');
17
+
18
+ const visitorReservations = {
19
+ code: 'visitor-reservations',
20
+ name: '访客预约',
21
+ dataPolicyCode: 'reservation-host',
22
+ fields: [
23
+ {
24
+ code: 'visitorName', type: 'string', label: '访客姓名', required: true,
25
+ indexed: true, list: true, filter: true, searchable: true, sortable: true,
26
+ section: '访客信息',
27
+ },
28
+ {
29
+ code: 'visitDate', type: 'date', label: '来访日期', required: true,
30
+ list: true, filter: true, sortable: true, section: '来访安排',
31
+ },
32
+ {
33
+ code: 'hostUserId', type: 'string', label: '接待人', required: true,
34
+ reference: { kind: 'directory-user' }, list: true, filter: true,
35
+ },
36
+ {
37
+ code: 'hostDepartmentId', type: 'uuid', label: '接待部门',
38
+ reference: { kind: 'directory-department' }, list: true, filter: true,
39
+ },
40
+ {
41
+ code: 'attachments', type: 'file', label: '附件',
42
+ file: { multiple: true, maxCount: 5, maxSizeMb: 20, accept: ['image/*', '.pdf'] },
43
+ },
44
+ {
45
+ code: 'internalNote', type: 'text', label: '内部备注',
46
+ access: { read: ['app:visitor-center:internal-note:read'], update: false },
47
+ },
48
+ ],
49
+ list: { defaultPageSize: 20, defaultSort: { field: 'visitDate', order: 'desc' } },
50
+ form: { layout: 'sections' }, detail: { layout: 'sections' },
51
+ mobile: { enabled: true },
52
+ };
53
+ ```
54
+
55
+ Put it in `data: { resources: [visitorReservations] }`. Resource CRUD
56
+ capabilities are derived by `resourceCapabilityCodes`; grant the needed values
57
+ to roles. Directory-backed roles also require
58
+ `app:<app-code>:directory:read`. Explicit field `access` capability codes are
59
+ also granted only to the intended roles.
60
+
61
+ `required: true` owns both storage nullability and form validation. A field
62
+ without `access` inherits the resource read/create/update capability. Each
63
+ access array is all-of; `false` is explicit deny. The same arrays drive the
64
+ generated UI and platform field policies.
65
+
66
+ The complete storage type set is `string`, `text`, `integer`, `decimal`,
67
+ `boolean`, `date`, `datetime`, `uuid`, `json` and `file`. Use `integer` for
68
+ whole numbers and `decimal` for other numeric values; `number` is not a field
69
+ type. `openxiangda check` reports an invalid type at the authored field path.
70
+
71
+ A single directory user reference uses `type: 'string'`; a single department
72
+ or same-app resource reference uses `uuid`; any `reference.multiple: true` uses
73
+ `json`. A resource reference also declares `resourceCode` and a string/text
74
+ `labelField`. File limits exist only under `file` and use `maxSizeMb`.
75
+
76
+ Current-user row access has one spelling only:
77
+
78
+ ```ts
79
+ currentUserDataPolicy({
80
+ code: 'reservation-host',
81
+ name: '接待人员仅查看本人预约',
82
+ resourceCode: 'visitor-reservations',
83
+ field: 'hostUserId',
84
+ roleCodes: ['reception_staff'],
85
+ unrestrictedRoleCodes: ['visitor_admin'],
86
+ })
87
+ ```
88
+
89
+ Put that value in `authz.dataPolicies`, declare both roles, and set the
90
+ resource `dataPolicyCode` to the same code. Do not invent `operator`, `value`,
91
+ `current_user: true`, lowercase match modes, or policy-level `roleCodes`.
92
+
93
+ Run `pnpm openxiangda check` after every declaration or permission change.
@@ -2,14 +2,19 @@
2
2
 
3
3
  - Use only the workspace-pinned CLI: `pnpm openxiangda <command>`. Never invoke a bare global `openxiangda` inside a 2.0 task.
4
4
  - Use Vite, React Router, Refine Core and Ant Design. Do not add Umi, ProComponents or another admin shell.
5
- - Declare each resource once in `openxiangda.config.ts`. Resource codes are lower kebab-case. The same declaration owns storage, Surface metadata, permissions and generated AI Schema.
5
+ - Declare each resource once in `openxiangda.config.ts` with only `code`, `name`, `fields` and optional list/layout/data-policy settings. Each field owns type, label, required state, Surface flags, reference/file metadata and access. Resource codes are lower kebab-case.
6
+ - Never write resource-level `schemaVersion`, `appCode`, `schema`, `surface`, `capabilities`, `fieldPolicies` or `platform/data` modules. The compiler derives the strict DataResource, CRUD capabilities, Surface and AI Schema. The application manifest still starts with its one top-level `schemaVersion: 3`.
6
7
  - Ordinary list/get/create/update/delete, filters, export and batch operations use the platform Native Data API. Do not create Function CRUD or NestJS wrappers.
7
8
  - Add NestJS only for a named business action that needs a cross-resource transaction, an invariant or an external side effect.
8
9
  - A NestJS backend declares only `enabled`, `isolation: 'shared' | 'dedicated'` and `resourceProfile: 'light' | 'standard'`. Never put raw Kubernetes resources, replicas, ports or environment maps in application metadata; the platform owns capacity and scaling.
9
10
  - Use the current logged-in user and the union of application roles. Do not select RoleSession, persist platform Token or implement a second authorization path.
10
- - Declare restricted field read, create and update permissions explicitly. There is no `write` fallback; generated update permission is denied unless explicitly granted.
11
+ - Fields inherit the resource read/create/update capabilities. Use field `access` only to tighten them; arrays are all-of and `false` is explicit deny. There is no `write` fallback.
12
+ - Field storage types are exactly `string`, `text`, `integer`, `decimal`, `boolean`, `date`, `datetime`, `uuid`, `json` and `file`; there is no `number` type.
13
+ - Declare every custom operation capability in `authz.capabilities` with `kind: 'backend'`, then reference that same code from the operation and its allowed roles. Generated resource CRUD capabilities do not go in this catalog.
14
+ - Visitor duplicate protection uses `createVisitorReservation({ duplicateMatch: { fieldCode: submittedValue }, ... })`. `duplicateMatch` is a non-empty value map, never a field-name array, and no mutable pre-read is allowed.
11
15
  - Desktop and mobile pages share values, validation and authorization, but use separate renderers. Members, departments, resources and attachments use platform-owned selectors and stable IDs.
12
16
  - A single directory user reference uses a `string` field; a single department or same-app resource reference uses `uuid`; every `multiple: true` reference uses `json`. Roles that consume directory-backed fields explicitly include `app:<app-code>:directory:read`.
17
+ - Derive role grants with `resourceCapabilityCodes(appCode, resourceCode)`. Declare current-user rows only with `currentUserDataPolicy(...)`; do not invent operators, values or alternate current-user spellings.
13
18
  - Do not add compatibility aliases, migration branches or silent fallbacks for an earlier 2.0 alpha contract. Replace an incorrect contract and regenerate the application.
14
19
  - Run `pnpm openxiangda check` after contract changes. Deploy with `pnpm openxiangda deploy`, inspect with `pnpm openxiangda status` and `pnpm openxiangda logs`, and use the platform rollback command rather than mutating K3s directly.
15
20
  - AI-native clients start the workspace protocol through the same pinned binary: `pnpm exec openxiangda --mcp-stdio --cwd <workspace>`. Read `openxiangda://workspace/contracts` or call `contract_describe`, and require its `aiCatalog` and `aiCatalogDigest` to match the normal compiler output. This is a stdio transport mode, not a ninth CLI command. Never write an application MCP server, Catalog file, preview store or second authorization path.