feat: revenue tracking

* wip

* wip

* wip

* wip

* show revenue better on overview

* align realtime and overview counters

* update revenue docs

* always return device id

* add project settings, improve projects charts,

* fix: comments

* fixes

* fix migration

* ignore sql files

* fix comments
This commit is contained in:
Carl-Gerhard Lindesvärd
2025-11-19 14:27:34 +01:00
committed by GitHub
parent d61cbf6f2c
commit 790801b728
58 changed files with 2191 additions and 23691 deletions

View File

@@ -15,6 +15,7 @@ import {
getHasFunnelRules,
getNotificationRulesByProjectId,
sessionBuffer,
transformSessionToEvent,
} from '@openpanel/db';
import type { EventsQueuePayloadCreateSessionEnd } from '@openpanel/queue';
@@ -31,7 +32,7 @@ async function getSessionEvents({
sessionId: string;
startAt: Date;
endAt: Date;
}): Promise<ReturnType<typeof getEvents>> {
}): Promise<IServiceEvent[]> {
const sql = `
SELECT * FROM ${TABLE_NAMES.events}
WHERE
@@ -42,16 +43,18 @@ async function getSessionEvents({
`;
const [lastScreenView, eventsInDb] = await Promise.all([
eventBuffer.getLastScreenView({
projectId,
sessionBuffer.getExistingSession({
sessionId,
}),
getEvents(sql),
]);
// sort last inserted first
return [lastScreenView, ...eventsInDb]
.filter((event): event is IServiceEvent => !!event)
return [
lastScreenView ? transformSessionToEvent(lastScreenView) : null,
...eventsInDb,
]
.flatMap((event) => (event ? [event] : []))
.sort(
(a, b) =>
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
@@ -69,7 +72,9 @@ export async function createSessionEnd(
logger.debug('Processing session end job');
const session = await sessionBuffer.getExistingSession(payload.sessionId);
const session = await sessionBuffer.getExistingSession({
sessionId: payload.sessionId,
});
if (!session) {
throw new Error('Session not found');
@@ -86,26 +91,21 @@ export async function createSessionEnd(
});
}
const lastScreenView = await eventBuffer.getLastScreenView({
projectId: payload.projectId,
sessionId: payload.sessionId,
});
// Create session end event
return createEvent({
...payload,
properties: {
...payload.properties,
...(lastScreenView?.properties ?? {}),
...(session?.properties ?? {}),
__bounce: session.is_bounce,
},
name: 'session_end',
duration: session.duration ?? 0,
path: lastScreenView?.path ?? '',
path: session.exit_path ?? '',
createdAt: new Date(
convertClickhouseDateToJs(session.ended_at).getTime() + 100,
convertClickhouseDateToJs(session.ended_at).getTime() + 1000,
),
profileId: lastScreenView?.profileId || payload.profileId,
profileId: session.profile_id || payload.profileId,
});
}