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

@@ -5,34 +5,28 @@ import type { Db } from '@mosaic/db';
/**
* Build a mock Drizzle DB where the select chain supports:
* db.select().from().where() → resolves to `listRows`
* db.select().from().where().limit(n) → resolves to `singleRow`
* db.insert().values().onConflictDoUpdate() → resolves to []
*/
function makeMockDb(
listRows: Array<{ key: string; value: unknown }> = [],
singleRow: Array<{ id: string }> = [],
): Db {
function makeMockDb(listRows: Array<{ key: string; value: unknown }> = []): Db {
const chainWithLimit = {
limit: vi.fn().mockResolvedValue(singleRow),
limit: vi.fn().mockResolvedValue([]),
then: (resolve: (v: typeof listRows) => unknown) => Promise.resolve(listRows).then(resolve),
};
const selectFrom = {
from: vi.fn().mockReturnThis(),
where: vi.fn().mockReturnValue(chainWithLimit),
};
const updateResult = {
set: vi.fn().mockReturnThis(),
where: vi.fn().mockResolvedValue([]),
};
const deleteResult = {
where: vi.fn().mockResolvedValue([]),
};
// Single-round-trip upsert chain: insert().values().onConflictDoUpdate()
const insertResult = {
values: vi.fn().mockResolvedValue([]),
values: vi.fn().mockReturnThis(),
onConflictDoUpdate: vi.fn().mockResolvedValue([]),
};
return {
select: vi.fn().mockReturnValue(selectFrom),
update: vi.fn().mockReturnValue(updateResult),
delete: vi.fn().mockReturnValue(deleteResult),
insert: vi.fn().mockReturnValue(insertResult),
} as unknown as Db;
@@ -98,23 +92,14 @@ describe('PreferencesService', () => {
expect(result.message).toContain('platform enforcement');
});
it('upserts a mutable preference and returns success — insert path', async () => {
// singleRow=[] → no existing row → insert path
const db = makeMockDb([], []);
it('upserts a mutable preference and returns success', async () => {
// Single-round-trip INSERT … ON CONFLICT DO UPDATE path.
const db = makeMockDb([]);
const service = new PreferencesService(db);
const result = await service.set('user-1', 'agent.thinkingLevel', 'high');
expect(result.success).toBe(true);
expect(result.message).toContain('"agent.thinkingLevel"');
});
it('upserts a mutable preference and returns success — update path', async () => {
// singleRow has an id → existing row → update path
const db = makeMockDb([], [{ id: 'existing-id' }]);
const service = new PreferencesService(db);
const result = await service.set('user-1', 'agent.thinkingLevel', 'low');
expect(result.success).toBe(true);
expect(result.message).toContain('"agent.thinkingLevel"');
});
});
describe('reset', () => {