toga-ai 1.0.296 → 1.0.297
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.
|
@@ -21,3 +21,4 @@
|
|
|
21
21
|
| [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, _underscore/Model/Client/AclRecordScript.php, _underscore/Model/Core/RecordScript.php, dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql, dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql, dbchanges2/Client_Quad/2026-07-01a - GrantSurfacesMetaGroupScriptAcl.sql, dbchanges2/Client_CompassCanada/2026-07-01a - GrantSurfacesMetaGroupScriptAcl.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 |
|
|
22
22
|
| [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 |
|
|
23
23
|
| [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 | |
|
|
24
|
+
| [Running a 2.0 App Locally (browser, end-to-end via api2)](workflows/running-a-2.0-app-locally.md) | The full dependency chain required to run a 2.0 client app **through the browser**, end-to-end, against a **local `api2`** (e.g. | _underscore/Environment.php, _underscore/Config.php, _underscore/Database.php, _underscore/Route.php, api2/Component/Api/V2/V2.php, api2/index.php, api2/.htaccess |
|
|
@@ -6,8 +6,8 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-
|
|
10
|
-
owners: ["dfranks", "jcardinal"]
|
|
9
|
+
updated: 2026-07-09
|
|
10
|
+
owners: ["dfranks", "jcardinal", "mhammontree"]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Database.php
|
|
13
13
|
- _underscore/ApiRequest.php
|
|
@@ -93,6 +93,7 @@ registration is region-aware in `api2/Controller/Index.php`; the alias const is
|
|
|
93
93
|
|
|
94
94
|
## Change history
|
|
95
95
|
|
|
96
|
+
- 2026-07-09 — Linked the new [Running a 2.0 app locally](../workflows/running-a-2.0-app-locally.md) runbook, which frames these three connections as one requirement of a full local browser run. (mhammontree)
|
|
96
97
|
- 2026-07-07 — Noted the new shared **Cache** cluster (`Databases` id 145, alias `DB_CACHE`,
|
|
97
98
|
region-aware) added for the api2 cross-client retrieval engine. (jcardinal)
|
|
98
99
|
- 2026-06-18 — Documented after the `Logs_Growrk`/`Logs_Aig` local 500s while testing the
|
|
@@ -101,4 +102,5 @@ registration is region-aware in `api2/Controller/Index.php`; the alias const is
|
|
|
101
102
|
## Related docs
|
|
102
103
|
|
|
103
104
|
- [_underscore architecture](../architecture.md)
|
|
105
|
+
- [Running a 2.0 app locally (browser end-to-end)](../workflows/running-a-2.0-app-locally.md) — the full local-stack runbook these three connections are one requirement of.
|
|
104
106
|
- [NetSuite → TOGa Supply per-client sync](../../../1.0/apps/worker/features/netsuite-togasupply-per-client-sync.md) — the work that surfaced this.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Running a 2.0 App Locally (browser, end-to-end via api2)
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: _underscore
|
|
5
|
+
project: _Underscore
|
|
6
|
+
client: shared
|
|
7
|
+
type: workflow
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-07-09
|
|
10
|
+
owners: ["mhammontree"]
|
|
11
|
+
files:
|
|
12
|
+
- _underscore/Environment.php
|
|
13
|
+
- _underscore/Config.php
|
|
14
|
+
- _underscore/Database.php
|
|
15
|
+
- _underscore/Route.php
|
|
16
|
+
- api2/Component/Api/V2/V2.php
|
|
17
|
+
- api2/index.php
|
|
18
|
+
- api2/.htaccess
|
|
19
|
+
related:
|
|
20
|
+
- ../features/per-client-database-connections.md
|
|
21
|
+
- ../../dbchanges2/workflows/client-onboarding.md
|
|
22
|
+
- ../../dbchanges2/architecture.md
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Summary
|
|
26
|
+
|
|
27
|
+
The full dependency chain required to run a 2.0 client app **through the browser**,
|
|
28
|
+
end-to-end, against a **local `api2`** (e.g. pointing the `toga2-view` frontend at a laptop
|
|
29
|
+
`api2` instead of beta/prod). This is separate from CLI/script backend testing — it exercises
|
|
30
|
+
the web SAPI, the Apache-supplied environment, Core-driven client-DB registration, and the
|
|
31
|
+
`/v2/auth/login` browser auth gate, none of which the CLI path touches. It cost hours to
|
|
32
|
+
reverse-engineer; the notes below are platform-general (any 2.0 client app), with Rate used
|
|
33
|
+
only as the running example.
|
|
34
|
+
|
|
35
|
+
**Bottom line:** most local failures here are a **provisioning gap in the local stack**
|
|
36
|
+
(missing/stale DB, unregistered origin, unseeded Core), *not* an app bug. The confusing
|
|
37
|
+
`Route.php:525` "failed to determine how to render view" and stale-Core "missing model file"
|
|
38
|
+
fatals below both mean "the local stack isn't fully stood up."
|
|
39
|
+
|
|
40
|
+
> Cost/benefit note from the originating session: because standing the full local backend up
|
|
41
|
+
> is this involved, the team's chosen shortcut for front-end work was to **deploy api2 to beta
|
|
42
|
+
> and point the local frontend at beta** rather than rebuild the entire local backend stack.
|
|
43
|
+
|
|
44
|
+
## Steps / requirements
|
|
45
|
+
|
|
46
|
+
### 1. ENVIRONMENT comes from Apache for the web app (not the CLI)
|
|
47
|
+
|
|
48
|
+
- `_Environment::initialize()` reads `getenv('ENVIRONMENT')` (`_underscore/Environment.php:11`)
|
|
49
|
+
and **throws if unset**. `_Config` then loads `Config/<ENVIRONMENT>.ini` (`Config.php:38`).
|
|
50
|
+
- The **web app** gets `ENVIRONMENT` from **Apache** — a `SetEnv ENVIRONMENT <name>` in the
|
|
51
|
+
api2 vhost — *not* from your shell/CLI environment. Dev convention:
|
|
52
|
+
`ENVIRONMENT=dev-<name>-laptop` → loads `Config/dev-<name>-laptop.ini`.
|
|
53
|
+
- To see what the **web** app actually resolves (the frontend URL/console won't show it — api2
|
|
54
|
+
is a separate host), temporarily add to the top of `api2/index.php`:
|
|
55
|
+
`if (isset($_GET['__env'])) die(getenv('ENVIRONMENT'));` and hit `http://api2/?__env=1`.
|
|
56
|
+
Remove it afterward.
|
|
57
|
+
|
|
58
|
+
### 2. api2 collapses the environment name to a slug
|
|
59
|
+
|
|
60
|
+
- `V2.php:146`: `$this->environment = (substr($name,0,4)=='dev-') ? 'dev' : $name`. So **any**
|
|
61
|
+
`dev-*` INI resolves to the slug **`dev`** for downstream lookups (notably Core DB host
|
|
62
|
+
selection, below).
|
|
63
|
+
|
|
64
|
+
### 3. Client DB connections are Core-driven, not from the INI
|
|
65
|
+
|
|
66
|
+
- `_Database::registerClientDatabases($environment, $clientId)` (`_underscore/Database.php:56`)
|
|
67
|
+
SELECTs from **Core**, joining `Clients → Databases → DatabaseHosts → Environments(slug=<env>)`
|
|
68
|
+
to resolve the client's **client, log, AND archive** databases (all three INNER-JOINed — a
|
|
69
|
+
missing row for any one drops the whole registration).
|
|
70
|
+
- For local, Core must have an `Environments.slug='dev'` row plus `DatabaseHosts` rows pointing
|
|
71
|
+
all three DBs at `localhost`. A prod Core backup **already carries a `dev`→localhost row by
|
|
72
|
+
design** — do not assume it's missing.
|
|
73
|
+
- There are **two** log connections: `DB_LOGS` (base framework `Logs`) and `DB_CLIENT_LOGS`
|
|
74
|
+
(per-tenant `Logs_<tenant>`). See
|
|
75
|
+
[per-client database connections](../features/per-client-database-connections.md) for the
|
|
76
|
+
three-alias mechanism and the logs-DB write trap.
|
|
77
|
+
|
|
78
|
+
### 4. Browser login `POST /v2/auth/login` — requirements in the order code checks them
|
|
79
|
+
|
|
80
|
+
Checked in `V2.php` (~lines 485–800):
|
|
81
|
+
|
|
82
|
+
1. **POST with an `Origin` header.** A browser address-bar **GET** has neither → silent
|
|
83
|
+
fallthrough (no auth, no useful error). Requests must come from the frontend (fetch/XHR),
|
|
84
|
+
not a typed URL.
|
|
85
|
+
2. **`Core.Domains` row for the port-stripped origin.** `V2.php:98-103` strips the port, so
|
|
86
|
+
`http://rate.togaview:5173` matches a `Core.Domains` row for `http://rate.togaview`. That
|
|
87
|
+
row's `clientId`/`appId` must resolve to the local client/app.
|
|
88
|
+
3. **Active login user** must exist in `Client_<tenant>.Users`.
|
|
89
|
+
4. **All four databases must exist WITH SCHEMAS:** `Client_<tenant>`, `Logs_<tenant>`,
|
|
90
|
+
`Archive_<tenant>`, and base `Logs`. An **empty** database is not enough — every request
|
|
91
|
+
writes a transaction log via `$log->save()` at `execute()` finalization (`V2.php:2138`) into
|
|
92
|
+
`Logs_<tenant>.Api` / `Logs.Api`. Structure-only imports of the log/archive DBs are fine.
|
|
93
|
+
5. **`Core.Apis` must be seeded** — API auth uses `Apis.uuid`/`Apis.secret`. `Apis` is
|
|
94
|
+
deliberately **excluded from blanks/backups**, so a freshly restored Core often has it empty.
|
|
95
|
+
|
|
96
|
+
## Gotchas / known issues
|
|
97
|
+
|
|
98
|
+
- **The silent `Route.php:525` error** — `"Failed to determine how to render view for route
|
|
99
|
+
'/v2/...'"` (thrown at `_underscore/Route.php:525`) means the API handler returned **no**
|
|
100
|
+
response, so `_Route` fell through to view rendering. It is thrown during bootstrap
|
|
101
|
+
**outside** api2's JSON error handler, so the browser shows raw HTML and often **nothing** is
|
|
102
|
+
written to the PHP error log. The real cause is almost always a **local DB/registration gap**
|
|
103
|
+
(missing DB or schema, unresolved client-DB registration, or the auth gate being skipped per
|
|
104
|
+
step 4.1) — treat it as "the local stack isn't fully provisioned," not a request/app defect.
|
|
105
|
+
|
|
106
|
+
- **A STALE local Core silently 500s every api2 request.** api2's V2 loops **every**
|
|
107
|
+
`Core.Records` model at request time (`$thisModelName::TABLE`, `V2.php:3442-3446`). If local
|
|
108
|
+
Core is missing recent migrations it still references removed models and **fatals on a missing
|
|
109
|
+
model file** — a confusing error that looks unrelated to the DB and breaks *all* requests.
|
|
110
|
+
Concrete example: `dbchanges2/Core/2026-06-10 - TrackingNumberBridges.sql` is **non-idempotent**
|
|
111
|
+
(fixed record ids 317–322, RecordFields 2171–2200 — cannot be re-run) and its Section 9
|
|
112
|
+
**DELETES** Core `Records` row 41 (`ItemFulfillmentPackages`, model
|
|
113
|
+
`\_Model_Client_ItemFulfillmentPackage`), consolidating it into
|
|
114
|
+
`ItemFulfillments_TrackingNumbers` (record 317). A local Core missing this migration still has
|
|
115
|
+
record 41, so V2 fatals on the removed `_Model_Client_ItemFulfillmentPackage` file.
|
|
116
|
+
**Fix:** bring local Core current — apply the missing Core migrations in date order, or refresh
|
|
117
|
+
Core wholesale. Do not re-run a single non-idempotent migration in isolation.
|
|
118
|
+
|
|
119
|
+
## Change history
|
|
120
|
+
|
|
121
|
+
- 2026-07-09 — Documented the full local browser-run dependency chain (Apache `ENVIRONMENT`,
|
|
122
|
+
`dev-*`→`dev` slug collapse, Core-driven client-DB registration, `/v2/auth/login` browser gate,
|
|
123
|
+
the `Route.php:525` silent-fallthrough gotcha, and the stale-Core "missing model file" fatal),
|
|
124
|
+
discovered while trying to run `toga2-view` against a local `api2`. (mhammontree)
|
package/knowledge/INDEX.md
CHANGED
|
@@ -17,7 +17,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
17
17
|
|
|
18
18
|
## 2.0 framework
|
|
19
19
|
|
|
20
|
-
- **_underscore** (_Underscore) _(framework core)_ —
|
|
20
|
+
- **_underscore** (_Underscore) _(framework core)_ — 27 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
|
|
21
21
|
- **worker2** (Worker) — 27 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
|
|
22
22
|
- **api2** (API) — 10 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
|
|
23
23
|
- **dbchanges2** (Database Changes) _(framework core)_ — 3 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
|
package/package.json
CHANGED