toga-ai 1.0.216 → 1.0.217

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.
@@ -4,6 +4,7 @@
4
4
  |-----|---------|-------|
5
5
  | [_underscore Framework Architecture](architecture.md) | `_underscore` is the shared PHP backend framework for **all 2.0 applications**. | _underscore/_underscore.php, _underscore/Loader.php, _underscore/Framework.php, _underscore/Model.php, _underscore/Database.php, _underscore/Query.php, _underscore/Route.php, _underscore/Component.php |
6
6
  | [ACL Permission Chain (Record & Field Authorization)](features/acl-permission-chain.md) | Authorization in the 2.0 API is **metadata-driven**: whether a role may Create/Read/Update/Delete a record is decided by rows across **four linked tables**, not | api2/Component/Api/V2/V2.php, _underscore/Model/Core/Page.php, dbchanges2/Client/2026-06-03- BLANK_CLIENT_DATABASE.sql, dbchanges2/Client/2026-06-23b - ItemTranslationsAcl.sql |
7
+ | [Assortment Name Translation (AssortmentTranslations sidecar)](features/assortment-name-translation.md) | Serves Assortment (product-grouping) **names** in multiple languages by adding a per-language **sidecar** table `AssortmentTranslations`, reusing the platform's | _underscore/Model/Client/AssortmentTranslation.php, dbchanges2/Client/2026-06-26a - AssortmentTranslations.sql, dbchanges2/Core/2026-06-26a - AssortmentTranslationsRecord.sql, dbchanges2/Client/2026-06-26b - AssortmentTranslationsAcl.sql |
7
8
  | [Carrier Shipping Labels (UPS/FedEx) & NetSuite Item Fulfillment](features/carrier-shipping-labels.md) | Backend mechanics behind TOGa Supply's Fulfill & Ship: buying a carrier label (UPS/FedEx), persisting it, and creating the NetSuite Item Fulfillment with tracki | _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Client/ItemFulfillments/TrackingNumber.php, _underscore/Component/Library/LabelPdf/LabelPdf.php, _underscore/Component/Library/Carriers/Ups/Ups.php, _underscore/Component/Library/Carriers/Fedex/Fedex.php, _underscore/Trait/Netsuite/ItemFulfillment.php, _underscore/Trait/Netsuite/SalesOrder.php, _underscore/Component/Library/NetSuite/NetSuite.php, _underscore/Model/Client/TrackingNumber.php, _underscore/Model/Client/ShippingMethod.php, _underscore/Model.php, _underscore/Cloud.php |
8
9
  | [Client Email Template Sending](features/email-template-sending.md) | `_Model_Client_EmailTemplate` sends a stored, client-defined email template by UUID. | _underscore/Model/Client/EmailTemplate.php, _underscore/Model/Client/EmailTemplateOutgoingEmailAddress.php, _underscore/Email.php |
9
10
  | [Forecast.Sales NetSuite import engine (real-time webhook)](features/forecast-sale-import.md) | Real-time importer that takes a NetSuite **sale** record and writes its lines into `Forecast.Sales` (the Forecast2 revenue table). | _underscore/Component/Forecast/SaleImport/SaleImport.php, _underscore/Component/Forecast/Db/Db.php, worker2/Worker/Netsuite/Invoice.php, worker2/Worker/Netsuite/CashSale.php, worker2/Worker/Netsuite/CreditMemo.php, worker2/Worker/Netsuite/CashRefund.php, worker2/Worker/Netsuite/JournalEntry.php, worker2/Worker/Netsuite/Opportunity.php, worker2/Worker/Netsuite/SalesOrder.php, dbchanges2/Forecast/2026-06-26a - Add journalEntry to Sales transaction type enum.sql, test/@dave/test_invoice_lifecycle.php, test/@dave/test_je_lifecycle.php, test/@dave/test_creditmemo_lifecycle.php, test/@dave/test_cashsale_lifecycle.php, test/@dave/test_cashrefund_lifecycle.php, test/@dave/NetSuite/api-message-queue/ue_api_msg_queue_enqueue.js, test/@dave/NetSuite/api-message-queue/dev_ue_api_msg_queue_enqueue.js |
@@ -0,0 +1,86 @@
1
+ ---
2
+ title: Assortment Name Translation (AssortmentTranslations sidecar)
3
+ framework: "2.0"
4
+ repo: _underscore
5
+ project: _Underscore
6
+ client: shared
7
+ type: feature
8
+ status: active
9
+ updated: 2026-06-26
10
+ owners: ["bala"]
11
+ files:
12
+ - _underscore/Model/Client/AssortmentTranslation.php
13
+ - dbchanges2/Client/2026-06-26a - AssortmentTranslations.sql
14
+ - dbchanges2/Core/2026-06-26a - AssortmentTranslationsRecord.sql
15
+ - dbchanges2/Client/2026-06-26b - AssortmentTranslationsAcl.sql
16
+ related:
17
+ - ../../api2/features/language-translation-layer.md
18
+ - ./acl-permission-chain.md
19
+ ---
20
+
21
+ ## Summary
22
+
23
+ Serves Assortment (product-grouping) **names** in multiple languages by adding a per-language
24
+ **sidecar** table `AssortmentTranslations`, reusing the platform's existing translation mechanism.
25
+ English stays in `Assortments.name`; the sidecar holds only non-English overlays. Because the
26
+ translation layer is fully metadata-driven (see
27
+ [Language Translation Layer](../../api2/features/language-translation-layer.md)), wiring this up
28
+ required **no api2 code change** — only a new table, model, Core record registration, ACL grant,
29
+ and a single field link. Compass Canada's French (fr-CA) assortment names are seeded as the first
30
+ consumer.
31
+
32
+ ## Key files / entry points
33
+
34
+ - `_underscore/Model/Client/AssortmentTranslation.php` — the sidecar model (`_Model_Client_AssortmentTranslation`).
35
+ - `dbchanges2/Client/2026-06-26a - AssortmentTranslations.sql` — the sidecar table (every client DB).
36
+ - `dbchanges2/Core/2026-06-26a - AssortmentTranslationsRecord.sql` — Core record + fields + the field link.
37
+ - `dbchanges2/Client/2026-06-26b - AssortmentTranslationsAcl.sql` — Base-role ACL grant (every client DB).
38
+
39
+ ## How it works
40
+
41
+ The mechanism itself is the data-driven translation layer documented in
42
+ [Language Translation Layer](../../api2/features/language-translation-layer.md) — this feature only
43
+ **registers a new translatable field** into it:
44
+
45
+ 1. **Sidecar table.** `Client.AssortmentTranslations` holds non-English overlays for assortment names.
46
+ English remains in `Assortments.name`; a null/absent sidecar row falls back to English.
47
+ 2. **Model.** `_Model_Client_AssortmentTranslation` is the ORM model for the sidecar.
48
+ 3. **Core record registration.** `Core.Records` registers route `assortment-translations` →
49
+ model `\_Model_Client_AssortmentTranslation` (record id **332**, `aclDatabase = 'CLIENT'`), with
50
+ `Core.RecordFields` rows for `id`, `uuid`, `assortmentId`, `languageId`, and `name`.
51
+ 4. **The field link (what makes it translate automatically).** The translatable `Assortments.name`
52
+ RecordField gets its `Core.RecordFields.translationRecordFieldId` set to the sidecar's `name`
53
+ RecordField. The api2 V2 layer reads `translationRecordFieldId` for every field and automatically
54
+ returns the sidecar value for the caller's resolved language (falling back to English when absent) —
55
+ so assortment names now translate **without any api2 code change**.
56
+ 5. **ACL.** A full ACL chain grants the **Base** role read/write on the new record. Because the
57
+ record's `aclDatabase = 'CLIENT'`, the grant lives in each client DB — see
58
+ [ACL Permission Chain](./acl-permission-chain.md).
59
+
60
+ ## Data model
61
+
62
+ - `Client.AssortmentTranslations` — `id, uuid, dtCreated, dtUpdated, assortmentId (FK Assortments),
63
+ languageId (FK Languages), name`; `UNIQUE(assortmentId, languageId)`. English stays in `Assortments`;
64
+ sidecar holds only non-English overlays (null → English fallback).
65
+ - `Core.Records` **332** = `assortment-translations` (`aclDatabase = 'CLIENT'`); `Core.RecordFields`
66
+ for id/uuid/assortmentId/languageId/name.
67
+ - `Assortments.name` RecordField → `translationRecordFieldId` points at the sidecar `name` RecordField.
68
+
69
+ ## Client variations
70
+
71
+ - **Compass Canada** seeds fr-CA assortment names (16 rows) into `AssortmentTranslations`. The French
72
+ text was extracted from the existing bilingual `Assortments.name` values (stored as `"English/French"`),
73
+ and a companion migration cleans `Assortments.name` back to English-only so the base value is pure
74
+ English and the French overlay lives only in the sidecar. See the Compass Canada profile.
75
+
76
+ ## Change history
77
+
78
+ - 2026-06-26 — Initial build: `AssortmentTranslations` sidecar table + `_Model_Client_AssortmentTranslation`
79
+ model + `Core.Records` 332 registration + `translationRecordFieldId` link on `Assortments.name` + Base-role
80
+ ACL chain. Reuses the existing metadata-driven translation layer, so no api2 code change was needed.
81
+ Compass Canada French (fr-CA) assortment names seeded, with `Assortments.name` cleaned to English-only. (bala)
82
+
83
+ ## Related docs
84
+
85
+ - [Language Translation Layer](../../api2/features/language-translation-layer.md)
86
+ - [ACL Permission Chain](./acl-permission-chain.md)
@@ -16,7 +16,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
16
16
 
17
17
  ## 2.0 framework
18
18
 
19
- - **_underscore** (_Underscore) _(framework core)_ — 16 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
19
+ - **_underscore** (_Underscore) _(framework core)_ — 17 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
20
20
  - **worker2** (Worker) — 17 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
21
21
  - **api2** (API) — 7 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
22
22
  - **dbchanges2** (Database Changes) _(framework core)_ — 3 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
@@ -44,5 +44,9 @@ to but distinct from Compass USA. Like Compass USA it spans the **2.0** commerce
44
44
  ## Notes
45
45
  - Customer language preference: `UserGlobalSettings.settingId = 2` (`en` / `fr-CA`); customer-
46
46
  facing emails are sent in EN or FR accordingly.
47
+ - Assortment (product-grouping) names are served in fr-CA via the `AssortmentTranslations` sidecar
48
+ (16 rows seeded). French was extracted from the old bilingual `"English/French"` `Assortments.name`
49
+ values, which were then cleaned to English-only. See
50
+ [Assortment Name Translation](../../2.0/apps/_underscore/features/assortment-name-translation.md).
47
51
  - The 2026-06-08 ASN → ItemFulfillment work was for **Compass USA**, not Compass Canada.
48
52
  - Related: [Compass USA](../compass-usa/profile.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.216",
3
+ "version": "1.0.217",
4
4
  "description": "TOGA Technology Team Claude Knowledge System — shared AI coding harness with skills, knowledge base CLI, and project installer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",