Escrow (src/common/entities/escrow.entity.ts) has no @Index on status, yet SponsorsService.budgetLocked (src/sponsors/sponsors.service.ts) runs WHERE escrow.sponsorId = :sponsorId AND escrow.status = :status on every sponsor dashboard load, and EscrowService's internal lookups filter by status implicitly via assertLocked after fetching by id. As the escrows table grows, budgetLocked's query — which has no sponsorId index either, compounding the problem — degrades from an index scan to a much more expensive plan.
This is a narrower, more specific gap than #13's general call for composite indexes on "webhook issue lookup, bounty status filtering, payment aggregation" — it names the exact table/columns and the exact two call sites (SponsorsService.budgetLocked's sponsorId+status filter, and any future status-scoped escrow listing) that #13 doesn't explicitly enumerate.
Fix: add a composite index on escrows(sponsorId, status) to directly serve budgetLocked's query pattern.
Escrow(src/common/entities/escrow.entity.ts) has no@Indexonstatus, yetSponsorsService.budgetLocked(src/sponsors/sponsors.service.ts) runsWHERE escrow.sponsorId = :sponsorId AND escrow.status = :statuson every sponsor dashboard load, andEscrowService's internal lookups filter by status implicitly viaassertLockedafter fetching by id. As theescrowstable grows,budgetLocked's query — which has nosponsorIdindex either, compounding the problem — degrades from an index scan to a much more expensive plan.This is a narrower, more specific gap than #13's general call for composite indexes on "webhook issue lookup, bounty status filtering, payment aggregation" — it names the exact table/columns and the exact two call sites (
SponsorsService.budgetLocked'ssponsorId+statusfilter, and any future status-scoped escrow listing) that #13 doesn't explicitly enumerate.Fix: add a composite index on
escrows(sponsorId, status)to directly servebudgetLocked's query pattern.