19903f89e5
## Context Incoming Microsoft messaging, Microsoft calendar, and Google calendar webhook notifications resolve their channel through `webhookSubscriptionExternalId`. The column was added without an index, so PostgreSQL has to scan the corresponding channel table for every notification. Under sustained webhook traffic, these repeated scans add unnecessary database work and keep core database connections occupied longer. ## What changed - Add a partial B-tree index on `messageChannel.webhookSubscriptionExternalId` - Add the equivalent index on `calendarChannel.webhookSubscriptionExternalId` - Register both indexes in the TypeORM entity metadata - Add an idempotent 2.25 fast instance upgrade command to create and remove them The webhook handlers and their queries remain unchanged. ## Why this design - The indexes contain only non-null subscription IDs, channels without an active subscription do not add index entries - A single-column index supports both the equality lookup used by Google and the `IN` lookup used by Microsoft - The indexes are intentionally non-unique, this preserves existing behavior and avoids making the upgrade fail if historical duplicate values exist - Subscription IDs are read much more often than they are updated, so index maintenance overhead should be negligible ## Expected impact Webhook channel resolution should require a targeted index lookup instead of a table scan. This reduces database work, shortens connection occupancy, and improves latency on webhook notification paths. This is a targeted database optimization. It complements the database pool changes, but is not expected to resolve every source of API tail latency by itself. ## Validation - Server typecheck passes - Oxlint and formatting checks pass - Upgrade command uses idempotent `CREATE INDEX IF NOT EXISTS` and `DROP INDEX IF EXISTS` statements <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/23386?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->