diff --git a/next.config.ts b/next.config.ts index 070eba635..ab7fbf484 100644 --- a/next.config.ts +++ b/next.config.ts @@ -6,6 +6,8 @@ const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts'); const TRACKER_SCRIPT = '/script.js'; +const isProd = process.env.NODE_ENV === 'production'; + const basePath = process.env.BASE_PATH || ''; const cloudMode = process.env.CLOUD_MODE || ''; const cloudUrl = process.env.CLOUD_URL || ''; @@ -17,6 +19,8 @@ const forceSSL = process.env.FORCE_SSL || ''; const frameAncestors = process.env.ALLOWED_FRAME_URLS || ''; const trackerScriptName = process.env.TRACKER_SCRIPT_NAME || ''; const trackerScriptURL = process.env.TRACKER_SCRIPT_URL || ''; +const selfTrack = process.env.UMAMI_SELF_TRACK || ''; +const selfRecord = process.env.UMAMI_SELF_RECORD || ''; const contentSecurityPolicy = ` default-src 'self'; @@ -88,11 +92,14 @@ const headers = [ source: '/:path*', headers: defaultHeaders, }, - { +]; + +if (isProd) { + headers.push({ source: TRACKER_SCRIPT, headers: trackerHeaders, - }, -]; + }); +} const rewrites = []; @@ -169,7 +176,7 @@ if (trackerScriptName) { } } -if (cloudMode) { +if (isProd && cloudMode) { rewrites.push({ source: '/script.js', destination: 'https://cloud.umami.is/script.js', @@ -186,6 +193,8 @@ export default withNextIntl({ currentVersion: pkg.version, defaultCurrency, defaultLocale, + selfTrack, + selfRecord, }, basePath, output: 'standalone', diff --git a/prisma/migrations/20_add_session_replay_visit_id/migration.sql b/prisma/migrations/20_add_session_replay_visit_id/migration.sql new file mode 100644 index 000000000..3f16db6f6 --- /dev/null +++ b/prisma/migrations/20_add_session_replay_visit_id/migration.sql @@ -0,0 +1,36 @@ +ALTER TABLE "session_replay" +ADD COLUMN IF NOT EXISTS "visit_id" UUID; + +UPDATE "session_replay" AS sr +SET "visit_id" = we."visit_id" +FROM ( + SELECT DISTINCT ON ("website_id", "session_id") + "website_id", + "session_id", + "visit_id" + FROM "website_event" + WHERE "visit_id" IS NOT NULL + ORDER BY "website_id", "session_id", "created_at" DESC +) AS we +WHERE sr."visit_id" IS NULL + AND sr."website_id" = we."website_id" + AND sr."session_id" = we."session_id"; + +UPDATE "session_replay" +SET "visit_id" = ( + substr(md5("session_id"::text || ':' || "chunk_index"::text), 1, 8) || + '-' || + substr(md5("session_id"::text || ':' || "chunk_index"::text), 9, 4) || + '-' || + substr(md5("session_id"::text || ':' || "chunk_index"::text), 13, 4) || + '-' || + substr(md5("session_id"::text || ':' || "chunk_index"::text), 17, 4) || + '-' || + substr(md5("session_id"::text || ':' || "chunk_index"::text), 21, 12) +)::uuid +WHERE "visit_id" IS NULL; + +ALTER TABLE "session_replay" +ALTER COLUMN "visit_id" SET NOT NULL; + +CREATE INDEX IF NOT EXISTS "session_replay_visit_id_idx" ON "session_replay"("visit_id"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index bcb6a86b3..92cdc649b 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -385,6 +385,7 @@ model SessionReplay { id String @id() @map("replay_id") @db.Uuid websiteId String @map("website_id") @db.Uuid sessionId String @map("session_id") @db.Uuid + visitId String @map("visit_id") @db.Uuid chunkIndex Int @map("chunk_index") @db.Integer events Bytes @map("events") eventCount Int @map("event_count") @db.Integer @@ -396,6 +397,7 @@ model SessionReplay { @@index([websiteId]) @@index([sessionId]) + @@index([visitId]) @@index([websiteId, sessionId]) @@index([websiteId, createdAt]) @@index([sessionId, chunkIndex]) diff --git a/src/app/(main)/App.tsx b/src/app/(main)/App.tsx index 6ac744aac..162d34023 100644 --- a/src/app/(main)/App.tsx +++ b/src/app/(main)/App.tsx @@ -58,6 +58,23 @@ export function App({ children }) { {process.env.NODE_ENV === 'production' && !pathname.includes('/share/') && (