Skip to content

Commit b744cd2

Browse files
authored
feat(analytics): posthog audit — remove noise, add 10 new events (#3917)
* 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 * fix(analytics): use usePostHog + captureEvent in hooks, track custom date range * fix(analytics): always fire scheduled_task_deleted regardless of workspaceId * fix(analytics): correct format field logic and add missing useCallback deps
1 parent d290e06 commit b744cd2

File tree

12 files changed

+328
-71
lines changed

12 files changed

+328
-71
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: 8 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,13 @@ export async function DELETE(
298299
request,
299300
})
300301

302+
captureServerEvent(
303+
session.user.id,
304+
'scheduled_task_deleted',
305+
{ workspace_id: workspaceId ?? '' },
306+
workspaceId ? { groups: { workspace: workspaceId } } : undefined
307+
)
308+
301309
return NextResponse.json({ message: 'Schedule deleted successfully' })
302310
} catch (error) {
303311
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: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ export function Home({ chatId }: HomeProps = {}) {
213213
if (!trimmed && !(fileAttachments && fileAttachments.length > 0)) return
214214

215215
captureEvent(posthogRef.current, 'task_message_sent', {
216+
workspace_id: workspaceId,
216217
has_attachments: !!(fileAttachments && fileAttachments.length > 0),
217218
has_contexts: !!(contexts && contexts.length > 0),
218219
is_new_task: !chatId,
@@ -224,7 +225,7 @@ export function Home({ chatId }: HomeProps = {}) {
224225

225226
sendMessage(trimmed || 'Analyze the attached file(s).', fileAttachments, contexts)
226227
},
227-
[sendMessage]
228+
[sendMessage, workspaceId, chatId]
228229
)
229230

230231
useEffect(() => {

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

Lines changed: 60 additions & 10 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
/**
@@ -360,8 +406,12 @@ export const LogsToolbar = memo(function LogsToolbar({
360406
(start: string, end: string) => {
361407
setDateRange(start, end)
362408
setDatePickerOpen(false)
409+
captureEvent(posthogRef.current, 'logs_filter_applied', {
410+
filter_type: 'time',
411+
workspace_id: workspaceId,
412+
})
363413
},
364-
[setDateRange]
414+
[setDateRange, workspaceId]
365415
)
366416

367417
/**
@@ -545,7 +595,7 @@ export const LogsToolbar = memo(function LogsToolbar({
545595
options={workflowOptions}
546596
multiSelect
547597
multiSelectValues={workflowIds}
548-
onMultiSelectChange={setWorkflowIds}
598+
onMultiSelectChange={handleWorkflowFilterChange}
549599
placeholder='All workflows'
550600
overlayContent={
551601
<span className='flex items-center gap-1.5 truncate text-[var(--text-primary)]'>
@@ -580,7 +630,7 @@ export const LogsToolbar = memo(function LogsToolbar({
580630
options={folderOptions}
581631
multiSelect
582632
multiSelectValues={folderIds}
583-
onMultiSelectChange={setFolderIds}
633+
onMultiSelectChange={handleFolderFilterChange}
584634
placeholder='All folders'
585635
overlayContent={
586636
<span className='truncate text-[var(--text-primary)]'>
@@ -605,7 +655,7 @@ export const LogsToolbar = memo(function LogsToolbar({
605655
options={triggerOptions}
606656
multiSelect
607657
multiSelectValues={triggers}
608-
onMultiSelectChange={setTriggers}
658+
onMultiSelectChange={handleTriggerFilterChange}
609659
placeholder='All triggers'
610660
overlayContent={
611661
<span className='truncate text-[var(--text-primary)]'>
@@ -676,7 +726,7 @@ export const LogsToolbar = memo(function LogsToolbar({
676726
options={workflowOptions}
677727
multiSelect
678728
multiSelectValues={workflowIds}
679-
onMultiSelectChange={setWorkflowIds}
729+
onMultiSelectChange={handleWorkflowFilterChange}
680730
placeholder='Workflow'
681731
overlayContent={
682732
<span className='flex items-center gap-1.5 truncate text-[var(--text-primary)]'>
@@ -707,7 +757,7 @@ export const LogsToolbar = memo(function LogsToolbar({
707757
options={folderOptions}
708758
multiSelect
709759
multiSelectValues={folderIds}
710-
onMultiSelectChange={setFolderIds}
760+
onMultiSelectChange={handleFolderFilterChange}
711761
placeholder='Folder'
712762
overlayContent={
713763
<span className='truncate text-[var(--text-primary)]'>{folderDisplayLabel}</span>
@@ -726,7 +776,7 @@ export const LogsToolbar = memo(function LogsToolbar({
726776
options={triggerOptions}
727777
multiSelect
728778
multiSelectValues={triggers}
729-
onMultiSelectChange={setTriggers}
779+
onMultiSelectChange={handleTriggerFilterChange}
730780
placeholder='Trigger'
731781
overlayContent={
732782
<span className='truncate text-[var(--text-primary)]'>{triggerDisplayLabel}</span>

0 commit comments

Comments
 (0)