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:
2026-06-01 22:27:07 +08:00
parent 6e87e9b6da
commit 495eb98787
2 changed files with 32 additions and 1 deletions

View File

@@ -226,12 +226,19 @@ const migrate = async () => {
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
customer_id UUID NOT NULL REFERENCES customers(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,
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`
CREATE INDEX IF NOT EXISTS idx_customer_transactions_customer_id
ON customer_transactions (customer_id)