@carthooks/arcubase-cli 0.1.10 → 0.1.12

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 (105) hide show
  1. package/bundle/arcubase-admin.mjs +1274 -375
  2. package/bundle/arcubase.mjs +1274 -375
  3. package/dist/generated/command_registry.generated.d.ts +36 -35
  4. package/dist/generated/command_registry.generated.d.ts.map +1 -1
  5. package/dist/generated/command_registry.generated.js +37 -36
  6. package/dist/generated/type_index.generated.d.ts +23 -23
  7. package/dist/generated/type_index.generated.js +23 -23
  8. package/dist/runtime/entity_save_schema.d.ts.map +1 -1
  9. package/dist/runtime/entity_save_schema.js +30 -0
  10. package/dist/runtime/env.d.ts +2 -1
  11. package/dist/runtime/env.d.ts.map +1 -1
  12. package/dist/runtime/env.js +10 -1
  13. package/dist/runtime/errors.d.ts +2 -0
  14. package/dist/runtime/errors.d.ts.map +1 -1
  15. package/dist/runtime/execute.d.ts +4 -2
  16. package/dist/runtime/execute.d.ts.map +1 -1
  17. package/dist/runtime/execute.js +944 -134
  18. package/dist/runtime/paths.d.ts +1 -1
  19. package/dist/runtime/paths.d.ts.map +1 -1
  20. package/dist/runtime/paths.js +9 -2
  21. package/dist/runtime/upload.d.ts +1 -11
  22. package/dist/runtime/upload.d.ts.map +1 -1
  23. package/dist/runtime/upload.js +19 -133
  24. package/dist/runtime/zod_registry.d.ts +5 -3
  25. package/dist/runtime/zod_registry.d.ts.map +1 -1
  26. package/dist/runtime/zod_registry.js +108 -48
  27. package/dist/tests/bootstrap.test.js +12 -0
  28. package/dist/tests/command_registry.test.js +8 -0
  29. package/dist/tests/docs_readability.test.d.ts +2 -0
  30. package/dist/tests/docs_readability.test.d.ts.map +1 -0
  31. package/dist/tests/docs_readability.test.js +87 -0
  32. package/dist/tests/entity_save_schema.test.js +22 -0
  33. package/dist/tests/execute_validation.test.js +381 -44
  34. package/dist/tests/help.test.js +45 -8
  35. package/dist/tests/upload.test.js +30 -77
  36. package/package.json +1 -1
  37. package/sdk-dist/docs/runtime-reference/README.md +43 -29
  38. package/sdk-dist/docs/runtime-reference/access-rule.md +109 -0
  39. package/sdk-dist/docs/runtime-reference/condition.md +182 -0
  40. package/sdk-dist/docs/runtime-reference/entity-schema/README.md +6 -5
  41. package/sdk-dist/docs/runtime-reference/entity-schema/checkbox.md +1 -1
  42. package/sdk-dist/docs/runtime-reference/entity-schema/file.md +2 -2
  43. package/sdk-dist/docs/runtime-reference/entity-schema/image.md +2 -2
  44. package/sdk-dist/docs/runtime-reference/entity-schema/linkto.md +3 -3
  45. package/sdk-dist/docs/runtime-reference/entity-schema/number.md +1 -1
  46. package/sdk-dist/docs/runtime-reference/entity-schema/query.md +3 -3
  47. package/sdk-dist/docs/runtime-reference/entity-schema/relation.md +3 -3
  48. package/sdk-dist/docs/runtime-reference/entity-schema/relationfield.md +3 -3
  49. package/sdk-dist/docs/runtime-reference/entity-schema/status.md +1 -1
  50. package/sdk-dist/docs/runtime-reference/entity-schema/text.md +1 -1
  51. package/sdk-dist/docs/runtime-reference/entity-schema.md +28 -21
  52. package/sdk-dist/docs/runtime-reference/examples/README.md +1 -1
  53. package/sdk-dist/docs/runtime-reference/examples/crm-01/README.md +30 -11
  54. package/sdk-dist/docs/runtime-reference/examples/crm-01/contact.create-entity.json +1 -0
  55. package/sdk-dist/docs/runtime-reference/examples/crm-01/contact.schema.json +1 -0
  56. package/sdk-dist/docs/runtime-reference/examples/crm-01/create-app.json +1 -0
  57. package/sdk-dist/docs/runtime-reference/examples/crm-01/customer.create-entity.json +1 -0
  58. package/sdk-dist/docs/runtime-reference/examples/crm-01/customer.schema.json +1 -0
  59. package/sdk-dist/docs/runtime-reference/examples/crm-01/follow-up.create-entity.json +1 -0
  60. package/sdk-dist/docs/runtime-reference/examples/crm-01/follow-up.schema.json +1 -0
  61. package/sdk-dist/docs/runtime-reference/examples/crm-01/lead.bulk-update.json +1 -0
  62. package/sdk-dist/docs/runtime-reference/examples/crm-01/lead.create-entity.json +1 -0
  63. package/sdk-dist/docs/runtime-reference/examples/crm-01/lead.query.json +1 -0
  64. package/sdk-dist/docs/runtime-reference/examples/crm-01/lead.row.insert.json +1 -0
  65. package/sdk-dist/docs/runtime-reference/examples/crm-01/lead.schema.json +1 -0
  66. package/sdk-dist/docs/runtime-reference/examples/crm-01/lead.selection.condition.json +1 -0
  67. package/sdk-dist/docs/runtime-reference/examples/oms-01/README.md +26 -26
  68. package/sdk-dist/docs/runtime-reference/examples/oms-01/sales-order.row.insert.json +1 -1
  69. package/sdk-dist/docs/runtime-reference/examples/wms-01/README.md +26 -10
  70. package/sdk-dist/docs/runtime-reference/examples/wms-01/create-app.json +1 -0
  71. package/sdk-dist/docs/runtime-reference/examples/wms-01/goods-receipt.create-entity.json +1 -0
  72. package/sdk-dist/docs/runtime-reference/examples/wms-01/goods-receipt.schema.json +1 -0
  73. package/sdk-dist/docs/runtime-reference/examples/wms-01/inventory-snapshot.bulk-update.json +1 -0
  74. package/sdk-dist/docs/runtime-reference/examples/wms-01/inventory-snapshot.create-entity.json +1 -0
  75. package/sdk-dist/docs/runtime-reference/examples/wms-01/inventory-snapshot.query.json +1 -0
  76. package/sdk-dist/docs/runtime-reference/examples/wms-01/inventory-snapshot.schema.json +1 -0
  77. package/sdk-dist/docs/runtime-reference/examples/wms-01/inventory-snapshot.selection.condition.json +1 -0
  78. package/sdk-dist/docs/runtime-reference/examples/wms-01/item-master.create-entity.json +1 -0
  79. package/sdk-dist/docs/runtime-reference/examples/wms-01/item-master.schema.json +1 -0
  80. package/sdk-dist/docs/runtime-reference/examples/wms-01/stock-issue.create-entity.json +1 -0
  81. package/sdk-dist/docs/runtime-reference/examples/wms-01/stock-issue.schema.json +1 -0
  82. package/sdk-dist/docs/runtime-reference/row-crud.md +35 -8
  83. package/sdk-dist/docs/runtime-reference/search-and-bulk-actions.md +31 -95
  84. package/sdk-dist/docs/runtime-reference/selection.md +128 -0
  85. package/sdk-dist/docs/runtime-reference/table-lifecycle.md +113 -30
  86. package/sdk-dist/docs/runtime-reference/uploads.md +30 -59
  87. package/sdk-dist/docs/runtime-reference/workflow/README.md +129 -13
  88. package/sdk-dist/generated/command_registry.generated.ts +37 -36
  89. package/sdk-dist/generated/type_index.generated.ts +23 -23
  90. package/src/generated/command_registry.generated.ts +37 -36
  91. package/src/generated/type_index.generated.ts +23 -23
  92. package/src/runtime/entity_save_schema.ts +30 -0
  93. package/src/runtime/env.ts +14 -2
  94. package/src/runtime/errors.ts +2 -0
  95. package/src/runtime/execute.ts +1166 -134
  96. package/src/runtime/paths.ts +11 -2
  97. package/src/runtime/upload.ts +19 -178
  98. package/src/runtime/zod_registry.ts +113 -48
  99. package/src/tests/bootstrap.test.ts +16 -0
  100. package/src/tests/command_registry.test.ts +9 -0
  101. package/src/tests/docs_readability.test.ts +96 -0
  102. package/src/tests/entity_save_schema.test.ts +22 -0
  103. package/src/tests/execute_validation.test.ts +508 -47
  104. package/src/tests/help.test.ts +49 -8
  105. package/src/tests/upload.test.ts +34 -91
@@ -0,0 +1,182 @@
1
+ # Condition
2
+
3
+ There are three different condition shapes. Do not mix them.
4
+
5
+ ## 1. Selection Condition
6
+
7
+ Used only inside:
8
+
9
+ - `EntitySelectionVO.condition`
10
+ - `arcubase row bulk-update`
11
+ - `arcubase row selection-action`
12
+
13
+ Shape:
14
+
15
+ ```json
16
+ {
17
+ "selection": {
18
+ "type": "condition",
19
+ "length": 10,
20
+ "condition": {
21
+ "q": "SO-1001",
22
+ "filter_:1002": "%7B%22is%22%3A%22new%22%7D",
23
+ "selectAll": true
24
+ }
25
+ }
26
+ }
27
+ ```
28
+
29
+ Rules:
30
+
31
+ - route-query search state
32
+ - keys: `q`, `tab`, `filter_<column>`, `selectAll`
33
+ - `selectAll` must be `true`
34
+ - `filter_<column>` value is URL-encoded `FilterCond` JSON
35
+ - not `ConditionSet`
36
+ - not `{field, operator, value}`
37
+
38
+ Source paths:
39
+
40
+ - `backend/app/controllers/entityUtils/queryContext.go`
41
+ - `frontend/src/views/Entity/ListView.vue`
42
+ - `frontend/src/views/Entity/Admin/Data/Index.vue`
43
+ - `$ARCUBASE_SDK_ROOT/types/user-action.ts`
44
+
45
+ ## 2. FilterCond
46
+
47
+ Used as the decoded value of route-query `filter_<column>`.
48
+
49
+ Shape:
50
+
51
+ ```json
52
+ {
53
+ "is": "new"
54
+ }
55
+ ```
56
+
57
+ More shapes:
58
+
59
+ ```json
60
+ {"in":["new","qualified"]}
61
+ ```
62
+
63
+ ```json
64
+ {"number_in":[2188890411,2188890412]}
65
+ ```
66
+
67
+ ```json
68
+ {"gt":0,"le":100}
69
+ ```
70
+
71
+ Rules:
72
+
73
+ - encode before putting into `filter_<column>`
74
+ - field columns use `:<field_id>`, for example `filter_:1002`
75
+ - property columns use the property name, for example `filter_id`
76
+ - supported keys: `is`, `in`, `number_in`, `null`, `lt`, `gt`, `ge`, `le`, `eq`, `at`, `expr`
77
+
78
+ Encoded example:
79
+
80
+ ```json
81
+ {
82
+ "selection": {
83
+ "type": "condition",
84
+ "length": 1,
85
+ "condition": {
86
+ "filter_:1002": "%7B%22is%22%3A%22new%22%7D",
87
+ "selectAll": true
88
+ }
89
+ }
90
+ }
91
+ ```
92
+
93
+ Source paths:
94
+
95
+ - `backend/app/models/permit/listOptions.go`
96
+ - `backend/app/controllers/entityUtils/queryContext.go`
97
+ - `frontend/src/types/vo/permit.ts`
98
+
99
+ ## 3. ConditionSet
100
+
101
+ Used by configuration systems:
102
+
103
+ - access-rule policies
104
+ - list tabs
105
+ - relation/linkto field config
106
+ - automate rules
107
+ - workflow branches
108
+ - dashboard widgets
109
+
110
+ Shape:
111
+
112
+ ```json
113
+ {
114
+ "mode": "and",
115
+ "conditions": [
116
+ {
117
+ "column": ":1004",
118
+ "operator": "$eq",
119
+ "value": "confirmed"
120
+ }
121
+ ]
122
+ }
123
+ ```
124
+
125
+ Relation value shape:
126
+
127
+ ```json
128
+ {
129
+ "mode": "and",
130
+ "conditions": [
131
+ {
132
+ "column": ":2002",
133
+ "operator": "$eq",
134
+ "value_from": 2,
135
+ "value_relation": ":1001"
136
+ }
137
+ ]
138
+ }
139
+ ```
140
+
141
+ Nested shape:
142
+
143
+ ```json
144
+ {
145
+ "mode": "or",
146
+ "conditions": [
147
+ {
148
+ "subset": {
149
+ "mode": "and",
150
+ "conditions": [
151
+ { "column": ":1002", "operator": "$eq", "value": "A" }
152
+ ]
153
+ }
154
+ }
155
+ ]
156
+ }
157
+ ```
158
+
159
+ Rules:
160
+
161
+ - this is not valid inside `selection.condition`
162
+ - `column` and `value_relation` are `PermitEntityProp`, for example `:1001`
163
+ - operators use backend operators such as `$eq`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`
164
+ - empty condition set is `{ "mode": "and", "conditions": [] }`
165
+
166
+ Source paths:
167
+
168
+ - `backend/app/models/permit/policy.go`
169
+ - `backend/app/models/permit/listOptions.go`
170
+ - `backend/app/models/linkto/types.go`
171
+ - `frontend/src/types/vo/condition.vo.ts`
172
+ - `$ARCUBASE_SDK_ROOT/types/common.ts`
173
+
174
+ ## Quick Decision
175
+
176
+ | Need | Use |
177
+ | --- | --- |
178
+ | Act on exact rows | `selection.type=ids` |
179
+ | Act on current filtered list | `selection.type=condition` with route-query keys |
180
+ | Query all rows through selection-action | `selection.type=all` |
181
+ | Filter one route-query column | `FilterCond` JSON under `filter_<column>` |
182
+ | Configure permission/rule/relation/workflow condition | `ConditionSet` |
@@ -3,10 +3,10 @@
3
3
  Use this directory while building `save-entity.json` for:
4
4
 
5
5
  ```bash
6
- arcubase-admin entity admin-save-entity \
6
+ arcubase-admin table update-schema \
7
7
  --app-id <app_id> \
8
8
  --table-id <table_id> \
9
- --body-file save-entity.json
9
+ --body-file save-entity.json | --body-json <json-string>
10
10
  ```
11
11
 
12
12
  ## How to use these field pages
@@ -14,7 +14,7 @@ arcubase-admin entity admin-save-entity \
14
14
  1. fetch the current shell with:
15
15
 
16
16
  ```bash
17
- arcubase-admin entity admin-get-entity-info \
17
+ arcubase-admin table get \
18
18
  --app-id <app_id> \
19
19
  --table-id <table_id>
20
20
  ```
@@ -32,7 +32,7 @@ These field pages do **not** replace the full base field shape. They only explai
32
32
  ## Global save rules
33
33
 
34
34
  - `fields` must be `FieldVO[]`
35
- - field ids should start from `1001`
35
+ - first field id is `1001`; `1000` is the empty-schema baseline
36
36
  - field ids must be non-zero
37
37
  - `field_id_seq > max(field.id)`
38
38
  - top-level `layout` may only reference top-level field ids
@@ -53,8 +53,9 @@ If you need row payloads, read:
53
53
 
54
54
  Current important row rules:
55
55
 
56
- - row delete uses:
56
+ - row delete / restore uses:
57
57
  - `arcubase row delete`
58
+ - `arcubase row update`
58
59
  - `selection.type = "ids"`
59
60
  - `subform` row values use:
60
61
  - `[{ "id": 0, "fields": { ... } }]`
@@ -47,7 +47,7 @@ Multi-select enum field.
47
47
 
48
48
  ## Save-ready reminder
49
49
 
50
- For `arcubase-admin entity admin-save-entity`, keep the full base `FieldVO`.
50
+ For `arcubase-admin table update-schema`, keep the full base `FieldVO`.
51
51
 
52
52
  The saved field still needs:
53
53
 
@@ -48,6 +48,6 @@ File upload field.
48
48
  When inserting or updating row data for a `file` field:
49
49
 
50
50
  - do not construct upload payload objects by hand
51
- - run `arcubase upload <local-file>` first
52
- - use the returned `data` array directly as the row field value
51
+ - use the `upload token` flow in `../uploads.md`
52
+ - pass the returned upload value array directly as the row field value
53
53
  - read `../uploads.md`
@@ -47,6 +47,6 @@ Image upload field.
47
47
  When inserting or updating row data for an `image` field:
48
48
 
49
49
  - do not construct upload payload objects by hand
50
- - run `arcubase upload <local-file>` first
51
- - use the returned `data` array directly as the row field value
50
+ - use the `upload token` flow in `../uploads.md`
51
+ - pass the returned upload value array directly as the row field value
52
52
  - read `../uploads.md`
@@ -25,7 +25,7 @@ Relation picker field.
25
25
  "structure": "multiple",
26
26
  "relation": {
27
27
  "app_id": 1,
28
- "table_id": 2,
28
+ "entity_id": 2,
29
29
  "type": "entity",
30
30
  "show_fields": [1001],
31
31
  "queryFields": [1001],
@@ -45,7 +45,7 @@ Relation picker field.
45
45
  - `backfill`
46
46
  - `addValue`
47
47
  - `relation.app_id`
48
- - `relation.table_id`
48
+ - `relation.entity_id`
49
49
  - `relation.type`
50
50
  - `relation.show_fields`
51
51
  - `relation.queryFields`
@@ -55,7 +55,7 @@ Relation picker field.
55
55
 
56
56
  ## Constraints
57
57
 
58
- - `relation.app_id` and `relation.table_id` are required
58
+ - `relation.app_id` and `relation.entity_id` are required
59
59
  - `relation.show_fields` should be explicit
60
60
  - `relation.sorts` should include at least one default sort
61
61
  - row CRUD may store an empty array when no linked record is selected
@@ -58,7 +58,7 @@ Numeric field.
58
58
 
59
59
  ## Save-ready reminder
60
60
 
61
- For `arcubase-admin entity admin-save-entity`, keep the full base `FieldVO`.
61
+ For `arcubase-admin table update-schema`, keep the full base `FieldVO`.
62
62
 
63
63
  In practice, do not forget:
64
64
 
@@ -15,7 +15,7 @@ Selection-query field based on relation config.
15
15
  "addValue": true,
16
16
  "relation": {
17
17
  "app_id": 1,
18
- "table_id": 2,
18
+ "entity_id": 2,
19
19
  "type": "entity",
20
20
  "show_fields": [1001],
21
21
  "queryFields": [1001],
@@ -32,7 +32,7 @@ Selection-query field based on relation config.
32
32
  - `structure`
33
33
  - `addValue`
34
34
  - `relation.app_id`
35
- - `relation.table_id`
35
+ - `relation.entity_id`
36
36
  - `relation.type`
37
37
  - `relation.show_fields`
38
38
  - `relation.queryFields`
@@ -41,7 +41,7 @@ Selection-query field based on relation config.
41
41
 
42
42
  ## Constraints
43
43
 
44
- - `relation.app_id` and `relation.table_id` are required
44
+ - `relation.app_id` and `relation.entity_id` are required
45
45
  - `relation.type` must be explicit; use `entity`
46
46
  - `relation.show_fields` should be explicit
47
47
  - `relation.queryFields` should be explicit in manual mode
@@ -14,7 +14,7 @@ Entity relation field.
14
14
  "placeholder": "",
15
15
  "relation": {
16
16
  "app_id": 1,
17
- "table_id": 2,
17
+ "entity_id": 2,
18
18
  "type": "entity",
19
19
  "show_fields": [1001],
20
20
  "queryFields": [1001],
@@ -33,7 +33,7 @@ Entity relation field.
33
33
  - `structure`
34
34
  - `addValue`
35
35
  - `relation.app_id`
36
- - `relation.table_id`
36
+ - `relation.entity_id`
37
37
  - `relation.type`
38
38
  - `relation.show_fields`
39
39
  - `relation.queryFields`
@@ -44,7 +44,7 @@ Entity relation field.
44
44
 
45
45
  ## Constraints
46
46
 
47
- - `relation.app_id` and `relation.table_id` are required
47
+ - `relation.app_id` and `relation.entity_id` are required
48
48
  - `relation.show_fields` should be explicit
49
49
  - `relation.sorts` should include at least one default sort
50
50
  - In the current direct-write path, `mode` common values:
@@ -12,7 +12,7 @@ Derived field that reads a target value through an existing relation field.
12
12
  "options": {
13
13
  "relation": {
14
14
  "app_id": 1,
15
- "table_id": 2,
15
+ "entity_id": 2,
16
16
  "type": "entity"
17
17
  }
18
18
  }
@@ -22,7 +22,7 @@ Derived field that reads a target value through an existing relation field.
22
22
  ## Available options
23
23
 
24
24
  - `relation.app_id`
25
- - `relation.table_id`
25
+ - `relation.entity_id`
26
26
  - `relation.type`
27
27
  - `relation.show_fields`
28
28
  - `relation.queryFields`
@@ -33,6 +33,6 @@ Derived field that reads a target value through an existing relation field.
33
33
  ## Constraints
34
34
 
35
35
  - `options.relation` is required
36
- - `relation.app_id` and `relation.table_id` are required
36
+ - `relation.app_id` and `relation.entity_id` are required
37
37
  - use `relation.type = "entity"` in the current direct-write path
38
38
  - do not send empty `options`
@@ -56,7 +56,7 @@ Status field.
56
56
 
57
57
  ## Save-ready reminder
58
58
 
59
- For `arcubase-admin entity admin-save-entity`, keep the full base `FieldVO`.
59
+ For `arcubase-admin table update-schema`, keep the full base `FieldVO`.
60
60
 
61
61
  The field-specific part only covers `options`. The saved field still needs:
62
62
 
@@ -49,7 +49,7 @@ Single-line text field.
49
49
 
50
50
  ## Save-ready reminder
51
51
 
52
- For `arcubase-admin entity admin-save-entity`, do not send only `type + options`.
52
+ For `arcubase-admin table update-schema`, do not send only `type + options`.
53
53
 
54
54
  Wrap this field-specific shape in the full base `FieldVO` described in `entity-schema.md`, including:
55
55
 
@@ -1,23 +1,25 @@
1
1
  # Entity Schema
2
2
 
3
- Use this page when writing the full table schema with `arcubase-admin`.
3
+ Use this page when creating or updating a table schema with `arcubase-admin`.
4
4
 
5
5
  Primary command:
6
6
 
7
7
  ```bash
8
- arcubase-admin entity admin-save-entity \
8
+ arcubase-admin table create \
9
+ --app-id <app_id> \
10
+ --body-json <json-string> | --body-file table-create.json
11
+
12
+ arcubase-admin table update-schema \
9
13
  --app-id <app_id> \
10
14
  --table-id <table_id> \
11
- --body-file save-entity.json
15
+ --body-json <json-string> | --body-file save-entity.json
12
16
  ```
13
17
 
14
- Before writing `save-entity.json`, always fetch the current shell:
18
+ Rules:
15
19
 
16
- ```bash
17
- arcubase-admin entity admin-get-entity-info \
18
- --app-id <app_id> \
19
- --table-id <table_id>
20
- ```
20
+ - `table create` must include non-empty `fields`; empty table shell creation is not allowed
21
+ - `table update-schema` is for changing an existing table
22
+ - prefer `--body-json` to avoid an extra file operation
21
23
 
22
24
  If you already know the field type you want, go to:
23
25
 
@@ -27,16 +29,16 @@ If you already know the field type you want, go to:
27
29
 
28
30
  The current direct-write path is:
29
31
 
30
- 1. create the entity shell
31
- 2. fetch the current shell
32
- 3. save the full schema
32
+ 1. create app
33
+ 2. create table with full schema
34
+ 3. verify `table get` returns non-empty `fields`
33
35
  4. probe rows with `arcubase row query`
34
36
 
35
- Do not treat shell creation as table created”.
37
+ Do not create or accept a table with empty `fields`.
36
38
 
37
39
  ## Top-level save payload
38
40
 
39
- The practical save-ready shape is:
41
+ The practical create-ready shape is:
40
42
 
41
43
  ```json
42
44
  {
@@ -55,9 +57,9 @@ The practical save-ready shape is:
55
57
 
56
58
  Rules:
57
59
 
58
- - start from the current shell
59
- - reuse `schema_version` from the shell
60
- - keep `id`, `app_id`, `name`, and `workflow_enabled`
60
+ - for `table create`, omit `id` and `app_id`; CLI fills them after creation
61
+ - for `table update-schema`, keep `id`, `app_id`, `name`, and `workflow_enabled`
62
+ - keep `schema_version` from the current table when updating
61
63
  - do not rebuild top-level `options` unless you really need to
62
64
 
63
65
  ## Shell placeholder normalization
@@ -86,7 +88,8 @@ The CLI already performs this normalization on the direct save path. Your `save-
86
88
  ## Global invariants
87
89
 
88
90
  - `fields` must be `FieldVO[]`
89
- - field ids should start from `1001`
91
+ - `table create` requires at least one field
92
+ - first field id is `1001`; `1000` is the empty-schema baseline
90
93
  - field ids must be positive and non-zero
91
94
  - `field_id_seq > max(field.id)`
92
95
  - `layout` is `number[][]`
@@ -99,6 +102,9 @@ The CLI already performs this normalization on the direct save path. Your `save-
99
102
  - formula references must point to real field ids
100
103
  - do not manually add `tags`
101
104
  - do not manually add `workflow_status`
105
+ - use `text`, not `string`
106
+ - use `member`, not `user`
107
+ - for `select`, `radio`, `checkbox`, and `status`, use `options.options.items`
102
108
 
103
109
  ## Generic field shape
104
110
 
@@ -148,7 +154,7 @@ Each inner array is one layout row. Only reference top-level field ids here.
148
154
 
149
155
  ## Entity-level options boundary
150
156
 
151
- This document is for `admin-save-entity`.
157
+ This document is for `table create` and `table update-schema`.
152
158
 
153
159
  Keep that command focused on:
154
160
 
@@ -179,8 +185,9 @@ Also:
179
185
 
180
186
  Do not call schema creation successful until:
181
187
 
182
- 1. `arcubase-admin entity admin-save-entity ...` succeeds without top-level `error`
183
- 2. `arcubase row query ...` succeeds against the saved table
188
+ 1. `arcubase-admin table create ...` or `arcubase-admin table update-schema ...` succeeds without top-level `error`
189
+ 2. `arcubase-admin table get ...` returns non-empty `fields`
190
+ 3. `arcubase row query ...` succeeds against the saved table
184
191
 
185
192
  If row probing still fails, the table is not ready.
186
193
 
@@ -21,7 +21,7 @@ These examples are not raw tenant exports.
21
21
  - When a save payload needs shell values, replace placeholder tokens such as `__APP_ID__`, `__ENTITY_ID__`, and `__SCHEMA_VERSION__` from the current shell returned by:
22
22
 
23
23
  ```bash
24
- arcubase-admin entity admin-get-entity-info \
24
+ arcubase-admin table get \
25
25
  --app-id <app_id> \
26
26
  --table-id <table_id>
27
27
  ```
@@ -1,20 +1,39 @@
1
1
  # CRM Example 01
2
2
 
3
- This directory is reserved for a generic CRM and quote example set.
3
+ CRM lead, customer, contact, and follow-up example set.
4
4
 
5
- Planned tables:
5
+ ## Tables
6
6
 
7
7
  - `Customer`
8
8
  - `Contact`
9
- - `Quote`
10
- - `Invoice`
9
+ - `Lead`
10
+ - `Follow Up`
11
11
 
12
- Planned field patterns:
12
+ ## Files
13
13
 
14
- - `text`
15
- - `select`
16
- - `status`
17
- - `member`
18
- - `textarea`
14
+ - `create-app.json`
15
+ - `customer.create-entity.json`
16
+ - `customer.schema.json`
17
+ - `contact.create-entity.json`
18
+ - `contact.schema.json`
19
+ - `lead.create-entity.json`
20
+ - `lead.schema.json`
21
+ - `follow-up.create-entity.json`
22
+ - `follow-up.schema.json`
23
+ - `lead.query.json`
24
+ - `lead.row.insert.json`
25
+ - `lead.selection.condition.json`
26
+ - `lead.bulk-update.json`
19
27
 
20
- All names will remain generic and English-only.
28
+ ## Commands
29
+
30
+ ```bash
31
+ arcubase-admin app create --body-file create-app.json | --body-json <json-string>
32
+ arcubase-admin table create --app-id <app_id> --body-file lead.create-entity.json | --body-json <json-string>
33
+ arcubase-admin table get --app-id <app_id> --table-id <table_id>
34
+ arcubase-admin table update-schema --app-id <app_id> --table-id <table_id> --body-file lead.schema.json | --body-json <json-string>
35
+ arcubase row create --app-id <app_id> --table-id <table_id> --body-file lead.row.insert.json | --body-json <json-string>
36
+ arcubase row query --app-id <app_id> --table-id <table_id> --body-file lead.query.json | --body-json <json-string>
37
+ arcubase row bulk-update --app-id <app_id> --table-id <table_id> --body-file lead.bulk-update.json | --body-json <json-string>
38
+ arcubase row selection-action --app-id <app_id> --table-id <table_id> --action archive --body-file lead.selection.condition.json | --body-json <json-string>
39
+ ```
@@ -0,0 +1 @@
1
+ {"id":"__TABLE_ID__","app_id":"__APP_ID__","name":"Contact","workflow_enabled":false,"fields":[{"id":1001,"label":"Contact Name","type":"text","required":true,"unique":false,"editable":true,"visible":true,"show_label":true,"scannable":false,"default_value_mode":0,"description":"","value":null,"number_decimal":0,"depends":[],"key":"contact_name","code_index":false,"options":{},"transfers":null,"children":null},{"id":1002,"label":"Mobile","type":"mobile","required":false,"unique":false,"editable":true,"visible":true,"show_label":true,"scannable":false,"default_value_mode":0,"description":"","value":null,"number_decimal":0,"depends":[],"key":"mobile","code_index":false,"options":{},"transfers":null,"children":null}],"layout":[[1001],[1002]],"options":{},"schema_version":0,"field_id_seq":1003}
@@ -0,0 +1 @@
1
+ {"name":"CRM Example 01"}
@@ -0,0 +1 @@
1
+ {"id":"__TABLE_ID__","app_id":"__APP_ID__","name":"Customer","workflow_enabled":false,"fields":[{"id":1001,"label":"Customer Name","type":"text","required":true,"unique":false,"editable":true,"visible":true,"show_label":true,"scannable":false,"default_value_mode":0,"description":"","value":null,"number_decimal":0,"depends":[],"key":"customer_name","code_index":false,"options":{},"transfers":null,"children":null},{"id":1002,"label":"Segment","type":"select","required":false,"unique":false,"editable":true,"visible":true,"show_label":true,"scannable":false,"default_value_mode":0,"description":"","value":null,"number_decimal":0,"depends":[],"key":"segment","code_index":false,"options":{"options":{"items":[{"key":1,"value":"Enterprise"},{"key":2,"value":"SMB"}]}},"transfers":null,"children":null}],"layout":[[1001],[1002]],"options":{},"schema_version":0,"field_id_seq":1003}
@@ -0,0 +1 @@
1
+ {"id":"__TABLE_ID__","app_id":"__APP_ID__","name":"Follow Up","workflow_enabled":false,"fields":[{"id":1001,"label":"Follow Up At","type":"datetime","required":true,"unique":false,"editable":true,"visible":true,"show_label":true,"scannable":false,"default_value_mode":0,"description":"","value":null,"number_decimal":0,"depends":[],"key":"follow_up_at","code_index":false,"options":{"type":"date"},"transfers":null,"children":null},{"id":1002,"label":"Notes","type":"textarea","required":false,"unique":false,"editable":true,"visible":true,"show_label":true,"scannable":false,"default_value_mode":0,"description":"","value":null,"number_decimal":0,"depends":[],"key":"notes","code_index":false,"options":{},"transfers":null,"children":null}],"layout":[[1001],[1002]],"options":{},"schema_version":0,"field_id_seq":1003}
@@ -0,0 +1 @@
1
+ {"selection":{"type":"condition","condition":{"field":":1002","operator":"eq","value":"new"}},"values":{":1002":"qualified"}}
@@ -0,0 +1 @@
1
+ {"limit":20,"offset":0,"search":{"text_search":"lead"},"sorts":[{"column":":1001","order":"asc"}]}
@@ -0,0 +1 @@
1
+ {":1001":"Upgrade opportunity",":1002":"new"}
@@ -0,0 +1 @@
1
+ {"id":"__TABLE_ID__","app_id":"__APP_ID__","name":"Lead","workflow_enabled":false,"fields":[{"id":1001,"label":"Lead Title","type":"text","required":true,"unique":false,"editable":true,"visible":true,"show_label":true,"scannable":false,"default_value_mode":0,"description":"","value":null,"number_decimal":0,"depends":[],"key":"lead_title","code_index":false,"options":{},"transfers":null,"children":null},{"id":1002,"label":"Lead Status","type":"status","required":true,"unique":false,"editable":true,"visible":true,"show_label":true,"scannable":false,"default_value_mode":0,"description":"","value":null,"number_decimal":0,"depends":[],"key":"lead_status","code_index":false,"options":{"options":{"items":[{"key":1,"code":"new","value":"New"},{"key":2,"code":"qualified","value":"Qualified"},{"key":3,"code":"lost","value":"Lost"}]}},"transfers":null,"children":null}],"layout":[[1001],[1002]],"options":{},"schema_version":0,"field_id_seq":1003}
@@ -0,0 +1 @@
1
+ {"selection":{"type":"condition","condition":{"field":":1002","operator":"eq","value":"lost"}}}