Skip to content

Commit 76eee93

Browse files
committed
feat(analytics): posthog audit — remove noise, add 10 new events
Remove task_marked_read (fires automatically on every task view). Add workspace_id to task_message_sent for group analytics. New events: - search_result_selected: block/tool/trigger/workflow/table/file/ knowledge_base/workspace/task/page/docs with query_length - workflow_imported: count + format (json/zip) - workflow_exported: count + format (json/zip) - folder_created / folder_deleted - logs_filter_applied: status/workflow/folder/trigger/time - knowledge_base_document_deleted - scheduled_task_created / scheduled_task_deleted
1 parent 7971a64 commit 76eee93

File tree

12 files changed

+314
-68
lines changed

12 files changed

+314
-68
lines changed

apps/sim/app/api/folders/[id]/route.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { eq } from 'drizzle-orm'
55
import { type NextRequest, NextResponse } from 'next/server'
66
import { z } from 'zod'
77
import { getSession } from '@/lib/auth'
8+
import { captureServerEvent } from '@/lib/posthog/server'
89
import { performDeleteFolder } from '@/lib/workflows/orchestration'
910
import { checkForCircularReference } from '@/lib/workflows/utils'
1011
import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils'
@@ -156,6 +157,13 @@ export async function DELETE(
156157
return NextResponse.json({ error: result.error }, { status })
157158
}
158159

160+
captureServerEvent(
161+
session.user.id,
162+
'folder_deleted',
163+
{ workspace_id: existingFolder.workspaceId },
164+
{ groups: { workspace: existingFolder.workspaceId } }
165+
)
166+
159167
return NextResponse.json({
160168
success: true,
161169
deletedItems: result.deletedItems,

apps/sim/app/api/folders/route.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { type NextRequest, NextResponse } from 'next/server'
66
import { z } from 'zod'
77
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
88
import { getSession } from '@/lib/auth'
9+
import { captureServerEvent } from '@/lib/posthog/server'
910
import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils'
1011

1112
const logger = createLogger('FoldersAPI')
@@ -145,6 +146,13 @@ export async function POST(request: NextRequest) {
145146

146147
logger.info('Created new folder:', { id, name, workspaceId, parentId })
147148

149+
captureServerEvent(
150+
session.user.id,
151+
'folder_created',
152+
{ workspace_id: workspaceId },
153+
{ groups: { workspace: workspaceId } }
154+
)
155+
148156
recordAudit({
149157
workspaceId,
150158
actorId: session.user.id,

apps/sim/app/api/knowledge/[id]/documents/[documentId]/route.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
retryDocumentProcessing,
1111
updateDocument,
1212
} from '@/lib/knowledge/documents/service'
13+
import { captureServerEvent } from '@/lib/posthog/server'
1314
import { checkDocumentAccess, checkDocumentWriteAccess } from '@/app/api/knowledge/utils'
1415

1516
const logger = createLogger('DocumentByIdAPI')
@@ -285,6 +286,14 @@ export async function DELETE(
285286
request: req,
286287
})
287288

289+
const kbWorkspaceId = accessCheck.knowledgeBase?.workspaceId ?? ''
290+
captureServerEvent(
291+
userId,
292+
'knowledge_base_document_deleted',
293+
{ knowledge_base_id: knowledgeBaseId, workspace_id: kbWorkspaceId },
294+
kbWorkspaceId ? { groups: { workspace: kbWorkspaceId } } : undefined
295+
)
296+
288297
return NextResponse.json({
289298
success: true,
290299
data: result,

apps/sim/app/api/mothership/chats/[chatId]/route.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -159,16 +159,7 @@ export async function PATCH(
159159
}
160160
)
161161
}
162-
if (isUnread === false) {
163-
captureServerEvent(
164-
userId,
165-
'task_marked_read',
166-
{ workspace_id: updatedChat.workspaceId },
167-
{
168-
groups: { workspace: updatedChat.workspaceId },
169-
}
170-
)
171-
} else if (isUnread === true) {
162+
if (isUnread === true) {
172163
captureServerEvent(
173164
userId,
174165
'task_marked_unread',

apps/sim/app/api/schedules/[id]/route.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { z } from 'zod'
77
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
88
import { getSession } from '@/lib/auth'
99
import { generateRequestId } from '@/lib/core/utils/request'
10+
import { captureServerEvent } from '@/lib/posthog/server'
1011
import { validateCronExpression } from '@/lib/workflows/schedules/utils'
1112
import { authorizeWorkflowByWorkspacePermission } from '@/lib/workflows/utils'
1213
import { verifyWorkspaceMembership } from '@/app/api/workflows/utils'
@@ -298,6 +299,15 @@ export async function DELETE(
298299
request,
299300
})
300301

302+
if (workspaceId) {
303+
captureServerEvent(
304+
session.user.id,
305+
'scheduled_task_deleted',
306+
{ workspace_id: workspaceId },
307+
{ groups: { workspace: workspaceId } }
308+
)
309+
}
310+
301311
return NextResponse.json({ message: 'Schedule deleted successfully' })
302312
} catch (error) {
303313
logger.error(`[${requestId}] Error deleting schedule`, error)

apps/sim/app/api/schedules/route.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { and, eq, isNull, or } from 'drizzle-orm'
55
import { type NextRequest, NextResponse } from 'next/server'
66
import { getSession } from '@/lib/auth'
77
import { generateRequestId } from '@/lib/core/utils/request'
8+
import { captureServerEvent } from '@/lib/posthog/server'
89
import { validateCronExpression } from '@/lib/workflows/schedules/utils'
910
import { authorizeWorkflowByWorkspacePermission } from '@/lib/workflows/utils'
1011
import { verifyWorkspaceMembership } from '@/app/api/workflows/utils'
@@ -277,6 +278,13 @@ export async function POST(req: NextRequest) {
277278
lifecycle,
278279
})
279280

281+
captureServerEvent(
282+
session.user.id,
283+
'scheduled_task_created',
284+
{ workspace_id: workspaceId },
285+
{ groups: { workspace: workspaceId } }
286+
)
287+
280288
return NextResponse.json(
281289
{ schedule: { id, status: 'active', cronExpression, nextRunAt } },
282290
{ status: 201 }

apps/sim/app/workspace/[workspaceId]/home/home.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ export function Home({ chatId }: HomeProps = {}) {
228228
if (!trimmed && !(fileAttachments && fileAttachments.length > 0)) return
229229

230230
captureEvent(posthogRef.current, 'task_message_sent', {
231+
workspace_id: workspaceId,
231232
has_attachments: !!(fileAttachments && fileAttachments.length > 0),
232233
has_contexts: !!(contexts && contexts.length > 0),
233234
is_new_task: !chatId,

apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
'use client'
22

3-
import { memo, useCallback, useMemo, useState } from 'react'
3+
import { memo, useCallback, useMemo, useRef, useState } from 'react'
44
import { ArrowUp, Bell, Library, MoreHorizontal, RefreshCw } from 'lucide-react'
55
import { useParams } from 'next/navigation'
6+
import { usePostHog } from 'posthog-js/react'
67
import { useShallow } from 'zustand/react/shallow'
78
import {
89
Button,
@@ -18,6 +19,7 @@ import { DatePicker } from '@/components/emcn/components/date-picker/date-picker
1819
import { cn } from '@/lib/core/utils/cn'
1920
import { hasActiveFilters } from '@/lib/logs/filters'
2021
import { getTriggerOptions } from '@/lib/logs/get-trigger-options'
22+
import { captureEvent } from '@/lib/posthog/client'
2123
import { type LogStatus, STATUS_CONFIG } from '@/app/workspace/[workspaceId]/logs/utils'
2224
import { getBlock } from '@/blocks/registry'
2325
import { useFolderMap } from '@/hooks/queries/folders'
@@ -179,6 +181,9 @@ export const LogsToolbar = memo(function LogsToolbar({
179181
}: LogsToolbarProps) {
180182
const params = useParams()
181183
const workspaceId = params.workspaceId as string
184+
const posthog = usePostHog()
185+
const posthogRef = useRef(posthog)
186+
posthogRef.current = posthog
182187

183188
const {
184189
level,
@@ -258,8 +263,45 @@ export const LogsToolbar = memo(function LogsToolbar({
258263
} else {
259264
setLevel(values.join(','))
260265
}
266+
captureEvent(posthogRef.current, 'logs_filter_applied', {
267+
filter_type: 'status',
268+
workspace_id: workspaceId,
269+
})
261270
},
262-
[setLevel]
271+
[setLevel, workspaceId]
272+
)
273+
274+
const handleWorkflowFilterChange = useCallback(
275+
(values: string[]) => {
276+
setWorkflowIds(values)
277+
captureEvent(posthogRef.current, 'logs_filter_applied', {
278+
filter_type: 'workflow',
279+
workspace_id: workspaceId,
280+
})
281+
},
282+
[setWorkflowIds, workspaceId]
283+
)
284+
285+
const handleFolderFilterChange = useCallback(
286+
(values: string[]) => {
287+
setFolderIds(values)
288+
captureEvent(posthogRef.current, 'logs_filter_applied', {
289+
filter_type: 'folder',
290+
workspace_id: workspaceId,
291+
})
292+
},
293+
[setFolderIds, workspaceId]
294+
)
295+
296+
const handleTriggerFilterChange = useCallback(
297+
(values: string[]) => {
298+
setTriggers(values)
299+
captureEvent(posthogRef.current, 'logs_filter_applied', {
300+
filter_type: 'trigger',
301+
workspace_id: workspaceId,
302+
})
303+
},
304+
[setTriggers, workspaceId]
263305
)
264306

265307
const statusDisplayLabel = useMemo(() => {
@@ -348,9 +390,13 @@ export const LogsToolbar = memo(function LogsToolbar({
348390
} else {
349391
clearDateRange()
350392
setTimeRange(val as typeof timeRange)
393+
captureEvent(posthogRef.current, 'logs_filter_applied', {
394+
filter_type: 'time',
395+
workspace_id: workspaceId,
396+
})
351397
}
352398
},
353-
[timeRange, setTimeRange, clearDateRange]
399+
[timeRange, setTimeRange, clearDateRange, workspaceId]
354400
)
355401

356402
/**
@@ -545,7 +591,7 @@ export const LogsToolbar = memo(function LogsToolbar({
545591
options={workflowOptions}
546592
multiSelect
547593
multiSelectValues={workflowIds}
548-
onMultiSelectChange={setWorkflowIds}
594+
onMultiSelectChange={handleWorkflowFilterChange}
549595
placeholder='All workflows'
550596
overlayContent={
551597
<span className='flex items-center gap-1.5 truncate text-[var(--text-primary)]'>
@@ -580,7 +626,7 @@ export const LogsToolbar = memo(function LogsToolbar({
580626
options={folderOptions}
581627
multiSelect
582628
multiSelectValues={folderIds}
583-
onMultiSelectChange={setFolderIds}
629+
onMultiSelectChange={handleFolderFilterChange}
584630
placeholder='All folders'
585631
overlayContent={
586632
<span className='truncate text-[var(--text-primary)]'>
@@ -605,7 +651,7 @@ export const LogsToolbar = memo(function LogsToolbar({
605651
options={triggerOptions}
606652
multiSelect
607653
multiSelectValues={triggers}
608-
onMultiSelectChange={setTriggers}
654+
onMultiSelectChange={handleTriggerFilterChange}
609655
placeholder='All triggers'
610656
overlayContent={
611657
<span className='truncate text-[var(--text-primary)]'>
@@ -676,7 +722,7 @@ export const LogsToolbar = memo(function LogsToolbar({
676722
options={workflowOptions}
677723
multiSelect
678724
multiSelectValues={workflowIds}
679-
onMultiSelectChange={setWorkflowIds}
725+
onMultiSelectChange={handleWorkflowFilterChange}
680726
placeholder='Workflow'
681727
overlayContent={
682728
<span className='flex items-center gap-1.5 truncate text-[var(--text-primary)]'>
@@ -707,7 +753,7 @@ export const LogsToolbar = memo(function LogsToolbar({
707753
options={folderOptions}
708754
multiSelect
709755
multiSelectValues={folderIds}
710-
onMultiSelectChange={setFolderIds}
756+
onMultiSelectChange={handleFolderFilterChange}
711757
placeholder='Folder'
712758
overlayContent={
713759
<span className='truncate text-[var(--text-primary)]'>{folderDisplayLabel}</span>
@@ -726,7 +772,7 @@ export const LogsToolbar = memo(function LogsToolbar({
726772
options={triggerOptions}
727773
multiSelect
728774
multiSelectValues={triggers}
729-
onMultiSelectChange={setTriggers}
775+
onMultiSelectChange={handleTriggerFilterChange}
730776
placeholder='Trigger'
731777
overlayContent={
732778
<span className='truncate text-[var(--text-primary)]'>{triggerDisplayLabel}</span>

0 commit comments

Comments
 (0)