Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 33 additions & 4 deletions .github/workflows/deploy-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ jobs:
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
NEXT_PUBLIC_COOKIE_DOMAIN: ${{ secrets.NEXT_PUBLIC_COOKIE_DOMAIN }}
NEXT_PUBLIC_POSTHOG_KEY: ${{ secrets.NEXT_PUBLIC_POSTHOG_KEY }}
NEXT_PUBLIC_POSTHOG_HOST: ${{ secrets.NEXT_PUBLIC_POSTHOG_HOST }}
DESKTOP_AUTH_SECRET: ${{ secrets.DESKTOP_AUTH_SECRET }}
run: |
vercel pull --yes --environment=preview --token=$VERCEL_TOKEN
Expand All @@ -217,7 +219,14 @@ jobs:
--env CLERK_SECRET_KEY=$CLERK_SECRET_KEY \
--env DATABASE_URL=$DATABASE_URL \
--env DATABASE_URL_UNPOOLED=$DATABASE_URL_UNPOOLED \
--env DESKTOP_AUTH_SECRET=$DESKTOP_AUTH_SECRET)
--env DESKTOP_AUTH_SECRET=$DESKTOP_AUTH_SECRET \
--env NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL \
--env NEXT_PUBLIC_MARKETING_URL=$NEXT_PUBLIC_MARKETING_URL \
--env NEXT_PUBLIC_DOCS_URL=$NEXT_PUBLIC_DOCS_URL \
--env NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=$NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY \
--env NEXT_PUBLIC_COOKIE_DOMAIN=$NEXT_PUBLIC_COOKIE_DOMAIN \
--env NEXT_PUBLIC_POSTHOG_KEY=$NEXT_PUBLIC_POSTHOG_KEY \
--env NEXT_PUBLIC_POSTHOG_HOST=$NEXT_PUBLIC_POSTHOG_HOST)
vercel alias $VERCEL_URL ${{ env.WEB_ALIAS }} --scope=$VERCEL_ORG_ID --token=$VERCEL_TOKEN
echo "vercel_url=$VERCEL_URL" >> $GITHUB_OUTPUT

Expand Down Expand Up @@ -272,11 +281,19 @@ jobs:
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
NEXT_PUBLIC_COOKIE_DOMAIN: ${{ secrets.NEXT_PUBLIC_COOKIE_DOMAIN }}
NEXT_PUBLIC_POSTHOG_KEY: ${{ secrets.NEXT_PUBLIC_POSTHOG_KEY }}
NEXT_PUBLIC_POSTHOG_HOST: ${{ secrets.NEXT_PUBLIC_POSTHOG_HOST }}
run: |
vercel pull --yes --environment=preview --token=$VERCEL_TOKEN
vercel build --token=$VERCEL_TOKEN
VERCEL_URL=$(vercel deploy --prebuilt --token=$VERCEL_TOKEN \
--env CLERK_SECRET_KEY=$CLERK_SECRET_KEY)
--env CLERK_SECRET_KEY=$CLERK_SECRET_KEY \
--env NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL \
--env NEXT_PUBLIC_WEB_URL=$NEXT_PUBLIC_WEB_URL \
--env NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=$NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY \
--env NEXT_PUBLIC_COOKIE_DOMAIN=$NEXT_PUBLIC_COOKIE_DOMAIN \
--env NEXT_PUBLIC_POSTHOG_KEY=$NEXT_PUBLIC_POSTHOG_KEY \
--env NEXT_PUBLIC_POSTHOG_HOST=$NEXT_PUBLIC_POSTHOG_HOST)
vercel alias $VERCEL_URL ${{ env.MARKETING_ALIAS }} --scope=$VERCEL_ORG_ID --token=$VERCEL_TOKEN
echo "vercel_url=$VERCEL_URL" >> $GITHUB_OUTPUT

Expand Down Expand Up @@ -344,13 +361,21 @@ jobs:
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
NEXT_PUBLIC_COOKIE_DOMAIN: ${{ secrets.NEXT_PUBLIC_COOKIE_DOMAIN }}
NEXT_PUBLIC_POSTHOG_KEY: ${{ secrets.NEXT_PUBLIC_POSTHOG_KEY }}
NEXT_PUBLIC_POSTHOG_HOST: ${{ secrets.NEXT_PUBLIC_POSTHOG_HOST }}
run: |
vercel pull --yes --environment=preview --token=$VERCEL_TOKEN
vercel build --token=$VERCEL_TOKEN
VERCEL_URL=$(vercel deploy --prebuilt --token=$VERCEL_TOKEN \
--env CLERK_SECRET_KEY=$CLERK_SECRET_KEY \
--env DATABASE_URL=$DATABASE_URL \
--env DATABASE_URL_UNPOOLED=$DATABASE_URL_UNPOOLED)
--env DATABASE_URL_UNPOOLED=$DATABASE_URL_UNPOOLED \
--env NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL \
--env NEXT_PUBLIC_WEB_URL=$NEXT_PUBLIC_WEB_URL \
--env NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=$NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY \
--env NEXT_PUBLIC_COOKIE_DOMAIN=$NEXT_PUBLIC_COOKIE_DOMAIN \
--env NEXT_PUBLIC_POSTHOG_KEY=$NEXT_PUBLIC_POSTHOG_KEY \
--env NEXT_PUBLIC_POSTHOG_HOST=$NEXT_PUBLIC_POSTHOG_HOST)
vercel alias $VERCEL_URL ${{ env.ADMIN_ALIAS }} --scope=$VERCEL_ORG_ID --token=$VERCEL_TOKEN
echo "vercel_url=$VERCEL_URL" >> $GITHUB_OUTPUT

Expand Down Expand Up @@ -403,10 +428,14 @@ jobs:
NEXT_PUBLIC_API_URL: https://${{ env.API_ALIAS }}
NEXT_PUBLIC_WEB_URL: https://${{ env.WEB_ALIAS }}
NEXT_PUBLIC_MARKETING_URL: https://${{ env.MARKETING_ALIAS }}
NEXT_PUBLIC_POSTHOG_KEY: ${{ secrets.NEXT_PUBLIC_POSTHOG_KEY }}
NEXT_PUBLIC_POSTHOG_HOST: ${{ secrets.NEXT_PUBLIC_POSTHOG_HOST }}
run: |
vercel pull --yes --environment=preview --token=$VERCEL_TOKEN
vercel build --token=$VERCEL_TOKEN
VERCEL_URL=$(vercel deploy --prebuilt --token=$VERCEL_TOKEN)
VERCEL_URL=$(vercel deploy --prebuilt --token=$VERCEL_TOKEN \
--env NEXT_PUBLIC_POSTHOG_KEY=$NEXT_PUBLIC_POSTHOG_KEY \
--env NEXT_PUBLIC_POSTHOG_HOST=$NEXT_PUBLIC_POSTHOG_HOST)
vercel alias $VERCEL_URL ${{ env.DOCS_ALIAS }} --scope=$VERCEL_ORG_ID --token=$VERCEL_TOKEN
echo "vercel_url=$VERCEL_URL" >> $GITHUB_OUTPUT

Expand Down
37 changes: 33 additions & 4 deletions .github/workflows/deploy-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ jobs:
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
NEXT_PUBLIC_COOKIE_DOMAIN: ${{ secrets.NEXT_PUBLIC_COOKIE_DOMAIN }}
NEXT_PUBLIC_POSTHOG_KEY: ${{ secrets.NEXT_PUBLIC_POSTHOG_KEY }}
NEXT_PUBLIC_POSTHOG_HOST: ${{ secrets.NEXT_PUBLIC_POSTHOG_HOST }}
DESKTOP_AUTH_SECRET: ${{ secrets.DESKTOP_AUTH_SECRET }}
run: |
vercel pull --yes --environment=production --token=$VERCEL_TOKEN
Expand All @@ -141,7 +143,14 @@ jobs:
--env CLERK_SECRET_KEY=$CLERK_SECRET_KEY \
--env DATABASE_URL=$DATABASE_URL \
--env DATABASE_URL_UNPOOLED=$DATABASE_URL_UNPOOLED \
--env DESKTOP_AUTH_SECRET=$DESKTOP_AUTH_SECRET
--env DESKTOP_AUTH_SECRET=$DESKTOP_AUTH_SECRET \
--env NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL \
--env NEXT_PUBLIC_MARKETING_URL=$NEXT_PUBLIC_MARKETING_URL \
--env NEXT_PUBLIC_DOCS_URL=$NEXT_PUBLIC_DOCS_URL \
--env NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=$NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY \
--env NEXT_PUBLIC_COOKIE_DOMAIN=$NEXT_PUBLIC_COOKIE_DOMAIN \
--env NEXT_PUBLIC_POSTHOG_KEY=$NEXT_PUBLIC_POSTHOG_KEY \
--env NEXT_PUBLIC_POSTHOG_HOST=$NEXT_PUBLIC_POSTHOG_HOST

deploy-marketing:
name: Deploy Marketing to Vercel
Expand Down Expand Up @@ -180,11 +189,19 @@ jobs:
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
NEXT_PUBLIC_COOKIE_DOMAIN: ${{ secrets.NEXT_PUBLIC_COOKIE_DOMAIN }}
NEXT_PUBLIC_POSTHOG_KEY: ${{ secrets.NEXT_PUBLIC_POSTHOG_KEY }}
NEXT_PUBLIC_POSTHOG_HOST: ${{ secrets.NEXT_PUBLIC_POSTHOG_HOST }}
run: |
vercel pull --yes --environment=production --token=$VERCEL_TOKEN
vercel build --prod --token=$VERCEL_TOKEN
vercel deploy --prod --prebuilt --token=$VERCEL_TOKEN \
--env CLERK_SECRET_KEY=$CLERK_SECRET_KEY
--env CLERK_SECRET_KEY=$CLERK_SECRET_KEY \
--env NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL \
--env NEXT_PUBLIC_WEB_URL=$NEXT_PUBLIC_WEB_URL \
--env NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=$NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY \
--env NEXT_PUBLIC_COOKIE_DOMAIN=$NEXT_PUBLIC_COOKIE_DOMAIN \
--env NEXT_PUBLIC_POSTHOG_KEY=$NEXT_PUBLIC_POSTHOG_KEY \
--env NEXT_PUBLIC_POSTHOG_HOST=$NEXT_PUBLIC_POSTHOG_HOST

deploy-admin:
name: Deploy Admin to Vercel
Expand Down Expand Up @@ -225,13 +242,21 @@ jobs:
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
NEXT_PUBLIC_COOKIE_DOMAIN: ${{ secrets.NEXT_PUBLIC_COOKIE_DOMAIN }}
NEXT_PUBLIC_POSTHOG_KEY: ${{ secrets.NEXT_PUBLIC_POSTHOG_KEY }}
NEXT_PUBLIC_POSTHOG_HOST: ${{ secrets.NEXT_PUBLIC_POSTHOG_HOST }}
run: |
vercel pull --yes --environment=production --token=$VERCEL_TOKEN
vercel build --prod --token=$VERCEL_TOKEN
vercel deploy --prod --prebuilt --token=$VERCEL_TOKEN \
--env CLERK_SECRET_KEY=$CLERK_SECRET_KEY \
--env DATABASE_URL=$DATABASE_URL \
--env DATABASE_URL_UNPOOLED=$DATABASE_URL_UNPOOLED
--env DATABASE_URL_UNPOOLED=$DATABASE_URL_UNPOOLED \
--env NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL \
--env NEXT_PUBLIC_WEB_URL=$NEXT_PUBLIC_WEB_URL \
--env NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=$NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY \
--env NEXT_PUBLIC_COOKIE_DOMAIN=$NEXT_PUBLIC_COOKIE_DOMAIN \
--env NEXT_PUBLIC_POSTHOG_KEY=$NEXT_PUBLIC_POSTHOG_KEY \
--env NEXT_PUBLIC_POSTHOG_HOST=$NEXT_PUBLIC_POSTHOG_HOST

deploy-docs:
name: Deploy Docs to Vercel
Expand Down Expand Up @@ -268,7 +293,11 @@ jobs:
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
NEXT_PUBLIC_WEB_URL: ${{ secrets.NEXT_PUBLIC_WEB_URL }}
NEXT_PUBLIC_MARKETING_URL: ${{ secrets.NEXT_PUBLIC_MARKETING_URL }}
NEXT_PUBLIC_POSTHOG_KEY: ${{ secrets.NEXT_PUBLIC_POSTHOG_KEY }}
NEXT_PUBLIC_POSTHOG_HOST: ${{ secrets.NEXT_PUBLIC_POSTHOG_HOST }}
run: |
vercel pull --yes --environment=production --token=$VERCEL_TOKEN
vercel build --prod --token=$VERCEL_TOKEN
vercel deploy --prod --prebuilt --token=$VERCEL_TOKEN
vercel deploy --prod --prebuilt --token=$VERCEL_TOKEN \
--env NEXT_PUBLIC_POSTHOG_KEY=$NEXT_PUBLIC_POSTHOG_KEY \
--env NEXT_PUBLIC_POSTHOG_HOST=$NEXT_PUBLIC_POSTHOG_HOST
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Bun + Turbo monorepo with:
- **Database**: Drizzle ORM + Neon PostgreSQL
- **UI**: React + TailwindCSS v4 + shadcn/ui
- **Code Quality**: Biome (formatting + linting at root)
- **Next.js**: Version 16 - NEVER create `middleware.ts`. Next.js 16 renamed middleware to `proxy.ts`. Always use `proxy.ts` for request interception.

## Common Commands

Expand Down
19 changes: 19 additions & 0 deletions apps/admin/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,25 @@ if (process.env.NODE_ENV !== "production") {
const config: NextConfig = {
reactCompiler: true,
typescript: { ignoreBuildErrors: true },

async rewrites() {
return [
{
source: "/ingest/static/:path*",
destination: "https://us-assets.i.posthog.com/static/:path*",
},
{
source: "/ingest/:path*",
destination: "https://us.i.posthog.com/:path*",
},
{
source: "/ingest/decide",
destination: "https://us.i.posthog.com/decide",
},
];
},

skipTrailingSlashRedirect: true,
};

export default config;
1 change: 1 addition & 0 deletions apps/admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"date-fns": "^4.1.0",
"next": "^16.0.10",
"next-themes": "^0.4.6",
"posthog-js": "^1.306.1",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"react-icons": "^5.5.0",
Expand Down
31 changes: 19 additions & 12 deletions apps/admin/src/app/providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,29 @@
import { THEME_STORAGE_KEY } from "@superset/shared/constants";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { ThemeProvider } from "next-themes";
import posthog from "posthog-js";
import { PostHogProvider } from "posthog-js/react";

import { PostHogUserIdentifier } from "@/components/PostHogUserIdentifier";

import { TRPCReactProvider } from "../trpc/react";

export function Providers({ children }: { children: React.ReactNode }) {
return (
<TRPCReactProvider>
<ThemeProvider
attribute="class"
defaultTheme="dark"
forcedTheme="dark"
storageKey={THEME_STORAGE_KEY}
disableTransitionOnChange
>
{children}
<ReactQueryDevtools initialIsOpen={false} />
</ThemeProvider>
</TRPCReactProvider>
<PostHogProvider client={posthog}>
<TRPCReactProvider>
<ThemeProvider
attribute="class"
defaultTheme="dark"
forcedTheme="dark"
storageKey={THEME_STORAGE_KEY}
disableTransitionOnChange
>
<PostHogUserIdentifier />
{children}
<ReactQueryDevtools initialIsOpen={false} />
</ThemeProvider>
</TRPCReactProvider>
</PostHogProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"use client";

import { useUser } from "@clerk/nextjs";
import posthog from "posthog-js";
import { useEffect } from "react";

export function PostHogUserIdentifier() {
const { user, isLoaded } = useUser();

useEffect(() => {
if (!isLoaded) return;

if (user) {
posthog.identify(user.id, {
email: user.primaryEmailAddress?.emailAddress,
name: user.fullName,
});
} else {
posthog.reset();
}
}, [user, isLoaded]);

return null;
}
1 change: 1 addition & 0 deletions apps/admin/src/components/PostHogUserIdentifier/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { PostHogUserIdentifier } from "./PostHogUserIdentifier";
4 changes: 4 additions & 0 deletions apps/admin/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export const env = createEnv({
NEXT_PUBLIC_WEB_URL: z.string().url(),
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string(),
NEXT_PUBLIC_COOKIE_DOMAIN: z.string(),
NEXT_PUBLIC_POSTHOG_KEY: z.string(),
NEXT_PUBLIC_POSTHOG_HOST: z.string().url(),
},

experimental__runtimeEnv: {
Expand All @@ -30,6 +32,8 @@ export const env = createEnv({
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY:
process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
NEXT_PUBLIC_COOKIE_DOMAIN: process.env.NEXT_PUBLIC_COOKIE_DOMAIN,
NEXT_PUBLIC_POSTHOG_KEY: process.env.NEXT_PUBLIC_POSTHOG_KEY,
NEXT_PUBLIC_POSTHOG_HOST: process.env.NEXT_PUBLIC_POSTHOG_HOST,
},

skipValidation: !!process.env.SKIP_ENV_VALIDATION,
Expand Down
23 changes: 23 additions & 0 deletions apps/admin/src/instrumentation-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { POSTHOG_COOKIE_NAME } from "@superset/shared/constants";
import posthog from "posthog-js";

import { env } from "@/env";

posthog.init(env.NEXT_PUBLIC_POSTHOG_KEY, {
api_host: "/ingest",
ui_host: "https://us.posthog.com",
defaults: "2025-11-30",
capture_pageview: "history_change",
capture_pageleave: true,
capture_exceptions: true,
debug: env.NODE_ENV === "development",
cross_subdomain_cookie: true,
persistence: "cookie",
persistence_name: POSTHOG_COOKIE_NAME,
loaded: (posthog) => {
posthog.register({
app_name: "admin",
domain: window.location.hostname,
});
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useEffect } from "react";
import { trpc } from "renderer/lib/trpc";

import { posthog } from "../../lib/posthog";

export function PostHogUserIdentifier() {
const { data: user, isLoading } = trpc.user.me.useQuery();

useEffect(() => {
if (isLoading) return;

if (user) {
posthog.identify(user.id, {
email: user.email,
name: user.name,
});
} else {
posthog.reset();
}
}, [user, isLoading]);

return null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { PostHogUserIdentifier } from "./PostHogUserIdentifier";
2 changes: 2 additions & 0 deletions apps/desktop/src/renderer/contexts/AppProviders.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type React from "react";
import { PostHogUserIdentifier } from "renderer/components/PostHogUserIdentifier";
import { MonacoProvider } from "./MonacoProvider";
import { PostHogProvider } from "./PostHogProvider";
import { TRPCProvider } from "./TRPCProvider";
Expand All @@ -11,6 +12,7 @@ export function AppProviders({ children }: AppProvidersProps) {
return (
<PostHogProvider>
<TRPCProvider>
<PostHogUserIdentifier />
<MonacoProvider>{children}</MonacoProvider>
</TRPCProvider>
</PostHogProvider>
Expand Down
Loading