-
-
Notifications
You must be signed in to change notification settings - Fork 395
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
📈 Posthog package #1431
📈 Posthog package #1431
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
1 Skipped Deployment
|
WalkthroughThis pull request introduces significant changes to the integration of the PostHog analytics library within a Next.js application. Key modifications include updating import paths to the new Changes
Possibly related PRs
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Outside diff range and nitpick comments (41)
apps/web/src/auth/session-provider.tsx (1)
6-8
: Consider enhancing the component with documentation and optimization.While the implementation is correct, consider the following improvements:
- Add JSDoc documentation to explain the component's purpose and usage
- Memoize the component since it's likely used high in the component tree
Here's a suggested implementation:
+/** + * SessionProvider wraps next-auth's SessionProvider to manage authentication state. + * This component should be used near the root of your application. + */ -export function SessionProvider(props: SessionProviderProps) { +export const SessionProvider = React.memo(function SessionProvider( + props: SessionProviderProps, +) { return <NextAuthSessionProvider {...props} />; -} +}); + +SessionProvider.displayName = "SessionProvider";apps/web/src/app/components/logout-button.tsx (1)
Line range hint
14-21
: Add error handling for logout request.The current implementation doesn't handle potential failures in the logout request, which could lead to an inconsistent state where PostHog is reset but the user remains logged in.
Consider adding error handling:
onClick={async (e) => { onClick?.(e); - await fetch("/api/logout", { method: "POST" }); - posthog?.capture("logout"); - posthog?.reset(); - window.location.href = "/login"; + try { + const response = await fetch("/api/logout", { method: "POST" }); + if (!response.ok) { + throw new Error('Logout failed'); + } + posthog?.capture("logout"); + posthog?.reset(); + window.location.href = "/login"; + } catch (error) { + posthog?.capture("logout_error", { error: String(error) }); + // Consider showing an error message to the user + } }}packages/posthog/src/server/index.ts (2)
5-5
: Consider caching the environment check resultSince environment variables don't change during runtime, consider caching this check result to avoid repeated lookups.
+const POSTHOG_API_KEY = process.env.NEXT_PUBLIC_POSTHOG_API_KEY; +const POSTHOG_API_HOST = process.env.NEXT_PUBLIC_POSTHOG_API_HOST; function PostHogClient() { - if (!process.env.NEXT_PUBLIC_POSTHOG_API_KEY) return null; + if (!POSTHOG_API_KEY) return null; - const posthogClient = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_API_KEY, { + const posthogClient = new PostHog(POSTHOG_API_KEY, { - host: process.env.NEXT_PUBLIC_POSTHOG_API_HOST, + host: POSTHOG_API_HOST,
7-11
: Review immediate event flushing configurationThe current configuration (
flushAt: 1, flushInterval: 0
) triggers immediate event flushing. While this ensures real-time data, it might impact performance by creating more HTTP requests. Consider buffering events if real-time tracking isn't critical.const posthogClient = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_API_KEY, { host: process.env.NEXT_PUBLIC_POSTHOG_API_HOST, - flushAt: 1, - flushInterval: 0, + // Buffer up to 20 events or flush every 10 seconds + flushAt: 20, + flushInterval: 10, });packages/posthog/src/client/provider.tsx (2)
6-18
: Consider externalizing the PostHog configuration.Move the configuration object to a separate file for better maintainability and reusability.
+// posthog-config.ts +export const posthogConfig = { + debug: false, + api_host: process.env.NEXT_PUBLIC_POSTHOG_API_HOST, + capture_pageview: false, + capture_pageleave: true, + disable_session_recording: true, + enable_heatmaps: false, + persistence: "memory", + autocapture: false, + opt_out_capturing_by_default: false, +} as const; // provider.tsx +import { posthogConfig } from "./posthog-config"; if (typeof window !== "undefined" && process.env.NEXT_PUBLIC_POSTHOG_API_KEY) { - posthog.init(process.env.NEXT_PUBLIC_POSTHOG_API_KEY, { - debug: false, - api_host: process.env.NEXT_PUBLIC_POSTHOG_API_HOST, - capture_pageview: false, - capture_pageleave: true, - disable_session_recording: true, - enable_heatmaps: false, - persistence: "memory", - autocapture: false, - opt_out_capturing_by_default: false, - }); + posthog.init(process.env.NEXT_PUBLIC_POSTHOG_API_KEY, posthogConfig); }
20-22
: Add memoization and documentation to the Provider component.Consider memoizing the component and adding JSDoc documentation for better maintainability.
+/** + * PostHog analytics provider component that initializes and provides PostHog client + * to the React component tree. + * + * @param props.children - Child components that will have access to PostHog analytics + */ -export function PostHogProvider(props: { children?: React.ReactNode }) { +export const PostHogProvider = React.memo(function PostHogProvider( + props: { children?: React.ReactNode } +) { return <Provider client={posthog}>{props.children}</Provider>; -} +}); + +PostHogProvider.displayName = "PostHogProvider";apps/web/src/app/[locale]/layout.tsx (1)
33-33
: Consider adding error handling for session fetching.While the session fetching is implemented correctly, consider adding error handling to gracefully handle potential authentication service failures.
- const session = await getServerSession(); + try { + const session = await getServerSession(); + } catch (error) { + console.error("Failed to fetch session:", error); + // Provide a fallback or handle the error appropriately + const session = null; + }apps/web/src/components/upgrade-button.tsx (1)
Line range hint
28-30
: Consider enriching the analytics event with additional context.The current event tracking could be enhanced by including the subscription period (monthly/annual) and other relevant metadata to gain better insights into user preferences.
onClick={() => { - posthog?.capture("click upgrade button"); + posthog?.capture("click upgrade button", { + subscriptionPeriod: annual ? "yearly" : "monthly", + buttonSize: large ? "lg" : "default", + path: window.location.pathname + }); }}apps/web/src/pages/api/trpc/[trpc].ts (2)
Line range hint
12-16
: Consider adding global error boundaryWhile
externalResolver: true
is correct for tRPC, consider adding a global error boundary to catch and handle any unhandled errors that might occur during request processing.export const config = { api: { externalResolver: true, }, }; + +process.on('unhandledRejection', (error) => { + Sentry.captureException(error); +});
Line range hint
40-45
: Expand error handling coverageCurrent error handling only captures INTERNAL_SERVER_ERROR. Consider handling other error types:
- TIMEOUT errors for monitoring performance issues
- CONFLICT errors for concurrent operations
- FORBIDDEN errors for security monitoring
onError({ error }) { - if (error.code === "INTERNAL_SERVER_ERROR") { + if (["INTERNAL_SERVER_ERROR", "TIMEOUT", "FORBIDDEN"].includes(error.code)) { Sentry.captureException(error); } + // Log non-critical errors for monitoring + console.error(`[${error.code}] ${error.message}`); },apps/web/src/components/poll/manage-poll/delete-poll-dialog.tsx (1)
Line range hint
24-31
: Consider enriching analytics data for better insights.While the basic event tracking is good, consider adding more context to the "deleted poll" event to gain better insights into user behavior.
queryClient.polls.invalidate(); - posthog?.capture("deleted poll"); + posthog?.capture("deleted poll", { + pollId: urlId, + // Add any non-PII metadata that could be useful for analytics + }); onOpenChange(false); router.replace("/polls");apps/web/src/app/[locale]/poll/[urlId]/duplicate-dialog.tsx (1)
Line range hint
48-54
: Consider enhancing error tracking and PostHog initialization handling.
- Consider tracking failed duplications to monitor error rates:
- Add a fallback for when PostHog isn't initialized
onSuccess: async (res) => { posthog?.capture("duplicate poll", { pollId, newPollId: res.id, }); queryClient.invalidate(); router.push(`/poll/${res.id}`); }, + onError: (error) => { + posthog?.capture("duplicate poll failed", { + pollId, + error: error.message, + }); + },Also consider adding a debug log when PostHog isn't initialized:
-posthog?.capture("duplicate poll", { +if (posthog) { + posthog.capture("duplicate poll", { pollId, newPollId: res.id, }); +} else { + console.debug('PostHog not initialized, skipping event tracking'); +}apps/web/src/app/[locale]/auth/login/login-page.tsx (2)
Line range hint
31-39
: Add error handling for PostHog identificationThe PostHog identification is performed without error handling, which could silently fail. Consider wrapping the identification in a try-catch block and logging any failures.
if (updatedSession) { + try { // identify the user in posthog posthog?.identify(updatedSession.user.id, { email: updatedSession.user.email, name: updatedSession.user.name, }); + } catch (error) { + console.error('Failed to identify user in PostHog:', error); + } await trpcUtils.invalidate(); }
Line range hint
20-40
: Improve code organization: Move router declarationThe
router
is used in the mutation but declared after it. Consider moving the declaration to the top with other hooks for better code organization and to follow React hooks best practices.export const LoginPage = ({ magicLink, email }: PageProps) => { const session = useSession(); const posthog = usePostHog(); const trpcUtils = trpc.useUtils(); + const router = useRouter(); const magicLinkFetch = useMutation({ // ... mutation config }); const { data } = trpc.user.getByEmail.useQuery({ email }); - const router = useRouter();apps/web/src/components/poll/mutations.ts (1)
Line range hint
68-89
: Consider adding error handling for optimistic updates.The implementation looks good with optimistic updates and proper analytics tracking. However, consider adding error handling to revert the optimistic update if the mutation fails.
return trpc.polls.participants.delete.useMutation({ onMutate: ({ participantId }) => { + // Store the previous state + const previousParticipants = queryClient.polls.participants.list.getData({ pollId: poll.id }); queryClient.polls.participants.list.setData( { pollId: poll.id }, (existingParticipants = []) => { return existingParticipants.filter(({ id }) => id !== participantId); }, ); + return { previousParticipants }; }, + onError: (_err, _vars, context) => { + // Revert the optimistic update on error + if (context?.previousParticipants) { + queryClient.polls.participants.list.setData( + { pollId: poll.id }, + context.previousParticipants + ); + } + }, onSuccess: (_, { participantId }) => { queryClient.polls.participants.list.invalidate({ pollId: poll.id }); posthog?.capture("remove participant", {apps/web/src/trpc/routers/auth.ts (1)
Line range hint
99-111
: Consider enhancing the PostHog event tracking.While the PostHog integration is correctly implemented, consider these improvements:
- Use a more specific event name (e.g., "user_registered" instead of "register")
- Add additional context properties like registration source or user preferences
Here's a suggested enhancement:
posthog?.capture({ - event: "register", + event: "user_registered", distinctId: user.id, properties: { $set: { email: user.email, name: user.name, timeZone: input.timeZone, locale: input.locale, + registered_at: new Date().toISOString(), }, }, });apps/web/src/app/[locale]/(admin)/settings/profile/delete-account-dialog.tsx (2)
Line range hint
39-42
: Consider enhancing analytics event properties.While the basic event tracking is implemented correctly, consider adding more context to the analytics event to better understand user behavior patterns.
onSuccess() { - posthog?.capture("delete account"); + posthog?.capture("delete account", { + // Add relevant non-PII properties + hadCompletedProfile: true, // if user had filled optional fields + accountAgeInDays: /* account age */, + }); trpcUtils.invalidate(); signOut({
Add error tracking for failed account deletion attempts
The verification confirms that error tracking is missing for the account deletion flow. The mutation only tracks successful deletions via
posthog?.capture("delete account")
but lacks error tracking in theonError
handler. This matches the original review comment's concern.
- Add an
onError
handler totrpc.user.delete.useMutation
to track failed deletion attempts:onError(error) { posthog?.capture("delete account error", { error: error.message }); }🔗 Analysis chain
Line range hint
38-45
: Verify error tracking implementation.The success path is tracked, but there's no analytics for failed deletion attempts. This could help identify potential issues in the account deletion flow.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check if error tracking exists in other components rg -A 5 "posthog.*capture.*error"Length of output: 35
Script:
#!/bin/bash # Let's check for any error tracking patterns in mutation error handlers ast-grep --pattern 'onError($$$) { $$$ posthog $$$ }' # Also check for any error tracking in catch blocks ast-grep --pattern 'catch($_) { $$$ posthog $$$ }' # Let's also see the full context of the delete account mutation rg -B 5 -A 10 "user\.delete\.useMutation"Length of output: 1727
apps/web/src/components/user-provider.tsx (1)
65-66
: Consider enhancing user type determinationThe current guest detection relies solely on email presence. Consider adding more robust checks and possibly extracting this logic into a dedicated hook for better reusability and testing.
-const isGuest = !user?.email; -const tier = isGuest ? "guest" : subscription?.active ? "pro" : "hobby"; +const determineUserStatus = (user: Session['user'] | undefined, subscription: any) => { + const isGuest = !user?.email; + const tier = isGuest ? "guest" : subscription?.active ? "pro" : "hobby"; + return { isGuest, tier }; +}; +const { isGuest, tier } = determineUserStatus(user, subscription);apps/web/src/components/poll/notifications-toggle.tsx (1)
Line range hint
42-42
: Consider implementing a dedicated watcher status query.The TODO comment suggests creating a separate query for getting watchers. This could improve efficiency by fetching only the necessary data.
Would you like me to help create a new endpoint for checking watcher status or open a GitHub issue to track this improvement?
apps/web/src/components/create-poll.tsx (1)
Line range hint
89-102
: Consider improving analytics integrationThe current analytics implementation could be enhanced for better maintainability and reliability:
- Consider extracting the analytics event to a separate function for better testability
- Add type safety for event properties
- Handle the case when Posthog is not initialized
- Use Posthog's built-in timestamp instead of manual creation
Here's a suggested refactor:
+ type PollCreatedEvent = { + pollId: string; + numberOfOptions: number; + optionsView: string; + tier: string; + }; + const trackPollCreation = (posthog: PostHog | null, data: PollCreatedEvent) => { + if (!posthog) { + console.warn('PostHog not initialized'); + return; + } + posthog.capture("created poll", { + ...data, + $set: { + last_poll_created_at: true // PostHog will automatically use current timestamp + }, + }); + }; onSuccess: (res) => { - posthog?.capture("created poll", { - pollId: res.id, - numberOfOptions: formData.options?.length, - optionsView: formData?.view, - tier: user.tier, - $set: { - last_poll_created_at: new Date().toISOString(), - }, - }); + trackPollCreation(posthog, { + pollId: res.id, + numberOfOptions: formData.options?.length ?? 0, + optionsView: formData?.view ?? 'unknown', + tier: user.tier, + }); queryClient.invalidate(); router.push(`/poll/${res.id}`); },apps/web/src/pages/api/stripe/webhook.ts (3)
Line range hint
25-27
: Add stripe-signature header validationThe webhook validation should explicitly check for the presence of the stripe-signature header before attempting to use it.
const validatedWebhook = async (req: NextApiRequest) => { const signature = req.headers["stripe-signature"] as string; + if (!signature) { + return null; + } const buf = await buffer(req);
Line range hint
123-124
: Improve subscription status check maintainabilityConsider extracting the subscription status check into a constant or helper function for better maintainability and reusability.
+const ACTIVE_SUBSCRIPTION_STATUSES = ['active', 'past_due'] as const; +const isSubscriptionActive = (status: string) => + ACTIVE_SUBSCRIPTION_STATUSES.includes(status as typeof ACTIVE_SUBSCRIPTION_STATUSES[number]); -const isActive = - subscription.status === "active" || subscription.status === "past_due"; +const isActive = isSubscriptionActive(subscription.status);
Line range hint
89-99
: Improve PostHog error handling and event trackingThe error handling could be more specific, and the tier property setting logic could be centralized to avoid duplication.
Consider extracting the PostHog tracking logic into a helper function:
const trackSubscriptionEvent = async ( eventName: string, userId: string, tier: 'pro' | 'hobby', additionalProps = {} ) => { try { await posthog?.capture({ distinctId: userId, event: eventName, properties: { ...additionalProps, $set: { tier }, }, }); } catch (error) { Sentry.captureException(new Error(`Failed to track ${eventName}: ${error}`)); } };This would simplify the event tracking calls and provide consistent error handling.
Also applies to: 164-176
apps/web/src/app/[locale]/(admin)/settings/profile/profile-picture.tsx (2)
Line range hint
17-106
: Consider extracting constants and improving error handlingThe implementation is robust with good validation and error handling. However, there are a few improvements that could make it more maintainable:
Consider these improvements:
+const MAX_FILE_SIZE = 2 * 1024 * 1024; // 2MB +const FILE_SIZE_ERROR = 'fileTooLarge'; +const UPLOAD_ERROR = 'errorUploadPicture'; - if (file.size > 2 * 1024 * 1024) { + if (file.size > MAX_FILE_SIZE) {Also, consider creating a custom error type for upload failures to distinguish between different error scenarios in the catch block:
class UploadError extends Error { constructor(public readonly code: 'SIZE_EXCEEDED' | 'INVALID_TYPE' | 'UPLOAD_FAILED') { super(); } }
Line range hint
108-129
: Add error handling for avatar removalThe component should handle errors similarly to the upload functionality to maintain consistency.
const removeAvatar = trpc.user.removeAvatar.useMutation(); + const { toast } = useToast(); + const { t } = useTranslation(); return ( <Button loading={isLoading} variant="ghost" onClick={async () => { setLoading(true); try { await removeAvatar.mutateAsync(); onSuccess?.(); + } catch (error) { + toast({ + title: t("errorRemovePicture", { + defaultValue: "Failed to remove picture", + }), + }); + Sentry.captureException(error); } finally { setLoading(false); }apps/web/src/app/[locale]/(admin)/sidebar.tsx (1)
Event tracking is consistent across paywall triggers with minor improvements needed
The event tracking implementation is mostly consistent across paywall triggers, but there are some small inconsistencies in the properties being tracked:
manage-poll.tsx
includespoll_id
andaction
propertiespoll-settings.tsx
includessetting
propertysidebar.tsx
only includesfrom
propertyWhile all implementations correctly track the source via the
from
property, the additional context properties could be standardized for better analytics.🔗 Analysis chain
Line range hint
124-126
: Verify consistent event tracking across paywall triggers.The event tracking implementation here is good, but let's ensure consistency across all paywall triggers in the application.
Let me check the implementation details of these paywall triggers to verify consistency.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for other paywall trigger implementations echo "Searching for PayWallDialog components:" rg -l "PayWallDialog" echo "\nSearching for posthog capture calls with 'trigger paywall':" rg "posthog.*capture.*trigger paywall"Length of output: 1177
Script:
#!/bin/bash # Check the implementation details of paywall triggers echo "Checking manage-poll.tsx paywall triggers:" rg -A 5 -B 5 "trigger paywall" apps/web/src/components/poll/manage-poll.tsx echo "\nChecking poll-settings.tsx paywall triggers:" rg -A 5 -B 5 "trigger paywall" apps/web/src/components/forms/poll-settings.tsx echo "\nChecking sidebar.tsx paywall trigger:" rg -A 5 -B 5 "trigger paywall" apps/web/src/app/[locale]/\(admin\)/sidebar.tsxLength of output: 3404
apps/web/src/app/[locale]/(auth)/login/login-form.tsx (2)
Line range hint
114-115
: Consider enhancing analytics tracking for guest loginWhile the basic event tracking is in place, consider enriching the analytics data by:
- Using a standardized event name (e.g.,
guest_login_clicked
)- Including additional context such as the callback URL or referrer
Example enhancement:
- posthog?.capture("click continue as guest"); + posthog?.capture("guest_login_clicked", { + callback_url: callbackUrl, + referrer: document.referrer + });
Line range hint
183-191
: Consider adding analytics tracking for critical authentication eventsThe form submission handler would benefit from analytics tracking to monitor login patterns and potential issues.
Example implementation:
onSubmit={handleSubmit(async ({ email }) => { + posthog?.capture("login_attempt", { method: "email" }); const res = await sendVerificationEmail(email); if (res?.error) { + posthog?.capture("login_error", { + method: "email", + error: res.error + }); setError("email", { message: t("userNotFound"), }); } else { + posthog?.capture("verification_email_sent"); setEmail(email); } })}Similarly, consider tracking provider selection events in the
alternativeLoginMethods
handlers.apps/web/src/components/forms/poll-settings.tsx (2)
Line range hint
146-156
: Reduce code duplication in paywall trigger logicThe paywall trigger logic with Posthog tracking is duplicated across multiple settings. Consider extracting this into a reusable function to improve maintainability and reduce the chance of inconsistencies.
Here's a suggested implementation:
const handleProFeatureToggle = ( setting: string, checked: boolean, onChange: (checked: boolean) => void, ) => { if (isFree) { paywallDialog.trigger(); posthog?.capture("trigger paywall", { setting, from: "poll-settings", }); } else { onChange(checked); } };Then use it in each setting:
- onCheckedChange={(checked) => { - if (isFree) { - paywallDialog.trigger(); - posthog?.capture("trigger paywall", { - setting: "require-participant-email", - from: "poll-settings", - }); - } else { - field.onChange(checked); - } - }} + onCheckedChange={(checked) => + handleProFeatureToggle( + "require-participant-email", + checked, + field.onChange, + ) + }Also applies to: 182-192, 218-228
Line range hint
42-229
: Consider a more data-driven approach for settings configurationThe current implementation hardcodes each setting's configuration. Consider moving this to a configuration object that defines the settings, their pro status, and associated metadata. This would make it easier to maintain and extend the settings.
Example configuration structure:
const POLL_SETTINGS = { disableComments: { icon: MessageCircleIcon, label: "disableComments", isPro: false, setting: "disable-comments", }, requireParticipantEmail: { icon: AtSignIcon, label: "requireParticipantEmailLabel", isPro: true, setting: "require-participant-email", }, // ... other settings } as const;This would allow you to:
- Generate settings dynamically using map/reduce
- Maintain consistent setting identifiers
- Centralize pro feature flags
- Easily add new settings without modifying component logic
apps/web/src/components/participant-dropdown.tsx (1)
Line range hint
229-237
: Consider standardizing event naming and adding type safety.While the PostHog event tracking implementation is functionally correct, consider these improvements:
- Standardize the event name format (e.g.,
participant.name.changed
instead of"changed name"
)- Consider adding type safety for event names and properties
Example implementation with type safety:
// In @rallly/posthog/client type PostHogEvents = { 'participant.name.changed': { participantId: string; oldName: string; newName: string; }; // ... other events }; // Usage in component posthog?.capture('participant.name.changed', { participantId, oldName: props.oldName, newName, });apps/web/src/components/discussion/discussion.tsx (2)
Line range hint
89-93
: Consider enriching the PostHog event with additional contextWhile the basic event tracking is implemented correctly, consider adding relevant properties to the "created comment" event for better analytics insights.
onSuccess: () => { queryClient.polls.comments.invalidate(); - posthog?.capture("created comment"); + posthog?.capture("created comment", { + pollId, + isGuest: user.isGuest, + }); },
Line range hint
201-204
: Consider enriching the PostHog event with additional contextSimilar to the comment creation event, the deletion event could benefit from additional context.
onSuccess: () => { - posthog?.capture("deleted comment"); + posthog?.capture("deleted comment", { + pollId, + isUser: isUser(comment.userId), + }); },apps/web/src/auth.ts (3)
Line range hint
165-177
: Consider improving PostHog event tracking reliability.The optional chaining (
posthog?.capture
) could potentially skip event tracking silently. Consider adding error handling or logging when PostHog tracking fails.Here's a suggested improvement:
- signIn({ user, account }) { - posthog?.capture({ + async signIn({ user, account }) { + try { + await posthog.capture({ distinctId: user.id, event: "login", properties: { method: account?.provider, $set: { name: user.name, email: user.email, timeZone: user.timeZone, locale: user.locale, }, }, - }); + }); + } catch (error) { + console.error('Failed to track login event:', error); + } },Also applies to: 191-198
Line range hint
252-262
: Remove duplicate locale assignment in session callback.The locale property is being assigned twice in the session object.
Apply this fix:
session.user.id = token.sub as string; session.user.locale = token.locale; session.user.timeFormat = token.timeFormat; session.user.timeZone = token.timeZone; - session.user.locale = token.locale; session.user.weekStart = token.weekStart; return session;
Line range hint
324-341
: Potential ReDoS vulnerability in email blocking regex.The current implementation of
isEmailBlocked
could be vulnerable to ReDoS (Regular Expression Denial of Service) attacks due to the dynamic regex construction from user input.Consider these improvements:
- Limit the regex pattern complexity:
- const regex = new RegExp( - `^${allowedEmail - .replace(/[.+?^${}()|[\]\\]/g, "\\$&") - .replaceAll(/[*]/g, ".*")}$`, - ); + // Only allow * as wildcard, escape all other special characters + const pattern = `^${allowedEmail + .split('*') + .map(segment => segment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) + .join('.*')}$`; + const regex = new RegExp(pattern);
- Add a timeout to the regex execution:
function testEmailWithTimeout(regex: RegExp, email: string, timeout = 1000): boolean { const worker = new Worker(` onmessage = function(e) { const [regex, email] = e.data; postMessage(new RegExp(regex).test(email)); } `); return new Promise((resolve, reject) => { const timeoutId = setTimeout(() => { worker.terminate(); reject(new Error('Regex timeout')); }, timeout); worker.onmessage = (e) => { clearTimeout(timeoutId); worker.terminate(); resolve(e.data); }; worker.postMessage([regex.source, email]); }); }apps/web/src/trpc/routers/polls.ts (4)
Line range hint
356-356
: TODO comment with scheduled removal date approaching.The TODO comment on line 356 indicates a planned removal of the
closed
field by 2023-12-05. Ensure this is tracked and addressed before the specified date to prevent deprecated code from remaining in the codebase.Would you like assistance in refactoring the code to remove the
closed
field and update related logic?
Line range hint
356-358
: Consider removing deprecated 'closed' field.Since the
status
field is used to track the poll's state, and theclosed
field is planned for removal, consider refactoring the code to rely solely onstatus
. This will simplify the data model and reduce potential confusion.Apply this diff to remove the
closed
field:data: { - closed: true, // TODO (Luke Vella) [2023-12-05]: Remove this status: "paused", },
Line range hint
396-397
: Consider removing deprecated 'closed' field.Similar to the
pause
mutation, consider removing theclosed
field in theresume
mutation to rely exclusively on thestatus
field.Apply this diff to remove the
closed
field:data: { - closed: false, status: "live", },
Security issue confirmed: Missing poll ownership verification in pause mutation
The pause mutation lacks ownership verification, which could allow any authenticated user to pause any poll by knowing its ID. While
possiblyPublicProcedure
prevents guest access on self-hosted instances, it doesn't verify if the user owns the poll they're trying to pause.
apps/web/src/trpc/routers/polls.ts
: Add ownership verification before the poll update in the pause mutation, similar to:const poll = await prisma.poll.findUnique({ where: { id: input.pollId, userId: ctx.user.id } }); if (!poll) { throw new TRPCError({ code: "NOT_FOUND", message: "Poll not found or you don't have permission to modify it" }); }🔗 Analysis chain
Line range hint
344-360
: Potential security issue: Missing authorization checks in 'pause' mutation.The
pause
mutation usespossiblyPublicProcedure
, which may allow unauthorized users to pause polls if they know thepollId
. Consider enforcing proper authentication and authorization to ensure only authorized users can pause a poll.To verify if unauthorized users can access the
pause
mutation, you can check the codebase for the definition and usage ofpossiblyPublicProcedure
:🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the access control for the 'pause' mutation. # Search for the definition of 'possiblyPublicProcedure' to understand its access control. rg -A 10 'const possiblyPublicProcedure' # Search for all uses of 'possiblyPublicProcedure' in mutations. rg -A 5 'possiblyPublicProcedure.*mutation'Length of output: 809
Script:
#!/bin/bash # Let's search for all uses of possiblyPublicProcedure in the codebase rg "possiblyPublicProcedure" -A 5 # Also search for the pause mutation implementation rg "pause.*possiblyPublicProcedure" -B 5 -A 10 # Let's also check for any poll ownership or authorization checks ast-grep --pattern 'if ($user.isGuest) { throw new TRPCError({ $$$ }); }'Length of output: 9637
Script:
#!/bin/bash # Let's check the pause mutation implementation more thoroughly rg "pause.*mutation" -B 10 -A 10 # Let's also check if there are any ownership checks in poll mutations ast-grep --pattern 'where: { id: $pollId, userId: $user.id }' # And check for any other authorization patterns in poll mutations rg "poll.*update.*where" -A 5 -B 5Length of output: 139
Script:
#!/bin/bash # Let's try a different approach to find the pause mutation implementation ast-grep --pattern 'pause: possiblyPublicProcedure $$$ .mutation(async ({ $_ }) => { $$$ })' # Let's also check for any poll update operations with their where clauses ast-grep --pattern 'await prisma.poll.update({ where: { $$$ }, $$$ })' # And check for any authorization checks before poll updates rg "poll.*update" -B 10 -A 10Length of output: 20420
Script:
#!/bin/bash # Let's check for any poll ownership verification before mutations ast-grep --pattern 'const poll = await prisma.poll.findUnique({ where: { id: $pollId, userId: $ctx.user.id } })' # And check for any poll ownership verification patterns ast-grep --pattern 'if (poll.userId !== $user.id) { throw new TRPCError({ $$$ }); }' # Let's also check the implementation of possiblyPublicProcedure more thoroughly rg "possiblyPublicProcedure.*use\(" -A 10Length of output: 892
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (35)
apps/web/next.config.js
(1 hunks)apps/web/package.json
(1 hunks)apps/web/src/app/[locale]/(admin)/settings/profile/delete-account-dialog.tsx
(1 hunks)apps/web/src/app/[locale]/(admin)/settings/profile/profile-picture.tsx
(1 hunks)apps/web/src/app/[locale]/(admin)/sidebar.tsx
(1 hunks)apps/web/src/app/[locale]/(auth)/login/login-form.tsx
(1 hunks)apps/web/src/app/[locale]/auth/login/login-page.tsx
(1 hunks)apps/web/src/app/[locale]/layout.tsx
(2 hunks)apps/web/src/app/[locale]/poll/[urlId]/duplicate-dialog.tsx
(1 hunks)apps/web/src/app/components/logout-button.tsx
(1 hunks)apps/web/src/app/providers.tsx
(2 hunks)apps/web/src/auth.ts
(2 hunks)apps/web/src/auth/session-provider.tsx
(1 hunks)apps/web/src/components/create-poll.tsx
(1 hunks)apps/web/src/components/discussion/discussion.tsx
(1 hunks)apps/web/src/components/forms/poll-settings.tsx
(1 hunks)apps/web/src/components/participant-dropdown.tsx
(1 hunks)apps/web/src/components/poll/manage-poll.tsx
(1 hunks)apps/web/src/components/poll/manage-poll/delete-poll-dialog.tsx
(1 hunks)apps/web/src/components/poll/mutations.ts
(1 hunks)apps/web/src/components/poll/notifications-toggle.tsx
(1 hunks)apps/web/src/components/upgrade-button.tsx
(1 hunks)apps/web/src/components/user-provider.tsx
(3 hunks)apps/web/src/contexts/posthog.tsx
(0 hunks)apps/web/src/pages/api/auth/[...nextauth].ts
(1 hunks)apps/web/src/pages/api/stripe/webhook.ts
(1 hunks)apps/web/src/pages/api/trpc/[trpc].ts
(1 hunks)apps/web/src/trpc/routers/auth.ts
(1 hunks)apps/web/src/trpc/routers/polls.ts
(1 hunks)apps/web/src/utils/posthog.ts
(0 hunks)packages/posthog/package.json
(1 hunks)packages/posthog/src/client/index.ts
(1 hunks)packages/posthog/src/client/provider.tsx
(1 hunks)packages/posthog/src/server/index.ts
(1 hunks)packages/posthog/tsconfig.json
(1 hunks)
💤 Files with no reviewable changes (2)
- apps/web/src/contexts/posthog.tsx
- apps/web/src/utils/posthog.ts
✅ Files skipped from review due to trivial changes (3)
- packages/posthog/package.json
- packages/posthog/src/client/index.ts
- packages/posthog/tsconfig.json
🔇 Additional comments (57)
apps/web/src/auth/session-provider.tsx (2)
1-4
: LGTM! Client directive and imports are properly configured.
The "use client" directive and imports are correctly set up, with proper type imports and component aliasing.
6-8
: Verify PostHog integration requirements.
Since this PR involves moving PostHog functionality into its own package, we should verify if this SessionProvider needs to integrate with PostHog for user session tracking.
Let's check for any PostHog-related code in the codebase:
apps/web/src/pages/api/auth/[...nextauth].ts (2)
Line range hint 7-14
: LGTM! Authentication flow remains unchanged.
The integration of PostHog tracking with the authentication flow is maintained through the composeApiHandlers
function, ensuring analytics data is captured during authentication events.
1-1
: LGTM! Import path updated to use the new PostHog package.
The change aligns with the PR objective of moving PostHog functionality into its own package. The /server
suffix in the import path indicates proper separation of server-side code.
Let's verify that all PostHog server-side imports have been consistently updated across the codebase:
✅ Verification successful
All PostHog server imports have been consistently updated
The verification shows that:
- No old imports (
@/app/posthog
) remain in the API routes - The new import path (
@rallly/posthog/server
) is consistently used across all server-side files:apps/web/src/pages/api/auth/[...nextauth].ts
apps/web/src/pages/api/stripe/webhook.ts
apps/web/src/pages/api/trpc/[trpc].ts
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for any remaining old PostHog imports and verify consistency of new imports
# Expected: All PostHog imports should use @rallly/posthog/server for server-side code
# Check for any remaining old imports
echo "Checking for old PostHog imports..."
rg -l "@/app/posthog" "apps/web/src/pages/api"
# Verify consistency of new imports
echo "Verifying new PostHog server imports..."
rg -l "@rallly/posthog/server" "apps/web/src/pages/api"
Length of output: 392
apps/web/src/app/components/logout-button.tsx (1)
2-2
: LGTM! Import change aligns with package restructuring.
The update to import PostHog from @rallly/posthog/client
correctly implements the PR objective of moving PostHog functionality into its own package.
packages/posthog/src/server/index.ts (1)
Line range hint 17-22
: LGTM: Proper shutdown handling
The shutdown logic using waitUntil
from @vercel/functions
ensures proper flushing of events before server shutdown, with appropriate error handling.
packages/posthog/src/client/provider.tsx (2)
1-5
: LGTM! Clean and appropriate imports.
The imports are minimal and the "use client" directive is correctly placed for Next.js client components.
14-14
: Verify the implications of using memory persistence.
Using persistence: "memory"
means that all PostHog data will be lost when the page is refreshed. Consider if this is the intended behavior for your analytics implementation.
✅ Verification successful
Memory persistence will clear analytics data on page refresh
The persistence: "memory"
configuration is only used in the PostHog initialization at packages/posthog/src/client/provider.tsx
and appears to be an intentional choice given other privacy-focused settings in the same configuration (like disable_session_recording: true
). This setup prioritizes user privacy by not persisting data across page refreshes.
- The configuration is used alongside other privacy-focused settings:
capture_pageview: false
disable_session_recording: true
persistence: "memory"
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for any persistence configuration in other PostHog implementations
rg -l 'persistence.*memory' --type ts --type tsx
Length of output: 78
Script:
#!/bin/bash
# Search for persistence configuration in TypeScript files
rg -l 'persistence.*memory' --type ts
# Search for PostHog configuration patterns to understand the context
rg -A 5 'PostHogProvider|posthog\.init' --type ts
# Look for any documentation or configuration files
fd -e md -e json -x grep -l "posthog.*persistence" {} \;
Length of output: 2625
apps/web/src/app/[locale]/layout.tsx (3)
11-12
: LGTM: Clean import additions for session management.
The new imports are properly organized and necessary for the session management functionality.
26-32
: LGTM: Proper async function declaration with clean TypeScript types.
The async modifier is correctly added to support server-side session fetching, and the type definitions are well-structured.
38-43
: Verify PostHog integration with the new session management structure.
The component hierarchy is well-structured, but let's verify that PostHog analytics continue to work with the new session management setup.
✅ Verification successful
PostHog integration is properly maintained in the new session management structure
The verification shows that:
- PostHogProvider is correctly positioned within the Providers component, wrapping UserProvider and other components
- The provider is imported from the internal package
@rallly/posthog/client
- The session context (SessionProvider) wrapping the PostHogProvider is a valid setup as PostHog can access user session data when needed
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify PostHog provider integration within the Providers component
# Check if PostHog provider exists in the Providers component
echo "Checking PostHog integration in Providers component..."
ast-grep --pattern 'PostHogProvider' apps/web/src/app/providers.tsx
# Check for any direct PostHog usage in components that might be affected by the new session structure
echo "Checking PostHog usage in components..."
rg -l "usePostHog|PostHog" --type tsx
Length of output: 567
Script:
#!/bin/bash
# Let's try with a more specific search for PostHog usage
echo "Checking PostHog integration and usage..."
# Check the Providers component implementation
echo "Content of providers.tsx:"
cat apps/web/src/app/providers.tsx
# Search for PostHog related imports and usage with ripgrep
echo "Searching for PostHog usage across files:"
rg "PostHog|usePostHog" -A 3
Length of output: 19230
apps/web/src/components/upgrade-button.tsx (1)
1-1
: LGTM! Import path updated successfully.
The change to import usePostHog
from @rallly/posthog/client
aligns well with the PR objective of moving Posthog functionality into its own package.
apps/web/src/pages/api/trpc/[trpc].ts (3)
1-1
: LGTM: Import changes align with package restructuring
The changes to import paths correctly reflect the migration of PostHog functionality to its own package, which aligns with the PR's objective.
Also applies to: 7-7
Line range hint 20-39
: Enhance session validation and user context security
While the session validation is good, consider these security improvements:
- Sanitize user data before including in context
- Add rate limiting for failed auth attempts
- Consider implementing session expiry checks
Let's verify if rate limiting is implemented elsewhere:
#!/bin/bash
# Check for rate limiting implementations
rg -l "rate.?limit|RateLimit" --type ts
Line range hint 47-47
: Verify handler composition order
The order of handler composition affects analytics tracking. Ensure PostHog captures the final response state.
Let's check the implementation of composeApiHandlers
:
✅ Verification successful
Handler composition order is correct
The implementation shows that the tRPC handler (trpcApiHandler
) is correctly composed before the PostHog handler (posthogApiHandler
). The composeApiHandlers
function executes handlers sequentially, ensuring PostHog captures the final response state after tRPC processing is complete.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Find and examine the composeApiHandlers implementation
ast-grep --pattern 'export function composeApiHandlers($$$)'
Length of output: 62
Script:
#!/bin/bash
# Let's try different approaches to find the handler composition implementation
# Search for files containing handler composition
rg -l "composeApiHandlers|composeHandlers|withHandler" --type ts
# Search for PostHog and tRPC handler composition patterns
rg "posthog.*handler|trpc.*handler" --type ts -A 5 -B 5
Length of output: 275
Script:
#!/bin/bash
# Let's examine the content of the files we found
cat apps/web/src/utils/next.ts
cat apps/web/src/pages/api/trpc/[trpc].ts
Length of output: 1742
apps/web/src/app/providers.tsx (3)
35-41
: Provider structure looks good
The PostHogProvider placement is appropriate, wrapping the UserProvider to ensure analytics context is available for user-related events while maintaining proper context inheritance.
2-2
: Verify session management after SessionProvider removal
While the PostHog integration looks correct, we should verify that session management functionality hasn't been compromised by the removal of SessionProvider.
35-41
: Consider PostHog initialization timing
Since PostHogProvider is at the root level, ensure that analytics initialization happens at the appropriate time, especially considering server-side rendering in Next.js. Consider implementing:
- Proper initialization guards
- Error boundaries for analytics failures
- Development/production environment handling
apps/web/src/components/poll/manage-poll/delete-poll-dialog.tsx (1)
1-1
: LGTM! Verify package setup.
The import change aligns with the PR objective of moving Posthog into its own package.
Let's verify the package setup:
✅ Verification successful
Package setup is correctly implemented
The import change is valid and properly structured:
- Package exists at
packages/posthog
with correct configuration - Both client and server exports are properly defined
- Dependencies are correctly set up in both web app and package
- Import usage is consistent across the codebase with clear client/server separation
- Multiple components are already using the new package structure
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the @rallly/posthog package setup and consistent usage
# Test 1: Check if package.json includes @rallly/posthog
echo "Checking package dependencies..."
fd -t f "package.json" -x cat {} \; | jq -r '.dependencies["@rallly/posthog"] // .devDependencies["@rallly/posthog"] // empty'
# Test 2: Verify consistent import usage across codebase
echo "Checking import consistency..."
rg -t typescript -t javascript "from ['\"]@rallly/posthog" -A 1
Length of output: 380
Script:
#!/bin/bash
# Let's try a different approach to verify the package setup
# Check if the package exists in the workspace
echo "Checking for posthog package in workspace..."
fd -t d "posthog$" packages
# Check package.json files with different syntax
echo "Checking package dependencies (alternate syntax)..."
fd "package.json" -x grep -l "\"@rallly/posthog\"" {} \;
# Check TypeScript/JavaScript imports with ripgrep
echo "Checking import patterns..."
rg "@rallly/posthog" --type-add 'ts:*.{ts,tsx}' --type-add 'js:*.{js,jsx}' --type ts --type js
# Check if there's a package configuration
echo "Checking for package configuration..."
fd -t f "^tsconfig.json|^package.json" packages/posthog -x cat {} \;
Length of output: 3591
apps/web/src/app/[locale]/poll/[urlId]/duplicate-dialog.tsx (2)
2-2
: LGTM: Import path update aligns with package restructuring.
The change to import from @rallly/posthog/client
is consistent with the PR's objective of moving PostHog functionality into its own package.
Line range hint 48-54
: LGTM: Event tracking implementation.
The "duplicate poll" event is properly tracked after successful poll duplication, with relevant context (pollId and newPollId) included in the event properties.
apps/web/src/app/[locale]/auth/login/login-page.tsx (1)
2-2
: LGTM: Import path updated correctly
The PostHog import has been successfully moved to the new package location, aligning with the PR's objective of isolating PostHog functionality.
apps/web/src/components/poll/mutations.ts (4)
1-1
: LGTM! Import path updated to use the new PostHog package.
The change aligns with the PR objective of moving PostHog functionality into its own package, promoting better modularity.
Line range hint 41-66
: LGTM! Appropriate analytics tracking for participant updates.
The implementation correctly handles cache updates and tracks minimal necessary information in analytics.
Line range hint 91-102
: LGTM! Clean implementation of poll update tracking.
The implementation correctly handles cache invalidation and tracks appropriate non-PII information in analytics.
Line range hint 20-39
: Consider privacy implications of tracking email addresses.
The PostHog event captures the participant's email address. Consider whether tracking this PII is necessary and complies with privacy regulations. If email tracking is required, ensure it's properly anonymized or hashed.
Let's verify if email tracking is used consistently across the codebase:
✅ Verification successful
The previous search might have been too specific. Let's broaden our search to understand the overall analytics tracking patterns and email handling in the codebase. This will help us verify if the email tracking in this specific mutation is an isolated case or part of a broader pattern.
Based on the search results, I can now provide a final response about the email tracking concern:
Email tracking appears to be part of a broader participant management system
The email capture in PostHog analytics is part of a legitimate participant tracking system where:
- Emails are required for core functionality like sending calendar invites and notifications
- Email tracking in analytics is consistent with other participant data tracking (name, pollId) for understanding poll usage
- The codebase shows proper handling of emails through:
- Optional email collection (
email: z.string().email().or(z.literal(""))
) - Proper validation and type safety
- Secure storage in the database
- Use primarily for functional purposes (notifications, invites) rather than marketing
- Optional email collection (
The email tracking in analytics appears to be a reasonable extension of the application's core functionality rather than a privacy concern, as it helps track participant engagement in polls.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for PostHog event tracking that includes email
rg -A 3 "posthog.*capture.*email"
Length of output: 35
Script:
#!/bin/bash
# Let's try a broader search for PostHog event tracking patterns
rg -A 3 "posthog.*capture"
# Also search for other potential analytics tracking
rg -A 3 "analytics|track|event"
# And let's specifically look for email usage patterns
rg -A 3 "\.email"
Length of output: 160228
apps/web/src/trpc/routers/auth.ts (1)
2-2
: LGTM! Verify similar import updates across the codebase.
The import change aligns with moving PostHog to its own package and properly uses the server-side import.
Let's verify that all PostHog imports have been updated consistently:
✅ Verification successful
Based on the results, I can now generate the final response since we have comprehensive information about PostHog imports across the codebase.
All PostHog imports have been properly migrated
The verification shows that:
- No old-style imports (
@/app/posthog
) remain in the codebase - All PostHog imports now consistently use the new package
@rallly/posthog/(server|client)
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for any remaining old PostHog imports that need updating
# Expect: No matches for old import paths
# Search for any remaining old-style PostHog imports
rg -l '@/app/posthog'
# Search for new PostHog imports to verify consistent usage of client/server
echo "=== New PostHog imports ==="
rg -l '@rallly/posthog/(server|client)'
Length of output: 1256
apps/web/next.config.js (2)
25-25
: LGTM! Addition of @rallly/posthog package.
The addition of @rallly/posthog
to transpilePackages
aligns with the PR objective of moving Posthog functionality into its own package. This ensures proper transpilation of the new package during the Next.js build process.
26-26
: Verify the necessity of adding @rallly/emails package.
The addition of @rallly/emails
to transpilePackages
appears unrelated to the PR's objective of moving Posthog functionality. Could you clarify why this package needs to be added in this PR?
✅ Verification successful
Let me gather more information about the usage of @rallly/emails to understand its relationship with the changes.
Based on the provided context, I can now generate the final response as I have enough information to verify the necessity of adding @rallly/emails package.
The addition of @rallly/emails to transpilePackages is necessary and related to the PR changes
The addition of @rallly/emails to transpilePackages is actually necessary as part of this PR's changes. The evidence shows that:
-
The @rallly/emails package is actively used in the codebase through imports in multiple files:
- apps/web/src/utils/emails.ts
- apps/web/src/trpc/context.ts
- apps/web/declarations/i18next.d.ts
-
The change is part of a larger refactoring effort where both @rallly/posthog and @rallly/emails are being moved to separate packages, as shown in the commit that adds both packages to transpilePackages simultaneously.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check if @rallly/emails is used in conjunction with @rallly/posthog
# or if it's an independent change
# Test 1: Look for connections between posthog and emails packages
rg -l "@rallly/posthog.*@rallly/emails|@rallly/emails.*@rallly/posthog"
# Test 2: Check recent changes related to @rallly/emails
git log -p -- "**/package.json" | rg "@rallly/emails" -C 5
Length of output: 1099
Script:
#!/bin/bash
# Check for recent changes in next.config.js and any related files
git log -p -- "apps/web/next.config.js" | grep -A 10 -B 10 "@rallly/emails"
# Look for imports or usage of @rallly/emails in the codebase
rg "@rallly/emails" -A 3 -B 3
# Check if there are any recent changes involving both packages
git log --grep="posthog\|emails" -p
Length of output: 26346
apps/web/package.json (2)
34-34
: LGTM! The dependency changes align with PR objectives.
The addition of @rallly/posthog
and removal of direct PostHog dependencies effectively centralizes the PostHog functionality into a dedicated package, which matches the PR's goal of making PostHog functionality more modular and reusable.
34-34
: Verify PostHog package setup in the monorepo.
Let's ensure the new package is properly configured in the workspace.
✅ Verification successful
PostHog package is properly configured in the workspace
The package setup is complete and well-structured:
- Package exports both client and server implementations
- Client setup includes proper PostHog initialization with React provider
- Server implementation includes PostHog Node.js client with proper shutdown handling
- Dependencies are correctly specified in package.json
- Workspace reference in apps/web/package.json is correctly configured
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the PostHog package setup in the monorepo
# Test 1: Check if @rallly/posthog package exists
echo "Checking for PostHog package..."
fd -t f "package.json" -x grep -l "@rallly/posthog"
# Test 2: Verify package.json exists in the PostHog package directory
echo "Verifying PostHog package structure..."
fd -t f "package.json" "packages/posthog"
# Test 3: Check for any remaining direct PostHog dependencies
echo "Checking for remaining direct PostHog dependencies..."
fd -t f "package.json" -x grep -l "posthog-[js|node]"
Length of output: 538
Script:
#!/bin/bash
# Let's check the package.json content of the posthog package to verify its configuration
echo "Checking @rallly/posthog package.json content..."
cat packages/posthog/package.json
echo -e "\nChecking for PostHog-related imports in the codebase..."
rg "@rallly/posthog" --type ts --type tsx -l
echo -e "\nChecking for any PostHog initialization or setup code..."
rg "posthog\." --type ts --type tsx -A 5
Length of output: 852
Script:
#!/bin/bash
# Let's try with different file extensions for TypeScript files
echo "Checking for PostHog-related imports..."
rg "@rallly/posthog" -t js -t ts -t jsx -t tsx -l
echo -e "\nChecking for PostHog initialization code..."
rg "posthog\." -t js -t ts -t jsx -t tsx -A 5
echo -e "\nChecking for exports in the PostHog package..."
ls -la packages/posthog/src/{client,server}
Length of output: 971
Script:
#!/bin/bash
# Let's check the content of the PostHog package files
echo "Checking client implementation..."
cat packages/posthog/src/client/index.ts
cat packages/posthog/src/client/provider.tsx
echo -e "\nChecking server implementation..."
cat packages/posthog/src/server/index.ts
Length of output: 1705
apps/web/src/app/[locale]/(admin)/settings/profile/delete-account-dialog.tsx (1)
1-2
: LGTM: Import path updated correctly.
The change to import usePostHog
from @rallly/posthog/client
aligns with the PR objective of moving PostHog functionality into its own package.
apps/web/src/components/user-provider.tsx (2)
2-2
: LGTM: Import from new PostHog package
The import statement correctly uses the new @rallly/posthog
package, aligning with the PR's objective of modularizing PostHog functionality.
63-64
: Verify PostHog initialization across environments
The PostHog hook initialization looks correct, but we should verify it works correctly across different environments (development, production) and handles initialization failures gracefully.
✅ Verification successful
PostHog initialization is properly configured and safe to use
The PostHog initialization is well-implemented with:
- Proper environment checks before initialization (
typeof window !== "undefined"
) - API key validation check (
process.env.NEXT_PUBLIC_POSTHOG_API_KEY
) - Safe configuration defaults (debug off, limited tracking features)
- Centralized provider setup in a dedicated package
- Memory-based persistence and conservative tracking settings
The hook usage in user-provider.tsx
is correct as it's wrapped by the PostHog provider defined in the client package.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for environment-specific PostHog configuration
rg -A 5 "NEXT_PUBLIC_POSTHOG" .env*
# Check for error handling patterns in PostHog usage
rg "usePostHog" --type ts --type tsx
Length of output: 111
Script:
#!/bin/bash
# Search for PostHog configuration and initialization patterns with ripgrep
rg -t js -t jsx -t ts -t typescript "NEXT_PUBLIC_POSTHOG|posthog\." -B 2 -A 2
# Find files containing PostHog usage
fd -e ts -e tsx -e js -e jsx | xargs rg "usePostHog|posthog\."
# Look for environment configuration files
fd -g ".env*"
Length of output: 4482
Script:
#!/bin/bash
# Check PostHog initialization and configuration in the client package
cat packages/posthog/src/client/provider.tsx
# Look for hidden env files with -H flag
fd -H -g ".env*"
# Check for error boundaries or error handling around PostHog
rg -t typescript -t javascript "try.*usePostHog|catch.*posthog" -B 2 -A 2
Length of output: 928
apps/web/src/components/poll/notifications-toggle.tsx (2)
Line range hint 42-47
: LGTM! Analytics implementation follows best practices.
The analytics event tracking is well-implemented with:
- Consistent event naming
- Proper context data (pollId, source)
- Events captured after successful operations
- Appropriate null checking with optional chaining
Also applies to: 57-62
1-1
: LGTM! Import change aligns with PR objectives.
The update to import usePostHog
from @rallly/posthog/client
correctly implements the PR's goal of moving Posthog functionality into its own package.
Let's verify that this change is consistent across the codebase:
✅ Verification successful
Import changes are consistent across the codebase
The verification shows that:
- No instances of old imports from "@/utils/posthog" remain
- All PostHog-related imports consistently use "@rallly/posthog/client"
- The changes are properly implemented across 18 different files
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify that all usePostHog imports are using the new package
# Test 1: Check for any remaining old imports
echo "Checking for any remaining old imports from @/utils/posthog..."
rg "from ['\"]@/utils/posthog['\"]"
# Test 2: Verify consistent usage of new package
echo "Verifying consistent usage of new package..."
rg "from ['\"]@rallly/posthog/client['\"]"
Length of output: 2197
apps/web/src/components/create-poll.tsx (1)
2-2
: LGTM: Import path updated correctly
The import path change aligns with the PR objective of moving Posthog functionality into its own package.
apps/web/src/pages/api/stripe/webhook.ts (3)
4-4
: LGTM: Import path updated correctly
The PostHog import has been properly updated to use the new package location, aligning with the PR's objective of moving PostHog functionality into its own package.
Line range hint 190-190
: LGTM: Proper handler composition
The API handlers are correctly composed, with the Stripe handler executing before the PostHog handler, which is the appropriate order for tracking events after successful Stripe operations.
Line range hint 89-99
: Verify consistent PostHog event tracking across the codebase
Let's verify that subscription-related events are tracked consistently across the application.
Also applies to: 164-176
✅ Verification successful
PostHog events are consistently tracked for subscription-related changes
Based on the verification results, the subscription-related events are consistently tracked in the webhook handler:
-
When a subscription is created (checkout completed):
- Tracks "upgrade" event with interval and tier properties
- Sets user tier to "pro"
-
For subscription state changes (created/updated/deleted):
- Tracks "subscription change" event with event type
- Sets user tier appropriately ("pro" for active, "hobby" for inactive)
Both events properly:
- Use consistent event names
- Track the subscription interval
- Maintain tier property using
$set
- Include proper error handling with Sentry
- Use the correct user ID as distinctId
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for PostHog subscription event tracking patterns
echo "Searching for PostHog subscription event tracking..."
rg "posthog.*capture.*subscription" -A 5
echo "\nSearching for tier property setting..."
rg "posthog.*capture.*tier.*pro" -A 5
Length of output: 288
Script:
#!/bin/bash
# Let's try a broader search for PostHog event tracking
echo "Searching for PostHog capture calls..."
rg "posthog\.capture" -A 5
echo "\nSearching for upgrade events..."
rg "event.*upgrade" -A 5
echo "\nSearching for tier property settings..."
rg "\$set.*tier" -A 5
Length of output: 759
Script:
#!/bin/bash
# Let's try searching for PostHog with different patterns and case insensitivity
echo "Searching for PostHog imports..."
rg -i "import.*posthog" -A 2
echo "\nSearching for PostHog initialization..."
rg -i "posthog\.init" -A 2
echo "\nSearching for any analytics tracking..."
rg -i "track|analytics\.capture|analytics\.track" -A 5
echo "\nSearching specifically in the webhook file..."
cat "apps/web/src/pages/api/stripe/webhook.ts"
Length of output: 27345
apps/web/src/app/[locale]/(admin)/settings/profile/profile-picture.tsx (3)
1-1
: LGTM! Import changes align with package restructuring
The PostHog import path has been updated correctly to use the new package structure, and the addition of the allowedMimeTypes
schema using zod provides good type safety for file validation.
Also applies to: 15-15
Line range hint 131-157
: LGTM! Good implementation of analytics tracking
The component correctly implements PostHog event tracking for both upload and remove operations, aligning with the PR's analytics objectives.
Line range hint 159-171
: LGTM! Clean implementation with proper conditional rendering
The component is well-structured and correctly uses the IfCloudHosted
wrapper for conditional rendering of the upload functionality.
apps/web/src/app/[locale]/(admin)/sidebar.tsx (1)
3-3
: LGTM! Import path updated correctly.
The import path change aligns with the PR objective of moving PostHog functionality into its own package.
apps/web/src/app/[locale]/(auth)/login/login-form.tsx (2)
2-2
: LGTM: Import path updated to use the new PostHog package
The import change aligns with the PR objective of moving PostHog functionality into its own package, improving modularity.
2-2
: Verify consistent PostHog integration across auth components
Let's verify that other authentication-related components are using the new PostHog package and following consistent event naming patterns.
✅ Verification successful
PostHog integration is consistent across auth components
The verification shows that PostHog is properly integrated across authentication-related components with consistent usage patterns:
- Auth components using PostHog:
apps/web/src/auth.ts
- captures "login" and "login failed" eventsapps/web/src/app/[locale]/(auth)/login/login-form.tsx
- captures "click continue as guest"apps/web/src/app/[locale]/(auth)/register/register-page.tsx
- imports PostHogapps/web/src/trpc/routers/auth.ts
- captures "register" eventapps/web/src/app/components/logout-button.tsx
- captures "logout" event
The event naming follows a consistent pattern:
- Authentication events use clear, action-based names: "login", "register", "logout"
- All events use lowercase with spaces for readability
- Events include relevant context data where needed
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for PostHog imports and usage in auth-related components
echo "Checking PostHog imports in auth components..."
rg -l "import.*posthog" "apps/web/src/app/\[locale\]/\(auth\)/"
echo "\nChecking PostHog event captures in auth components..."
rg "posthog.*capture\(" "apps/web/src/app/\[locale\]/\(auth\)/"
Length of output: 511
Script:
#!/bin/bash
# Let's first find the correct auth-related paths
echo "Finding auth-related paths..."
fd -t d "auth"
echo "\nChecking PostHog imports across the codebase..."
rg -l "import.*posthog"
echo "\nChecking PostHog event captures..."
rg "posthog.*capture\(" -A 2
Length of output: 10503
apps/web/src/components/forms/poll-settings.tsx (1)
1-1
: LGTM: Import path updated correctly
The import path change aligns with the PR objective of moving Posthog functionality into its own package.
apps/web/src/components/participant-dropdown.tsx (2)
2-2
: LGTM: Import path updated correctly.
The PostHog import has been successfully migrated to the new package structure, aligning with the PR's objective of moving PostHog functionality into its own package.
Line range hint 229-237
: Verify consistent event naming patterns across the codebase.
Let's ensure that PostHog event naming follows a consistent pattern across the application.
✅ Verification successful
Event naming patterns are consistent across the codebase
After analyzing the PostHog event capture calls across the codebase, the event naming follows consistent patterns:
- Uses lowercase with hyphens for multi-word events (e.g., "timezone-change-detected", "trigger-paywall")
- Action-oriented names that clearly describe the user action (e.g., "created-poll", "delete-account")
- Consistent property naming using camelCase (e.g.,
pollId
,participantId
) - Proper context properties included with relevant events (e.g.,
from
,source
,previousTimeZone
)
The event "changed name" in participant-dropdown.tsx follows these same conventions and includes appropriate context properties (participantId
, oldName
, newName
).
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check PostHog event naming patterns across the codebase
# Expected: Event names should follow a consistent format
# Search for PostHog capture calls
echo "PostHog event naming patterns:"
rg -A 1 "posthog.*capture\(" --type typescript
Length of output: 154
Script:
#!/bin/bash
# Let's try different approaches to find PostHog usage patterns
# Search for PostHog related imports
echo "=== PostHog imports ==="
rg "import.*posthog"
# Search for capture method calls without file type restriction
echo -e "\n=== PostHog capture calls ==="
rg -A 1 "posthog.*capture\("
# Search for any PostHog related code
echo -e "\n=== General PostHog usage ==="
rg "posthog" -A 2
Length of output: 35251
apps/web/src/components/poll/manage-poll.tsx (2)
Line range hint 277-282
: LGTM! PostHog analytics implementation is consistent.
The PostHog event tracking for paywall triggers is well-implemented with consistent event names and properties, providing good context for analytics.
Also applies to: 290-295
1-1
: LGTM! Import path updated correctly.
The PostHog import has been updated to use the new package path @rallly/posthog/client
, which aligns with the PR objective of moving PostHog functionality into its own package.
Let's verify that this import pattern is consistent across the codebase:
✅ Verification successful
All PostHog imports have been consistently updated to use the new package path
The verification results show that:
- No instances of the old import pattern
@/utils/posthog
were found - All PostHog imports now use the new pattern
@rallly/posthog/client
- The import in
manage-poll.tsx
follows the same consistent pattern as all other files
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for any remaining old PostHog imports and verify new import pattern usage
# Test 1: Check for any remaining old PostHog imports
echo "Checking for old PostHog imports..."
rg -l "from \"@/utils/posthog\""
# Test 2: Verify the new import pattern usage
echo "Verifying new PostHog import pattern..."
rg -l "from \"@rallly/posthog/client\""
Length of output: 1156
apps/web/src/components/discussion/discussion.tsx (2)
2-2
: LGTM: Import path updated correctly
The PostHog import has been properly updated to use the new package path, aligning with the PR's objective of moving PostHog functionality into its own package.
2-2
: Verify consistent PostHog event tracking patterns
Let's verify that similar event tracking patterns are used consistently across other components.
Also applies to: 89-93, 201-204
✅ Verification successful
PostHog event tracking patterns are consistent across the codebase
The verification shows that PostHog event tracking is implemented consistently throughout the application:
- All components use the
usePostHog
hook from@rallly/posthog/client
- Event tracking follows a consistent pattern with optional context data
- Events are properly categorized (user actions, state changes, feature usage)
- Sensitive data is handled appropriately in tracking calls
The implementation in discussion.tsx
aligns with the established patterns seen across other components.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for PostHog event capture patterns across the codebase
echo "Checking PostHog event capture patterns:"
rg "posthog.*capture\(" --type ts --type tsx -A 2
Length of output: 170
Script:
#!/bin/bash
# Search for PostHog event capture patterns across the codebase with correct file extensions
echo "Checking PostHog event tracking patterns:"
rg "posthog.*capture" -t typescript -t javascriptreact -t typescriptreact -A 2
# Also search for usePostHog hook usage to understand the implementation pattern
echo -e "\nChecking usePostHog hook usage:"
rg "usePostHog" -t typescript -t javascriptreact -t typescriptreact -A 2
Length of output: 395
Script:
#!/bin/bash
# Search for PostHog event tracking patterns using simpler approach
echo "Checking PostHog event tracking patterns:"
rg "posthog.*capture" --type-add 'ts:*.{ts,tsx}' -t ts -A 2
# Also search for usePostHog hook usage
echo -e "\nChecking usePostHog hook usage:"
rg "usePostHog" --type-add 'ts:*.{ts,tsx}' -t ts -A 2
# Look for PostHog-related imports
echo -e "\nChecking PostHog imports:"
rg "import.*posthog" --type-add 'ts:*.{ts,tsx}' -t ts
Length of output: 22827
apps/web/src/auth.ts (1)
2-2
: LGTM! Import changes align with package restructuring.
The PostHog import path has been updated to use the new package structure, and additional auth-related utilities have been properly imported.
Also applies to: 26-27
apps/web/src/trpc/routers/polls.ts (3)
3-3
: Import statement updated correctly.
The posthog
module is now correctly imported from @rallly/posthog/server
.
Line range hint 182-192
: Analytics event captured with appropriate properties.
The posthog?.capture
call correctly logs the "finalize poll" event with relevant properties. Ensure that no personally identifiable information (PII) is being sent.
Line range hint 384-400
: Potential security issue: Missing authorization checks in 'resume' mutation.
The resume
mutation uses possiblyPublicProcedure
, which may allow unauthorized users to resume polls if they know the pollId
. Ensure that proper authentication and authorization checks are in place to restrict this action to authorized users.
To confirm the access control for the resume
mutation, you can search the codebase:
#!/bin/bash
# Description: Verify the access control for the 'resume' mutation.
# Search for the definition of 'possiblyPublicProcedure'.
rg -A 10 'const possiblyPublicProcedure'
# Search for all uses of 'possiblyPublicProcedure' in mutations.
rg -A 5 'possiblyPublicProcedure.*mutation'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Outside diff range and nitpick comments (10)
packages/posthog/package.json (2)
2-4
: Consider using semantic versioning for the initial release.The package version is set to "0.0.0". Since this is a new package that will be used by other parts of the application, consider starting with version "1.0.0" or "0.1.0" following semantic versioning principles.
1-18
: Consider adding additional package.json fields.The package configuration is minimal but functional. Consider adding these fields to improve package documentation and maintainability:
description
: Brief description of the package's purposemain
: Default entry pointtypes
: TypeScript declaration filefiles
: Whitelist of files to be included when publishedscripts
: Build and test scripts{ "name": "@rallly/posthog", "version": "0.0.0", "private": true, + "description": "PostHog analytics integration for Rallly", + "main": "./src/client/index.ts", + "types": "./src/client/index.ts", + "files": [ + "src/**/*" + ], + "scripts": { + "build": "tsc", + "test": "jest" + }, "exports": {packages/posthog/src/next/middleware.ts (2)
6-12
: Add input validation and error handling.Consider adding validation for the bootstrapData object and error handling for JSON serialization:
export async function withPostHog( res: NextResponse, bootstrapData: { distinctID?: string }, ) { if (!posthogApiKey) { return; } + + try { + // Validate bootstrapData structure + if (bootstrapData && typeof bootstrapData === 'object') { + if (bootstrapData.distinctID && typeof bootstrapData.distinctID !== 'string') { + console.warn('PostHog: distinctID must be a string'); + return; + } + } else { + console.warn('PostHog: Invalid bootstrap data format'); + return; + }
14-21
: Document security considerations for the non-HTTP-only cookie.The cookie is intentionally set as non-HTTP-only to allow client-side access by PostHog. While this is necessary for functionality, it's important to document this decision and its security implications.
Add a comment explaining the security considerations:
+ // Cookie must be non-HTTP-only to allow client-side access by PostHog. + // This is secure as we only store non-sensitive analytics configuration data. res.cookies.set({ name: POSTHOG_BOOTSTAP_DATA_COOKIE_NAME, value: JSON.stringify(bootstrapData), httpOnly: false, secure: true, sameSite: "lax", path: "/", });packages/posthog/src/client/provider.tsx (1)
9-19
: Add cookie name validation.While the error handling for JSON parsing is good, consider validating the cookie name constant before use.
if (typeof window !== "undefined" && process.env.NEXT_PUBLIC_POSTHOG_API_KEY) { let bootstrapData = {}; try { + if (!POSTHOG_BOOTSTAP_DATA_COOKIE_NAME) { + throw new Error("PostHog bootstrap cookie name is not defined"); + } const cookieData = Cookies.get(POSTHOG_BOOTSTAP_DATA_COOKIE_NAME); if (cookieData) { bootstrapData = JSON.parse(cookieData); } } catch (error) { - console.warn("Failed to parse PostHog bootstrap data:", error); + console.warn("PostHog bootstrap data error:", error); }apps/web/src/middleware.ts (2)
38-39
: Consider adding error handling for initGuest.The JWT assignment lacks error handling. While the subsequent check for
jwt?.sub
provides some safety, we should consider catching potential initialization errors.- const jwt = await initGuest(req, res); + let jwt; + try { + jwt = await initGuest(req, res); + } catch (error) { + console.error('Failed to initialize guest:', error); + // Continue without analytics tracking + }
38-42
: Consider middleware performance optimization.The current implementation adds an additional async operation in the middleware chain. Consider:
- Evaluating if PostHog initialization can be moved to a client-side solution for non-critical paths
- Implementing caching strategies if the distinctID needs to be frequently accessed
- Monitoring the performance impact of this middleware in production
apps/web/src/app/guest.ts (1)
64-77
: Security: Consider enhancing error loggingThe token validation logic is more robust now, but the error logging could be improved:
- Avoid logging the full error object as it might contain sensitive information
- Consider adding structured logging with error types
Consider this improvement:
} catch (error) { - // invalid token - console.error(error); + console.error({ + type: 'INVALID_GUEST_TOKEN', + message: error instanceof Error ? error.message : 'Unknown error', + }); }apps/web/src/app/[locale]/timezone-change-detector.tsx (1)
Line range hint
16-102
: Consider refactoring for improved maintainabilityThe component could benefit from some structural improvements:
- Extract localStorage operations into a custom hook or utility
- Define constants for localStorage keys
- Create a dedicated analytics service for PostHog events
- Separate concerns between UI, storage, and analytics
Here's a suggested refactoring approach:
// constants.ts export const STORAGE_KEYS = { PREVIOUS_TIMEZONE: 'previousTimeZone', } as const; // hooks/useTimezoneStorage.ts export function useTimezoneStorage() { const getPreviousTimezone = () => safeLocalStorage.getItem(STORAGE_KEYS.PREVIOUS_TIMEZONE); const setPreviousTimezone = (timezone: string) => safeLocalStorage.setItem(STORAGE_KEYS.PREVIOUS_TIMEZONE, timezone); return { getPreviousTimezone, setPreviousTimezone }; } // services/analytics.ts export function useTimezoneAnalytics() { const posthog = usePostHog(); const trackTimezoneChange = (previousTimeZone: string, currentTimeZone: string) => { posthog?.capture("timezone change detected", { previousTimeZone, currentTimeZone }); }; const trackTimezoneChangeAccepted = (previousTimeZone: string, currentTimeZone: string) => { posthog?.capture("timezone change accepted", { previousTimeZone, currentTimeZone }); }; const trackTimezoneChangeRejected = (previousTimeZone: string, currentTimeZone: string) => { posthog?.capture("timezone change rejected", { previousTimeZone, currentTimeZone }); }; return { trackTimezoneChange, trackTimezoneChangeAccepted, trackTimezoneChangeRejected }; }This refactoring would make the component more maintainable and easier to test.
apps/web/src/app/[locale]/(auth)/register/register-page.tsx (1)
Review PII handling and add error handling for analytics
The code review concerns are valid based on the following findings:
- While there is a cookie consent component, it only covers general cookie usage and doesn't specifically handle consent for PII collection in analytics.
- PostHog is initialized with
opt_out_capturing_by_default: false
and there's no explicit PII consent management.- The registration flow sends PII (email, name) to PostHog without error handling and before sign-in completion.
Suggested improvements:
- Add specific analytics consent handling before sending PII to PostHog
- Move the PostHog identify call after successful sign-in
- Add error handling as shown in the original review
- Consider using the existing cookie consent mechanism to also manage analytics consent
- posthog?.identify(res.user.id, { - email: res.user.email, - name: res.user.name, - }); - signIn("registration-token", { - token, - callbackUrl: searchParams?.get("callbackUrl") ?? undefined, - }); + // First complete the sign-in + await signIn("registration-token", { + token, + callbackUrl: searchParams?.get("callbackUrl") ?? undefined, + }); + + // Then safely identify the user in PostHog if consent is given + try { + const hasConsent = Cookies.get("rallly_cookie_consent") === "1"; + if (hasConsent && posthog) { + await posthog.identify(res.user.id, { + email: res.user.email, + name: res.user.name, + }); + } + } catch (error) { + console.error('Failed to identify user in PostHog:', error); + }🔗 Analysis chain
Line range hint
67-73
: Review PII handling and add error handling for analyticsThe current implementation sends PII (email and name) to PostHog without explicit user consent verification. Additionally, the PostHog operation lacks error handling and could potentially delay the sign-in process.
Consider these improvements:
- Ensure user consent is obtained before sending PII to analytics
- Add error handling for the PostHog operation
- Move the identify call after successful sign-in to prevent race conditions
Here's a suggested implementation:
- posthog?.identify(res.user.id, { - email: res.user.email, - name: res.user.name, - }); - signIn("registration-token", { - token, - callbackUrl: searchParams?.get("callbackUrl") ?? undefined, - }); + // First complete the sign-in + await signIn("registration-token", { + token, + callbackUrl: searchParams?.get("callbackUrl") ?? undefined, + }); + + // Then safely identify the user in PostHog if consent is given + try { + if (hasAnalyticsConsent()) { // Add this function to check user consent + await posthog?.identify(res.user.id, { + email: res.user.email, + name: res.user.name, + }); + } + } catch (error) { + // Log analytics error but don't block the user + console.error('Failed to identify user in PostHog:', error); + }
Let me search for these patterns to verify the existence of consent management and current PostHog implementation details. This will help us determine if the review comment's concerns about PII handling and error management are valid.
Let me examine the cookie consent implementation and PostHog provider setup to verify if there's existing consent management and how it's integrated with analytics. This will help determine if the review comment's concerns about PII handling are already addressed or if additional measures are needed.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check if user consent handling exists in the codebase rg -l "consent" --type ts --type tsxLength of output: 64
Script:
#!/bin/bash # Search for consent-related code with ripgrep, including all possible extensions rg -l "consent" . --type-add 'ts:*.{ts,tsx}' --type ts # Search for PostHog configuration and initialization rg -l "posthog" . --type-add 'ts:*.{ts,tsx}' --type ts # Look for analytics-related configuration or utilities rg -l "analytics" . --type-add 'ts:*.{ts,tsx}' --type ts # Check if there's any existing error handling around PostHog calls rg "posthog.*catch" . --type-add 'ts:*.{ts,tsx}' --type tsLength of output: 1894
Script:
#!/bin/bash # Check cookie-consent implementation cat ./apps/web/src/components/cookie-consent.tsx # Check PostHog provider setup for any existing consent management cat ./packages/posthog/src/client/provider.tsx # Check if there's any existing error handling in the registration flow cat ./apps/web/src/app/[locale]/\(auth\)/register/register-page.tsxLength of output: 10274
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (10)
apps/web/src/app/[locale]/(auth)/register/register-page.tsx
(1 hunks)apps/web/src/app/[locale]/timezone-change-detector.tsx
(1 hunks)apps/web/src/app/guest.ts
(2 hunks)apps/web/src/middleware.ts
(2 hunks)packages/posthog/.eslintrc.js
(1 hunks)packages/posthog/package.json
(1 hunks)packages/posthog/src/client/index.ts
(1 hunks)packages/posthog/src/client/provider.tsx
(1 hunks)packages/posthog/src/constants.ts
(1 hunks)packages/posthog/src/next/middleware.ts
(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- packages/posthog/.eslintrc.js
- packages/posthog/src/constants.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/posthog/src/client/index.ts
🔇 Additional comments (12)
packages/posthog/package.json (3)
10-13
: Review PostHog dependencies compatibility.
The PostHog dependencies look appropriate:
- posthog-js@^1.178.0 for client-side tracking
- posthog-node@^4.2.1 for server-side tracking
However, let's verify these versions are compatible with each other and the latest stable releases.
#!/bin/bash
# Description: Check for latest stable versions of PostHog packages
echo "Checking latest PostHog package versions..."
npm view posthog-js version
npm view posthog-node version
14-17
: Verify peer dependencies alignment with the main application.
The peer dependencies on React and Next.js need to match the versions used in the main application to prevent version conflicts.
#!/bin/bash
# Description: Verify peer dependency versions match the main application
echo "Checking main application dependencies..."
if [ -f "package.json" ]; then
echo "Main package.json React version:"
jq '.dependencies.react' package.json
echo "Main package.json Next.js version:"
jq '.dependencies.next' package.json
fi
5-9
: Verify the export paths match the file structure.
The exports configuration looks good, providing clear separation between server, client, and middleware functionality. However, let's verify these paths exist in the repository.
✅ Verification successful
Export paths verified and match the file structure ✓
All the exported paths in package.json
correctly correspond to existing files in the repository:
./src/server/index.ts
exists./src/client/index.ts
exists./src/next/middleware.ts
exists
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify that the exported TypeScript files exist in the correct locations
echo "Checking for source files..."
for path in "src/server/index.ts" "src/client/index.ts" "src/next/middleware.ts"; do
if [ -f "packages/posthog/$path" ]; then
echo "✓ Found $path"
else
echo "✗ Missing $path"
fi
done
Length of output: 433
Script:
#!/bin/bash
# Let's try with fd to find these files
echo "Searching for index.ts files in server and client directories:"
fd "index.ts" "packages/posthog/src/server" "packages/posthog/src/client"
echo -e "\nSearching for middleware.ts in next directory:"
fd "middleware.ts" "packages/posthog/src/next"
# Let's also check if the directories exist
echo -e "\nChecking directories:"
for dir in "packages/posthog/src/server" "packages/posthog/src/client" "packages/posthog/src/next"; do
if [ -d "$dir" ]; then
echo "✓ Directory exists: $dir"
else
echo "✗ Missing directory: $dir"
fi
done
Length of output: 1266
packages/posthog/src/next/middleware.ts (2)
1-4
: LGTM! Imports and configuration look good.
The imports are appropriate, and using an environment variable for the API key follows security best practices.
2-2
: Verify the cookie name constant and middleware usage.
Let's verify the integration points:
✅ Verification successful
Integration verified: Cookie constant and middleware are properly integrated
The verification shows:
- The cookie constant
POSTHOG_BOOTSTAP_DATA_COOKIE_NAME
is properly defined inconstants.ts
and correctly imported where needed - The middleware is properly integrated in the application:
- Defined in
packages/posthog/src/next/middleware.ts
- Used in
apps/web/src/middleware.ts
with correct parameters
- Defined in
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check the cookie name constant definition
echo "Checking cookie name constant..."
rg "POSTHOG_BOOTSTAP_DATA_COOKIE_NAME" -A 2
# Check middleware usage in the application
echo "Checking middleware usage..."
rg "withPostHog" -A 5
Length of output: 2398
packages/posthog/src/client/provider.tsx (1)
1-8
: LGTM! Clean imports and proper client-side directive.
The imports are well-organized and the "use client" directive is correctly placed.
apps/web/src/middleware.ts (3)
2-2
: LGTM: Clean import of PostHog middleware.
The import statement correctly follows the new package structure, aligning with the PR's objective of moving PostHog functionality into its own package.
40-42
: 🛠️ Refactor suggestion
Verify PostHog initialization impact and error handling.
The PostHog initialization adds an async operation to the middleware chain. Additionally, error handling should be considered.
Consider applying this improvement:
- if (jwt?.sub) {
- await withPostHog(res, { distinctID: jwt.sub });
- }
+ if (jwt?.sub) {
+ try {
+ await withPostHog(res, { distinctID: jwt.sub });
+ } catch (error) {
+ console.error('Failed to initialize PostHog:', error);
+ // Continue serving the request even if analytics fails
+ }
+ }
40-42
: Review security implications of using JWT sub as distinctID.
While using jwt.sub
as the PostHog distinctID is a common practice, ensure this identifier doesn't expose sensitive information.
✅ Verification successful
Let me check how randomid()
is implemented to ensure it's using secure random generation.
Let me check the implementation of customAlphabet
to ensure it's using a cryptographically secure random number generator.
Using JWT sub as PostHog distinctID is secure in this implementation
The jwt.sub
is generated using nanoid
library's customAlphabet
function which:
- Uses cryptographically secure random number generator
- Generates a 12-character string using alphanumeric characters
- Prefixes it with "user-" making it a non-sensitive, random identifier
The implementation doesn't expose any sensitive information and follows security best practices for anonymous user tracking.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check how jwt.sub is generated
rg -A 5 "jwt.*sub" --type ts
Length of output: 1912
Script:
#!/bin/bash
# Check randomid implementation
rg -A 5 "randomid.*=" --type ts
rg -A 5 "function randomid" --type ts
Length of output: 399
Script:
#!/bin/bash
# Check nanoid implementation and imports
rg "from.*nanoid" --type ts
cat packages/utils/src/nanoid.ts
Length of output: 770
apps/web/src/app/guest.ts (1)
7-7
: LGTM: Import addition is appropriate
The addition of decode
import aligns with its usage in the token validation logic.
apps/web/src/app/[locale]/timezone-change-detector.tsx (1)
3-3
: LGTM: Import path updated correctly
The import path change aligns with the PR objective of moving Posthog functionality into its own package.
apps/web/src/app/[locale]/(auth)/register/register-page.tsx (1)
3-3
: LGTM: Import path updated correctly
The PostHog import has been successfully moved to the new package location, which aligns with the PR's objective of modularizing the PostHog functionality.
Move posthog to its own package so that we can use it on the landing page as well
Summary by CodeRabbit
Release Notes
New Features
PostHogProvider
component for improved analytics management.SessionProvider
component for handling user sessions.Improvements
Bug Fixes
Chores