toga-ai 1.0.852 → 1.0.854
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/1.0/apps/worker/INDEX.md +1 -0
- package/knowledge/1.0/apps/worker/features/walmart-daily-sales-report.md +76 -0
- package/knowledge/2.0/apps/toga2-commerce/INDEX.md +1 -0
- package/knowledge/2.0/apps/toga2-commerce/architecture.md +2 -1
- package/knowledge/2.0/apps/toga2-commerce/features/catalog-cache-freshness.md +9 -8
- package/knowledge/2.0/apps/toga2-commerce/features/sso-redirect-and-session-gating.md +74 -0
- package/knowledge/INDEX.md +2 -2
- package/knowledge/clients/compass-canada/profile.md +11 -1
- package/knowledge/clients/walmart/profile.md +2 -1
- package/package.json +1 -1
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
| [OneUptime external uptime monitoring for 1.0 workers](features/oneuptime-worker-uptime-monitoring.md) | Per-minute external OneUptime "Incoming Request" heartbeat from every 1.0 worker box (Degraded 3 min / Offline 5 min); open for the heartbeat push, monitor prov |
|
|
17
17
|
| [Prudential: Send Shipments for the Day report (daily cron)](features/send-shipments-for-the-day.md) | Daily 9:00 PM Prudential/Dell cron emailing an Excel of every device shipped today (tracking, serial, XID, FedEx status, vendor); open for the ASN join chain an |
|
|
18
18
|
| [Staples cXML Order Import (SFTP → NetSuite)](features/staples-cxml-order-import.md) | Hourly cron importing Staples cXML POs from SFTP into NetSuite Sales Orders (writes 855 ack back); open for the per-file flow, saved-search-8412 Location resolu |
|
|
19
|
+
| [Walmart Daily Sales Report (send_toga_walmart_report.php)](features/walmart-daily-sales-report.md) | The two Walmart sales workbooks (summary + details) built from `TOGA_Walmart` (in-store) and `TOGA_WalmartEComm` (.COM); open for the pseudo-store 1472 channel |
|
|
19
20
|
| [Diagnosing frozen 1.0 worker cron check-ins (Sentry "missed" flood)](workflows/diagnosing-frozen-cron-checkins.md) | Ordered path to diagnose frozen 1.0 worker cron timestamps + a Sentry `worker1` "missed" flood; open when check-ins stall and you suspect a wedged lock. |
|
|
20
21
|
| [isFulfillable Multi-Client Backfill (all togasupply clients)](workflows/isfulfillable-multi-client-backfill.md) | One-time backfill catching up `Items.isFulfillable` on existing items across all 17 togasupply clients; open when running/re-running it or deciding whether rema |
|
|
21
22
|
| [Deduplicating NetSuite duplicate Items across client DBs (recursive MERGE)](workflows/netsuite-duplicate-items-dedup.md) | Per-client cleanup collapsing duplicate `Items` rows (same `partNumber`) to one canonical via recursive MERGE; open before running it — and read the catalog-bli |
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Walmart Daily Sales Report (send_toga_walmart_report.php)
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: worker
|
|
5
|
+
project: Worker
|
|
6
|
+
client: walmart
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-09-21
|
|
10
|
+
owners: ["mhammontree"]
|
|
11
|
+
files:
|
|
12
|
+
- worker/crons/notifications/reports/send_toga_walmart_report.php
|
|
13
|
+
- worker/crons/notifications/reports/send_incomm_report.php
|
|
14
|
+
related:
|
|
15
|
+
- ../../../clients/walmart/profile.md
|
|
16
|
+
- ../workflows/tracing-a-worker-cron-run-in-production.md
|
|
17
|
+
- ../../library/features/email-test-mode-and-write-free-sends.md
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
The two Walmart sales workbooks (summary + details) built from `TOGA_Walmart` (in-store) and `TOGA_WalmartEComm` (.COM); open for the pseudo-store 1472 channel trap, the registration-not-sale counting rule, and the unmapped-category hole.
|
|
21
|
+
|
|
22
|
+
## Summary
|
|
23
|
+
|
|
24
|
+
`send_toga_walmart_report.php` emails two Excel workbooks:
|
|
25
|
+
|
|
26
|
+
- `WalmartTOGaSales_<date>.xlsx` — "Stores *" summary tabs (Weekly / Prior Week / YTD), categories in columns.
|
|
27
|
+
- `WalmartTOGaSalesDetails_<date>.xlsx` — item-level tabs, one row per paid sale.
|
|
28
|
+
|
|
29
|
+
Data comes from two databases, unioned: **`TOGA_Walmart`** (in-store) and
|
|
30
|
+
**`TOGA_WalmartEComm`** (online, rendered as a pseudo-store `.COM`). The report reads
|
|
31
|
+
`togaClientId = 6` with database `TOGA_Walmart` — **not** the `TOGA.Clients.id = 7` on the
|
|
32
|
+
[Walmart profile](../../../clients/walmart/profile.md). Both identifiers are live; do not
|
|
33
|
+
"correct" one to the other.
|
|
34
|
+
|
|
35
|
+
## How it works
|
|
36
|
+
|
|
37
|
+
1. `$storeNumberSql` (defined once at the top) is the shared channel-label expression, reused
|
|
38
|
+
by the item-level query and both store-level queries so every tab labels a sale the same way.
|
|
39
|
+
Named constants: `$multiChannelStoreId = 1472`, `$areaNumberNoStoreArea = '998'`,
|
|
40
|
+
`$areaNumberEComm = '999'`.
|
|
41
|
+
2. Store-level tabs: `UNION ALL` of the `TOGA_Walmart` in-store leg and the
|
|
42
|
+
`TOGA_WalmartEComm` `.COM` leg, in both the "get stores" and "get data" queries. The store
|
|
43
|
+
list is scoped to stores that **actually sold in the reporting period**, so the ~29 dormant
|
|
44
|
+
stores stay off the tab.
|
|
45
|
+
3. Item-level tabs: `LEFT OUTER JOIN Stores ON Stores.id = ServiceRequests.storeId`, grouped by
|
|
46
|
+
`$storeNumberSql` (not `Stores.id`).
|
|
47
|
+
4. Rows are bucketed into columns by `$cntCategoryMapping` / `$amountCategoryMapping`.
|
|
48
|
+
|
|
49
|
+
## Gotchas
|
|
50
|
+
|
|
51
|
+
- **`TOGA_Walmart.Stores.id = 1472` is a pseudo-store catch-all, and its own `storeNumber` is
|
|
52
|
+
wrong.** Every non-store sale hangs off id 1472. The real channel lives on
|
|
53
|
+
**`ServiceRequests.storeNumber`**, not `Stores.storeNumber`. Verified in prod: id 1472 carries
|
|
54
|
+
`WB` (219 rows, 2023-06-29 → 2026-09-20), `WM+` (118 rows, ended 2023-09-27), and one NULL
|
|
55
|
+
(2025-02-13) — while `Stores.storeNumber` for id 1472 says `WM+`. Reading the Stores row
|
|
56
|
+
mislabels every current sale. Store 1472 also has no `Addresses` row, so City/State render blank.
|
|
57
|
+
- **Never `INNER JOIN Stores` off `ServiceRequests.storeId`** — `storeId` is nullable and the
|
|
58
|
+
inner join silently deletes paid sales (4 lost since 2026-07-01, incl. the 2026-09-13 sale the
|
|
59
|
+
business flagged missing from `WalmartTOGaSalesDetails_20260915.xlsx`).
|
|
60
|
+
- **The report counts registrations, not sales.** `ServiceRequests` rows are created when a
|
|
61
|
+
customer registers the card, never when Walmart rings it up. The InComm SFTP feed is **never
|
|
62
|
+
imported**: `send_incomm_report.php` only downloads the day's files and emails them as
|
|
63
|
+
attachments — no DB write anywhere. So the report's in-store count is structurally lower than
|
|
64
|
+
the InComm file. Investigated under TRUE-81324; **no importer is being built** because Mike
|
|
65
|
+
confirmed Walmart no longer does in-store sales. Do not re-investigate this gap.
|
|
66
|
+
(InComm product: `TOGA_Walmart.Services` id 43558, SKU 302010001, UPC 643570190193,
|
|
67
|
+
`reportingCategory` 'Support'; FY26-to-date 44 units / $3,996.)
|
|
68
|
+
- **Open defect — unmapped categories vanish from the Stores tabs.** The category mappings cover
|
|
69
|
+
only Phone Repair, Tablet Repair, Set-up, Repair, Support, In-Home, Associate Performed.
|
|
70
|
+
Anything else lands in no column and is excluded from the Total. Verified: `TOGA_WalmartEComm`
|
|
71
|
+
has 181 items / $14,118 YTD with `reportingCategory = '0'` that are invisible on the report;
|
|
72
|
+
`TOGA_Walmart` has 6 such services. Fix for a future ticket: add an "Other" catch-all column.
|
|
73
|
+
|
|
74
|
+
## Change history
|
|
75
|
+
|
|
76
|
+
- 2026-09-21 — Restored the in-store `TOGA_Walmart` leg on the Stores tabs (deleted by 4d8e48803 / TRUE-60157 in 2025-03), switched the item query to `LEFT OUTER JOIN Stores`, and extracted the shared `$storeNumberSql` label expression (TRUE-81324). (mhammontree)
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
| [Multi-Tenant Resolution & Theming](features/multi-tenant-theming.md) | How the hostname resolves the tenant and fans out to API base URL, theme (CSS variables), and fields; open when adding a tenant or debugging wrong-theme/wrong-A |
|
|
19
19
|
| [Order-submit sync sequencing (useSubmitOrder) — why these calls must not run in parallel](features/order-submit-sync-sequencing.md) | The item sync must finish before the header sync on order submit, or concurrent line deletes race a depth-3 response into an uncaught api2 500; open when touchi |
|
|
20
20
|
| [Config-Driven Shipping Cost Waiver (Standard Ground free for computer kits)](features/shipping-cost-waiver-gating.md) | Config-driven cost waiver making Standard Ground free for a bare computer kit (Compass USA); open when touching shipping cost gates or the Compass free-freight |
|
|
21
|
+
| [SSO redirect & public-vs-user session gating (useAuthenticationFlow)](features/sso-redirect-and-session-gating.md) | How commerce decides on "/" whether a visitor is signed in, goes to SSO, or goes to /login; open for "blank page at /" or "SSO never fires" reports on any tenan |
|
|
21
22
|
| [Storefront persona gating — the Home page's kit / category / item counts, and the persona switcher](features/storefront-persona-gating-and-home-counts.md) | What a storefront user sees on the Home page is decided **in the front end**, from `user._personaIds`, not by the API's ACL. |
|
|
22
23
|
| [View-as another user — parked admin tokens & return-to-self](features/view-as-session-tokens.md) | How an admin impersonates another user and gets back: the delegated token pair, the parked admin pair in localStorage, and the return path. |
|
|
23
24
|
| [AWS Amplify Build & Deploy (non-prod environments)](workflows/amplify-build-and-deploy.md) | How toga2-commerce builds/deploys on AWS Amplify (one dynamic amplify.yml, branch-per-env, per-env blox channel); open to deploy, stand up an env, resolve a blo |
|
|
@@ -80,7 +80,7 @@ E2E tests use **Cypress** (`cypress/`, `cypress.config.ts`).
|
|
|
80
80
|
## Routing (`src/routes.tsx`, createBrowserRouter)
|
|
81
81
|
|
|
82
82
|
Public:
|
|
83
|
-
- `/` → `AuthRedirect` (→ `/home` if authenticated, else
|
|
83
|
+
- `/` → `AuthRedirect` (→ `/home` if authenticated, else an `AuthLoading` spinner while the auth flow redirects to SSO or `/login` — never `null`, which is what made `/` blank)
|
|
84
84
|
- `/login` → `LoginRoute` (→ `/home` if already authenticated, else `<Login/>`)
|
|
85
85
|
- `/reset-password` → `ResetPasswordPage`
|
|
86
86
|
|
|
@@ -196,3 +196,4 @@ The backend (`api2`) returns the standard 2.0 envelope (`success`/`data`/`errors
|
|
|
196
196
|
- **Tenant resolution depends on the hostname.** On `localhost` with no `*.togacommerce` host the first DNS label won't match a tenant, so config falls back (`getClientLoginFields` → COMPASS, theme → DEFAULT). Use the per-tenant dev scripts.
|
|
197
197
|
- **Theme vs. fields language keys differ** — theme/field *folder* names are uppercase (`COMPASSCANADA`, `ENGLISH`/`FRENCH`) but the runtime `FIELDS` registry keys language as `en` / **`fr-CA`** (not `fr`). Any language branch must use `startsWith("fr")` — a `=== "fr"` comparison silently never matches. See the client-fields doc.
|
|
198
198
|
- **Tailwind: not every `<n>px` name is a token.** `max-h-300px` does not exist (300px is only on the height/width scales) — write `max-h-[300px]`. `w-345px`, `h-300px`, `border-1` and `shadow-subMenu` do exist. A non-existent class silently renders unstyled.
|
|
199
|
+
- **⚠ A token in `localStorage` is not a session.** Any logged-out request mints a **public** `accessToken` via `fetchPublicToken` (`src/api/axiosInstance.ts`). Gating auth on `accessToken` made `/` render blank until the user cleared site data, on every tenant. Gate on a stored `user` JSON with a `uuid`. See [SSO redirect & session gating](features/sso-redirect-and-session-gating.md).
|
|
@@ -6,8 +6,8 @@ project: TOGa Commerce
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
10
|
-
owners: ["bala", "apeterson"]
|
|
9
|
+
updated: 2026-09-21
|
|
10
|
+
owners: ["bala", "apeterson", "tcox"]
|
|
11
11
|
files:
|
|
12
12
|
- toga2-commerce/src/App.tsx
|
|
13
13
|
- toga2-commerce/src/contexts/AuthContext.tsx
|
|
@@ -89,11 +89,7 @@ Verified 2026-09-03 on branch `TRUE-81610`. Read-only; none of these are fixed.
|
|
|
89
89
|
|
|
90
90
|
This is the "it's not successfully clearing their caches" report. Supply already solved it with an `awaitRestoration()` promise built from `useIsRestoring()` (`toga25-supply/src/contexts/AuthContext.tsx:56-77`) and gates every clear behind it.
|
|
91
91
|
|
|
92
|
-
**3. Two auth gates read two different localStorage keys → stuck on a
|
|
93
|
-
- The axios request interceptor gates on **`user`** (`src/api/axiosInstance.ts:112-118`). With no `user` it calls `fetchPublicToken()`, which POSTs `/auth/public` and **writes the public token back as `accessToken`** (`src/api/axiosInstance.ts:53-64`).
|
|
94
|
-
- But `src/hooks/useAuthenticationFlow.ts:213-217` gates on **`accessToken`** and returns early if it exists.
|
|
95
|
-
|
|
96
|
-
So after a forced logout: the first API call writes a *public* `accessToken`, the auth flow sees a token, skips **both** the SSO redirect and `/login`, and the user is logged out while the app believes they are not. Supply gates on `user` — with an explicit comment at `toga25-supply/src/contexts/AuthContext.tsx:47-51`. This is the app-side twin of the blox `fetchPublicToken` gotcha already recorded in `2.0/standards/frontend.md` §22.
|
|
92
|
+
**3. Two auth gates read two different localStorage keys → blank page / stuck login.** ✅ **Fixed on `TRUE-82172` (2026-09-21) — not yet merged.** Moved to its own doc: [SSO redirect & session gating](./sso-redirect-and-session-gating.md). It is an auth-gating defect, not a cache defect — clearing site data only masked it.
|
|
97
93
|
|
|
98
94
|
**4. The forced logout is too aggressive, and login never clears the cache.** `src/contexts/AuthContext.tsx:192-252`:
|
|
99
95
|
- On **any** core-parameter change it calls `logout()` + `window.location.href = "/"` with **no notice** to the user. On an SSO client `/` re-triggers the IdP.
|
|
@@ -131,13 +127,18 @@ Keep the **app default at `0`**, like supply.
|
|
|
131
127
|
- **⚠ Nothing is excluded from persistence on `_production`** — the `shouldDehydrateQuery` allowlist lives only on `_beta`/`#sprint84`. Check the branch.
|
|
132
128
|
- **⚠ The core-parameters watcher is not a targeted invalidation** — any Core parameter change force-logs-out every user on the environment. Use per-query opt-out or `queryClient.invalidateQueries` for anything narrower.
|
|
133
129
|
- **⚠ A `queryClient.clear()` that is not awaited behind cache restoration is undone.** All three of commerce's clear sites have this bug.
|
|
134
|
-
- **⚠ Gate auth on `user`, never `accessToken`** — `fetchPublicToken` writes a public token into `accessToken`.
|
|
130
|
+
- **⚠ Gate auth on `user`, never `accessToken`** — `fetchPublicToken` writes a public token into `accessToken`. See [SSO redirect & session gating](./sso-redirect-and-session-gating.md).
|
|
135
131
|
- **A `persistOptions.buster` keyed on the build version** would fix stale data at deploy time. Commerce has a committed `amplify.yml`, so injecting `AWS_COMMIT_ID` as a build id is straightforward here (`package.json` `version` is `0.0.0` and `vite.config.ts` has no `define` block, so the id must be created first). Mechanics and the scope limit — a buster runs inside the app and can never fix a browser-cached JS bundle — are written up in [supply's persisted query cache](../../toga25-supply/features/persisted-query-cache.md#the-buster-gap). Still **not implemented**.
|
|
136
132
|
- **`AuthLayout` never remounts**, so `refetchOnMount` fires once per session for queries it owns — a route-change refresh has to be wired explicitly. That interacts with everything above: a query can be both stale *and* never refetched during a session.
|
|
137
133
|
|
|
134
|
+
## Change history
|
|
135
|
+
- 2026-09-21 — Cause 3 (public-token auth gate) fixed on `TRUE-82172` and moved to its own doc; causes 1, 2, 4 still open. (tcox)
|
|
136
|
+
- 2026-09-03 — Four stacked causes pinned to `file:line`; `gcTime`-vs-`staleTime` decision recorded. (bala, apeterson)
|
|
137
|
+
|
|
138
138
|
## Related
|
|
139
139
|
|
|
140
140
|
- [inactive-item-purchase-gating](./inactive-item-purchase-gating.md)
|
|
141
|
+
- [sso-redirect-and-session-gating](./sso-redirect-and-session-gating.md)
|
|
141
142
|
- [architecture](../architecture.md)
|
|
142
143
|
- [supply persisted-query-cache](../../toga25-supply/features/persisted-query-cache.md)
|
|
143
144
|
- [supply force-logout-on-deployment](../../toga25-supply/features/force-logout-on-deployment.md)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: SSO redirect & public-vs-user session gating (useAuthenticationFlow)
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: toga2-commerce
|
|
5
|
+
project: TOGa Commerce
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-09-21
|
|
10
|
+
owners: [tcox]
|
|
11
|
+
files:
|
|
12
|
+
- toga2-commerce/src/hooks/useAuthenticationFlow.ts
|
|
13
|
+
- toga2-commerce/src/routes.tsx
|
|
14
|
+
- toga2-commerce/src/contexts/AuthContext.tsx
|
|
15
|
+
- toga2-commerce/src/api/axiosInstance.ts
|
|
16
|
+
related:
|
|
17
|
+
- ./catalog-cache-freshness.md
|
|
18
|
+
- ./view-as-session-tokens.md
|
|
19
|
+
- ../architecture.md
|
|
20
|
+
- ../../toga25-supply/features/sso-redirect-and-session-gating.md
|
|
21
|
+
- ../../../standards/frontend.md
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
How commerce decides on "/" whether a visitor is signed in, goes to SSO, or goes to /login; open for "blank page at /" or "SSO never fires" reports on any tenant.
|
|
25
|
+
|
|
26
|
+
## Summary
|
|
27
|
+
|
|
28
|
+
Three pieces decide it, and they must all read the same signal:
|
|
29
|
+
|
|
30
|
+
| Piece | File | Question it answers |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| axios request interceptor | `src/api/axiosInstance.ts:105-125` | Bearer a real token or a **public** one? |
|
|
33
|
+
| `useAuthenticationFlow` | `src/hooks/useAuthenticationFlow.ts:185-215` | Already signed in → do nothing; else SSO or `/login` |
|
|
34
|
+
| `AuthRedirect` (route `/`) | `src/routes.tsx` | Render `/home`, or a spinner while the flow runs |
|
|
35
|
+
|
|
36
|
+
**The only valid "is this visitor signed in?" test is a stored `user` JSON with a `uuid`** — never `localStorage.accessToken`. Shared code, so every tenant (compass, compasscanada, quad) behaves the same.
|
|
37
|
+
|
|
38
|
+
## How it works
|
|
39
|
+
|
|
40
|
+
1. **Logged-out requests mint a public token into `accessToken`.** `fetchPublicToken` (`axiosInstance.ts:52-64`) POSTs `/auth/public` and writes **both** `accessToken` and `refreshToken` to `localStorage`. The interceptor calls it whenever `localStorage.user` is absent — the SSO domain lookup on `/`, the login page's `/domains` and `/languages` calls, a failed SSO return. So a token in storage proves nothing.
|
|
41
|
+
2. **The flow gates on the user, parsed safely** (`useAuthenticationFlow.ts:193-204`):
|
|
42
|
+
```ts
|
|
43
|
+
const hasUserInStorage = (() => {
|
|
44
|
+
try {
|
|
45
|
+
const storedUser = localStorage.getItem("user");
|
|
46
|
+
return Boolean(storedUser && JSON.parse(storedUser)?.uuid);
|
|
47
|
+
} catch (error) { console.error("Could not read stored user:", error); return false; }
|
|
48
|
+
})();
|
|
49
|
+
if (isAuthenticated || hasUserInStorage) return;
|
|
50
|
+
```
|
|
51
|
+
Missing, invalid, or unparsable storage counts as logged out. Same test as `AuthProvider`'s initial `isAuthenticated` (`AuthContext.tsx:73-85`) and as toga25-supply.
|
|
52
|
+
3. **Otherwise it saves the post-auth redirect and runs `checkSsoAuth`** — a `singleSignOnServiceUrl` for the domain → `window.location` to the IdP; none → `/login`.
|
|
53
|
+
4. **`AuthRedirect` at `/` renders `<AuthLoading/>`, never `null`,** in the not-authenticated case. A `<Navigate to="/login"/>` there was **rejected**: it fires before the SSO lookup resolves and cancels the IdP redirect for a first-time visitor.
|
|
54
|
+
|
|
55
|
+
### Reproducing it without Cypress
|
|
56
|
+
|
|
57
|
+
- **Prod:** log in, then DevTools `localStorage.removeItem('user')`, load `/`.
|
|
58
|
+
- **Local:** `npm run compasscanada`; a temp page under `public/` sets `localStorage.accessToken='stale'`, removes `user`, `location.replace('/')`; dump with
|
|
59
|
+
`chrome.exe --headless=new --disable-extensions --user-data-dir=<temp> --virtual-time-budget=25000 --dump-dom <url>` and assert `input[name="userEmail"]` exists.
|
|
60
|
+
- Old code renders no login form (blank page); fixed code renders `/login`.
|
|
61
|
+
|
|
62
|
+
**Local and prod end differently for compasscanada — that is data, not a bug.** Beta has `Core.Domains` id 588 with **no** `ClientAuthentications` row, so the domains list is empty and the flow lands on `/login`; prod has `Core.Domains` id 600 → `ClientAuthentications` id 8 (type SSO, created 2026-04-06) and ends in an IdP redirect. Beta `/auth/public` also needs an allowed `Origin` header or it 401s `EN-6 "domain not permitted"` (`http://compasscanada.togacommerce:5173` is allowed).
|
|
63
|
+
|
|
64
|
+
## Gotchas
|
|
65
|
+
|
|
66
|
+
- **⚠ A token in `localStorage` is not a session.** Gating on `accessToken` made any visitor who had touched the API look authenticated → the flow skipped **both** the SSO redirect and `/login`, `AuthRedirect` returned `null`, and `/` was **permanently blank** until the user cleared site data. Per browser profile, so Chrome and Edge fail independently. It reads as an HTTP-caching bug and is not one — prod headers are correct (HTML `no-cache/no-store`, hashed immutable JS/CSS, missing chunk 404s, no service worker). Introduced 2026-02-12 by the `hasTokenInStorage` "Fix logout" change; fixed on `TRUE-82172`.
|
|
67
|
+
- **⚠ Don't `Navigate` to `/login` from `AuthRedirect`.** It races the SSO lookup and kills the IdP redirect for first-time visitors. Show the spinner.
|
|
68
|
+
- **⚠ Open: the cross-tab `storage` handler still gates on the token.** `AuthContext.tsx:254-262` does `setIsAuthenticated(Boolean(localStorage.getItem("accessToken")))`, so a logged-out tab minting a public token can flip another logged-out tab to "authenticated" → 401s. Derive it from `user` too. **Not fixed.**
|
|
69
|
+
- **⚠ Open: a malformed `user` crashes the whole tree.** `AuthProvider`'s initial state does `JSON.parse(localStorage.user)` in a `try`/**`finally` with no `catch`** (`AuthContext.tsx:73-85`). **Not fixed.**
|
|
70
|
+
- **A 403 on `GET /notifications` during the manual repro is expected** — after `user` is removed the interceptor swaps the still-mounted app onto a public token.
|
|
71
|
+
- **Cypress can't cover this on a broken binary cache.** A regression spec exists untracked at `cypress/e2e/AuthFlow/staleTokenRedirect.cy.ts` (stubs `**/auth/public` + `**/domains?*`, asserts `/login`). Local Cypress 15.19.0 fails with `bad option: --smoke-test` → `npx cypress install --force`. Machine-local, not a repo problem.
|
|
72
|
+
|
|
73
|
+
## Change history
|
|
74
|
+
- 2026-09-21 — Blank page at `/` fixed: gate on stored `user.uuid`, `AuthRedirect` renders the spinner instead of `null`. Branch `TRUE-82172` (`1eebdd96`, `3dc53d9a`), **not merged or deployed**. (tcox)
|
package/knowledge/INDEX.md
CHANGED
|
@@ -5,7 +5,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
5
5
|
## 1.0 framework
|
|
6
6
|
|
|
7
7
|
- **library** (Library) _(framework core)_ — 26 doc(s) → [1.0/apps/library/INDEX.md](1.0/apps/library/INDEX.md)
|
|
8
|
-
- **worker** (Worker) —
|
|
8
|
+
- **worker** (Worker) — 37 doc(s) → [1.0/apps/worker/INDEX.md](1.0/apps/worker/INDEX.md)
|
|
9
9
|
- **dbchanges** (Database Changes) _(framework core)_ — 1 doc(s) → [1.0/apps/dbchanges/INDEX.md](1.0/apps/dbchanges/INDEX.md)
|
|
10
10
|
- **worker1.5** (Worker 1.5) — 0 doc(s) → [1.0/apps/worker1.5/INDEX.md](1.0/apps/worker1.5/INDEX.md)
|
|
11
11
|
- **togadesk** (TOGa Desk) — 13 doc(s) → [1.0/apps/togadesk/INDEX.md](1.0/apps/togadesk/INDEX.md)
|
|
@@ -31,7 +31,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
31
31
|
- **talos-backend** (TOGa IQ Backend) — 1 doc(s) → [2.0/apps/talos-backend/INDEX.md](2.0/apps/talos-backend/INDEX.md)
|
|
32
32
|
- **voice-to-voice** (TOGa Voice) — 4 doc(s) → [2.0/apps/voice-to-voice/INDEX.md](2.0/apps/voice-to-voice/INDEX.md)
|
|
33
33
|
- **ai-bdr** (AI-BDR) — 13 doc(s) → [2.0/apps/ai-bdr/INDEX.md](2.0/apps/ai-bdr/INDEX.md)
|
|
34
|
-
- **toga2-commerce** (TOGa Commerce) —
|
|
34
|
+
- **toga2-commerce** (TOGa Commerce) — 25 doc(s) → [2.0/apps/toga2-commerce/INDEX.md](2.0/apps/toga2-commerce/INDEX.md)
|
|
35
35
|
- **toga25-supply** (TOGa 2.5 Supply) — 21 doc(s) → [2.0/apps/toga25-supply/INDEX.md](2.0/apps/toga25-supply/INDEX.md)
|
|
36
36
|
- **toga-blox** (TOGa Blox) — 14 doc(s) → [2.0/apps/toga-blox/INDEX.md](2.0/apps/toga-blox/INDEX.md)
|
|
37
37
|
- **bdr** (BDR) — 0 doc(s) → [2.0/apps/bdr/INDEX.md](2.0/apps/bdr/INDEX.md)
|
|
@@ -17,7 +17,7 @@ project: _Underscore
|
|
|
17
17
|
client: compass-canada
|
|
18
18
|
type: profile
|
|
19
19
|
status: active
|
|
20
|
-
updated: 2026-09-
|
|
20
|
+
updated: 2026-09-21
|
|
21
21
|
owners: [jcardinal, bala, tcox, apeterson, ajean]
|
|
22
22
|
files: []
|
|
23
23
|
related:
|
|
@@ -35,6 +35,7 @@ related:
|
|
|
35
35
|
- features/order-fulfillment-status-per-line.md
|
|
36
36
|
- features/item-fulfillment-tableviews.md
|
|
37
37
|
- ../../2.0/apps/toga2-commerce/features/expedited-shipping-gating.md
|
|
38
|
+
- ../../2.0/apps/toga2-commerce/features/sso-redirect-and-session-gating.md
|
|
38
39
|
- ../../2.0/apps/_underscore/features/item-fulfillment-stage-lifecycle-and-order-status.md
|
|
39
40
|
- ../../2.0/apps/_underscore/features/surface-resolver.md
|
|
40
41
|
---
|
|
@@ -117,6 +118,15 @@ to but distinct from Compass USA. Like Compass USA it spans the **2.0** commerce
|
|
|
117
118
|
instead of **12 / 8 / 33**. Removing the hack gives them *more* access; whether Canada should get
|
|
118
119
|
it is an **open decision**. See
|
|
119
120
|
[Storefront persona gating](../../2.0/apps/toga2-commerce/features/storefront-persona-gating-and-home-counts.md).
|
|
121
|
+
- **⚠ "Blank page at `https://compasscanada.togacommerce.com/`" (reported by Compass Canada IT,
|
|
122
|
+
Sept 2026) is a shared auth-gating bug, not a Canada or caching problem.** A stale **public**
|
|
123
|
+
`accessToken` made the app think the visitor was signed in, so `/` rendered nothing until the
|
|
124
|
+
user cleared site data. Canada was hit hardest because the "Tech Hub is now available in Canada"
|
|
125
|
+
memo points everyone at `/`, and anyone who visited before the Canada SSO row existed
|
|
126
|
+
(`ClientAuthentications` id 8, created 2026-04-06) or landed on `/login` once already carried that
|
|
127
|
+
token. Same code path on Compass USA and Quad. Fixed on `TRUE-82172` (TRUE-82172 branch off
|
|
128
|
+
`_production`) — **not merged or deployed**. See
|
|
129
|
+
[SSO redirect & session gating](../../2.0/apps/toga2-commerce/features/sso-redirect-and-session-gating.md).
|
|
120
130
|
- **No persona switcher here** (that is Quad-only), but Canada **is** the tenant with
|
|
121
131
|
`languageSwitcher.isEnabled = true` (`fieldsConfig/clientFields/COMPASSCANADA.json`).
|
|
122
132
|
|
|
@@ -9,7 +9,7 @@ apps:
|
|
|
9
9
|
client: walmart
|
|
10
10
|
type: client-feature
|
|
11
11
|
status: active
|
|
12
|
-
updated: 2026-09-
|
|
12
|
+
updated: 2026-09-21
|
|
13
13
|
owners: ["mhammontree"]
|
|
14
14
|
files:
|
|
15
15
|
- library/app/client/walmart.php
|
|
@@ -19,6 +19,7 @@ related:
|
|
|
19
19
|
- clients/walmart/features/domain-migration.md
|
|
20
20
|
- clients/walmart/features/registration-route.md
|
|
21
21
|
- clients/walmart/features/customer-email-lifecycle.md
|
|
22
|
+
- 1.0/apps/worker/features/walmart-daily-sales-report.md
|
|
22
23
|
---
|
|
23
24
|
|
|
24
25
|
Walmart B2C tech-services tenant (client id 7); open for its identifiers, key files, and the `requireRegistrationUrl` DB rule.
|
package/package.json
CHANGED