fix(db): widen customer_transactions.type to VARCHAR(128)
TransactionType.FIRST_SESSION_DISCOUNT ('first_session_discount', 22 chars) overflowed the VARCHAR(20) column, throwing in acceptPairingRequest AFTER the session was flipped to ACTIVE but before startSessionTimer/startSessionListener/PAIRED-notify ran. Every first-session-discount pairing thus half-completed: lost transaction row, no server-side timer, and a 500 to the mitra so its app never opened the chat. Widen the column (CREATE TABLE + idempotent ALTER). Deferred hardening (bookkeeping INSERT in the critical path) logged in TECH_DEBT.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
24
TECH_DEBT.md
24
TECH_DEBT.md
@@ -10,6 +10,30 @@ to act on it without re-deriving the discussion.
|
|||||||
|
|
||||||
## Backend
|
## Backend
|
||||||
|
|
||||||
|
### `[2026-06-01]` Bookkeeping INSERT sits in the pairing critical path
|
||||||
|
|
||||||
|
**File:** `backend/src/services/pairing.service.js` (`acceptPairingRequest`, ~line 506)
|
||||||
|
|
||||||
|
**What happened:** the `INSERT INTO customer_transactions` runs *after* the session
|
||||||
|
is flipped to `ACTIVE` but *before* `startSessionTimer`, `startSessionListener`,
|
||||||
|
the customer `PAIRED` WS notify, and the other-mitra dismiss fan-out. A
|
||||||
|
`varchar(20)` overflow on `type = 'first_session_discount'` (22 chars) threw
|
||||||
|
there, so every first-session-discount pairing half-completed: no transaction
|
||||||
|
row, no server-side timer, no PAIRED push (customer recovered via polling), and a
|
||||||
|
500 returned to the mitra so its app never opened the chat.
|
||||||
|
|
||||||
|
**Fixed now:** column widened to `VARCHAR(128)` (migrate.js), so the INSERT no
|
||||||
|
longer throws.
|
||||||
|
|
||||||
|
**Why it's still debt:** a *bookkeeping* write can still abort *critical* pairing
|
||||||
|
steps if it ever fails again (constraint change, DB hiccup, future longer enum).
|
||||||
|
Hardening: either move the `customer_transactions` INSERT to the end of
|
||||||
|
`acceptPairingRequest`, or wrap it in a `try/catch` that logs-but-doesn't-throw,
|
||||||
|
so transaction recording can never again half-complete a pairing. Same applies to
|
||||||
|
the equivalent INSERT in `extension.service.js`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `[2026-05-11]` Public `GET /api/public/bestie/available` needs rate limiting before prod
|
### `[2026-05-11]` Public `GET /api/public/bestie/available` needs rate limiting before prod
|
||||||
|
|
||||||
**File:** `backend/src/routes/public/public.bestie-availability.routes.js`
|
**File:** `backend/src/routes/public/public.bestie-availability.routes.js`
|
||||||
|
|||||||
@@ -226,12 +226,19 @@ const migrate = async () => {
|
|||||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
customer_id UUID NOT NULL REFERENCES customers(id),
|
customer_id UUID NOT NULL REFERENCES customers(id),
|
||||||
session_id UUID NOT NULL REFERENCES chat_sessions(id),
|
session_id UUID NOT NULL REFERENCES chat_sessions(id),
|
||||||
type VARCHAR(20) NOT NULL,
|
type VARCHAR(128) NOT NULL,
|
||||||
amount INT NOT NULL DEFAULT 0,
|
amount INT NOT NULL DEFAULT 0,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
)
|
)
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// Idempotent widen for DBs created when this column was VARCHAR(20): the
|
||||||
|
// TransactionType.FIRST_SESSION_DISCOUNT value 'first_session_discount' is
|
||||||
|
// 22 chars and overflowed varchar(20), throwing in acceptPairingRequest()
|
||||||
|
// *after* the session was already marked ACTIVE — losing the transaction row,
|
||||||
|
// the server-side timer, the PAIRED WS notify, and returning 500 to the mitra.
|
||||||
|
await sql`ALTER TABLE customer_transactions ALTER COLUMN type TYPE VARCHAR(128)`
|
||||||
|
|
||||||
await sql`
|
await sql`
|
||||||
CREATE INDEX IF NOT EXISTS idx_customer_transactions_customer_id
|
CREATE INDEX IF NOT EXISTS idx_customer_transactions_customer_id
|
||||||
ON customer_transactions (customer_id)
|
ON customer_transactions (customer_id)
|
||||||
|
|||||||
Reference in New Issue
Block a user