perf: gateway + DB + frontend optimizations (P8-003)

- DB client: configure connection pool (max=20, idle_timeout=30s, connect_timeout=5s)
- DB schema: add missing indexes for auth sessions, accounts, conversations, agent_logs
- DB schema: promote preferences(user_id,key) to UNIQUE index for ON CONFLICT upsert
- Drizzle migration: 0003_p8003_perf_indexes.sql
- preferences.service: replace 2-query SELECT+INSERT/UPDATE with single-round-trip upsert
- conversations repo: add ORDER BY + LIMIT to findAll (200) and findMessages (500)
- session-gc.service: make onModuleInit fire-and-forget (removes cold-start TTFB block)
- next.config.ts: enable compress, productionBrowserSourceMaps:false, image avif/webp
- docs/PERFORMANCE.md: full profiling report and change impact notes
This commit is contained in:
2026-03-18 21:26:45 -05:00
parent cbfd6fb996
commit 3b81bc9f3d
11 changed files with 2823 additions and 88 deletions

View File

@@ -33,36 +33,54 @@ export const users = pgTable('users', {
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
});
export const sessions = pgTable('sessions', {
id: text('id').primaryKey(),
expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
token: text('token').notNull().unique(),
ipAddress: text('ip_address'),
userAgent: text('user_agent'),
userId: text('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
});
export const sessions = pgTable(
'sessions',
{
id: text('id').primaryKey(),
expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
token: text('token').notNull().unique(),
ipAddress: text('ip_address'),
userAgent: text('user_agent'),
userId: text('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
},
(t) => [
// Auth hot path: look up all sessions for a user (BetterAuth session list).
index('sessions_user_id_idx').on(t.userId),
// Session expiry cleanup queries.
index('sessions_expires_at_idx').on(t.expiresAt),
],
);
export const accounts = pgTable('accounts', {
id: text('id').primaryKey(),
accountId: text('account_id').notNull(),
providerId: text('provider_id').notNull(),
userId: text('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
accessToken: text('access_token'),
refreshToken: text('refresh_token'),
idToken: text('id_token'),
accessTokenExpiresAt: timestamp('access_token_expires_at', { withTimezone: true }),
refreshTokenExpiresAt: timestamp('refresh_token_expires_at', { withTimezone: true }),
scope: text('scope'),
password: text('password'),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
});
export const accounts = pgTable(
'accounts',
{
id: text('id').primaryKey(),
accountId: text('account_id').notNull(),
providerId: text('provider_id').notNull(),
userId: text('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
accessToken: text('access_token'),
refreshToken: text('refresh_token'),
idToken: text('id_token'),
accessTokenExpiresAt: timestamp('access_token_expires_at', { withTimezone: true }),
refreshTokenExpiresAt: timestamp('refresh_token_expires_at', { withTimezone: true }),
scope: text('scope'),
password: text('password'),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
},
(t) => [
// BetterAuth looks up accounts by (provider_id, account_id) on OAuth callback.
index('accounts_provider_account_idx').on(t.providerId, t.accountId),
// Also used in session validation to find linked accounts for a user.
index('accounts_user_id_idx').on(t.userId),
],
);
export const verifications = pgTable('verifications', {
id: text('id').primaryKey(),
@@ -306,10 +324,10 @@ export const conversations = pgTable(
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
},
(t) => [
index('conversations_user_id_idx').on(t.userId),
// Compound index for the most common query: conversations for a user filtered by archived.
index('conversations_user_archived_idx').on(t.userId, t.archived),
index('conversations_project_id_idx').on(t.projectId),
index('conversations_agent_id_idx').on(t.agentId),
index('conversations_archived_idx').on(t.archived),
],
);
@@ -369,7 +387,8 @@ export const preferences = pgTable(
},
(t) => [
index('preferences_user_id_idx').on(t.userId),
index('preferences_user_key_idx').on(t.userId, t.key),
// Unique constraint enables single-round-trip INSERT … ON CONFLICT DO UPDATE.
uniqueIndex('preferences_user_key_idx').on(t.userId, t.key),
],
);
@@ -431,10 +450,11 @@ export const agentLogs = pgTable(
archivedAt: timestamp('archived_at', { withTimezone: true }),
},
(t) => [
index('agent_logs_session_id_idx').on(t.sessionId),
// Compound index for session log queries (most common: session + tier filter).
index('agent_logs_session_tier_idx').on(t.sessionId, t.tier),
index('agent_logs_user_id_idx').on(t.userId),
index('agent_logs_tier_idx').on(t.tier),
index('agent_logs_created_at_idx').on(t.createdAt),
// Used by summarization cron to find hot logs older than a cutoff.
index('agent_logs_tier_created_at_idx').on(t.tier, t.createdAt),
],
);