Skip to content

Commit

Permalink
chore(analytics): track in-app groups with groups metrics (#2678)
Browse files Browse the repository at this point in the history
  • Loading branch information
Cosmin-Parvulescu authored Sep 25, 2023
1 parent 4fac590 commit c4f45cd
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { z } from 'zod'
import { Context } from '../../../context'
import { InternalServerError, UnauthorizedError } from '@proofzero/errors'
import { UnauthorizedError } from '@proofzero/errors'
import {
AccountURNInput,
IdentityGroupURNValidator,
} from '@proofzero/platform-middleware/inputValidators'
import { router } from '@proofzero/platform.core'
import { EDGE_ACCOUNT } from '@proofzero/platform.account/src/constants'
import { EDGE_MEMBER_OF_IDENTITY_GROUP } from '@proofzero/types/graph'
import { createAnalyticsEvent } from '@proofzero/utils/analytics'

export const ConnectIdentityGroupEmailInputSchema = z.object({
identityGroupURN: IdentityGroupURNValidator,
Expand Down Expand Up @@ -78,6 +79,18 @@ export const connectIdentityGroupEmail = async ({
dst: accountURN,
})

ctx.waitUntil?.(
createAnalyticsEvent({
eventName: 'group_email_connected',
apiKey: ctx.POSTHOG_API_KEY,
distinctId: identityGroupURN,
properties: {
$groups: { group: identityGroupURN },
connectedAccountURN: accountURN,
},
})
)

return {
existing: false,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { InternalServerError } from '@proofzero/errors'
import { router } from '@proofzero/platform.core'
import { EDGE_MEMBER_OF_IDENTITY_GROUP } from '@proofzero/types/graph'
import { IdentityURN } from '@proofzero/urns/identity'
import { createAnalyticsEvent } from '@proofzero/utils/analytics'

export const AcceptIdentityGroupMemberInvitationInputSchema = z.object({
identityGroupURN: IdentityGroupURNValidator,
Expand Down Expand Up @@ -68,4 +69,15 @@ export const acceptIdentityGroupMemberInvitation = async ({
tag: EDGE_MEMBER_OF_IDENTITY_GROUP,
dst: identityGroupURN,
})

ctx.waitUntil?.(
createAnalyticsEvent({
eventName: 'group_invitation_accepted',
apiKey: ctx.POSTHOG_API_KEY,
distinctId: ctx.identityURN as IdentityURN,
properties: {
$groups: { group: identityGroupURN },
},
})
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ export const createIdentityGroup = async ({
apiKey: ctx.POSTHOG_API_KEY,
distinctId: ctx.identityURN as IdentityURN,
properties: {
$groups: { group: groupURN },
$groups: { group: baseGroupURN },
$group_type: 'group',
$group_key: groupURN,
$group_key: baseGroupURN,
$group_set: {
name: input.name,
groupURN: groupURN,
groupURN: baseGroupURN,
date_joined: new Date().toISOString(),
},
},
Expand All @@ -65,7 +65,7 @@ export const createIdentityGroup = async ({
apiKey: ctx.POSTHOG_API_KEY,
distinctId: ctx.identityURN as IdentityURN,
properties: {
$groups: { group: groupURN },
$groups: { group: baseGroupURN },
},
})
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { IdentityGroupURNValidator } from '@proofzero/platform-middleware/inputV
import { initIdentityGroupNodeByName } from '../../../nodes'
import { BadRequestError } from '@proofzero/errors'
import { EDGE_APPLICATION } from '@proofzero/platform.starbase/src/types'
import { createAnalyticsEvent } from '@proofzero/utils/analytics'
import { IdentityURN } from '@proofzero/urns/identity'

export const DeleteIdentityGroupInputSchema = IdentityGroupURNValidator
type DeleteIdentityGroupInput = z.infer<typeof DeleteIdentityGroupInputSchema>
Expand Down Expand Up @@ -67,11 +69,19 @@ export const deleteIdentityGroup = async ({
urn: identityGroupURN,
})

const DO = await initIdentityGroupNodeByName(
identityGroupURN,
ctx.IdentityGroup
)
const DO = initIdentityGroupNodeByName(identityGroupURN, ctx.IdentityGroup)
if (DO) {
await DO.storage.deleteAll()
}

ctx.waitUntil?.(
createAnalyticsEvent({
eventName: 'group_deleted',
apiKey: ctx.POSTHOG_API_KEY,
distinctId: ctx.identityURN as IdentityURN,
properties: {
$groups: { group: identityGroupURN },
},
})
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
IdentityURNInput,
} from '@proofzero/platform-middleware/inputValidators'
import { InternalServerError } from '@proofzero/errors'
import { createAnalyticsEvent } from '@proofzero/utils/analytics'
import { IdentityURN } from '@proofzero/urns/identity'

export const DeleteIdentityGroupMembershipInputSchema = z.object({
identityURN: IdentityURNInput,
Expand Down Expand Up @@ -64,4 +66,16 @@ export const deleteIdentityGroupMembership = async ({
tag: EDGE_MEMBER_OF_IDENTITY_GROUP,
dst: identityGroupURN,
})

ctx.waitUntil?.(
createAnalyticsEvent({
eventName: 'group_member_removed',
apiKey: ctx.POSTHOG_API_KEY,
distinctId: ctx.identityURN as IdentityURN,
properties: {
$groups: { group: identityGroupURN },
removedIdentityURN: identityURN,
},
})
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { router } from '@proofzero/platform.core'
import { EDGE_MEMBER_OF_IDENTITY_GROUP } from '@proofzero/types/graph'

import { Context } from '../../../context'
import { InternalServerError } from '@proofzero/errors'
import { IdentityURN } from '@proofzero/urns/identity'
import { initIdentityGroupNodeByName } from '../../../nodes'
import { createAnalyticsEvent } from '@proofzero/utils/analytics'

export const purgeIdentityGroupMemberships = async ({
ctx,
Expand Down Expand Up @@ -45,11 +45,19 @@ export const purgeIdentityGroupMemberships = async ({
urn: igu,
})

const DO = await initIdentityGroupNodeByName(igu, ctx.IdentityGroup)
const DO = initIdentityGroupNodeByName(igu, ctx.IdentityGroup)
if (DO) {
await DO.storage.deleteAll()
}
}
})
)

ctx.waitUntil?.(
createAnalyticsEvent({
eventName: 'group_memberships_purged',
apiKey: ctx.POSTHOG_API_KEY,
distinctId: ctx.identityURN as IdentityURN,
})
)
}
2 changes: 1 addition & 1 deletion platform/starbase/src/jsonrpc/methods/createApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export const createApp = async ({
apiKey: ctx.POSTHOG_API_KEY,
distinctId: ctx.identityURN,
properties: {
$groups: { app: clientId },
$groups: { app: clientId, group: input.identityGroupURN },
},
})
)
Expand Down
23 changes: 18 additions & 5 deletions platform/starbase/src/jsonrpc/methods/deleteApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import { z } from 'zod'
import { router } from '@proofzero/platform.core'
import { Context } from '../context'
import { getApplicationNodeByClientId } from '../../nodes/application'
import { BadRequestError } from '@proofzero/errors'
import { BadRequestError, InternalServerError } from '@proofzero/errors'
import { ApplicationURNSpace } from '@proofzero/urns/application'
import { AppClientIdParamSchema } from '../validators/app'
import { EDGE_APPLICATION } from '../../types'
import { EDGE_HAS_REFERENCE_TO } from '@proofzero/types/graph'
import { createAnalyticsEvent } from '@proofzero/utils/analytics'
import type { IdentityURN } from '@proofzero/urns/identity'
import { IdentityURNSpace, type IdentityURN } from '@proofzero/urns/identity'
import { EDGE_APPLICATION } from '../../types'

export const DeleteAppInput = AppClientIdParamSchema

Expand Down Expand Up @@ -48,6 +47,15 @@ export const deleteApp = async ({
}),
])

const appOwnershipEdge = dstEdges.find(
(edge) => edge.tag === EDGE_APPLICATION
)
if (!appOwnershipEdge) {
throw new InternalServerError({
message: 'App ownership edge not found',
})
}

await Promise.all(
srcEdges.concat(dstEdges).map((e) =>
caller.edges.removeEdge({
Expand All @@ -69,7 +77,12 @@ export const deleteApp = async ({
eventName: 'identity_deleted_app',
distinctId: ctx.identityURN as IdentityURN,
properties: {
$groups: { app: input.clientId },
$groups: {
app: input.clientId,
group: IdentityURNSpace.is(appOwnershipEdge.src.baseUrn)
? appOwnershipEdge.src.baseUrn
: undefined,
},
},
})
)
Expand Down
32 changes: 28 additions & 4 deletions platform/starbase/src/jsonrpc/methods/publishApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import { createAnalyticsEvent } from '@proofzero/utils/analytics'
import { Context } from '../context'
import { getApplicationNodeByClientId } from '../../nodes/application'
import type { IdentityURN } from '@proofzero/urns/identity'
import { EDGE_APPLICATION } from '../../types'
import { InternalServerError } from '@proofzero/errors'
import { IdentityGroupURNSpace } from '@proofzero/urns/identity-group'

export const PublishAppInput = z.object({
clientId: z.string(),
Expand Down Expand Up @@ -58,16 +61,37 @@ export const publishApp = async ({

await appDO.class.publish(input.published)

ctx.waitUntil?.(
createAnalyticsEvent({
const buildAnalyticsEvent = async () => {
const { edges: ownershipEdges } = await caller.edges.getEdges({
query: {
tag: EDGE_APPLICATION,
dst: { baseUrn: appURN },
},
})
if (ownershipEdges.length === 0) {
throw new InternalServerError({
message: 'App ownership edge not found',
})
}

await createAnalyticsEvent({
distinctId: ctx.identityURN as IdentityURN,
eventName: input.published
? 'identity_published_app'
: 'identity_unpublished_app',
apiKey: ctx.POSTHOG_API_KEY,
properties: { $groups: { app: input.clientId } },
properties: {
$groups: {
app: input.clientId,
group: IdentityGroupURNSpace.is(ownershipEdges[0].src.baseUrn)
? ownershipEdges[0].src.baseUrn
: undefined,
},
},
})
)
}

ctx.waitUntil?.(buildAnalyticsEvent())

return {
published: true,
Expand Down
38 changes: 29 additions & 9 deletions platform/starbase/src/jsonrpc/methods/setAppPlan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { ServicePlanType } from '@proofzero/types/billing'
import { EDGE_PAYS_APP } from '@proofzero/types/graph'
import { IdentityRefURNValidator } from '@proofzero/platform-middleware/inputValidators'
import { createAnalyticsEvent } from '@proofzero/utils/analytics'
import { EDGE_APPLICATION } from '../../types'
import { InternalServerError } from '@proofzero/errors'
import { IdentityGroupURNSpace } from '@proofzero/urns/identity-group'

export const SetAppPlanInput = AppClientIdParamSchema.extend({
URN: IdentityRefURNValidator,
Expand Down Expand Up @@ -62,10 +65,10 @@ export const setAppPlan = async ({
})
}

// This is the way how we can update group properties
// https://posthog.com/tutorials/frontend-vs-backend-group-analytics
ctx.waitUntil?.(
createAnalyticsEvent({
const buildAnalyticsEvent = async () => {
// This is the way how we can update group properties
// https://posthog.com/tutorials/frontend-vs-backend-group-analytics
await createAnalyticsEvent({
eventName: '$groupidentify',
apiKey: ctx.POSTHOG_API_KEY,
distinctId: input.URN,
Expand All @@ -77,16 +80,33 @@ export const setAppPlan = async ({
},
},
})
)

ctx.waitUntil?.(
createAnalyticsEvent({
const { edges: ownershipEdges } = await caller.edges.getEdges({
query: {
tag: EDGE_APPLICATION,
dst: { baseUrn: appURN },
},
})
if (ownershipEdges.length === 0) {
throw new InternalServerError({
message: 'App ownership edge not found',
})
}

await createAnalyticsEvent({
eventName: `app_set_${plan}_plan`,
apiKey: ctx.POSTHOG_API_KEY,
distinctId: input.URN,
properties: {
$groups: { app: clientId },
$groups: {
app: clientId,
group: IdentityGroupURNSpace.is(ownershipEdges[0].src.baseUrn)
? ownershipEdges[0].src.baseUrn
: undefined,
},
},
})
)
}

ctx.waitUntil?.(buildAnalyticsEvent())
}

0 comments on commit c4f45cd

Please sign in to comment.