toga-ai 1.0.659 → 1.0.660
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/features/surface-resolver.md +11 -1
- package/knowledge/2.0/apps/dbchanges2/INDEX.md +1 -1
- package/knowledge/2.0/apps/dbchanges2/features/surface-layer-schema.md +57 -1
- package/knowledge/2.0/apps/toga25-supply/INDEX.md +1 -1
- package/knowledge/2.0/apps/toga25-supply/features/surface-frontend.md +74 -1
- package/knowledge/clients/elite/profile.md +2 -1
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-08-
|
|
9
|
+
updated: 2026-08-26
|
|
10
10
|
owners: [jcardinal, apeterson]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Model/Client/Language.php
|
|
@@ -79,6 +79,12 @@ with `const DATABASE`/`TABLE`, typed public-prop fields, and array FKs declaring
|
|
|
79
79
|
`FIELDOPT_FOREIGNKEY_MODEL` (cross-DB FKs are soft — no SQL constraint). Modeled on
|
|
80
80
|
`RecordField.php`/`TableView.php`.
|
|
81
81
|
|
|
82
|
+
**That Core/Client split is a CLUSTER boundary, not just a schema one.** `SurfaceOverrides` lives in
|
|
83
|
+
`DB_CLIENT` (there is no `Model/Core/SurfaceOverride.php`), so a question like "how many clients
|
|
84
|
+
override this element?" **cannot be answered with a join** on prod — resolve the element ids in Core
|
|
85
|
+
first, then count per client DB with those ids as literals. Same rule that forces client override
|
|
86
|
+
seeds to inline Core ids (below).
|
|
87
|
+
|
|
82
88
|
## How `resolve()` works
|
|
83
89
|
|
|
84
90
|
Inputs come from `$api` (the same accessor `_Model_Client_TableView::meta` uses):
|
|
@@ -606,6 +612,10 @@ Core record grants + their logic-group expressions all evaluate `all`/`"1"`. The
|
|
|
606
612
|
match Compass, a follow-up migration aligning both `meta` and `meta-group` to roles 1,3,4 is needed.
|
|
607
613
|
|
|
608
614
|
## Change history
|
|
615
|
+
- 2026-08-26 — Recorded that the Core/Client model split is a **cluster** boundary: `SurfaceOverrides`
|
|
616
|
+
is a CLIENT-DB model, so override counts across clients must be a two-step (Core ids → per-client
|
|
617
|
+
count with literal ids), never a join. Matters when deciding whether to fork or share a surface,
|
|
618
|
+
since a fork starts with **zero** overrides. (apeterson)
|
|
609
619
|
- 2026-08-25 — Fixed a **whole-platform gap**: Surface message translations were inert for **every
|
|
610
620
|
API-authenticated request, for every client**. `_resolveLanguageId` returned `0` when the JWT carried
|
|
611
621
|
neither `id.client.languageId` nor `id.language`, and `0` makes `_loadMessages` skip the
|
|
@@ -4,7 +4,7 @@
|
|
|
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
6
|
| [Re-runnable additive INSERTs (uuid4 in SQL, guards, and the DISTINCT trap)](features/rerunnable-additive-inserts.md) | Most `dbchanges2` files are **additive data grants** run by hand against production, often more than once (once per environment, or twice because someone was no | dbchanges2/Client_Compass/2026-08-26a - CompassCreativeStudioPersona.sql |
|
|
7
|
-
| [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-08-24b - SalesOrderStatusFilterSurfaceSeed.sql, dbchanges2/Client_Compass/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Client_CompassCanada/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Client_Quad/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Client_Nychh/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Core/2026-08-21 - SalesOrderDecisionSurfacesReseed.sql, dbchanges2/Core/2026-08-24 - RestoreApproveDenyRowActionsVisibility.sql, dbchanges2/Client_Quad/2026-08-24 - ProdPortApprovePoNumberEnabledRule.sql, dbchanges2/Client_Quad/2026-07-21b - ApproveDisabledTooltipPoNumber.sql, dbchanges2/Client_Quad/2026-08-21 - SalesOrderDecisionSummaryOverride.sql, dbchanges2/Client_Compass/2026-08-24 - ProdPortApprovalsGateAndApproveStepTwoRule.sql, dbchanges2/Client_CompassCanada/2026-08-24 - ProdPortApprovalsGateAndApproveStepTwoRule.sql, dbchanges2/Client_Nychh/2026-08-24 - FixInventoryGroupingsUnitsTopologyOverrideIds.sql, dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql, dbchanges2/Client_Compass/2026-06-25d - SalesOrderSurfaceClientSeed.sql, _underscore/Model/Client/ThemeToken.php, toga25-supply/src/themeConfig.json, 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, dbchanges2/Core/2026-07-17h - Update - ClearApprovalsFilterButtonConfig.sql, dbchanges2/Client_Compass/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Compass/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_Quad/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Quad/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Core/2026-07-20a - Update - HideAdminNotesSectionByDefault.sql, dbchanges2/Core/2026-07-20b - Update - NotesSectionFieldElements.sql, dbchanges2/Client_Compass/2026-07-20a - AdminNotesSectionVisibilityOverride.sql, dbchanges2/Client_Compass/2026-07-20b - NotesSectionFieldsOverride.sql, dbchanges2/Client_CompassCanada/2026-07-20a - AdminNotesSectionVisibilityOverride.sql, dbchanges2/Client_CompassCanada/2026-07-20b - NotesSectionFieldsOverride.sql, dbchanges2/Client_Quad/2026-07-20a - NotesSectionFieldsOverride.sql, dbchanges2/Core/2026-07-20c - Update - VendorItemsToggleSurfaceSeed.sql, dbchanges2/Client_Compass/2026-07-20c - ItemRecordEditButtonEnable.sql, dbchanges2/Client_Compass/2026-07-20d - ItemRecordVendorItemsEnable.sql, dbchanges2/Client_CompassCanada/2026-07-20c - ItemRecordEditButtonEnable.sql, dbchanges2/Client_CompassCanada/2026-07-20d - ItemRecordVendorItemsEnable.sql, dbchanges2/Core/2026-07-20e - RestoreApproveDenyRowActions.sql, dbchanges2/Client_Compass/2026-07-20e - RowActionsApprovalWorkflowAdminEnable.sql, dbchanges2/Client_CompassCanada/2026-07-20e - RowActionsApprovalWorkflowAdminEnable.sql, dbchanges2/Core/2026-07-17 - README - RUN ORDER.md, dbchanges2/Client_Compass/2026-07-21a - SalesOrderApproveEnabledRuleOverride.sql, dbchanges2/Client_Compass/2026-07-21b - SalesOrderApprovalsGateEnable.sql, dbchanges2/Client_CompassCanada/2026-07-21a - SalesOrderApproveEnabledRuleOverride.sql, dbchanges2/Client_CompassCanada/2026-07-21b - SalesOrderApprovalsGateEnable.sql, dbchanges2/Client_Quad/2026-07-21a - SalesOrderApproveEnabledRuleOverride.sql, dbchanges2/Client_Quad/2026-07-21b - SalesOrderApproveDisabledTooltipTranslation.sql, dbchanges2/Core/2026-07-21a - SalesOrderDecisionSummarySurfaceSeed.sql, dbchanges2/Core/2026-07-21b - SalesOrderDecisionActionSurfaceSeed.sql, dbchanges2/Client_Quad/2026-07-21c - SalesOrderDecisionSummaryOverride.sql, dbchanges2/Client_Compass/2026-07-21c - SalesOrderDecisionSummaryTotalConcat.sql, dbchanges2/Client_CompassCanada/2026-07-21c - SalesOrderDecisionSummaryTotalConcat.sql, dbchanges2/Core/2026-07-23a - PoNumberDetailFieldValueKey.sql, dbchanges2/Core/2026-07-29a - SalesOrderApprovalDetailsSurfaceSeed.sql, dbchanges2/Core/2026-08-05b - ApprovalDetailsShippingMethodConcatCharge.sql, dbchanges2/Core/2026-08-14a - NoteBadgesVocabularySurface.sql, dbchanges2/Client/2026-08-14a - NoteBadgeThemeTokens.sql, dbchanges2/Client/2026-08-14b - NoteBadgeUserColorFix.sql, dbchanges2/Client_Compass/2026-08-14a - NoteBadgeDelegateThemeTokens.sql, dbchanges2/Client_CompassCanada/2026-08-14a - NoteBadgeDelegateThemeTokens.sql |
|
|
7
|
+
| [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-08-24b - SalesOrderStatusFilterSurfaceSeed.sql, dbchanges2/Client_Compass/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Client_CompassCanada/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Client_Quad/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Client_Nychh/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Core/2026-08-21 - SalesOrderDecisionSurfacesReseed.sql, dbchanges2/Core/2026-08-24 - RestoreApproveDenyRowActionsVisibility.sql, dbchanges2/Client_Quad/2026-08-24 - ProdPortApprovePoNumberEnabledRule.sql, dbchanges2/Client_Quad/2026-07-21b - ApproveDisabledTooltipPoNumber.sql, dbchanges2/Client_Quad/2026-08-21 - SalesOrderDecisionSummaryOverride.sql, dbchanges2/Client_Compass/2026-08-24 - ProdPortApprovalsGateAndApproveStepTwoRule.sql, dbchanges2/Client_CompassCanada/2026-08-24 - ProdPortApprovalsGateAndApproveStepTwoRule.sql, dbchanges2/Client_Nychh/2026-08-24 - FixInventoryGroupingsUnitsTopologyOverrideIds.sql, dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql, dbchanges2/Client_Compass/2026-06-25d - SalesOrderSurfaceClientSeed.sql, _underscore/Model/Client/ThemeToken.php, toga25-supply/src/themeConfig.json, 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, dbchanges2/Core/2026-07-17h - Update - ClearApprovalsFilterButtonConfig.sql, dbchanges2/Client_Compass/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Compass/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_Quad/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Quad/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Core/2026-07-20a - Update - HideAdminNotesSectionByDefault.sql, dbchanges2/Core/2026-07-20b - Update - NotesSectionFieldElements.sql, dbchanges2/Client_Compass/2026-07-20a - AdminNotesSectionVisibilityOverride.sql, dbchanges2/Client_Compass/2026-07-20b - NotesSectionFieldsOverride.sql, dbchanges2/Client_CompassCanada/2026-07-20a - AdminNotesSectionVisibilityOverride.sql, dbchanges2/Client_CompassCanada/2026-07-20b - NotesSectionFieldsOverride.sql, dbchanges2/Client_Quad/2026-07-20a - NotesSectionFieldsOverride.sql, dbchanges2/Core/2026-07-20c - Update - VendorItemsToggleSurfaceSeed.sql, dbchanges2/Client_Compass/2026-07-20c - ItemRecordEditButtonEnable.sql, dbchanges2/Client_Compass/2026-07-20d - ItemRecordVendorItemsEnable.sql, dbchanges2/Client_CompassCanada/2026-07-20c - ItemRecordEditButtonEnable.sql, dbchanges2/Client_CompassCanada/2026-07-20d - ItemRecordVendorItemsEnable.sql, dbchanges2/Core/2026-07-20e - RestoreApproveDenyRowActions.sql, dbchanges2/Client_Compass/2026-07-20e - RowActionsApprovalWorkflowAdminEnable.sql, dbchanges2/Client_CompassCanada/2026-07-20e - RowActionsApprovalWorkflowAdminEnable.sql, dbchanges2/Core/2026-07-17 - README - RUN ORDER.md, dbchanges2/Client_Compass/2026-07-21a - SalesOrderApproveEnabledRuleOverride.sql, dbchanges2/Client_Compass/2026-07-21b - SalesOrderApprovalsGateEnable.sql, dbchanges2/Client_CompassCanada/2026-07-21a - SalesOrderApproveEnabledRuleOverride.sql, dbchanges2/Client_CompassCanada/2026-07-21b - SalesOrderApprovalsGateEnable.sql, dbchanges2/Client_Quad/2026-07-21a - SalesOrderApproveEnabledRuleOverride.sql, dbchanges2/Client_Quad/2026-07-21b - SalesOrderApproveDisabledTooltipTranslation.sql, dbchanges2/Core/2026-07-21a - SalesOrderDecisionSummarySurfaceSeed.sql, dbchanges2/Core/2026-07-21b - SalesOrderDecisionActionSurfaceSeed.sql, dbchanges2/Client_Quad/2026-07-21c - SalesOrderDecisionSummaryOverride.sql, dbchanges2/Client_Compass/2026-07-21c - SalesOrderDecisionSummaryTotalConcat.sql, dbchanges2/Client_CompassCanada/2026-07-21c - SalesOrderDecisionSummaryTotalConcat.sql, dbchanges2/Core/2026-07-23a - PoNumberDetailFieldValueKey.sql, dbchanges2/Core/2026-07-29a - SalesOrderApprovalDetailsSurfaceSeed.sql, dbchanges2/Core/2026-08-05b - ApprovalDetailsShippingMethodConcatCharge.sql, dbchanges2/Core/2026-08-14a - NoteBadgesVocabularySurface.sql, dbchanges2/Client/2026-08-14a - NoteBadgeThemeTokens.sql, dbchanges2/Client/2026-08-14b - NoteBadgeUserColorFix.sql, dbchanges2/Client_Compass/2026-08-14a - NoteBadgeDelegateThemeTokens.sql, dbchanges2/Client_CompassCanada/2026-08-14a - NoteBadgeDelegateThemeTokens.sql, dbchanges2/Core/2026-08-26a - ServiceRequestRecordHeaderSurfaceSeed.sql, dbchanges2/Core/2026-08-26b - ServiceRequestDetailsSurfaceSeed.sql |
|
|
8
8
|
| [2.0 New-Client Onboarding (manual process)](workflows/client-onboarding.md) | > **A local browser wizard now automates this.** Steps 2–9 below (create DBs, generate Core/API > inserts, append to `Clients_Db.txt`) — plus the dbchanges2 bla | Client/, Client_<Tenant>/, Core/, Logs_Client/ |
|
|
9
9
|
| [Auditing a client DB that drifted from its models (partially applied module migration)](workflows/client-schema-drift-audit.md) | A recurring 2.0 failure mode: **one client's database drifts from what the PHP models declare**, usually because a `_modules/<module>/` migration was applied to | dbchanges2/Client_Growrk/2026-05-28.sql, dbchanges2/Client_Growrk/2026-08-10c - GrowrkServiceRequestCustomFieldsCatchUp.sql, dbchanges2/Client_Growrk/2026-08-10d - GrowrkServiceRequestTypeAndDispositionSeeds.sql, dbchanges2/_modules/netsuite/2026-07-10a - UnitInventoryFields.sql, dbchanges2/Client_Growrk/2026-08-10 - GrowrkUnitInventoryFieldsCatchUp.sql, dbchanges2/Client_Growrk/2026-08-10b - GrowrkUnitItemDescriptionAcl.sql, dbchanges2/Client_Growrk/_modules.txt |
|
|
10
10
|
| [Local vs prod MySQL config parity — why “it passed locally” is not evidence](workflows/local-vs-prod-mysql-config-parity.md) | Several migration failures that look like "prod-only bugs" are actually **per-machine MySQL server-configuration differences**. | |
|
|
@@ -6,7 +6,7 @@ project: Database Changes
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-08-
|
|
9
|
+
updated: 2026-08-26
|
|
10
10
|
owners: [jcardinal, apeterson]
|
|
11
11
|
files:
|
|
12
12
|
- dbchanges2/Core/2026-08-24b - SalesOrderStatusFilterSurfaceSeed.sql
|
|
@@ -86,6 +86,8 @@ files:
|
|
|
86
86
|
- dbchanges2/Client/2026-08-14b - NoteBadgeUserColorFix.sql
|
|
87
87
|
- dbchanges2/Client_Compass/2026-08-14a - NoteBadgeDelegateThemeTokens.sql
|
|
88
88
|
- dbchanges2/Client_CompassCanada/2026-08-14a - NoteBadgeDelegateThemeTokens.sql
|
|
89
|
+
- dbchanges2/Core/2026-08-26a - ServiceRequestRecordHeaderSurfaceSeed.sql
|
|
90
|
+
- dbchanges2/Core/2026-08-26b - ServiceRequestDetailsSurfaceSeed.sql
|
|
89
91
|
related:
|
|
90
92
|
- ../../_underscore/features/surface-resolver.md
|
|
91
93
|
---
|
|
@@ -730,7 +732,61 @@ rule resumes.
|
|
|
730
732
|
Element 32 is likewise `isEnabled=0` (appears but disabled until an `IS_ENABLED`/`ENABLED_RULE`
|
|
731
733
|
override is added). **Open follow-up.**
|
|
732
734
|
|
|
735
|
+
## Forking a surface — Service Request record surfaces (Core 45/46, 2026-08-26)
|
|
736
|
+
|
|
737
|
+
The Service Request modal needed header chrome and a details section that **diverge** from the sales
|
|
738
|
+
order's, so two surfaces were forked (not the whole set — `Surfaces` are per-region, so forking one
|
|
739
|
+
region is the right granularity).
|
|
740
|
+
|
|
741
|
+
| File | Ids | Forked from |
|
|
742
|
+
|---|---|---|
|
|
743
|
+
| `Core/2026-08-26a - ServiceRequestRecordHeaderSurfaceSeed.sql` | `Surfaces` **45** (`service-request-record-header`), `SurfaceElements` **161–165**, `recordId` **35** (`Records` `service-requests`, hardcoded) | `sales-order-record-header` (Surfaces 11 / elements 25–28) |
|
|
744
|
+
| `Core/2026-08-26b - ServiceRequestDetailsSurfaceSeed.sql` | `Surfaces` **46** (`service-request-details`), `SurfaceElements` **166–169** | the `order-details` section |
|
|
745
|
+
|
|
746
|
+
The header adds a modal tag reading "Service Request" (new `Core.Messages` key
|
|
747
|
+
`serviceRequest.header.tag`) and a new **Type** FIELD element (165) between order date and status
|
|
748
|
+
badge. Element **164**'s `labelTemplate` still reads `'Order {order.number}'` — **intentional**,
|
|
749
|
+
confirmed by the developer; do not "fix" it.
|
|
750
|
+
|
|
751
|
+
The details surface adds Type and drops Cost Center: Customer (`contact._name`), PO Number
|
|
752
|
+
(`_purchaseOrders`), Type (`serviceRequest.serviceRequestType.name`), Description (`description`).
|
|
753
|
+
A **Provider** field was requested but **not seeded** — no `provider` field exists on
|
|
754
|
+
`_Model_Client_SalesOrder` or `_Model_Client_ServiceRequest` and nothing in `toga25-supply`
|
|
755
|
+
references one. Still unresolved.
|
|
756
|
+
|
|
757
|
+
> Valuekey trap: section elements use **bare** keys while header elements use `order.`-prefixed keys,
|
|
758
|
+
> and the SR modal actually fetches the **linked Sales Order** — see
|
|
759
|
+
> [surface-frontend](../../toga25-supply/features/surface-frontend.md#gotchas).
|
|
760
|
+
|
|
761
|
+
### 🚨 Forking a surface silently DROPS every client override of the original
|
|
762
|
+
`SurfaceOverrides` rows are keyed **per surface element**, so a fork starts with zero overrides — every
|
|
763
|
+
per-client customization of the original section is silently gone on the new surface. **The fork-vs-share
|
|
764
|
+
decision should be driven by an override count**, taken before writing the seed.
|
|
765
|
+
|
|
766
|
+
Counting them is **not a join**: `Surfaces`/`SurfaceElements` are **Core** models
|
|
767
|
+
(`Model/Core/Surface.php`, `Model/Core/SurfaceElement.php` → `DB_CORE`) but `SurfaceOverrides` is a
|
|
768
|
+
**Client** model (`Model/Client/SurfaceOverride.php` → `DB_CLIENT`; there is no
|
|
769
|
+
`Model/Core/SurfaceOverride.php`). "How many clients override this element?" spans the prod-core and
|
|
770
|
+
prod-client **clusters**, so it must be two steps: resolve the element ids in Core, then count per
|
|
771
|
+
client DB using those ids as **literals**.
|
|
772
|
+
|
|
773
|
+
### `Surfaces`/`SurfaceElements` ids are per-ENVIRONMENT AUTO_INCREMENT — re-verify before every run
|
|
774
|
+
House style seeds these with literal ids, but they are **not** among the two team-maintained-id tables
|
|
775
|
+
(`Records`/`RecordFields`), so the next free value **can differ per environment** and must be
|
|
776
|
+
re-verified before a migration runs anywhere new. On 2026-08-26 local and production happened to agree
|
|
777
|
+
exactly (`MAX(Surfaces.id)` 44, `MAX(SurfaceElements.id)` 160) — that was **verified, not assumed**.
|
|
778
|
+
Using literals is still correct: a collision then fails loudly on the primary key instead of silently
|
|
779
|
+
mis-wiring (which is what `INSERT IGNORE` did in the 2026-08-24 incident above).
|
|
780
|
+
|
|
733
781
|
## Change history
|
|
782
|
+
- 2026-08-26 — Seeded the **Service Request** record surfaces as a **fork** of the sales-order ones:
|
|
783
|
+
`Core/2026-08-26a` (Surfaces **45** / elements **161–165**, recordId 35) and `Core/2026-08-26b`
|
|
784
|
+
(Surfaces **46** / elements **166–169**). Recorded three durable rules: forking a surface **drops
|
|
785
|
+
every client `SurfaceOverride`** of the original, so fork-vs-share should be decided by an override
|
|
786
|
+
count; that count **cannot be a join** because `SurfaceOverrides` is a **CLIENT**-DB model while
|
|
787
|
+
`Surfaces`/`SurfaceElements` are **CORE**; and `Surfaces`/`SurfaceElements` ids are per-environment
|
|
788
|
+
`AUTO_INCREMENT` (not team-maintained), so the free block must be re-verified per environment —
|
|
789
|
+
local and prod agreed at 44/160 this time, verified not assumed. (apeterson)
|
|
734
790
|
- 2026-08-25 — Added a **worked before/after cluster-isolation example** on a real client migration:
|
|
735
791
|
`Client_Quad/2026-07-21b - ApproveDisabledTooltipPoNumber.sql` joins **`Core.Messages` to
|
|
736
792
|
`Client_Quad.Languages`**, so it runs locally (all-in-one endpoint) and can **never** run on prod or
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
| [Force Logout on Deployment (useDeploymentGuard)](features/force-logout-on-deployment.md) | On large deployments the backend bumps the Core parameter `META_LAST_REFRESH_DATETIME`. | toga25-supply/src/hooks/useDeploymentGuard.tsx, toga25-supply/src/App.tsx |
|
|
11
11
|
| [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 |
|
|
12
12
|
| [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/pages/SalesOrders/view/SalesOrderRecordModalLayout/hooks/usePurchaseOrderDetails.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/FIELDS/apiFields.json, toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts, toga25-supply/src/layout/PrimaryTableServerLayout/PrimaryTableServerLayout.tsx, toga25-supply/src/layout/PrimaryTableServerLayout/types.ts, 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/GenericNestedTables.tsx, toga25-supply/src/layout/GenericNestedTables/GenericTableLayout.tsx, toga25-supply/src/pages/Inventory/viewModel/useInventoryPageViewModel.tsx, toga25-supply/src/pages/Inventory/viewModel/FIELDS/DEFAULT/inventoryGroupings.json, toga25-supply/src/hooks/useTableCellInteractions.ts, toga25-supply/src/hooks/useServerTableUrlState.ts, toga25-supply/src/layout/RecordApprovalModal/helpers/handleFormatApprovalWorkflowPayload.ts, toga25-supply/src/layout/RecordApprovalModal/api/approvalDecisionsApi.ts |
|
|
13
|
-
| [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/App.tsx, toga25-supply/src/contexts/AuthContext.tsx, toga25-supply/src/surface/applyColSpan.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/sectionRenderers.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getVisibleSections.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/SalesOrderApprovalSummaryGrid.tsx, toga25-supply/src/surface/useFetchSurfaceMeta.ts, toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts, toga25-supply/src/pages/SalesOrders/helpers/buildPatchedTenantFields.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/SalesOrderView.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/SalesOrderSummaryGrid.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getDetailSections.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderNotesSection.tsx, toga25-supply/src/pages/SalesOrders/helpers/cleanOrder.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/AdminNotesSection.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getAdminNotes.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/index.ts, toga25-supply/src/surface/evaluateSurfaceRule.ts, toga25-supply/src/surface/resolveElementState.ts, toga25-supply/src/pages/SalesOrders/helpers/evaluateEnableRule.ts, toga25-supply/src/pages/SalesOrders/hooks/useSalesOrderRowRecordState.ts, toga25-supply/src/surface/actionRegistry.ts, toga25-supply/src/surface/componentRegistry.tsx, 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/SurfaceRowActions.tsx, toga25-supply/src/pages/SalesOrders/hooks/useSalesOrderVip.ts, 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, toga25-supply/src/layout/ItemRecordModalLayout/helpers/surfaceBundleToItemFields.ts, toga25-supply/src/layout/ItemRecordModalLayout/helpers/index.ts, toga25-supply/src/layout/ItemRecordModalLayout/viewModel/useItemRecordModalViewModel.tsx, toga25-supply/src/layout/ItemRecordModalLayout/ItemRecordModalLayout.tsx, toga25-supply/src/layout/ItemRecordModalLayout/components/ItemRecordView.tsx, toga25-supply/src/surface/useStatusColors.ts, toga25-supply/src/surface/SurfaceHeader.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderApprovalModalsLayout/helpers/surfaceBundlesToDecisionFields.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderApprovalModalsLayout/viewModel/useApprovalModalViewModel.tsx |
|
|
13
|
+
| [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/App.tsx, toga25-supply/src/contexts/AuthContext.tsx, toga25-supply/src/surface/applyColSpan.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/sectionRenderers.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getVisibleSections.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/SalesOrderApprovalSummaryGrid.tsx, toga25-supply/src/surface/useFetchSurfaceMeta.ts, toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts, toga25-supply/src/pages/ServiceRequests/view/ServiceRequestRecordModalLayout/ServiceRequestRecordModalLayout.tsx, toga25-supply/src/pages/ServiceRequests/view/ServiceRequestRecordModalLayout/view/ServiceRequestsView.tsx, toga25-supply/src/pages/ServiceRequests/view/ServiceRequestRecordModalLayout/viewModel/useServiceRequestRecordModalLayoutModel.tsx, toga25-supply/src/pages/ServiceRequests/view/ServiceRequestRecordModalLayout/viewModel/FIELDS/apiFields.json, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderTopBar.tsx, toga25-supply/src/pages/SalesOrders/helpers/buildPatchedTenantFields.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/SalesOrderView.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/SalesOrderSummaryGrid.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getDetailSections.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderNotesSection.tsx, toga25-supply/src/pages/SalesOrders/helpers/cleanOrder.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/AdminNotesSection.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getAdminNotes.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/index.ts, toga25-supply/src/surface/evaluateSurfaceRule.ts, toga25-supply/src/surface/resolveElementState.ts, toga25-supply/src/pages/SalesOrders/helpers/evaluateEnableRule.ts, toga25-supply/src/pages/SalesOrders/hooks/useSalesOrderRowRecordState.ts, toga25-supply/src/surface/actionRegistry.ts, toga25-supply/src/surface/componentRegistry.tsx, 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/SurfaceRowActions.tsx, toga25-supply/src/pages/SalesOrders/hooks/useSalesOrderVip.ts, 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, toga25-supply/src/layout/ItemRecordModalLayout/helpers/surfaceBundleToItemFields.ts, toga25-supply/src/layout/ItemRecordModalLayout/helpers/index.ts, toga25-supply/src/layout/ItemRecordModalLayout/viewModel/useItemRecordModalViewModel.tsx, toga25-supply/src/layout/ItemRecordModalLayout/ItemRecordModalLayout.tsx, toga25-supply/src/layout/ItemRecordModalLayout/components/ItemRecordView.tsx, toga25-supply/src/surface/useStatusColors.ts, toga25-supply/src/surface/SurfaceHeader.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderApprovalModalsLayout/helpers/surfaceBundlesToDecisionFields.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderApprovalModalsLayout/viewModel/useApprovalModalViewModel.tsx |
|
|
14
14
|
| [Talos Integration (AppLayout host + adapter wiring)](features/talos-integration.md) | toga25-supply is the first host of the shared blox [Talos assistant](../../toga-blox/features/talos-assistant.md). | toga25-supply/src/layout/AppLayout/AppLayout.tsx, toga25-supply/src/components/Header/Header.tsx, toga25-supply/src/components/Header/Header.module.css, toga25-supply/src/index.css, toga25-supply/src/assets/talos-owl.png |
|
|
15
15
|
| [AWS Amplify Multi-Environment Deployment](workflows/amplify-deployment.md) | How `toga25-supply` deploys to **all** of its environments on AWS Amplify from a **single shared `amplify.yml`**. | toga25-supply/amplify.yml, toga25-supply/src/api/api.ts, toga25-supply/src/hooks/useAuthenticationFlow.ts, toga25-supply/vite.config.ts, toga25-supply/package.json |
|
|
16
16
|
| [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,7 +6,7 @@ project: TOGa 2.5 Supply
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-08-
|
|
9
|
+
updated: 2026-08-26
|
|
10
10
|
owners: [jcardinal, apeterson]
|
|
11
11
|
files:
|
|
12
12
|
- toga25-supply/src/App.tsx
|
|
@@ -17,6 +17,11 @@ files:
|
|
|
17
17
|
- toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/SalesOrderApprovalSummaryGrid.tsx
|
|
18
18
|
- toga25-supply/src/surface/useFetchSurfaceMeta.ts
|
|
19
19
|
- toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts
|
|
20
|
+
- toga25-supply/src/pages/ServiceRequests/view/ServiceRequestRecordModalLayout/ServiceRequestRecordModalLayout.tsx
|
|
21
|
+
- toga25-supply/src/pages/ServiceRequests/view/ServiceRequestRecordModalLayout/view/ServiceRequestsView.tsx
|
|
22
|
+
- toga25-supply/src/pages/ServiceRequests/view/ServiceRequestRecordModalLayout/viewModel/useServiceRequestRecordModalLayoutModel.tsx
|
|
23
|
+
- toga25-supply/src/pages/ServiceRequests/view/ServiceRequestRecordModalLayout/viewModel/FIELDS/apiFields.json
|
|
24
|
+
- toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderTopBar.tsx
|
|
20
25
|
- toga25-supply/src/pages/SalesOrders/helpers/buildPatchedTenantFields.ts
|
|
21
26
|
- toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx
|
|
22
27
|
- toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/SalesOrderView.tsx
|
|
@@ -674,7 +679,75 @@ developer asked for the **whole component**, not just badges. The old
|
|
|
674
679
|
- **`tsc` not yet run** this session (the private `@agilant/toga-blox` registry needs npm creds);
|
|
675
680
|
treat type-checking as pending. Runtime `GET /v2/surfaces/{slug}/meta` also not yet exercised.
|
|
676
681
|
|
|
682
|
+
- **🚨 The Service Request modal renders the LINKED SALES ORDER, not the ServiceRequest record.**
|
|
683
|
+
`ServiceRequestRecordModalLayout.tsx` resolves the SR uuid to a SalesOrder uuid via
|
|
684
|
+
`SalesOrders.serviceRequestId` and fetches `/sales-orders/{uuid}`. So **any SR-specific field is one
|
|
685
|
+
hop further out**: the Type element was first seeded as `order.serviceRequestType.name`, which
|
|
686
|
+
resolves to nothing (SalesOrders has `serviceRequestId`, not `serviceRequestTypeId`) — the correct
|
|
687
|
+
path is `order.serviceRequest.serviceRequestType.name`. And **both halves are required**: the field
|
|
688
|
+
must ALSO be added to the modal's `apiFields.json` `fields` list or the API never returns it, and the
|
|
689
|
+
element renders blank with no error either way.
|
|
690
|
+
- **🚨 Header surfaces use `order.`-prefixed valueKeys; section surfaces use BARE keys.** The record
|
|
691
|
+
modal top bar builds its surface record as `{ order }`, so header elements read `order.dateOrder`,
|
|
692
|
+
`order._status`. Section surfaces (`order-details` etc.) resolve against the order **directly**, so
|
|
693
|
+
their keys are bare: `contact._name`, `_purchaseOrders`, `description`. The same field therefore has
|
|
694
|
+
two different valueKeys depending on which surface it lives in, and copying one into the other
|
|
695
|
+
renders blank with no error.
|
|
696
|
+
|
|
697
|
+
## Service Request record modal — forked from the SalesOrder modal (2026-08-26)
|
|
698
|
+
|
|
699
|
+
The Service Request (SR) modal was split off the SalesOrder record modal rather than being made a
|
|
700
|
+
mode of it. Three seams carry the fork; nothing else in the surface plumbing changed.
|
|
701
|
+
|
|
702
|
+
**1. Its own view model.** `useServiceRequestRecordModalLayoutModel.tsx` is a fork of
|
|
703
|
+
`useSalesOrderRecordModalViewModel` that keeps the record fetch, items, bundle items, invoices,
|
|
704
|
+
shipments, surface sections and contact-VIP, and **drops** `useFetchApprovalStages` + the approvals
|
|
705
|
+
surface gate, `usePurchaseOrderDetails` and the `meta.surface.poNumber.isComplete` derivation, and
|
|
706
|
+
assignee-VIP enrichment. It uses a distinct React Query cache scope **`"service-request-modal"`** so
|
|
707
|
+
it can never clobber the SO modal's `"record-modal"` scope — the two modals fetch the *same* record
|
|
708
|
+
shape, so a shared key would cross-contaminate.
|
|
709
|
+
|
|
710
|
+
**2. Its own view.** `ServiceRequestsView.tsx` drops `SalesOrderApprovalModalsLayout`,
|
|
711
|
+
`EnterPoNumberModal`, `AdminNotesSection`, the `approvalActive` gate and the approval/standard
|
|
712
|
+
summary-grid ternary.
|
|
713
|
+
|
|
714
|
+
**3. A parameterized slug map (the FE decides which tenantFields slot a section fills).**
|
|
715
|
+
`surfaceBundleToTenantFields(surfaces, slugToKey = SECTION_SLUG_TO_KEY)` now takes the map as an
|
|
716
|
+
argument. `SERVICE_REQUEST_SECTION_SLUG_TO_KEY` maps `service-request-details` → the **same**
|
|
717
|
+
`orderDetails` slot, so a forked surface renders in the existing `SalesOrderSummaryGrid` with no grid
|
|
718
|
+
change. `SalesOrderTopBar` gained an optional `headerSurfaceSlug` prop (default
|
|
719
|
+
`sales-order-record-header`) so the SR view passes `service-request-record-header`.
|
|
720
|
+
|
|
721
|
+
> Interim seam, deliberately. Extracting the top bar into a generic `RecordModalTopBar` was explicitly
|
|
722
|
+
> deferred by the developer — do not "clean this up" unprompted.
|
|
723
|
+
|
|
724
|
+
### Decision — FE-passed slug map, NOT a backend-declared `config.sectionKey`
|
|
725
|
+
Three options were weighed for how the FE maps a section surface to a tenantFields slot:
|
|
726
|
+
- **(a) derive the key from the slug** (kebab→camel) — rejected: breaks *silently* the moment slugs
|
|
727
|
+
diverge, which is exactly what forking does.
|
|
728
|
+
- **(b) key off `config.cardType`** — rejected: cardType is a *renderer* type shared by several
|
|
729
|
+
sections, so it cannot identify a slot.
|
|
730
|
+
- **(c) have each surface declare `config.sectionKey` and make the adapter generic** — drafted,
|
|
731
|
+
including a Core backfill migration for the 11 existing section surfaces, then **rejected by the
|
|
732
|
+
developer because of the backfill**. It remains the cleaner long-term design if the backfill is
|
|
733
|
+
ever accepted.
|
|
734
|
+
|
|
735
|
+
Final: the parameterized FE map above.
|
|
736
|
+
|
|
737
|
+
### Open — the SR modal still resolves `sales-order-record-actions`
|
|
738
|
+
`SurfaceActionBar` in the SR modal still resolves the sales-order actions surface, so every action
|
|
739
|
+
button except **View Log** renders and does nothing on click. Whether the SR modal gets its own
|
|
740
|
+
actions surface is **still an open decision**, not an oversight.
|
|
741
|
+
|
|
677
742
|
## Change history
|
|
743
|
+
- 2026-08-26 — Forked the **Service Request record modal** off the SalesOrder modal: own view model
|
|
744
|
+
(`"service-request-modal"` query scope; no approvals/PO-details/assignee-VIP), own view (no approval
|
|
745
|
+
modals, EnterPoNumberModal or AdminNotesSection), and a parameterized
|
|
746
|
+
`surfaceBundleToTenantFields(surfaces, slugToKey)` + `SalesOrderTopBar.headerSurfaceSlug` so forked
|
|
747
|
+
surfaces render in the existing grid. Recorded the decision to use an FE-passed slug map over a
|
|
748
|
+
backend `config.sectionKey` (backfill rejected), and two gotchas: the SR modal actually renders the
|
|
749
|
+
**linked Sales Order**, and header vs section surfaces use `order.`-prefixed vs **bare** valueKeys.
|
|
750
|
+
SR modal still resolves `sales-order-record-actions` — open. (apeterson)
|
|
678
751
|
- 2026-08-24 — **Corrected the surface-meta cache gotcha (supersedes the prior "a hard reload /
|
|
679
752
|
re-login is required" wording, which was wrong enough to misdirect debugging).** The React Query
|
|
680
753
|
cache is **persisted to `localStorage`**: `App.tsx` uses `PersistQueryClientProvider` +
|
|
@@ -6,6 +6,7 @@ apps:
|
|
|
6
6
|
- worker2
|
|
7
7
|
- library
|
|
8
8
|
- toga2-supply
|
|
9
|
+
- toga25-supply
|
|
9
10
|
- dbchanges2
|
|
10
11
|
- _underscore
|
|
11
12
|
- api2
|
|
@@ -15,7 +16,7 @@ project: Worker
|
|
|
15
16
|
client: elite
|
|
16
17
|
type: profile
|
|
17
18
|
status: active
|
|
18
|
-
updated: 2026-08-
|
|
19
|
+
updated: 2026-08-26
|
|
19
20
|
owners: [snaredla, apeterson, tcox, bala]
|
|
20
21
|
files:
|
|
21
22
|
- worker2/Worker/Elite.php
|
package/package.json
CHANGED