From a169995d0899240dbf09054ad76bae9bd529156e Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 13 Jul 2025 15:42:25 +0200 Subject: [PATCH 1/8] Install PostHog --- .env.example | 4 ++++ package.json | 1 + pnpm-lock.yaml | 41 +++++++++++++++++++++++++++++++++++++++++ src/env.js | 6 ++++-- 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index e9b7b09..d297e7c 100644 --- a/.env.example +++ b/.env.example @@ -22,3 +22,7 @@ CLERK_SECRET_KEY=some-secret-key # Uploadthing UPLOADTHING_TOKEN='uploadthing-token' + +# Posthog +NEXT_PUBLIC_POSTHOG_KEY=some-posthog-key +NEXT_PUBLIC_POSTHOG_HOST=the-posthog-host diff --git a/package.json b/package.json index 527b754..db12f6d 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "lucide-react": "^0.511.0", "mysql2": "^3.14.1", "next": "^15.2.3", + "posthog-js": "^1.257.0", "react": "^19.0.0", "react-dom": "^19.0.0", "tailwind-merge": "^3.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0de454c..9ebd051 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,6 +41,9 @@ importers: next: specifier: ^15.2.3 version: 15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + posthog-js: + specifier: ^1.257.0 + version: 1.257.0 react: specifier: ^19.0.0 version: 19.1.0 @@ -1281,6 +1284,9 @@ packages: resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} engines: {node: '>=18'} + core-js@3.44.0: + resolution: {integrity: sha512-aFCtd4l6GvAXwVEh3XbbVqJGHDJt0OZRa+5ePGx3LLwi12WfexqQxcsohb2wgsa/92xtl19Hd66G/L+TaAxDMw==} + cors@2.8.5: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} @@ -1717,6 +1723,9 @@ packages: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} + fflate@0.4.8: + resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -2374,6 +2383,20 @@ packages: resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} + posthog-js@1.257.0: + resolution: {integrity: sha512-Ujg9RGtWVCu+4tmlRpALSy2ZOZI6JtieSYXIDDdgMWm167KYKvTtbMPHdoBaPWcNu0Km+1hAIBnQFygyn30KhA==} + peerDependencies: + '@rrweb/types': 2.0.0-alpha.17 + rrweb-snapshot: 2.0.0-alpha.17 + peerDependenciesMeta: + '@rrweb/types': + optional: true + rrweb-snapshot: + optional: true + + preact@10.26.9: + resolution: {integrity: sha512-SSjF9vcnF27mJK1XyFMNJzFd5u3pQiATFqoaDy03XuN00u4ziveVVEGt5RKJrDR8MHE/wJo9Nnad56RLzS2RMA==} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -2835,6 +2858,9 @@ packages: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} + web-vitals@4.2.4: + resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} + which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} @@ -3879,6 +3905,8 @@ snapshots: cookie@1.0.2: {} + core-js@3.44.0: {} + cors@2.8.5: dependencies: object-assign: 4.1.1 @@ -4441,6 +4469,8 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 3.3.3 + fflate@0.4.8: {} + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -5106,6 +5136,15 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + posthog-js@1.257.0: + dependencies: + core-js: 3.44.0 + fflate: 0.4.8 + preact: 10.26.9 + web-vitals: 4.2.4 + + preact@10.26.9: {} + prelude-ls@1.2.1: {} prettier-plugin-tailwindcss@0.6.11(prettier@3.5.3): @@ -5607,6 +5646,8 @@ snapshots: web-streams-polyfill@3.3.3: {} + web-vitals@4.2.4: {} + which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 diff --git a/src/env.js b/src/env.js index 9f7c80d..1aedd71 100644 --- a/src/env.js +++ b/src/env.js @@ -23,7 +23,8 @@ export const env = createEnv({ * `NEXT_PUBLIC_`. */ client: { - // NEXT_PUBLIC_CLIENTVAR: z.string(), + NEXT_PUBLIC_POSTHOG_KEY: z.string(), + NEXT_PUBLIC_POSTHOG_HOST: z.string(), }, /** @@ -37,7 +38,8 @@ export const env = createEnv({ SINGLESTORE_HOST: process.env.SINGLESTORE_HOST, SINGLESTORE_PORT: process.env.SINGLESTORE_PORT, SINGLESTORE_DATABASE: process.env.SINGLESTORE_DATABASE, - // NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR, + NEXT_PUBLIC_POSTHOG_KEY: process.env.NEXT_PUBLIC_POSTHOG_KEY, + NEXT_PUBLIC_POSTHOG_HOST: process.env.NEXT_PUBLIC_POSTHOG_HOST, }, /** * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially From 1d9311b8fe629abfaa6799c6e026bdc7f9388e2f Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 13 Jul 2025 15:50:22 +0200 Subject: [PATCH 2/8] Restructure App Folder --- src/app/{ => (home)}/page.tsx | 0 src/app/f/[folderId]/page.tsx | 2 +- src/app/{ => f}/drive-contents.tsx | 0 src/app/{ => f}/file-row.tsx | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename src/app/{ => (home)}/page.tsx (100%) rename src/app/{ => f}/drive-contents.tsx (100%) rename src/app/{ => f}/file-row.tsx (100%) diff --git a/src/app/page.tsx b/src/app/(home)/page.tsx similarity index 100% rename from src/app/page.tsx rename to src/app/(home)/page.tsx diff --git a/src/app/f/[folderId]/page.tsx b/src/app/f/[folderId]/page.tsx index f788a9b..2b189b9 100644 --- a/src/app/f/[folderId]/page.tsx +++ b/src/app/f/[folderId]/page.tsx @@ -2,7 +2,7 @@ import { z } from "zod"; import * as queries from "~/server/db/queries"; -import DriveContents from "../../drive-contents"; +import DriveContents from "../drive-contents"; export default async function GoogleDriveClone(props: { params: Promise<{ folderId: number }>; diff --git a/src/app/drive-contents.tsx b/src/app/f/drive-contents.tsx similarity index 100% rename from src/app/drive-contents.tsx rename to src/app/f/drive-contents.tsx diff --git a/src/app/file-row.tsx b/src/app/f/file-row.tsx similarity index 100% rename from src/app/file-row.tsx rename to src/app/f/file-row.tsx From 4451770cef6e07447be69c8909ab39cf598433da Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 16 Jul 2025 08:32:45 +0200 Subject: [PATCH 3/8] Adding a PostHog Provider --- src/app/_providers/posthog-provider.tsx | 19 +++++++++++++++++++ src/app/layout.tsx | 14 +++++++++----- 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 src/app/_providers/posthog-provider.tsx diff --git a/src/app/_providers/posthog-provider.tsx b/src/app/_providers/posthog-provider.tsx new file mode 100644 index 0000000..fb11971 --- /dev/null +++ b/src/app/_providers/posthog-provider.tsx @@ -0,0 +1,19 @@ +"use client"; + +import { useEffect } from "react"; +import posthog from "posthog-js"; +import { PostHogProvider as PHProvider } from "posthog-js/react"; + +import { env } from "~/env"; + +export function PostHogProvider({ children }: { children: React.ReactNode }) { + useEffect(() => { + posthog.init(env.NEXT_PUBLIC_POSTHOG_KEY, { + api_host: env.NEXT_PUBLIC_POSTHOG_HOST, + person_profiles: "identified_only", // or 'always' to create profiles for anonymous users as well + defaults: "2025-05-24", + }); + }, []); + + return {children}; +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index d442c0e..7aa0a8a 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,9 +1,11 @@ -import "~/styles/globals.css"; - import { ClerkProvider } from "@clerk/nextjs"; import { type Metadata } from "next"; import { Geist } from "next/font/google"; +import { PostHogProvider } from "./_providers/posthog-provider"; + +import "~/styles/globals.css"; + export const metadata: Metadata = { title: "Drive Tutorial", description: "It's like Google Drive, but worse!", @@ -20,9 +22,11 @@ export default function RootLayout({ }: Readonly<{ children: React.ReactNode }>) { return ( - - {children} - + + + {children} + + ); } From 0a3b2692b639c13296b3a9d0e7ad87027165e250 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 16 Jul 2025 08:36:44 +0200 Subject: [PATCH 4/8] Setting Up a Reverse Proxy --- next.config.js | 18 ++++++++++++++++++ src/app/_providers/posthog-provider.tsx | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/next.config.js b/next.config.js index 952eb1e..a41ea8c 100644 --- a/next.config.js +++ b/next.config.js @@ -8,6 +8,24 @@ import "./src/env.js"; const config = { eslint: { ignoreDuringBuilds: true }, typescript: { ignoreBuildErrors: true }, + + async rewrites() { + return [ + { + source: "/relay-BxMI/static/:path*", + destination: "https://us-assets.i.posthog.com/static/:path*", + }, + { + source: "/relay-BxMI/:path*", + destination: "https://us.i.posthog.com/:path*", + }, + { + source: "/relay-BxMI/flags", + destination: "https://us.i.posthog.com/flags", + }, + ]; + }, + skipTrailingSlashRedirect: true, // This is required to support PostHog trailing slash API requests }; export default config; diff --git a/src/app/_providers/posthog-provider.tsx b/src/app/_providers/posthog-provider.tsx index fb11971..5d4244e 100644 --- a/src/app/_providers/posthog-provider.tsx +++ b/src/app/_providers/posthog-provider.tsx @@ -9,7 +9,8 @@ import { env } from "~/env"; export function PostHogProvider({ children }: { children: React.ReactNode }) { useEffect(() => { posthog.init(env.NEXT_PUBLIC_POSTHOG_KEY, { - api_host: env.NEXT_PUBLIC_POSTHOG_HOST, + api_host: "/relay-BxMI", + ui_host: env.NEXT_PUBLIC_POSTHOG_HOST, person_profiles: "identified_only", // or 'always' to create profiles for anonymous users as well defaults: "2025-05-24", }); From 42d830889a1f23169dd4619768bc1337127fb6a3 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 17 Jul 2025 07:54:11 +0200 Subject: [PATCH 5/8] User Identification --- src/app/_providers/posthog-provider.tsx | 11 +++++++++-- src/app/_providers/user-identification.tsx | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 src/app/_providers/user-identification.tsx diff --git a/src/app/_providers/posthog-provider.tsx b/src/app/_providers/posthog-provider.tsx index 5d4244e..92ece3b 100644 --- a/src/app/_providers/posthog-provider.tsx +++ b/src/app/_providers/posthog-provider.tsx @@ -1,8 +1,10 @@ "use client"; -import { useEffect } from "react"; import posthog from "posthog-js"; import { PostHogProvider as PHProvider } from "posthog-js/react"; +import { useEffect } from "react"; + +import UserIdentification from "./user-identification"; import { env } from "~/env"; @@ -16,5 +18,10 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) { }); }, []); - return {children}; + return ( + + + {children} + + ); } diff --git a/src/app/_providers/user-identification.tsx b/src/app/_providers/user-identification.tsx new file mode 100644 index 0000000..5c1d02b --- /dev/null +++ b/src/app/_providers/user-identification.tsx @@ -0,0 +1,20 @@ +import { useUser } from "@clerk/nextjs"; +import { usePostHog } from "posthog-js/react"; +import { useEffect } from "react"; + +export default function UserIdentification() { + const posthog = usePostHog(); + const { user } = useUser(); + + useEffect(() => { + if (user) { + posthog.identify(user.id, { + email: user.emailAddresses[0]?.emailAddress, + }); + } else { + posthog.reset(); + } + }, [posthog, user]); + + return null; // Do not render anything +} From 04b5623dcd3b7fd88c1768aae98ce39a653cc105 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 17 Jul 2025 08:15:09 +0200 Subject: [PATCH 6/8] Fix PostHog on Netlify --- netlify.toml | 13 +++++++++++++ next.config.js | 18 ------------------ 2 files changed, 13 insertions(+), 18 deletions(-) create mode 100644 netlify.toml diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000..fa67400 --- /dev/null +++ b/netlify.toml @@ -0,0 +1,13 @@ +[[redirects]] + from = "/ingest/static/*" + to = "https://us-assets.i.posthog.com/static/:splat" + host = "us-assets.i.posthog.com" + status = 200 + force = true + +[[redirects]] + from = "/ingest/*" + to = "https://us.i.posthog.com/:splat" + host = "us.i.posthog.com" + status = 200 + force = true diff --git a/next.config.js b/next.config.js index a41ea8c..952eb1e 100644 --- a/next.config.js +++ b/next.config.js @@ -8,24 +8,6 @@ import "./src/env.js"; const config = { eslint: { ignoreDuringBuilds: true }, typescript: { ignoreBuildErrors: true }, - - async rewrites() { - return [ - { - source: "/relay-BxMI/static/:path*", - destination: "https://us-assets.i.posthog.com/static/:path*", - }, - { - source: "/relay-BxMI/:path*", - destination: "https://us.i.posthog.com/:path*", - }, - { - source: "/relay-BxMI/flags", - destination: "https://us.i.posthog.com/flags", - }, - ]; - }, - skipTrailingSlashRedirect: true, // This is required to support PostHog trailing slash API requests }; export default config; From a3210b91a95c37b096f02ef4ad932f6629d2e97f Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 17 Jul 2025 08:16:32 +0200 Subject: [PATCH 7/8] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a7dea1f..354734d 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Tracking progress on key features and tasks for the project. - [x] 🔗 Sync folder open state with the URL - [x] 🔐 Implement user authentication - [x] 📁 Enable file upload functionality -- [ ] 📊 Add analytics tracking +- [x] 📊 Add analytics tracking ### 📝 Note from 5-28-2025 From 906c3856f5b67a67c6723c7c78c6be965b2320ac Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 17 Jul 2025 08:20:08 +0200 Subject: [PATCH 8/8] Correct PostHog Config --- src/app/_providers/posthog-provider.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/_providers/posthog-provider.tsx b/src/app/_providers/posthog-provider.tsx index 92ece3b..7177df8 100644 --- a/src/app/_providers/posthog-provider.tsx +++ b/src/app/_providers/posthog-provider.tsx @@ -11,8 +11,7 @@ import { env } from "~/env"; export function PostHogProvider({ children }: { children: React.ReactNode }) { useEffect(() => { posthog.init(env.NEXT_PUBLIC_POSTHOG_KEY, { - api_host: "/relay-BxMI", - ui_host: env.NEXT_PUBLIC_POSTHOG_HOST, + api_host: env.NEXT_PUBLIC_POSTHOG_HOST, person_profiles: "identified_only", // or 'always' to create profiles for anonymous users as well defaults: "2025-05-24", });