toga-ai 1.0.241 → 1.0.243
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/knowledge/2.0/apps/_underscore/INDEX.md +1 -1
- package/knowledge/2.0/apps/_underscore/features/surface-resolver.md +39 -1
- package/knowledge/2.0/apps/api2/features/surface-meta-option.md +8 -1
- package/knowledge/2.0/apps/dbchanges2/INDEX.md +1 -1
- package/knowledge/2.0/apps/dbchanges2/features/surface-layer-schema.md +43 -1
- package/knowledge/2.0/apps/toga25-supply/INDEX.md +1 -1
- package/knowledge/2.0/apps/toga25-supply/features/surface-frontend.md +47 -15
- package/knowledge/clients/compass-canada/profile.md +1 -0
- package/knowledge/clients/compass-usa/profile.md +1 -0
- package/knowledge/clients/quad/profile.md +2 -1
- package/knowledge/sessions/2026-06-30-surface-layer-jcardinal.md +74 -0
- package/package.json +1 -1
|
@@ -13,6 +13,6 @@
|
|
|
13
13
|
| [NetSuite REST Client (_Component_Api_Netsuite) — record writes & SuiteQL](features/netsuite-rest-client.md) | `_Component_Api_Netsuite` is the **2.0 `_underscore` NetSuite REST client** — the shared primitive every worker2/api2 NetSuite caller uses for record GETs, Suit | _underscore/Component/Api/Netsuite/Netsuite.php |
|
|
14
14
|
| [Per-Client Database Connections & the Local Logs Trap](features/per-client-database-connections.md) | When `_underscore` serves a request for a client it opens **three distinct per-client database connections**, not one. | _underscore/Database.php, _underscore/ApiRequest.php, _underscore/Model/Client/Logs/Api.php |
|
|
15
15
|
| [Recursive Item Fulfillments (upstream mirroring)](features/recursive-item-fulfillments.md) | In a multi-tier supply chain a sales order (SO) spawns a purchase order (PO) that becomes another SO downstream, and so on. | _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Client/ItemFulfillmentItem.php, _underscore/Model/Client/ItemFulfillmentItemUnit.php, _underscore/Model/Client/ItemFulfillmentPackage.php, _underscore/Model/Compass/AdvanceShippingNotice.php, dbchanges2/Core/2026-02-13 - 75601 - RecursiveItemFulfillmentCreation.sql, dbchanges2/Core/2026-06-04 - RecursiveItemFulfillmentPut.sql |
|
|
16
|
-
| [Surface Resolver (_Model_Core_Surface::resolve — replaces Page::meta)](features/surface-resolver.md) | The runtime for the platform-wide **Surface** UI presentation layer: 9 `_underscore` models plus a cached resolver, `_Model_Core_Surface::resolve(&$api, string | _underscore/Model/Core/Surface.php, dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql, dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql, dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql, _underscore/Model/Core/SurfaceElement.php, _underscore/Model/Core/Action.php, _underscore/Model/Core/Vocabulary.php, _underscore/Model/Core/VocabularyTerm.php, _underscore/Model/Core/Message.php, _underscore/Model/Client/SurfaceOverride.php, _underscore/Model/Client/MessageTranslation.php, _underscore/Model/Client/ThemeToken.php, _underscore/Model/Core/Page.php |
|
|
16
|
+
| [Surface Resolver (_Model_Core_Surface::resolve — replaces Page::meta)](features/surface-resolver.md) | The runtime for the platform-wide **Surface** UI presentation layer: 9 `_underscore` models plus a cached resolver, `_Model_Core_Surface::resolve(&$api, string | _underscore/Model/Core/Surface.php, dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql, dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql, dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql, dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql, dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql, _underscore/Model/Core/SurfaceElement.php, _underscore/Model/Core/Action.php, _underscore/Model/Core/Vocabulary.php, _underscore/Model/Core/VocabularyTerm.php, _underscore/Model/Core/Message.php, _underscore/Model/Client/SurfaceOverride.php, _underscore/Model/Client/MessageTranslation.php, _underscore/Model/Client/ThemeToken.php, _underscore/Model/Core/Page.php |
|
|
17
17
|
| [Tracking-Number Bridge Migration (ASN / Item Fulfillment / Item Receipt)](features/tracking-number-bridges.md) | Shipment tracking numbers used to live as **scalar FK columns** (`trackingNumberId`, `returnTrackingNumberId`) directly on the lowest-level "unit"/"item" tables | api2/Component/Api/V2/V2.php, _underscore/Model/Client/AdvanceShippingNoticeItemUnit.php, _underscore/Model/Client/AdvanceShippingNoticeItemUnits/TrackingNumber.php, _underscore/Model/Client/ItemFulfillmentItemUnits/TrackingNumber.php, _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Prudential/AdvanceShippingNotice.php, _underscore/Model/Compass/AdvanceShippingNotice.php, _underscore/Trait/Netsuite/ItemFulfillment.php, api2/Component/Api/Cxml/Cxml.php, dbchanges2/Client/2026-06-10 - TrackingNumberBridges.sql, dbchanges2/Core/2026-06-10 - TrackingNumberBridges.sql, dbchanges2/Client_Prudential/2026-06-15 - ItemFulfillmentTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Quad/2026-06-18a - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Nychh/2026-06-19b - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Nychh/2026-06-19a - FixItemFulfillmentTableViewTrackingAndRoot.sql, dbchanges2/Client_Quad/2026-06-19a - FixItemFulfillmentTableViewTrackingAndRoot.sql |
|
|
18
18
|
| [Units for Items for Purchase Orders — Data Structure](features/units-for-items-for-purchase-orders.md) | Describes how unit (serialized inventory) data is linked to sales-order and purchase-order line items behind the `units-for-items-for-purchase-orders` TableView | |
|
|
@@ -6,10 +6,12 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-06-
|
|
9
|
+
updated: 2026-06-30
|
|
10
10
|
owners: [jcardinal]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Model/Core/Surface.php
|
|
13
|
+
- dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql
|
|
14
|
+
- dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql
|
|
13
15
|
- dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql
|
|
14
16
|
- dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql
|
|
15
17
|
- dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql
|
|
@@ -69,6 +71,29 @@ Inputs come from `$api` (the same accessor `_Model_Client_TableView::meta` uses)
|
|
|
69
71
|
A `metaDebug()` inspector returns the resolved bundle plus the raw cascade layers (shipped with the
|
|
70
72
|
resolver, not "later"). It is **not** named `debug()` — see gotchas.
|
|
71
73
|
|
|
74
|
+
## Grouped resolution — `metaGroup()`
|
|
75
|
+
|
|
76
|
+
`_Model_Core_Surface::metaGroup(&$api, string $slugs): object` — a scripted-API method exposed at
|
|
77
|
+
`GET /v2/surfaces/meta-group?slugs=a,b,c` for screens (e.g. a record-detail modal) that need many
|
|
78
|
+
section surfaces at once: **one round trip instead of N**. It splits the comma-separated `slugs`
|
|
79
|
+
list (capped at `const META_GROUP_MAX_SLUGS = 25`, logging truncation), resolves **each slug via the
|
|
80
|
+
existing per-slug `resolve()` cache path**, and returns `{group, surfaces: {slug => bundle|null}}`.
|
|
81
|
+
It is **composition only** — no new cache layer; an unknown slug yields the structured **empty
|
|
82
|
+
bundle** so one missing surface never fails the whole group. (Chosen over a `parentSurfaceId` GROUP
|
|
83
|
+
row after CTO review — a slug list keeps the model schema-stateless and avoids id drift.)
|
|
84
|
+
|
|
85
|
+
`resolve()` now declares an explicit `: object` return type.
|
|
86
|
+
|
|
87
|
+
### Message/label resolution fixes (latent SECTION/BUTTON_BAR bugs)
|
|
88
|
+
The grouped SalesOrders section migration is the first real consumer of the SECTION/BUTTON_BAR path,
|
|
89
|
+
which surfaced latent resolution gaps in `_buildBundle`/`_resolveElement`:
|
|
90
|
+
- Element message slots (`label`/`tooltip`/`placeholder`/`disabledTooltip`) are now remapped from
|
|
91
|
+
**message-id → messageKey** before return, because `bundle.messages` is keyed by `messageKey` —
|
|
92
|
+
previously labels silently fell back to the element key.
|
|
93
|
+
- `disabledTooltipMessageId` is collected into the batch and emitted as a `disabledTooltip` slot.
|
|
94
|
+
- `bundle.surface.titleMessageKey` is set from `titleMessageId`.
|
|
95
|
+
- The 2nd `_loadMessages` return is merged into `$messageKeyById`; dangling message ids are logged.
|
|
96
|
+
|
|
72
97
|
## Caching & invalidation
|
|
73
98
|
|
|
74
99
|
- Disk cache keyed `surface:meta:{app}:{slug}:{client}:{sortedPersonaIds}:{sortedRoleIds}:{lang}`.
|
|
@@ -137,7 +162,20 @@ resolver, not "later"). It is **not** named `debug()` — see gotchas.
|
|
|
137
162
|
`record-fields` already expose Public READ. Only the `surfaces` record gets Public read — the
|
|
138
163
|
admin-CRUD sibling records stay Super-User-only (the resolver reads their tables server-side).
|
|
139
164
|
|
|
165
|
+
- **The meta-group dispatch grant is per-client-DB too.** A 403 EZ-1 on `meta-group` on dev-sandbox
|
|
166
|
+
was the same mechanism as the original `meta` 403: the `meta-group` RecordScript needs its own
|
|
167
|
+
per-role `Client.AclRecordScripts` dispatch grant. Verified via toga-db — `meta` script id 25 was
|
|
168
|
+
granted roles 1/3/4 but `meta-group` (id 27) had **none** until the grant ran. Any new surfaces
|
|
169
|
+
scripted-API method repeats this: record READ never authorizes dispatch.
|
|
170
|
+
|
|
140
171
|
## Change history
|
|
172
|
+
- 2026-06-30 — Added `metaGroup()` (`GET /v2/surfaces/meta-group?slugs=a,b,c`): batched composition
|
|
173
|
+
over the existing per-slug `resolve()` cache, capped at `META_GROUP_MAX_SLUGS=25`, unknown slug →
|
|
174
|
+
empty bundle (chosen over a `parentSurfaceId` GROUP row post-CTO-review). Fixed latent
|
|
175
|
+
SECTION/BUTTON_BAR resolution (message-id→messageKey remap for label/tooltip/placeholder/
|
|
176
|
+
disabledTooltip, titleMessageKey, dangling-id logging); added `: object` to `resolve()`. The
|
|
177
|
+
`meta-group` script needed its own per-client `AclRecordScripts` dispatch grant (403 EZ-1 until
|
|
178
|
+
granted). (jcardinal)
|
|
141
179
|
- 2026-06-29 — Deploy fixes (round 2): grant the surfaces `meta`/`debug` RecordScripts in
|
|
142
180
|
`Client.AclRecordScripts` per role (Public/SuperUser/Base) — record-level `AclRecordPermissions`
|
|
143
181
|
alone left every meta call 403 EZ-1 because V2 dispatch authorizes via `AclRecordScripts`
|
|
@@ -6,7 +6,7 @@ project: API
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-06-
|
|
9
|
+
updated: 2026-06-30
|
|
10
10
|
owners: [jcardinal]
|
|
11
11
|
files:
|
|
12
12
|
- api2/Component/Api/V2/V2.php
|
|
@@ -56,7 +56,14 @@ traffic), behavior is **byte-for-byte unchanged** — pure data, zero extra work
|
|
|
56
56
|
meta 403'd until the `meta`/`debug` scripts were granted per role in `AclRecordScripts`. See
|
|
57
57
|
[surface-resolver](../../_underscore/features/surface-resolver.md) gotchas.
|
|
58
58
|
|
|
59
|
+
- **Grouped meta endpoint `GET /v2/surfaces/meta-group?slugs=a,b,c`** (one round trip for a
|
|
60
|
+
multi-section screen) is a distinct RecordScript and needs its **own** per-role
|
|
61
|
+
`Client.AclRecordScripts` dispatch grant — it 403'd EZ-1 on dev-sandbox until granted, exactly like
|
|
62
|
+
`meta` did. See [surface-resolver](../../_underscore/features/surface-resolver.md).
|
|
63
|
+
|
|
59
64
|
## Change history
|
|
65
|
+
- 2026-06-30 — Noted the grouped `meta-group` endpoint (batched multi-slug resolve) and that it needs
|
|
66
|
+
its own per-role `AclRecordScripts` dispatch grant (403 EZ-1 until granted). (jcardinal)
|
|
60
67
|
- 2026-06-29 — Documented the second ACL layer: scripted-API dispatch is authorized via
|
|
61
68
|
`Client.AclRecordScripts` (per `recordScriptId`+`roleId`), not record `AclRecordPermissions` —
|
|
62
69
|
record READ alone still 403'd meta until the dispatch grants were seeded. (jcardinal)
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
| Doc | Summary | Files |
|
|
4
4
|
|-----|---------|-------|
|
|
5
5
|
| [Database Changes (dbchanges2) Repository Architecture](architecture.md) | `dbchanges2` is the **schema-migration / SQL change-set repository** for the entire 2.0 platform. | Core/, Client/, Client_<Tenant>/, Logs/, Logs_Client/, _modules/ |
|
|
6
|
-
| [Surface Layer Schema (UI presentation/config tables)](features/surface-layer-schema.md) | The persistent schema for the platform-wide **Surface** UI presentation/configuration layer (see the `_underscore` [surface-resolver](../../_underscore/features | dbchanges2/Core/2026-06-25a - SurfaceCoreTables.sql, dbchanges2/Core/2026-06-25b - SurfaceRecordsAndFields.sql, dbchanges2/Core/2026-06-25c - SalesOrderLoginSurfaceSeed.sql, dbchanges2/Core/2026-06-29a - ItemsSurfaceSeed.sql, dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql, dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql, dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql, dbchanges2/Core/2026-06-29d - VendorItemsSurfaceSeed.sql, dbchanges2/Core/2026-06-29e - InventorySurfaceSeed.sql, dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql, dbchanges2/Client/2026-06-25b - SurfaceClientSeed.sql, dbchanges2/Client/2026-06-25c - SurfaceClientAcl.sql, dbchanges2/Client/2026-06-03- BLANK_CLIENT_DATABASE.sql |
|
|
6
|
+
| [Surface Layer Schema (UI presentation/config tables)](features/surface-layer-schema.md) | The persistent schema for the platform-wide **Surface** UI presentation/configuration layer (see the `_underscore` [surface-resolver](../../_underscore/features | dbchanges2/Core/2026-06-25a - SurfaceCoreTables.sql, dbchanges2/Core/2026-06-25b - SurfaceRecordsAndFields.sql, dbchanges2/Core/2026-06-25c - SalesOrderLoginSurfaceSeed.sql, dbchanges2/Core/2026-06-29a - ItemsSurfaceSeed.sql, dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql, dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql, dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql, dbchanges2/Core/2026-06-29d - VendorItemsSurfaceSeed.sql, dbchanges2/Core/2026-06-29e - InventorySurfaceSeed.sql, dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql, dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql, dbchanges2/Client_Compass/2026-06-30a - SalesOrderDisplaySectionManagerOverrides.sql, dbchanges2/Client_CompassCanada/2026-06-30a - SalesOrderSurfaceManagerOverrides.sql, dbchanges2/Client_Quad/2026-06-30a - SalesOrderSurfaceClientOverrides.sql, dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql, dbchanges2/Client/2026-06-25b - SurfaceClientSeed.sql, dbchanges2/Client/2026-06-25c - SurfaceClientAcl.sql, dbchanges2/Client/2026-06-03- BLANK_CLIENT_DATABASE.sql |
|
|
7
7
|
| [2.0 New-Client Onboarding (manual process)](workflows/client-onboarding.md) | How to manually stand up a new 2.0 client (tenant). | Client/, Client_<Tenant>/, Core/, Logs_Client/ |
|
|
@@ -6,7 +6,7 @@ project: Database Changes
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-06-
|
|
9
|
+
updated: 2026-06-30
|
|
10
10
|
owners: [jcardinal]
|
|
11
11
|
files:
|
|
12
12
|
- dbchanges2/Core/2026-06-25a - SurfaceCoreTables.sql
|
|
@@ -18,6 +18,11 @@ files:
|
|
|
18
18
|
- dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql
|
|
19
19
|
- dbchanges2/Core/2026-06-29d - VendorItemsSurfaceSeed.sql
|
|
20
20
|
- dbchanges2/Core/2026-06-29e - InventorySurfaceSeed.sql
|
|
21
|
+
- dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql
|
|
22
|
+
- dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql
|
|
23
|
+
- dbchanges2/Client_Compass/2026-06-30a - SalesOrderDisplaySectionManagerOverrides.sql
|
|
24
|
+
- dbchanges2/Client_CompassCanada/2026-06-30a - SalesOrderSurfaceManagerOverrides.sql
|
|
25
|
+
- dbchanges2/Client_Quad/2026-06-30a - SalesOrderSurfaceClientOverrides.sql
|
|
21
26
|
- dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql
|
|
22
27
|
- dbchanges2/Client/2026-06-25b - SurfaceClientSeed.sql
|
|
23
28
|
- dbchanges2/Client/2026-06-25c - SurfaceClientAcl.sql
|
|
@@ -82,6 +87,19 @@ SurfaceElements`). Core migrations run first; Client after. The session built/se
|
|
|
82
87
|
purchase-orders/items/units via per-level fetchSlugs and has no single backing Record; carries
|
|
83
88
|
`groupByLabels` + `entityTags` in surface `config`) + `inventory-list-actions` (BUTTON_BAR:
|
|
84
89
|
Group by / Refresh). Actions anchored to `items(21)` because `Actions.recordId` is NOT NULL.
|
|
90
|
+
- `Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql` — registers the `meta-group`
|
|
91
|
+
RecordScript; seeds the previously-missing `order-recurring` SECTION surface (cardType
|
|
92
|
+
`recurringFields`, `isVisible 0`); seeds 5 display-toggle SECTION surfaces (invoices / shipments /
|
|
93
|
+
additional-order-details / notes / admin-notes), **each carrying a single `sectionVisibility`
|
|
94
|
+
marker element** (see gotcha — the override cascade only overrides ELEMENTS, never a surface's own
|
|
95
|
+
`isVisible`, so display-section visibility cannot be per-role-overridden without a marker element).
|
|
96
|
+
Core→Core only, so this file is prod-safe.
|
|
97
|
+
- `Client/2026-06-30a - SurfaceMetaGroupAcl.sql` — the `meta-group` `AclRecordScripts` dispatch grant
|
|
98
|
+
(roles 1/3/4), mirroring the `meta` grant.
|
|
99
|
+
- `Client_Compass/2026-06-30a` / `Client_CompassCanada/2026-06-30a` — per-client **MANAGER**-scope
|
|
100
|
+
SalesOrder section overrides; `Client_Quad/2026-06-30a` — Quad's **client-level** section deltas.
|
|
101
|
+
⚠ These three Client-DB seeds currently resolve **Core** ids via cross-DB subselect — see the
|
|
102
|
+
prod cross-cluster gotcha; they are paused before prod.
|
|
85
103
|
- `Client/2026-06-29c - SurfaceRecordScriptAcl.sql` — grants the surfaces `meta`/`debug` RecordScripts
|
|
86
104
|
in **`Client.AclRecordScripts`** per role (meta → Public(1)/SuperUser(3)/Base(4); debug →
|
|
87
105
|
SuperUser(3)). V2 authorizes scripted-API dispatch via `AclRecordScripts`, NOT record
|
|
@@ -122,7 +140,31 @@ SurfaceElements`). Core migrations run first; Client after. The session built/se
|
|
|
122
140
|
- **CLIENT-aclDatabase records** (`SurfaceOverrides`, `MessageTranslations`, `ThemeTokens`) need the
|
|
123
141
|
full 4-step ACL chain + field permissions in **each** client DB; resolve `roleId` by subselect.
|
|
124
142
|
|
|
143
|
+
- **⚠ PROD BLOCKER (ON HOLD) — Client-DB surface seeds must NOT resolve Core ids via cross-DB
|
|
144
|
+
subselect.** The `Client_Compass`/`Client_CompassCanada`/`Client_Quad` SalesOrder override seeds
|
|
145
|
+
resolve Core ids (`Core.RecordScripts`/`Core.Surfaces`/`Core.SurfaceElements`) with a cross-DB
|
|
146
|
+
subselect. This works only on the dev-sandbox **all-in-one** instance; in **production Core is a
|
|
147
|
+
separate cluster** and cross-DB queries require a single instance, so these seeds **break in prod**.
|
|
148
|
+
The established prod-safe pattern is `Client/2026-06-23b - ItemTranslationsAcl.sql`: **hardcode Core
|
|
149
|
+
ids as literals**, resolve only Client-local ids (e.g. `roleId` by name). The fix is paused; the
|
|
150
|
+
earlier `2026-06-25c` / `2026-06-29c` / `2026-06-25d` surface seeds **likely share the same
|
|
151
|
+
anti-pattern** and need auditing. Core→Core seeds are fine (same cluster). Also still open:
|
|
152
|
+
re-seeding NYCHH/Prudential/SPGlobal (deferred).
|
|
153
|
+
- **Display-section visibility cannot be per-role-overridden without an element.** The override
|
|
154
|
+
cascade overrides **ELEMENTS only**, never a surface's own `isVisible`. The 5 display-toggle SECTION
|
|
155
|
+
surfaces therefore each carry a single `sectionVisibility` marker element so a Client override can
|
|
156
|
+
flip a section per role/persona. Also discovered: `elementType` in `orderViewFields.json` is **dead
|
|
157
|
+
config** (no renderer reads it); and MANAGER/Quad summary tooltips can't be removed via the cascade
|
|
158
|
+
because `TOOLTIP_MESSAGE` is numeric-only (cosmetic, deferred).
|
|
159
|
+
|
|
125
160
|
## Change history
|
|
161
|
+
- 2026-06-30 — Added the SalesOrders SECTION-surface migration seeds: Core `meta-group` RecordScript +
|
|
162
|
+
`order-recurring` + 5 display-toggle SECTION surfaces (each with a `sectionVisibility` marker
|
|
163
|
+
element, since the cascade overrides elements not a surface's own isVisible), the `meta-group`
|
|
164
|
+
dispatch ACL grant, and per-client (Compass/CompassCanada MANAGER, Quad client-level) section
|
|
165
|
+
overrides. Recorded the ⚠ prod blocker: Client-DB seeds resolving Core ids via cross-DB subselect
|
|
166
|
+
break in prod (Core is a separate cluster) — must hardcode Core id literals per the
|
|
167
|
+
`ItemTranslationsAcl.sql` pattern; fix paused, earlier surface seeds likely share it. (jcardinal)
|
|
126
168
|
- 2026-06-29 — Added VendorItems + Inventory LIST seeds (`VendorItemsSurfaceSeed.sql` recordId 19 /
|
|
127
169
|
TableView 10; `InventorySurfaceSeed.sql` presentation-only, recordId+tableViewId NULL, Actions
|
|
128
170
|
anchored to items(21)). Added `SurfaceRecordScriptAcl.sql` (per-role `AclRecordScripts` dispatch
|
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
| [Column Visibility (URL-driven show/hide columns)](features/column-visibility.md) | A "Columns" header button that opens a modal listing every column from the table meta, lets the user show/hide columns, adjusts the table live, and persists the | toga25-supply/src/components/ColumnVisibilityModal/, toga25-supply/src/pages/SalesOrders/SalesOrders.tsx, toga25-supply/src/pages/SalesOrders/viewModel/useSalesOrdersPageViewModel.tsx, toga25-supply/src/pages/SalesOrders/hooks/useSalesOrdersTableData.tsx |
|
|
9
9
|
| [Meta-Driven Page & Table Setup](features/meta-driven-table-data.md) | A page in this app is **meta-driven end to end**: the page view model fetches *page meta* (labels, sections, ACL) and *table meta* (the columns/fields + table s | toga25-supply/src/pages/SalesOrders/viewModel/useSalesOrdersPageViewModel.tsx, toga25-supply/src/pages/SalesOrders/hooks/useSalesOrdersTableState.ts, toga25-supply/src/hooks/useTablePageMeta.ts, toga-blox-npm/dist/hooks/useFetchPageMeta.d.ts, toga-blox-npm/dist/hooks/useFetchTablePageMeta.d.ts, toga-blox-npm/dist/hooks/useAssignTableFieldLabels.d.ts, toga-blox-npm/dist/components/Table/hooks/useTableData.d.ts |
|
|
10
10
|
| [Record Modals & Nested Tables](features/record-modals-and-nested-tables.md) | The repo's family of modal + nested-table patterns layered over toga-blox `TableRecordModal` and `PrimaryTable*Layout`. | toga25-supply/src/layout/ItemRecordModalLayout/, toga25-supply/src/layout/SalesOrderRecordModalLayout/, toga25-supply/src/layout/SalesOrderItemsTableLayout/, toga25-supply/src/layout/ItemFulfillmentModal/, toga25-supply/src/layout/GenericNestedTables/, toga25-supply/src/hooks/useTableCellInteractions.ts |
|
|
11
|
-
| [Surface Frontend (DB-driven UI consumption, src/surface/)](features/surface-frontend.md) | The frontend consumer of the platform-wide Surface layer — DB-driven UI config fetched from `GET /v2/surfaces/meta?slug=<slug>` instead of statically-imported J | toga25-supply/src/surface/useFetchSurfaceMeta.ts, toga25-supply/src/surface/evaluateSurfaceRule.ts, toga25-supply/src/surface/actionRegistry.ts, toga25-supply/src/surface/SurfaceActionBar.tsx, toga25-supply/src/surface/SurfaceSection.tsx, toga25-supply/src/surface/resolve.ts, toga25-supply/src/surface/types.ts, toga25-supply/src/surface/index.ts, toga25-supply/src/pages/Login/LoginPage.tsx, toga25-supply/src/pages/SalesOrders/SalesOrders.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderTopBar.tsx, toga25-supply/src/pages/Items/ItemsPage.tsx, toga25-supply/src/pages/Items/viewModel/useItemsPageViewModel.tsx, toga25-supply/src/pages/VendorItems/VendorItemsPage.tsx, toga25-supply/src/pages/VendorItems/viewModel/useVendorItemsPageViewModel.tsx, toga25-supply/src/pages/Inventory/Inventory.tsx, toga25-supply/src/pages/Inventory/viewModel/useInventoryPageViewModel.tsx, toga25-supply/src/pages/Inventory/viewModel/FIELDS/index.ts, toga25-supply/src/fieldsConfig/index.ts |
|
|
11
|
+
| [Surface Frontend (DB-driven UI consumption, src/surface/)](features/surface-frontend.md) | The frontend consumer of the platform-wide Surface layer — DB-driven UI config fetched from `GET /v2/surfaces/meta?slug=<slug>` instead of statically-imported J | toga25-supply/src/surface/useFetchSurfaceMeta.ts, toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/index.ts, toga25-supply/src/surface/evaluateSurfaceRule.ts, toga25-supply/src/surface/actionRegistry.ts, toga25-supply/src/surface/SurfaceActionBar.tsx, toga25-supply/src/surface/SurfaceSection.tsx, toga25-supply/src/surface/resolve.ts, toga25-supply/src/surface/types.ts, toga25-supply/src/surface/index.ts, toga25-supply/src/pages/Login/LoginPage.tsx, toga25-supply/src/pages/SalesOrders/SalesOrders.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderTopBar.tsx, toga25-supply/src/pages/Items/ItemsPage.tsx, toga25-supply/src/pages/Items/viewModel/useItemsPageViewModel.tsx, toga25-supply/src/pages/VendorItems/VendorItemsPage.tsx, toga25-supply/src/pages/VendorItems/viewModel/useVendorItemsPageViewModel.tsx, toga25-supply/src/pages/Inventory/Inventory.tsx, toga25-supply/src/pages/Inventory/viewModel/useInventoryPageViewModel.tsx, toga25-supply/src/pages/Inventory/viewModel/FIELDS/index.ts, toga25-supply/src/fieldsConfig/index.ts |
|
|
12
12
|
| [Cypress Testing Harness (component + e2e)](workflows/cypress-testing.md) | The Cypress test harness for the `toga25-supply` frontend, bootstrapped from scratch (`cypress` was already a dependency but there was no config, no `cypress/` | toga25-supply/cypress.config.ts, toga25-supply/cypress/tsconfig.json, toga25-supply/cypress/support/component.tsx, toga25-supply/cypress/support/component-index.html, toga25-supply/cypress/support/e2e.ts, toga25-supply/cypress/support/commands.ts, toga25-supply/cypress/support/fixtures.ts, toga25-supply/cypress/support/mocks/useApprovalModalViewModel.ts, toga25-supply/cypress/component/SalesOrderApprovalModalsLayout.cy.tsx, toga25-supply/cypress/component/RecordApprovalModalLayout.cy.tsx, toga25-supply/cypress/component/EnterPoNumberModal.cy.tsx, toga25-supply/cypress/e2e/salesOrderApproval.cy.ts |
|
|
@@ -6,10 +6,13 @@ project: TOGa 2.5 Supply
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-06-
|
|
9
|
+
updated: 2026-06-30
|
|
10
10
|
owners: [jcardinal]
|
|
11
11
|
files:
|
|
12
12
|
- toga25-supply/src/surface/useFetchSurfaceMeta.ts
|
|
13
|
+
- toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts
|
|
14
|
+
- toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx
|
|
15
|
+
- toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/index.ts
|
|
13
16
|
- toga25-supply/src/surface/evaluateSurfaceRule.ts
|
|
14
17
|
- toga25-supply/src/surface/actionRegistry.ts
|
|
15
18
|
- toga25-supply/src/surface/SurfaceActionBar.tsx
|
|
@@ -51,6 +54,12 @@ feature flag — see below). Backend: [surface-resolver](../../_underscore/featu
|
|
|
51
54
|
`raw` / `raw.data` / `raw.data.<route-key>` — because V2 nests a scripted-API return value one
|
|
52
55
|
level deeper, under a route-keyed slot of `data` (e.g. `data.meta`, `data.surfaces`). On a malformed
|
|
53
56
|
payload it falls back to an empty-elements bundle so the page never crashes.
|
|
57
|
+
- **`useFetchSurfaceMetaGroup(slugs[])`** — the grouped sibling of `useFetchSurfaceMeta`, for a screen
|
|
58
|
+
needing many section surfaces at once. **Order-insensitive** (the slug list is normalized so cache
|
|
59
|
+
hits don't depend on argument order), `staleTime: Infinity`, hits the grouped endpoint
|
|
60
|
+
`GET /v2/surfaces/meta-group?slugs=...`, and extracts the `{surfaces}` map via `extractGroup()` /
|
|
61
|
+
`looksLikeGroup()` (the same structural-fingerprint approach as `extractBundle`). Returns `{}` for
|
|
62
|
+
unmigrated screens (`enabled:false`), so a non-roster client does no fetch.
|
|
54
63
|
- **`evaluateSurfaceRule`** — the Tier-1 rule evaluator: a **frozen `all/any/none` + `{field,op,value}`
|
|
55
64
|
grammar** that **throws on an unknown op** (generalized from the SalesOrders
|
|
56
65
|
`buildPatchedTenantFields`/`evaluateEnableRule`/`resolveFlag` helpers). Evaluated client-side against
|
|
@@ -114,20 +123,35 @@ modal copy, visibility/enable) to Surface; **leave data-fetch wiring (fetch slug
|
|
|
114
123
|
nested-table topology) in JSON/code.** Not every screen reduces to a generic `SurfaceSection` swap —
|
|
115
124
|
see SalesOrders below.
|
|
116
125
|
|
|
117
|
-
## SalesOrders
|
|
118
|
-
|
|
119
|
-
The SalesOrders detail
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
code
|
|
130
|
-
|
|
126
|
+
## SalesOrders record-modal sections — migrated via the registered-renderer seam (roster-gated)
|
|
127
|
+
|
|
128
|
+
The SalesOrders detail sections are now migrated onto Surface for the **seeded roster clients only**,
|
|
129
|
+
via the registered-renderer approach (not a generic `SurfaceSection` swap — `SalesOrderSummaryGrid`'s
|
|
130
|
+
three bespoke renderers `detailSection`/`locationCard`/`totalsCard` are untouched).
|
|
131
|
+
|
|
132
|
+
- **`surfaceBundleToTenantFields()`** (`SalesOrders/helpers/`) adapts the grouped Surface bundle into
|
|
133
|
+
the existing **`TenantFields`** shape, so the existing `SalesOrderSummaryGrid` renderers and
|
|
134
|
+
`getDetailSections` are untouched — **only the SOURCE of section config moves JSON → Surface.**
|
|
135
|
+
Business logic stays in code: the recurring-lease `_totalLease` gate in the grid and approval
|
|
136
|
+
gating are **not** moved. (Registered-renderer seam: *config describes, code decides.*)
|
|
137
|
+
- **Roster gate — `SALES_ORDER_SURFACE_MIGRATED_CLIENTS = [COMPASS, COMPASSCANADA, QUAD]`** (an
|
|
138
|
+
in-code roster in `surfaceBundleToTenantFields.ts`; the view-model
|
|
139
|
+
`useSalesOrderRecordModalLayoutModel.tsx` consults it). The view-model resolves sections from
|
|
140
|
+
Surface **only** for roster clients; every other client (incl. never-migrated
|
|
141
|
+
NYCHH/Prudential/SPGlobal) skips the fetch and stays fully JSON-driven. Merge is **JSON-base +
|
|
142
|
+
Surface-wins.** ⚠ **Why a roster, not a flag:** the Core SECTION surfaces are **shared** and seeded
|
|
143
|
+
from Compass's shape — without the gate every client would inherit Compass's base and regress. A
|
|
144
|
+
**code** roster (not an env flag) is deliberate: a client is removed from the roster only once its
|
|
145
|
+
own seeds are verified.
|
|
146
|
+
- **JSON cleanup:** the migrated section blocks (orderDetails/shipTo/billTo/orderSummary/
|
|
147
|
+
orderRecurring + the 5 display sections) were **deleted** from the COMPASS / COMPASSCANADA / QUAD
|
|
148
|
+
`orderViewFields.json` files. Data-wiring (`salesOrderDetailsConfig`/`itemFulfillmentClickRule`/
|
|
149
|
+
`recordActionFields`/`recordApprovals`) was **kept**. The DEFAULT `orderViewFields.json` is left
|
|
150
|
+
**intact** — non-roster clients are still JSON-driven.
|
|
151
|
+
|
|
152
|
+
**Still JSON / deferred:** the SalesOrders **action-bar / approval-modal** migration remains on JSON;
|
|
153
|
+
seeding NYCHH/Prudential/SPGlobal is deferred; the Client-DB prod cross-cluster seed fix is on hold
|
|
154
|
+
(see [surface-layer-schema](../../dbchanges2/features/surface-layer-schema.md)).
|
|
131
155
|
|
|
132
156
|
## Gotchas
|
|
133
157
|
|
|
@@ -147,6 +171,14 @@ code/`_underscore`, plus reconciling those seeds and the Compass approval-modal
|
|
|
147
171
|
treat type-checking as pending. Runtime `GET /v2/surfaces/{slug}/meta` also not yet exercised.
|
|
148
172
|
|
|
149
173
|
## Change history
|
|
174
|
+
- 2026-06-30 — Migrated the SalesOrders record-modal sections onto Surface for the roster clients
|
|
175
|
+
[COMPASS, COMPASSCANADA, QUAD] via the registered-renderer seam: added `useFetchSurfaceMetaGroup`
|
|
176
|
+
(order-insensitive grouped `/surfaces/meta-group` fetch) + `surfaceBundleToTenantFields()` (adapts
|
|
177
|
+
the grouped bundle to the existing `TenantFields` shape; bespoke grid renderers + lease/approval
|
|
178
|
+
logic stay in code). Roster-gated (code roster, JSON-base + Surface-wins) so non-roster clients
|
|
179
|
+
don't inherit Compass's shared base. Deleted the migrated section blocks from COMPASS/COMPASSCANADA/
|
|
180
|
+
QUAD `orderViewFields.json` (data-wiring kept; DEFAULT intact). Action-bar/approval-modal still
|
|
181
|
+
JSON. (jcardinal)
|
|
150
182
|
- 2026-06-29 — Migrated VendorItems (screen 2, recipe-exact) and Inventory (screen 3,
|
|
151
183
|
**presentation-only by decision** — fetch topology stays JSON; only title/buttons/modal copy/entity
|
|
152
184
|
tags moved). Fixed the "s.elements is not iterable" crash: `extractBundle()` now finds the bundle by
|
|
@@ -5,6 +5,7 @@ apps:
|
|
|
5
5
|
- _underscore
|
|
6
6
|
- api2
|
|
7
7
|
- toga2-supply
|
|
8
|
+
- toga25-supply
|
|
8
9
|
- toga2-commerce
|
|
9
10
|
- worker2
|
|
10
11
|
- dbchanges2
|
|
@@ -12,7 +13,7 @@ project: _Underscore
|
|
|
12
13
|
client: quad
|
|
13
14
|
type: profile
|
|
14
15
|
status: active
|
|
15
|
-
updated: 2026-06-
|
|
16
|
+
updated: 2026-06-30
|
|
16
17
|
owners: ["jcardinal", "bala"]
|
|
17
18
|
files: []
|
|
18
19
|
related:
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: session
|
|
3
|
+
slug: surface-layer
|
|
4
|
+
title: Surface grouped-meta + SalesOrders section migration (Compass/CompassCanada/Quad)
|
|
5
|
+
author: jcardinal
|
|
6
|
+
repos: [_underscore, dbchanges2, toga25-supply]
|
|
7
|
+
framework: "2.0"
|
|
8
|
+
client: shared
|
|
9
|
+
status: active
|
|
10
|
+
created: 2026-06-30
|
|
11
|
+
updated: 2026-06-30
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Session: surface-layer
|
|
15
|
+
**Date:** 2026-06-30
|
|
16
|
+
**Project/Repo:** _underscore / dbchanges2 / toga25-supply (2.0)
|
|
17
|
+
**Task:** Build a grouped surface-meta resolver and migrate the toga25-supply SalesOrders record-modal sections onto the Surface UI presentation layer for the seeded clients (Compass, CompassCanada, Quad), keeping non-migrated clients on JSON.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## What WORKED
|
|
22
|
+
- **`metaGroup` grouped resolver** — `_Model_Core_Surface::metaGroup(&$api, string $slugs): object` at `GET /v2/surfaces/meta-group?slugs=a,b,c`. Splits/dedupes the slug list (cap `META_GROUP_MAX_SLUGS=25`, logs truncation), calls the existing `resolve()` per slug (shares its per-slug file cache), returns `{group, surfaces:{slug=>bundle|null}}`. `php -l` clean. Verified live on dev-sandbox (200 after the ACL grant).
|
|
23
|
+
- **Resolver message-resolution fixes** (`Surface.php` `_buildBundle`/`_resolveElement`): remap element message slots id→messageKey before return (labels previously fell back to the element key); collect `disabledTooltipMessageId` + emit `disabledTooltip`; set `surface.titleMessageKey`; merge the 2nd `_loadMessages` return into `$messageKeyById`; log dangling message ids; `resolve()` now `: object`. These were latent because SECTION/BUTTON_BAR rendering was never shipped.
|
|
24
|
+
- **FE grouped fetch + adapter**: `useFetchSurfaceMetaGroup(slugs[])` (order-insensitive key, staleTime Infinity, `extractGroup` by `{surfaces}` fingerprint) and `surfaceBundleToTenantFields()` adapter → existing `TenantFields` shape, so `SalesOrderSummaryGrid` renderers + `getDetailSections` are untouched.
|
|
25
|
+
- **Migrated-client roster gate**: `SALES_ORDER_SURFACE_MIGRATED_CLIENTS=[COMPASS,COMPASSCANADA,QUAD]` in the view-model; only roster clients fetch+resolve Surface sections (merge = JSON-base + Surface-wins), everyone else stays JSON.
|
|
26
|
+
- **DB seeds (applied on dev-sandbox, working)**: Core `2026-06-30a` (meta-group RecordScript + `order-recurring` surface + 5 display-toggle marker surfaces); Client `2026-06-30a` meta-group AclRecordScripts grant; Compass/CompassCanada/Quad `2026-06-30a` SurfaceOverrides for section deltas.
|
|
27
|
+
- **403 EZ-1 on meta-group fixed** by applying the Client AclRecordScripts dispatch grant per client DB. Verified via toga-db: `meta` script id 25 → roles 1,3,4; `meta-group` id 27 had no grant until applied.
|
|
28
|
+
- **JSON cleanup**: removed the migrated section blocks from COMPASS/COMPASSCANADA/QUAD `orderViewFields.json` (kept salesOrderDetailsConfig/itemFulfillmentClickRule/recordActionFields/recordApprovals). DEFAULT left intact.
|
|
29
|
+
- **/capture PUSHED** — 4 surface feature docs + 3 client profiles updated on team `_main` (commits f732160 + fc8de41).
|
|
30
|
+
|
|
31
|
+
## What did NOT work — DO NOT RETRY THESE
|
|
32
|
+
- **Client-DB seeds resolving Core ids via cross-DB subselect** (`Core.RecordScripts`/`Core.Surfaces`/`Core.SurfaceElements` from a `Client_*` file). Works on the dev-sandbox all-in-one instance but **WILL FAIL in production** — Core is a separate MySQL cluster there, and cross-DB queries require one instance. This is the current id-agnostic approach in all 4 Client seeds; it is the prod blocker (see Blockers).
|
|
33
|
+
- **Parent `parentSurfaceId` GROUP-row design for grouped meta** — rejected by CTO review: adds Core schema state + a new TYPE, must be seeded per-client per-env for a grouping the FE already knows statically, and reintroduces id drift. The slug-list `metaGroup` is schema-stateless.
|
|
34
|
+
- **Surface-only cutover for all clients** (no roster gate) — would regress non-seeded clients (NYCHH/Prudential/SPGlobal/DEFAULT) because the Core section surfaces are SHARED and seeded from Compass's shape; they'd inherit it.
|
|
35
|
+
- **Overriding a section's visibility via the Surface row's own `isVisible`** — the resolver cascade (`_loadOverrides`) only overrides ELEMENTS, never a surface's `isVisible`. Hence each display-toggle surface carries one `sectionVisibility` marker element that the overrides target.
|
|
36
|
+
- **Removing MANAGER/Quad summary shipping/tax tooltips via override** — `_castOverride` treats `TOOLTIP_MESSAGE` as numeric-only, so it can't null a tooltip. Cosmetic; deferred.
|
|
37
|
+
- **Seeding `elementType` for Quad** — confirmed dead config (no `.ts/.tsx` reads it); needs no migration.
|
|
38
|
+
|
|
39
|
+
## Not tried yet (candidates for next session)
|
|
40
|
+
- **Prod cross-cluster seed fix** (the on-hold blocker): rewrite the 4 Client seeds to hardcode Core ids as literals + resolve `roleId` by name (per `Client/2026-06-23b - ItemTranslationsAcl.sql`), zero `Core.` refs. User chose "I'll give you the prod ids" — apply the Core seed to prod Core, run the lookup query (in session memory / below) to get literal recordScriptId/surfaceId/surfaceElementId, then bake them in. Also audit the EXISTING `2026-06-25c`/`2026-06-29c`/`2026-06-25d` surface seeds for the same anti-pattern.
|
|
41
|
+
- **Action-bar / approval-modal migration** — still JSON; pulls in the Compass approval state machine + Tier-2 `stepTwoAssigned`. The `sales-order-actions` BUTTON_BAR surface is already seeded but not yet consumed by the FE.
|
|
42
|
+
- **Seed NYCHH / Prudential / SPGlobal** (and add to the roster) once confirmed live on toga25-supply; they need Quad-like client-level overrides to match the DEFAULT shape.
|
|
43
|
+
|
|
44
|
+
## Current file state
|
|
45
|
+
| File | Status | Notes |
|
|
46
|
+
|------|--------|-------|
|
|
47
|
+
| _underscore/Model/Core/Surface.php | modified | metaGroup() + message-resolution fixes; php -l clean |
|
|
48
|
+
| dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql | created | meta-group script + order-recurring + 5 display surfaces + markers. Prod-safe (Core→Core). |
|
|
49
|
+
| dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql | created | meta-group dispatch grant. ⚠ cross-DB Core ref — prod fix pending. |
|
|
50
|
+
| dbchanges2/Client_Compass/2026-06-30a - SalesOrderDisplaySectionManagerOverrides.sql | created | MANAGER hide invoices/admin-notes. ⚠ cross-DB. |
|
|
51
|
+
| dbchanges2/Client_CompassCanada/2026-06-30a - SalesOrderSurfaceManagerOverrides.sql | created | MANAGER deltas (shippingMethod/invoices/admin-notes), role by name. ⚠ cross-DB. |
|
|
52
|
+
| dbchanges2/Client_Quad/2026-06-30a - SalesOrderSurfaceClientOverrides.sql | created | client-level deltas (costCenter/shippingMethod/recurringTotal + 3 display hides). ⚠ cross-DB. |
|
|
53
|
+
| toga25-supply/src/surface/useFetchSurfaceMeta.ts | modified | added useFetchSurfaceMetaGroup + extractGroup |
|
|
54
|
+
| toga25-supply/src/surface/index.ts | modified | re-export group hook |
|
|
55
|
+
| toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts | created | adapter + slug list + migrated-client roster |
|
|
56
|
+
| toga25-supply/.../SalesOrderRecordModalLayout/helpers/index.ts | modified | re-export adapter + roster |
|
|
57
|
+
| toga25-supply/.../viewModel/useSalesOrderRecordModalLayoutModel.tsx | modified | roster-gated Surface merge |
|
|
58
|
+
| toga25-supply/.../FIELDS/{COMPASS,COMPASSCANADA,QUAD}/orderViewFields.json | modified | section blocks deleted; data-wiring kept |
|
|
59
|
+
|
|
60
|
+
## Decisions made
|
|
61
|
+
- **Grouped meta = slug-list `metaGroup`, not a parent GROUP row** (CTO AGREE-with-alternative): schema-stateless, reuses resolve()/cache, avoids id drift.
|
|
62
|
+
- **Migrated-client roster gate in code, not an env flag**: protects unseeded/unknown clients from the shared Compass-shaped Core base. Remove a client from the roster only after its seeds are verified; then its JSON sections are safe to delete.
|
|
63
|
+
- **Display sections = field-less SECTION surfaces with one `sectionVisibility` marker element**: only way to express per-role section visibility given the resolver overrides elements, not surface.isVisible.
|
|
64
|
+
- **Data-wiring stays JSON** (salesOrderDetailsConfig, itemFulfillmentClickRule): presentation-only migration, config/logic boundary (Inventory precedent).
|
|
65
|
+
- **Prod-safe Client-seed pattern = literal Core ids + Client-local roleId-by-name** (per ItemTranslationsAcl). Deferred to the prod pass.
|
|
66
|
+
|
|
67
|
+
## Blockers
|
|
68
|
+
- **PROD CROSS-CLUSTER (on hold, user-paused):** the 4 Client-DB seeds use `Core.*` cross-DB subselects that break against prod's separate Core cluster. Fix recorded in memory [[surface-prod-crossdb-fix-pending]]. Lookup query to get prod literal ids is in the session thread. Dev-sandbox is unaffected (all-in-one) and fully working.
|
|
69
|
+
|
|
70
|
+
## Exact next step
|
|
71
|
+
> When resuming the prod fix: apply `Core/2026-06-30a` to the prod Core cluster, then run the labeled lookup query against prod Core (returns meta-group recordScriptId + surfaceId/surfaceElementId for order-details/c_erpEntityId, ship-to/shippingMethod.name, order-recurring/isTotal, and the invoices/admin-notes/additional-order-details/notes `sectionVisibility` markers). Paste results, then rewrite the 4 Client `2026-06-30a` seeds to hardcode those Core ids as literals and resolve only `roleId` by name — removing every `Core.` reference — following `dbchanges2/Client/2026-06-23b - ItemTranslationsAcl.sql`.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
_Saved by /session-save on 2026-06-30_
|
package/package.json
CHANGED