ธีม
Session notes — claude-2026-09-22
One person's notes, never rewritten by anyone else. docs/state/HANDOFF.md §18b/§18c holds what is NOT done, and STATE.md holds what is true now. This file is WHY each thing was done, and exactly how it was checked.
▶ HANDOFF — a slip bug, then a full SAMO Shop sweep, a second pass, and a gallery design
A student reported "อัปโหลดสลิป กดยืนยันแล้ว แต่ขึ้นว่า สั่งซื้อไม่สำเร็จ: [object ProgressEvent]". It became three things:
- the bug;
- a sweep for the same bug shape across every file picker;
- at the owner's request, a thorough bug hunt of the whole shop.
It ended with the product gallery BUILT, reviewed and fixed. Migrations 0202, 0203 and 0204 are applied to samo-dev first, then production. The deploys are all <== exit 0 — ran to the end; the sha's only home is the ✅ DEPLOYED line in STATE.md.
Read these before touching the same code
| If you touch… | Read first |
|---|---|
any picked File that is uploaded later | src/js/read-file.js header + docs/mistakes/frontend-ui.md ("[object ProgressEvent]") |
checkout, placeOrder, place_shop_order | §2 below + docs/mistakes/frontend-ui.md ("could place the order twice", "a recovery path placed AFTER the check") |
safeUrl or any URL into innerHTML | docs/mistakes/frontend-ui.md ("safeUrl said pair with escHtml()") |
| shop admin editors / order modal | docs/mistakes/app-state.md ("a save that awaits, then reads the current thing") |
| the buyer's own-order write path | docs/mistakes/authz-rls.md ("the column guard allowed the columns, not the values") |
| product pictures | docs/SHOP-GALLERY.md (built — its header says where each piece lives) + src/js/shop/pictures-readers.test.js |
1. [object ProgressEvent] — the slip bug
- Cause. A picked
Fileis a handle. The checkout read it for the preview at pick time, then again at submit. Phones revoke the handle in between (typically while the buyer is in the bank app), andr.onerror = rejectprinted the raw event. - Reproduced in headless Chrome by changing the file on disk after the preview read. That gave the exact string, with
NotReadableErrorunderneath. - Fixed with
holdInMemory(copy the bytes at pick time) and one sharedreadAsDataURLthat always rejects with Thai. - The sweep found six modules that parked a pick and read it later. All six now hold the bytes at pick.
read-file.test.jskeeps a registry of every module with a.filesreference, so a new one is red until someone classifies it.
2. The shop sweep — how it was run and checked
- Four areas: storefront + checkout, orders / API / uploads / QR, the admin panel (three reviewers, read-only), and the database (me: live policies and
pg_get_functiondefbodies). - About 40 findings, every one re-traced before it was fixed. A few PLAUSIBLE ones were fixed defensively and never reproduced; HANDOFF §18b names them.
- Database checks:
shop0202-stock-ruleis 22/22 on dev and production. All 14 of its refusals are red on the pre-0202 bodies. That ritual caught one case that was green for the wrong reason (tooling-proofs.md). - Client checks: every new guard test was mutation-checked. After the deploy, a headless load of
/#shopshowed that the LOADEDcore-*chunk carries the new strings, with no console errors. - Not checked: the checkout and admin flows were NOT clicked signed in. The first real order is the first real check.
3. The second pass
A fresh reviewer read the whole day's diff cold while I re-checked my own suspects. The one real new bug was the retry lookup, which sat after the stock check its own lost order trips. The rest were small; HANDOFF §18b lists them.
4. Product gallery — designed, then BUILT the same day
docs/SHOP-GALLERY.md. It rests on facts measured that day:
- 1 product, 1 picture;
- the stored master is 1200 px, so
=w2400and=s0return the same bytes, and zoom needs larger masters; - every picture reader is in
src/js/shop/.
The build order and the three owner defaults are in §9 and §10.
Open, owner-only
The shop's Apps Script upload limits need a production GAS redeploy (HANDOFF §18b, kept vague on purpose because docs/ is public).
5. Gallery build — how it was checked
0203 (
images+ a trigger-derived cover + a shape check): 16/16 at the time; 20/20 after 0204 and the RLS allow case (§6). On dev and production. It errors before the migration, as documented. The stale-tab branch is asserted.Headless Chrome against
npm run devat 390 px and 1280 px:- the pictures load, the colour jump and swipe tracking work;
- the viewer opens inside the modal;
- Esc and back close only the viewer;
- no console errors.
It first found every picture broken on localhost, from lh3's Referer check (frontend-ui.md), so pictures are now fetched with no referrer.
Production, through an ssh tunnel, because KKU-internal access to the public address broke mid-session (HANDOFF §18c): the real product in the gallery, and the lightbox.
Not driven: the admin picture strip, signed in.→ DONE in §6 (tools/browser/shop-admin-strip.mjs).The third-pass shop bug scan was started and stopped when the owner asked for the gallery. Its plan (a JS↔SQL differential of
cartLineProblemsagainstplace_shop_order) is not done.
6. Final pass — bug scan, the admin strip signed in, docs
- A second cold reviewer read the gallery commit; the admin strip had NO CSS on
/admin/. Every finding and its fix is in thedocs/SHOP-GALLERY.mdheader. - 0204 fixes the stale-tab trigger. Its two new proof rows are red on the 0203 body and green after.
shop0203-gallerygained the RLS ALLOW beside the anon DENY: a real shop admin, asauthenticated, changes the same row. Now 20/20 on dev and production.- The admin strip was driven signed in:
tools/browser/shop-admin-strip.mjsruns the whole cycle with Apps Script intercepted, then cleans samo-dev back to 0. How-to:skills/drive-the-browser.md§11. - Apps Script: the live endpoint runs the repo's code (verified with
deploy:gas --verify). No.gschanged today. docs/CONTEXT.md: the shop section gainedimagesand 0202/0204. It had a STALE claim that buyers may INSERT orders (0199 removed that), now corrected.README.md"Key features" has the gallery.