From 51b40cc06962ad98333a50ac7b4dbd82d8a3fe10 Mon Sep 17 00:00:00 2001 From: Dries Augustyns Date: Fri, 22 Aug 2025 14:17:21 +0200 Subject: [PATCH 1/3] FEAT: Optimize data retrieval and add new indexes for performance improvements --- packages/api/src/services/ProjectService.ts | 73 +++++++++++------- .../20250822121546_indexes/migration.sql | 74 +++++++++++++++++++ prisma/schema.prisma | 27 ++++++- 3 files changed, 146 insertions(+), 28 deletions(-) create mode 100644 prisma/migrations/20250822121546_indexes/migration.sql diff --git a/packages/api/src/services/ProjectService.ts b/packages/api/src/services/ProjectService.ts index 6490031..f7179b4 100644 --- a/packages/api/src/services/ProjectService.ts +++ b/packages/api/src/services/ProjectService.ts @@ -145,41 +145,60 @@ export class ProjectService { const itemsPerPage = 10; const skip = (page - 1) * itemsPerPage; - const triggers = await prisma.trigger.findMany({ - where: { contact: { projectId: id } }, - include: { - contact: { - select: { - id: true, - email: true, + const [triggers, emails] = await Promise.all([ + prisma.trigger.findMany({ + where: { + contact: { + projectId: id + } + }, + select: { + id: true, + createdAt: true, + contact: { + select: { + id: true, + email: true, + }, + }, + event: { + select: { + name: true, + }, }, }, - event: { - select: { - name: true, + orderBy: {createdAt: 'desc'}, + take: itemsPerPage, + skip, + }), + prisma.email.findMany({ + where: { + contact: { + projectId: id + } + }, + select: { + id: true, + createdAt: true, + messageId: true, + status: true, + contact: { + select: { + id: true, + email: true, + }, }, }, - }, - orderBy: { createdAt: "desc" }, - }); - - const emails = await prisma.email.findMany({ - where: { contact: { projectId: id } }, - include: { - contact: { - select: { - id: true, - email: true, - }, - }, - }, - orderBy: { createdAt: "desc" }, - }); + orderBy: {createdAt: 'desc'}, + take: itemsPerPage, + skip, + }), + ]); const combined = [...triggers, ...emails]; combined.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()); - return combined.slice(skip, skip + itemsPerPage); + return combined.slice(0, itemsPerPage); } public static usage(id: string) { diff --git a/prisma/migrations/20250822121546_indexes/migration.sql b/prisma/migrations/20250822121546_indexes/migration.sql new file mode 100644 index 0000000..12a7bce --- /dev/null +++ b/prisma/migrations/20250822121546_indexes/migration.sql @@ -0,0 +1,74 @@ +-- CreateIndex +CREATE INDEX "actions_projectId_idx" ON "actions"("projectId"); + +-- CreateIndex +CREATE INDEX "actions_templateId_idx" ON "actions"("templateId"); + +-- CreateIndex +CREATE INDEX "clicks_createdAt_idx" ON "clicks"("createdAt"); + +-- CreateIndex +CREATE INDEX "clicks_link_idx" ON "clicks"("link"); + +-- CreateIndex +CREATE INDEX "clicks_emailId_idx" ON "clicks"("emailId"); + +-- CreateIndex +CREATE INDEX "contacts_projectId_createdAt_idx" ON "contacts"("projectId", "createdAt"); + +-- CreateIndex +CREATE INDEX "contacts_email_idx" ON "contacts"("email"); + +-- CreateIndex +CREATE INDEX "contacts_createdAt_idx" ON "contacts"("createdAt"); + +-- CreateIndex +CREATE INDEX "emails_projectId_idx" ON "emails"("projectId"); + +-- CreateIndex +CREATE INDEX "emails_actionId_idx" ON "emails"("actionId"); + +-- CreateIndex +CREATE INDEX "emails_campaignId_idx" ON "emails"("campaignId"); + +-- CreateIndex +CREATE INDEX "emails_contactId_idx" ON "emails"("contactId"); + +-- CreateIndex +CREATE INDEX "emails_createdAt_idx" ON "emails"("createdAt"); + +-- CreateIndex +CREATE INDEX "events_projectId_idx" ON "events"("projectId"); + +-- CreateIndex +CREATE INDEX "events_templateId_idx" ON "events"("templateId"); + +-- CreateIndex +CREATE INDEX "events_campaignId_idx" ON "events"("campaignId"); + +-- CreateIndex +CREATE INDEX "tasks_actionId_idx" ON "tasks"("actionId"); + +-- CreateIndex +CREATE INDEX "tasks_campaignId_idx" ON "tasks"("campaignId"); + +-- CreateIndex +CREATE INDEX "tasks_contactId_idx" ON "tasks"("contactId"); + +-- CreateIndex +CREATE INDEX "tasks_createdAt_idx" ON "tasks"("createdAt"); + +-- CreateIndex +CREATE INDEX "tasks_runBy_idx" ON "tasks"("runBy"); + +-- CreateIndex +CREATE INDEX "triggers_contactId_idx" ON "triggers"("contactId"); + +-- CreateIndex +CREATE INDEX "triggers_eventId_idx" ON "triggers"("eventId"); + +-- CreateIndex +CREATE INDEX "triggers_actionId_idx" ON "triggers"("actionId"); + +-- CreateIndex +CREATE INDEX "triggers_createdAt_idx" ON "triggers"("createdAt"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 184d199..866a44f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -99,6 +99,9 @@ model Event { updatedAt DateTime @updatedAt @@index(fields: [projectId, templateId, campaignId]) + @@index([projectId]) + @@index([templateId]) + @@index([campaignId]) @@map("events") } @@ -155,6 +158,8 @@ model Action { updatedAt DateTime @updatedAt @@index(fields: [projectId, templateId]) + @@index([projectId]) + @@index([templateId]) @@map("actions") } @@ -203,6 +208,10 @@ model Trigger { updatedAt DateTime @updatedAt @@index(fields: [contactId, eventId, actionId, createdAt]) + @@index([contactId]) + @@index([eventId]) + @@index([actionId]) + @@index([createdAt]) @@map("triggers") } @@ -227,7 +236,10 @@ model Contact { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt - @@index(fields: [projectId]) + @@index(fields: [projectId, createdAt]) + @@index([projectId]) + @@index([email]) + @@index([createdAt]) @@map("contacts") } @@ -259,6 +271,11 @@ model Email { updatedAt DateTime @updatedAt @@index(fields: [projectId, actionId, campaignId, contactId, createdAt]) + @@index([projectId]) + @@index([actionId]) + @@index([campaignId]) + @@index([contactId]) + @@index([createdAt]) @@map("emails") } @@ -276,6 +293,9 @@ model Click { updatedAt DateTime @updatedAt @@index([emailId, createdAt]) + @@index([createdAt]) + @@index([link]) + @@index([emailId]) @@map("clicks") } @@ -300,6 +320,11 @@ model Task { updatedAt DateTime @updatedAt @@index([runBy, createdAt]) + @@index([actionId]) + @@index([campaignId]) + @@index([contactId]) + @@index([createdAt]) + @@index([runBy]) @@map("tasks") } From 7a047f11d8389f0f81d13671aa38d1f52a322681 Mon Sep 17 00:00:00 2001 From: Dries Augustyns Date: Fri, 22 Aug 2025 14:18:03 +0200 Subject: [PATCH 2/3] Bump version to 1.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index da9f646..601d914 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plunk", - "version": "1.1.0", + "version": "1.2.0", "private": true, "license": "agpl-3.0", "workspaces": { From 4fe90adf1e97c85afddeae0ad9e1ecc11dd0609b Mon Sep 17 00:00:00 2001 From: Dries Augustyns Date: Fri, 22 Aug 2025 14:35:05 +0200 Subject: [PATCH 3/3] FEAT: Increase pagination limits to improve data display and update version to 1.2.1 --- package.json | 2 +- packages/api/src/services/ProjectService.ts | 4 ++-- packages/dashboard/src/pages/contacts/index.tsx | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 601d914..2210725 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plunk", - "version": "1.2.0", + "version": "1.2.1", "private": true, "license": "agpl-3.0", "workspaces": { diff --git a/packages/api/src/services/ProjectService.ts b/packages/api/src/services/ProjectService.ts index f7179b4..df0e550 100644 --- a/packages/api/src/services/ProjectService.ts +++ b/packages/api/src/services/ProjectService.ts @@ -33,8 +33,8 @@ export class ProjectService { emails: { select: { createdAt: true } }, }, orderBy: [{ createdAt: "desc" }], - take: 20, - skip: (page - 1) * 20, + take: 100, + skip: (page - 1) * 100, }); }); }, diff --git a/packages/dashboard/src/pages/contacts/index.tsx b/packages/dashboard/src/pages/contacts/index.tsx index 0ce8aa7..d09dfe1 100644 --- a/packages/dashboard/src/pages/contacts/index.tsx +++ b/packages/dashboard/src/pages/contacts/index.tsx @@ -237,8 +237,8 @@ export default function Index() {