docs: sync from backend 2c5e80d — db audit waves 5-6
This commit is contained in:
@@ -11,6 +11,16 @@ entries on top. Maintained by agents per the rule in `../AGENTS.md`.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### 2026-06-07 — backend@2c5e80d, frontend@1f8fdc9 — DB audit Waves 5-6 chat create and points transaction enforcement
|
||||||
|
|
||||||
|
**Commits:** `2c5e80d` `1f8fdc9`
|
||||||
|
**Touched:** backend `src/db/repositories/drizzle/DrizzleChatRepo.ts`, `src/db/repositories/drizzle/DrizzleUserRepo.ts`, `src/db/repositories/drizzle/DrizzlePaymentRepo.ts`, `__tests__/drizzle-chat-repo.test.ts`, `__tests__/drizzle-user-repo.test.ts`, `package.json`, `package-lock.json`; frontend `package.json`; docs `09 - Audits/DB Query & Schema Audit - 2026-06-06.md`, `09 - Audits/Activity Log.md`
|
||||||
|
**Why:** Continue the 8-wave Critical/High plan after pulling Mojtaba's Forgejo changes (`backend@6e097c5`, `frontend@bcf9f03`). Wave 5 closes H13 by inserting the chat welcome message atomically with the chat row; Wave 6 closes H25 by refusing point balance/ledger writes on an unbound repo. The backend commit also keeps the pulled PaymentRepo user-id batch resolver null-safe for typecheck.
|
||||||
|
**Verification:** backend `npm test -- --runTestsByPath __tests__/drizzle-chat-repo.test.ts __tests__/drizzle-user-repo.test.ts --runInBand`, `npm test -- --runTestsByPath __tests__/drizzle-payment-repo-export.test.ts __tests__/drizzle-chat-repo.test.ts __tests__/drizzle-user-repo.test.ts --runInBand`, `BASE_URL=http://127.0.0.1:5001 scripts/smoke/db-audit-service-regressions.sh` (14 suites / 43 tests), `npm run typecheck`, `git diff --check`; frontend `git diff --check` for package bump. Pushed to Forgejo; direct `dev` SSH remote timed out and `origin` remained intentionally skipped.
|
||||||
|
**Linked docs updated:** [[09 - Audits/DB Query & Schema Audit - 2026-06-06]]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### 2026-06-06 — backend@f22794a/51ca048, frontend@4a86dc7 — DB audit Wave 4 delivery-code atomicity
|
### 2026-06-06 — backend@f22794a/51ca048, frontend@4a86dc7 — DB audit Wave 4 delivery-code atomicity
|
||||||
|
|
||||||
**Commits:** `f22794a` `51ca048` `4a86dc7`
|
**Commits:** `f22794a` `51ca048` `4a86dc7`
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ updated: 2026-06-06
|
|||||||
| H12: `updateReferralStats` count/update outside a transaction → serializable row-lock transaction | `885745e` v2.9.20 |
|
| H12: `updateReferralStats` count/update outside a transaction → serializable row-lock transaction | `885745e` v2.9.20 |
|
||||||
| H26: `processReferralReward` independent points + referralStats writes → one idempotent `grantReferralReward` transaction for points, referralStats, and ledger row | `885745e` v2.9.20 |
|
| H26: `processReferralReward` independent points + referralStats writes → one idempotent `grantReferralReward` transaction for points, referralStats, and ledger row | `885745e` v2.9.20 |
|
||||||
| H24: `verifyAndMarkDeliveryCodeUsed` read-check-then-write race → one conditional `UPDATE ... RETURNING` decides delivery-code consumption, with post-miss read only for failure reason | `f22794a` / `51ca048` v2.9.21 |
|
| H24: `verifyAndMarkDeliveryCodeUsed` read-check-then-write race → one conditional `UPDATE ... RETURNING` decides delivery-code consumption, with post-miss read only for failure reason | `f22794a` / `51ca048` v2.9.21 |
|
||||||
|
| H13: `DrizzleChatRepo.create` insert-then-update welcome message → build initial system message, lastMessage, and unread counts in the INSERT payload | `2c5e80d` v2.9.24 |
|
||||||
|
| H25: `updatePoints` + `createPointTransaction` could run outside one transaction → runtime guard requires a transaction-bound repo or explicit tx for both money writes | `2c5e80d` v2.9.24 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -609,7 +611,7 @@ The method reads the current row (line 558), performs an atomic CAS UPDATE with
|
|||||||
|
|
||||||
### 3. findPaymentById issues two separate SELECT queries for buyer and seller instead of a JOIN
|
### 3. findPaymentById issues two separate SELECT queries for buyer and seller instead of a JOIN
|
||||||
|
|
||||||
> **Category:** N+1 Query | **File:** `src/db/repositories/drizzle/DrizzleMarketplaceRepo.ts:490-533`
|
> **Category:** N+1 Query | **File:** `src/db/repositories/drizzle/DrizzleMarketplaceRepo.ts:490-533` | **FIXED** `61aa42a` v2.9.20
|
||||||
|
|
||||||
`findPaymentById` does SELECT * FROM payments WHERE id = $1, then conditionally fires one SELECT for the buyer and one for the seller. This is 3 sequential queries per call. Since `findAllPayments` calls this once per row, the cost multiplies to 1 + 2N.
|
`findPaymentById` does SELECT * FROM payments WHERE id = $1, then conditionally fires one SELECT for the buyer and one for the seller. This is 3 sequential queries per call. Since `findAllPayments` calls this once per row, the cost multiplies to 1 + 2N.
|
||||||
|
|
||||||
@@ -679,7 +681,7 @@ The method calls `this.findRows({...})` (full table scan), deserialises every ch
|
|||||||
|
|
||||||
### 10. ChatService.addParticipant fires N individual userRepo.findById queries for participant validation
|
### 10. ChatService.addParticipant fires N individual userRepo.findById queries for participant validation
|
||||||
|
|
||||||
> **Category:** N+1 Query | **File:** `src/services/chat/ChatService.ts:782-788`
|
> **Category:** N+1 Query | **File:** `src/services/chat/ChatService.ts:782-788` | **FIXED**
|
||||||
|
|
||||||
`Promise.all(participantIds.map((id) => userRepo.findById(id)))` fires one SELECT per participant concurrently. While Promise.all avoids sequential waits, it still sends N separate queries to the database, opening N statements from the pool.
|
`Promise.all(participantIds.map((id) => userRepo.findById(id)))` fires one SELECT per participant concurrently. While Promise.all avoids sequential waits, it still sends N separate queries to the database, opening N statements from the pool.
|
||||||
|
|
||||||
@@ -689,7 +691,7 @@ The method calls `this.findRows({...})` (full table scan), deserialises every ch
|
|||||||
|
|
||||||
### 11. resolveUserUuid issues a separate DB round-trip per legacy ObjectId in payment create and filter paths
|
### 11. resolveUserUuid issues a separate DB round-trip per legacy ObjectId in payment create and filter paths
|
||||||
|
|
||||||
> **Category:** N+1 Query | **File:** `src/db/repositories/drizzle/DrizzlePaymentRepo.ts:88-100, 116-129, 786-793`
|
> **Category:** N+1 Query | **File:** `src/db/repositories/drizzle/DrizzlePaymentRepo.ts:88-100, 116-129, 786-793` | **FIXED**
|
||||||
|
|
||||||
`resolveUserUuid()` executes one SELECT per legacy ObjectId. `create()` calls it twice (buyer + seller). `normalizeUserFilter` calls it sequentially for buyerId then sellerId. No batching or caching: creating multiple payments in a loop issues at least two extra round-trips per iteration.
|
`resolveUserUuid()` executes one SELECT per legacy ObjectId. `create()` calls it twice (buyer + seller). `normalizeUserFilter` calls it sequentially for buyerId then sellerId. No batching or caching: creating multiple payments in a loop issues at least two extra round-trips per iteration.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user