diff --git a/09 - Audits/Activity Log.md b/09 - Audits/Activity Log.md index 29915b3..cc11958 100644 --- a/09 - Audits/Activity Log.md +++ b/09 - Audits/Activity Log.md @@ -12,6 +12,16 @@ entries on top. Maintained by agents per the rule in `../AGENTS.md`. --- +### 2026-06-07 — backend@259f3fb, frontend@d9a59bd — DB audit H19-H21 auth save consolidation + +**Commits:** `259f3fb` `d9a59bd` +**Touched:** backend `src/services/auth/authController.ts`, `__tests__/db-audit-auth-controller-saves.test.ts`, `scripts/smoke/db-audit-service-regressions.sh`, `package.json`, `package-lock.json`; frontend `Dockerfile`, `package.json`; docs `09 - Audits/DB Query & Schema Audit - 2026-06-06.md`, `09 - Audits/Activity Log.md` +**Why:** Close High H19-H21 from the DB Query & Schema Audit. Login, Google sign-in, and Telegram auth now use the token helper without immediate persistence, stage audited mutations, and perform one final user save through the transactional save path. Telegram Mini App retry behavior remains preserved with no replay/dedup rejection added. +**Verification:** backend `npm test -- --runTestsByPath __tests__/db-audit-auth-controller-saves.test.ts __tests__/auth-store-pg-query.test.ts --runInBand` (2 suites / 18 tests), `npm run typecheck`, `scripts/smoke/db-audit-service-regressions.sh` (19 suites / 77 tests), backend/frontend scoped `git diff --check`; frontend/backend version metadata confirmed at v2.9.37. Pushed to Forgejo. +**Linked docs updated:** [[09 - Audits/DB Query & Schema Audit - 2026-06-06]] + +--- + ### 2026-06-07 — backend@5d7d2af, frontend@ade7352 — DB audit H10 sweep balance probe parallelism **Commits:** `5d7d2af` `ade7352` diff --git a/09 - Audits/DB Query & Schema Audit - 2026-06-06.md b/09 - Audits/DB Query & Schema Audit - 2026-06-06.md index 6979292..9fa44f9 100644 --- a/09 - Audits/DB Query & Schema Audit - 2026-06-06.md +++ b/09 - Audits/DB Query & Schema Audit - 2026-06-06.md @@ -86,6 +86,7 @@ updated: 2026-06-07 | M17: profile email verification pending-email race → single conditional SQL `UPDATE` with conflict outcome handling | `c3ad979` v2.9.34 | | C2/M26: `DrizzleChatRepo.findRows` unbounded chat fetch + JS pagination → bounded row scans, SQL pagination for SQL-pushable predicates, `findOne` `LIMIT 1`/id fast path, type pushdown, and archived-chat index | `8835068` v2.9.35 | | H10: `sweepDerivedDestinations` sequential token-balance RPC probes → bounded parallel balance probe phase before sequential sweep/broadcast handling | `5d7d2af` v2.9.36 | +| H19-H21: login, Google sign-in, and Telegram auth duplicate user saves → token helper save bypass plus one final user persistence after audited mutations | `259f3fb` v2.9.37 | --- @@ -365,33 +366,33 @@ Registration completes in separate writes: (1) `referrer.save()` increments refe --- -### 19. login calls user.save() twice in the same request path without a transaction +### 19. login calls user.save() twice in the same request path without a transaction | **FIXED** `259f3fb` v2.9.37 > **Category:** Missing Transaction | **File:** `src/services/auth/authController.ts:405-426` The login handler calls `user.save()` twice: once for `lastLoginAt` (line 407) and again after appending the refresh token (line 425). Each `save()` triggers the full `savePgUser` UPSERT + token-DELETE-INSERT + passkey-DELETE-INSERT sequence. No transaction spans both writes; a crash between them can leave an inconsistent token state. -**Fix:** Mutate all fields (`lastLoginAt`, `refreshTokens`) before calling `user.save()` once, wrapped in the transaction described in the savePgUser finding. +**Fix:** Implemented in `259f3fb`: `issueTokensForUser` now accepts `{ save: false }` so login mutates `lastLoginAt` and `refreshTokens` first, then calls `user.save()` once through the transactional save path before setting the cookie/response. --- -### 20. Google sign-in calls user.save() twice in the same request without a transaction +### 20. Google sign-in calls user.save() twice in the same request without a transaction | **FIXED** `259f3fb` v2.9.37 > **Category:** Missing Transaction | **File:** `src/services/auth/authController.ts:1381-1416` `googleSignIn` calls `existingUser.save()` at line 1398 (profile/lastLoginAt update), then again at line 1416 after pushing the refresh token. Two separate `savePgUser` executions each with their own DELETE+INSERT loops, without a shared transaction. -**Fix:** Consolidate all mutations and call `save()` once, wrapped in a transaction. +**Fix:** Implemented in `259f3fb`: profile/email-verification cleanup, `lastLoginAt`, and refresh-token mutation are staged together, then `existingUser.save()` runs once through the transactional save path. --- -### 21. Telegram auth performs up to 4 separate user.save() calls without a transaction +### 21. Telegram auth performs up to 4 separate user.save() calls without a transaction | **FIXED** `259f3fb` v2.9.37 > **Category:** Missing Transaction | **File:** `src/services/auth/authController.ts:459-613` `telegramAuth` can call `user.save()` for a new user (line 533), `user.save()` inside `issueTokensForUser` (line 148), and a try-catch save for mutations (line 558). Each invokes the full `savePgUser` path. With no transaction, a failure between any two leaves the DB inconsistent. -**Fix:** Merge all mutations and issue a single `save()` inside a transaction before responding. +**Fix:** Implemented in `259f3fb`: new-user creation, `telegramVerified`, lazy referral-code backfill, `lastLoginAt`, and refresh-token mutation are staged before one `user.save()`; Mini App retry behavior remains unchanged, with no replay/dedup rejection added to the Telegram login path. ---