@lotics/cli 0.317.1 → 0.318.2

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.
@@ -281,7 +281,7 @@ Acts: every figure or list whose definition is the business's own (open orders,
281
281
  }
282
282
  ```
283
283
 
284
- It reads under the table's read scope and, on the app's own table, exactly the rows its list reads —
284
+ It reads under the app's `rows` (every row, where the app states none of the table) and, on the app's own table, exactly the rows its list reads —
285
285
  so never the table of an app that states Books, whose list reads several tables. A condition reading an
286
286
  optional param narrows nothing when the call leaves it out; no param compares a number read in each row's
287
287
  own unit or currency, or a date holding a span. `"reading"` in place of `"fields"` returns a count or a sum —
@@ -93,7 +93,8 @@ nothing; a refusal lists everything wrong in it at once.
93
93
 
94
94
  The App node is the app: its `name`, `description`, `icon` and `color` are props of it, and no other input of
95
95
  `set_app` states them. It names the tables and templates it uses by their aliases (an entity is a table's alias, a `template` a template's alias);
96
- `set_app` fills the `tables` and `templates` maps by id from them and `get_app` shows aliases (`lotics docs reference/app-node`). A call that creates
96
+ `set_app` fills the `tables` and `templates` maps by id from them and `get_app` shows aliases (`lotics docs reference/app-node`).
97
+ Who reads which rows is the app's `rows` (§ Who reads which rows, below). A call that creates
97
98
  is `{"body": <the App tree>}`; one that changes a part is `{"app_id": "app_…", "nodes": {"<address>": <patch>}}`,
98
99
  each address a node's path of keys (`get_app` prints every one), a patch a JSON merge patch of that node's props
99
100
  and `null` removing the node; the App's own props change through `body`. A call stating `base_version_id` — the
@@ -135,6 +136,29 @@ family and how it is called. A question the screen never asks is a Query node th
135
136
  (`lotics docs reference/query-node`), beside its Workflow nodes. Both are part of the design: `lotics docs
136
137
  agent_surface`, § Declaring more.
137
138
 
139
+ ### Who reads which rows
140
+
141
+ An app runs with its owner's access, and the people it is shared with need the app alone, never its tables. Who of them
142
+ reads which rows is the app's `rows`, one rule per table in the grammar of a table's `read_scope` (`lotics docs reference/read-scope`); it narrows
143
+ the app's screens, its queries and workflows called through it (`run_app_query`, `run_app_workflow`), its acts and its
144
+ workflow bodies alike, and a record id a caller passes is refused where the rule hides the row. State a rule only where
145
+ people differ; a table with none is read whole by everyone the app is shared with.
146
+
147
+ | The business says | The app states |
148
+ |---|---|
149
+ | Everyone on the team sees every order | nothing |
150
+ | Each rep sees only their own deals | `"rows": { "deal": { "any": [{ "field": "rep", "is": "self" }] } }` |
151
+ | Reps see their own deals; managers see all | `"rows": { "deal": { "any": [{ "field": "rep", "is": "self" }, { "member_of": "<managers group id>" }] } }` |
152
+ | Each branch manager sees their branch's orders | `"rows": { "order": { "any": [{ "through": ["branch"], "field": "manager", "is": "self" }] } }` |
153
+ | Each employee sees only their own payslips; HR sees all | two apps: one stating `"payslip": { "any": [{ "field": "employee", "is": "self" }] }`, one for HR stating none |
154
+ | Team leads see people, not salaries | an app that draws no salary field — what it does not show, no one reads through it |
155
+
156
+ A child read under a ruled row states its own rule, through its link to the parent; only a status history inherits.
157
+ Admins are not narrowed in an app; someone on a public link, signed in as no one, reads no row a `self` clause would
158
+ choose. An app never reads past its owner's own access. A table's own `read_scope` governs opening the table directly.
159
+ Working inside one row of a folder (`scope`) narrows the view, not who may read: a branch app shared with every manager
160
+ still states the branch rule.
161
+
138
162
  ## 5 — A custom-code app
139
163
 
140
164
  ```
package/docs/examples.md CHANGED
@@ -75,6 +75,14 @@ among them: the `design` reference. Every key: the `model` reference, at the pag
75
75
  "name": "Service visits",
76
76
  "icon": "calendar",
77
77
  "color": "emerald",
78
+ "rows": {
79
+ "customer": {"any": [{"member_of": "sales"}]},
80
+ "order": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
81
+ "order_line": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
82
+ "payment": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
83
+ "order_stage": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
84
+ "service_visit": {"any": [{"member_of": "sales"}, {"member_of": "stores"}, {"member_of": "field"}]}
85
+ },
78
86
  "children": [
79
87
  {
80
88
  "type": "List",
@@ -258,6 +266,14 @@ among them: the `design` reference. Every key: the `model` reference, at the pag
258
266
  "name": "Dispatch",
259
267
  "icon": "wrench",
260
268
  "color": "sky",
269
+ "rows": {
270
+ "customer": {"any": [{"member_of": "sales"}]},
271
+ "order": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
272
+ "order_line": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
273
+ "payment": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
274
+ "order_stage": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
275
+ "service_visit": {"any": [{"member_of": "sales"}, {"member_of": "stores"}, {"member_of": "field"}]}
276
+ },
261
277
  "children": [
262
278
  {
263
279
  "type": "List",
@@ -613,6 +629,13 @@ among them: the `design` reference. Every key: the `model` reference, at the pag
613
629
  "name": "Stock",
614
630
  "icon": "boxes",
615
631
  "color": "teal",
632
+ "rows": {
633
+ "customer": {"any": [{"member_of": "sales"}]},
634
+ "order": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
635
+ "order_line": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
636
+ "payment": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
637
+ "order_stage": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]}
638
+ },
616
639
  "scope": "warehouse",
617
640
  "children": [
618
641
  {
@@ -841,6 +864,16 @@ among them: the `design` reference. Every key: the `model` reference, at the pag
841
864
  "name": "Customers",
842
865
  "icon": "users",
843
866
  "color": "violet",
867
+ "rows": {
868
+ "customer": {"any": [{"member_of": "sales"}]},
869
+ "order": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
870
+ "order_line": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
871
+ "payment": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
872
+ "order_stage": {"any": [{"member_of": "sales"}, {"member_of": "stores"}]},
873
+ "touch": {"any": [{"member_of": "sales"}]},
874
+ "customer_paper": {"any": [{"member_of": "sales"}]},
875
+ "service_visit": {"any": [{"member_of": "sales"}, {"member_of": "stores"}, {"member_of": "field"}]}
876
+ },
844
877
  "children": [
845
878
  {
846
879
  "type": "List",
@@ -142,7 +142,7 @@ One app, the counter's job, over the tables and template above. The register lis
142
142
  - `app.names-declared`: each alias a key names exists (a table, field, option, Act `key`, template).
143
143
  - A workflow writes a link as ids, `[x.id]`; a whole record or bare value is refused.
144
144
 
145
- Then `set_access` gives the app to the people whose job it is: a `principal_type` of `member` (id from `get_workspace`, `kind: "member"`), `member_group` (an admin lists them: `kind: "group"`) or `organization`, a `role` of `user` or `manager`; none loses access.
145
+ Then `set_access` gives the app to the people whose job it is: a `principal_type` of `member` (id from `get_workspace`, `kind: "member"`), `member_group` (an admin lists them: `kind: "group"`) or `organization`, a `role` of `user` or `manager`; none loses access. They need no table access; with no `rows` on the App, they read every row.
146
146
 
147
147
  ```
148
148
  set_access {"resources": [{"resource_type": "app", "resource_id": "app_…"}], "principals": [{"principal_type": "member", "principal_id": "<member id>", "role": "user"}]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/cli",
3
- "version": "0.317.1",
3
+ "version": "0.318.2",
4
4
  "description": "Lotics SDK and CLI for AI agents",
5
5
  "type": "module",
6
6
  "bin": {