Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
Important Review skippedMore than 25% of the files skipped due to max files limit. The review is being skipped to prevent a low-quality review. 121 files out of 270 files are above the max files limit of 100. Please upgrade to Pro plan to get higher limits. You can disable this status message by setting the WalkthroughThis update implements a comprehensive migration from user-centric to email-account-centric data models and logic throughout the web application. All API routes, server actions, database queries, and React components are refactored to use email account identifiers (typically the user's email address or an account ID) instead of user IDs. Authentication and authorization flows are unified using a new Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI (React)
participant useAccount Provider
participant API Route (withAuth)
participant Database
User->>UI (React): Interacts (e.g., switch account, fetch data)
UI (React)->>useAccount Provider: Get/set current account (email/accountId)
UI (React)->>API Route (withAuth): Make API call with account context
API Route (withAuth)->>API Route (withAuth): Extract email/accountId from request
API Route (withAuth)->>Database: Query/update using email/accountId
Database-->>API Route (withAuth): Return data
API Route (withAuth)-->>UI (React): Respond with data
UI (React)-->>User: Render updated UI
Possibly related PRs
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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.
Actionable comments posted: 4
🔭 Outside diff range comments (5)
apps/web/utils/redis/clean.ts (1)
110-113:⚠️ Potential issueInconsistency in
deleteAllUserDatafunctionWhile
getThreadsByJobIdhas been updated to useemailAccountId, thedeleteAllUserDatafunction still usesuserIdas the parameter and in the Redis key pattern. This is inconsistent with the rest of the refactoring.-export async function deleteAllUserData(userId: string) { +export async function deleteAllUserData(emailAccountId: string) { // Delete all thread keys for this user - const threadPattern = `thread:${userId}:*`; + const threadPattern = `thread:${emailAccountId}:*`;apps/web/utils/actions/categorize.ts (1)
50-56: 💡 Verification agent🧩 Analysis chain
Inconsistent use of userId in getUncategorizedSenders function.
While most of the file has been updated to use email-based identification, this function still uses
userId. Consider updating this for consistency.async function getUncategorizedSenders(offset: number) { const result = await getSenders({ - userId: user.id, + email: user.email, limit: LIMIT, offset, });Note: This would require updating the signature of the
getSendersfunction as well.
🏁 Script executed:
#!/bin/bash # Find the getSenders function definition to see if it accepts email parameter rg -A 5 "getSenders\s*=?\s*\(?\s*\{" apps/web/app/api/user/categorize/senders/uncategorized/get-senders.tsLength of output: 205
Update getUncategorizedSenders and getSenders to use email instead of userId
To keep identification consistent across the file, you’ll need to adjust both the call site in
categorize.tsand thegetSendersAPI signature:• apps/web/utils/actions/categorize.ts (around Lines 50–56)
async function getUncategorizedSenders(offset: number) { const result = await getSenders({ - userId: user.id, + email: user.email, limit: LIMIT, offset, });• apps/web/app/api/user/categorize/senders/uncategorized/get-senders.ts
-export async function getSenders({ - userId, +export async function getSenders({ + email, offset = 0, limit = 100, }: { - userId: string; + email: string; }) { // …implementation…Make sure to update any internal logic in
getSendersto query by email rather than userId.apps/web/utils/reply-tracker/outbound.ts (1)
38-44:⚠️ Potential issueInconsistent parameter in resolveReplyTrackers call.
While the rest of the file has been updated to use email-based identification, this function call still passes
user.userId. Consider updating this to useuser.emailfor consistency with the updated function signature.await resolveReplyTrackers( gmail, - user.userId, + user.email, message.threadId, needsReplyLabelId, );apps/web/app/api/resend/summary/route.ts (2)
218-236:⚠️ Potential issueDuplicate function identifier causes compilation error
sendEmailis declared at line 24 and redeclared here inside the same scope.
In ESM/TypeScript (strict mode) this is a duplicate lexical declaration and will fail to compile.Rename the inner helper:
-async function sendEmail({ email }: { email: string }) { +async function sendSummaryResend({ email }: { email: string }) {and update the single call at line 239 accordingly.
238-244: 🛠️ Refactor suggestionCall site still references shadowed name
After renaming the inner helper you’ll need:
-shouldSendEmail ? sendEmail({ email }) : Promise.resolve(), +shouldSendEmail ? sendSummaryResend({ email }) : Promise.resolve(),Failure to update will lead to an unresolved identifier once the duplicate definition is removed.
🧹 Nitpick comments (19)
apps/web/app/api/user/draft-actions/route.ts (1)
10-13: Authentication updated consistentlyGood update changing the authentication check from
user.idtouser.email, aligning with the email-account-centric model. Consider adding validation to ensure the email is properly formatted.Consider adding email format validation:
const session = await auth(); const email = session?.user.email; -if (!email) +if (!email || !isValidEmail(email)) return NextResponse.json({ error: "Not authenticated" }, { status: 401 });apps/web/app/(app)/reply-zero/page.tsx (1)
116-118: Update commented code for consistencyAlthough it's commented out, the
NeedsActioncomponent reference still usesuserIdanduserEmail. For consistency, this should be updated to use only{/* <TabsContent value="needsAction" className="mt-0 flex-1"> - <NeedsAction userId={userId} userEmail={userEmail} page={page} /> + <NeedsAction email={email} page={page} /> </TabsContent> */}apps/web/utils/ai/assistant/process-user-request.ts (2)
629-639: Unused userId parameter in function definitionThe
getUpdateCategoryToolfunction still takes auserIdparameter but doesn't use it in the implementation. Consider removing this unused parameter.-const getUpdateCategoryTool = ( - userId: string, +const getUpdateCategoryTool = ( categories: Pick<Category, "id" | "name">[], loggerOptions: { userId: string; email: string | null; messageId?: string | null; threadId?: string | null; }, userEmail: string, ) =>
162-167: Consider updating loggerOptions to remove userIdWhile the code will work fine, for consistency with the email-account-centric model, consider updating
loggerOptionsto focus on email rather than userId.apps/web/utils/actions/rule.ts (1)
437-438: Unused userId in authentication blockThere's an unused
userIdvariable that's extracted from the session but never used. Consider removing it.const session = await auth(); const email = session?.user.email; if (!email) return { error: "Not logged in" }; - const userId = session?.user.id;apps/web/scripts/migrateRedisPlansToPostgres.ts (1)
158-159: Minor nit: use object spreading instead of repeatingemailAccountIdYou set
emailAccountIdtwice in the twocreateblocks. To keep both branches in sync, consider pulling the common fields into a helper:const baseData = { threadId: plan.threadId, messageId: plan.messageId, emailAccountId: emailAccount.email, }; -// inside “plan.rule” branch +// inside “plan.rule” branch await prisma.executedRule.create({ data: { - threadId: plan.threadId, - messageId: plan.messageId, + ...baseData, … }, }); -// inside “else” branch -const data = { - threadId: plan.threadId, - messageId: plan.messageId, - status: "SKIPPED" as const, - automated: false, - emailAccountId: emailAccount.email, -}; +const data = { ...baseData, status: "SKIPPED" as const, automated: false };This removes duplication and guarantees the two paths never diverge accidentally.
Also applies to: 208-209
apps/web/app/(app)/automation/onboarding/page.tsx (2)
49-61: Gracefully handle missing relations
emailAccount.rulesis guaranteed to be an array, butcoldEmailBlockercan benull.
If you ever introduce partial selects (e.g., feature flags) Prisma may returnundefinedfor unselected fields. A defensive pattern avoids runtime surprises:-const emailAccount = await prisma.emailAccount.findUnique({ +const emailAccount = await prisma.emailAccount.findUnique({ where: { email }, select: { rules: { … }, coldEmailBlocker: true, }, }); -if (!emailAccount) return undefined; +if (!emailAccount) return undefined; + +const { rules = [], coldEmailBlocker = null } = emailAccount;Then use
rules/coldEmailBlockerdownstream.
64-72: Minor optimisation: compute look‑ups only once
getRuleSettingscans the rules array for every system type.
For ~5 categories this is fine, but as the list grows you’ll traverse the array N×M times.A quick win:
const rulesBySystem = new Map( emailAccount.rules.map((r) => [r.systemType, r]), ); const getSetting = (system: SystemType) => getRuleSetting(system, rulesBySystem.get(system));Not blocking, just a future scalability note.
apps/web/utils/actions/ai-rule.ts (4)
185-186: Consistency between create / update helpers
safeCreateRule,safeUpdateRule, and downstream helpers all expectemailAccountId).
That’s fine, but make sure all callers switched; a lingeringuserIdwould silently create orphaned rows.Consider adding a runtime assertion inside helpers:
invariant(email.includes("@"), "email param must be an email address");to catch accidental IDs early.
Also applies to: 461-466, 493-495
245-248: PreferupdateoverupdateManyfor single‑row ops
updateManyignores the case where zero rows match, hiding auth mistakes and typos.
updatewould surface aP2025error in that scenario, which you could translate into a 404.
617-639:emailAccountIdvs email variable namingInside
reportAiMistakeActionyou introduce:const emailAccountId = session?.user.email;This is actually the email string, not the database ID.
Rename toemailAddress) to avoid confusion:-const emailAccountId = session?.user.email; -if (!emailAccountId) … +const email = session?.user.email; +if (!email) …Then update subsequent occurrences.
687-690: Eager‑loadingcategoryFiltersmay explode row size
include: { actions: true, categoryFilters: true }pulls two potentially large relations for every enabled rule, even in flows that never touch them.If you only need
actions, dropcategoryFilters; otherwise request specific fields:-include: { actions: true, categoryFilters: true } +include: { + actions: true, + categoryFilters: { select: { id: true, categoryId: true } }, +}This keeps the response payload predictable and lowers the chances of hitting the 4 MB JSON limit on Vercel/Postgres.
apps/web/utils/assistant/process-assistant-email.ts (1)
17-22: Consider updating the ProcessAssistantEmailArgs interface in a future PR.The interface still includes
userId: stringwhile the implementation now primarily uses email-based identification. While this maintains backward compatibility during the transition, it would be cleaner to update this interface once the refactoring is complete.apps/web/utils/reply-tracker/draft-tracking.ts (1)
24-28: Unused userId variable in trackSentDraftStatus function.The function extracts
userIdfromuser.idbut after refactoring it's only used in the logger options. Consider removing it if no longer needed or keeping only email as the identifier.- const { id: userId, email: userEmail } = user; + const { email: userEmail } = user; const { threadId, id: sentMessageId, textPlain: sentTextPlain } = message; - const loggerOptions = { userId, userEmail, threadId, sentMessageId }; + const loggerOptions = { userEmail, threadId, sentMessageId };apps/web/utils/actions/categorize.ts (2)
80-83: Inconsistent use of userId in logging.While most of the file has been updated to use email-based identification, the logging still uses
userId. Consider updating this for consistency.logger.trace("Got uncategorized senders", { - userId: user.id, + email: user.email, uncategorizedSenders: newUncategorizedSenders.length, });
103-106: Inconsistent use of userId in logging.Similar to the previous comment, consider updating this log to use email-based identification for consistency.
logger.info("Queued senders for categorization", { - userId: user.id, + email: user.email, totalUncategorizedSenders, });apps/web/utils/reply-tracker/inbound.ts (1)
32-37: Prefer accurate field naming in structured logsThe logger enriches context with
email: emailAccountId.
BecauseemailAccountIdnow stores a stringified primary‑key (the user’s email) rather than a numeric/UUID id, tagging it as
Consider either:- const logger = createScopedLogger("reply-tracker/inbound").with({ - email: emailAccountId, + const logger = createScopedLogger("reply-tracker/inbound").with({ + emailAccountId,or renaming the variable throughout to
apps/web/app/api/ai/analyze-sender-pattern/route.ts (2)
67-70: Identifier confusion:emailAccountIdholds an email stringThroughout the refactor a raw email string is now passed as
emailAccountId.
Consider renaming the field (and composite index) to simply
148-149: Consistent parameter naming
savePatternCheck({ emailAccountId: emailAccount.email, ... })again mixes concepts. If you keep the string‑id design, rename the function argument toaccountEmailfor clarity. This small change reduces future slip‑ups when the real numeric/UUID id is re‑introduced.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (61)
apps/web/app/(app)/automation/onboarding/page.tsx(3 hunks)apps/web/app/(app)/automation/page.tsx(2 hunks)apps/web/app/(app)/automation/rule/[ruleId]/page.tsx(1 hunks)apps/web/app/(app)/clean/helpers.ts(1 hunks)apps/web/app/(app)/clean/page.tsx(1 hunks)apps/web/app/(app)/clean/run/page.tsx(1 hunks)apps/web/app/(app)/reply-zero/AwaitingReply.tsx(2 hunks)apps/web/app/(app)/reply-zero/NeedsReply.tsx(2 hunks)apps/web/app/(app)/reply-zero/ReplyTrackerEmails.tsx(5 hunks)apps/web/app/(app)/reply-zero/Resolved.tsx(4 hunks)apps/web/app/(app)/reply-zero/fetch-trackers.ts(3 hunks)apps/web/app/(app)/reply-zero/page.tsx(5 hunks)apps/web/app/(app)/setup/page.tsx(1 hunks)apps/web/app/(app)/smart-categories/page.tsx(1 hunks)apps/web/app/(app)/smart-categories/setup/page.tsx(1 hunks)apps/web/app/api/ai/analyze-sender-pattern/route.ts(8 hunks)apps/web/app/api/clean/gmail/route.ts(1 hunks)apps/web/app/api/google/labels/create/controller.ts(2 hunks)apps/web/app/api/google/webhook/process-history.ts(3 hunks)apps/web/app/api/reply-tracker/disable-unused-auto-draft/route.ts(6 hunks)apps/web/app/api/resend/summary/route.ts(7 hunks)apps/web/app/api/user/categories/route.ts(1 hunks)apps/web/app/api/user/categorize/senders/batch/handle-batch.ts(2 hunks)apps/web/app/api/user/draft-actions/route.ts(1 hunks)apps/web/app/api/user/group/[groupId]/items/route.ts(2 hunks)apps/web/app/api/user/group/route.ts(2 hunks)apps/web/app/api/user/rules/[id]/route.ts(2 hunks)apps/web/app/api/user/rules/route.ts(2 hunks)apps/web/prisma/schema.prisma(14 hunks)apps/web/scripts/migrateRedisPlansToPostgres.ts(4 hunks)apps/web/utils/actions/ai-rule.ts(19 hunks)apps/web/utils/actions/categorize.ts(7 hunks)apps/web/utils/actions/clean.ts(2 hunks)apps/web/utils/actions/cold-email.ts(2 hunks)apps/web/utils/actions/group.ts(5 hunks)apps/web/utils/actions/knowledge.ts(3 hunks)apps/web/utils/actions/mail.ts(3 hunks)apps/web/utils/actions/permissions.ts(1 hunks)apps/web/utils/actions/reply-tracking.ts(1 hunks)apps/web/utils/actions/rule.ts(15 hunks)apps/web/utils/actions/unsubscriber.ts(1 hunks)apps/web/utils/actions/user.ts(1 hunks)apps/web/utils/ai/actions.ts(1 hunks)apps/web/utils/ai/assistant/process-user-request.ts(4 hunks)apps/web/utils/assistant/process-assistant-email.ts(5 hunks)apps/web/utils/categorize/senders/categorize.ts(7 hunks)apps/web/utils/category.server.ts(2 hunks)apps/web/utils/group/group-item.ts(1 hunks)apps/web/utils/redis/clean.ts(1 hunks)apps/web/utils/redis/reply-tracker-analyzing.ts(1 hunks)apps/web/utils/reply-tracker/check-previous-emails.ts(1 hunks)apps/web/utils/reply-tracker/draft-tracking.ts(2 hunks)apps/web/utils/reply-tracker/enable.ts(3 hunks)apps/web/utils/reply-tracker/generate-draft.ts(1 hunks)apps/web/utils/reply-tracker/inbound.ts(6 hunks)apps/web/utils/reply-tracker/outbound.ts(4 hunks)apps/web/utils/rule/prompt-file.ts(1 hunks)apps/web/utils/rule/rule.ts(7 hunks)apps/web/utils/sender.ts(1 hunks)apps/web/utils/unsubscribe.ts(1 hunks)apps/web/utils/user/delete.ts(2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (23)
apps/web/app/(app)/clean/page.tsx (1)
apps/web/app/(app)/clean/helpers.ts (1)
getLastJob(15-20)
apps/web/app/(app)/smart-categories/setup/page.tsx (1)
apps/web/utils/category.server.ts (1)
getUserCategories(13-18)
apps/web/app/api/user/categorize/senders/batch/handle-batch.ts (1)
apps/web/utils/categorize/senders/categorize.ts (1)
getCategories(143-147)
apps/web/utils/actions/unsubscriber.ts (2)
apps/web/utils/actions/unsubscriber.validation.ts (1)
setNewsletterStatusBody(4-7)apps/web/utils/email.ts (1)
extractEmailAddress(16-36)
apps/web/app/api/user/categories/route.ts (3)
apps/web/utils/categorize/senders/categorize.ts (1)
getCategories(143-147)apps/web/utils/category.server.ts (1)
getUserCategories(13-18)apps/web/utils/middleware.ts (1)
withError(16-70)
apps/web/app/(app)/smart-categories/page.tsx (1)
apps/web/utils/category.server.ts (1)
getUserCategoriesWithRules(20-31)
apps/web/app/(app)/clean/run/page.tsx (3)
apps/web/utils/redis/clean.ts (1)
getThreadsByJobId(75-108)apps/web/app/(app)/clean/helpers.ts (2)
getJobById(3-13)getLastJob(15-20)apps/web/components/ui/card.tsx (1)
CardTitle(112-112)
apps/web/app/api/google/labels/create/controller.ts (3)
apps/web/utils/error.ts (1)
SafeError(87-95)apps/web/utils/gmail/client.ts (1)
getGmailClient(28-33)apps/web/utils/gmail/label.ts (1)
getOrCreateLabel(270-282)
apps/web/app/(app)/reply-zero/NeedsReply.tsx (2)
apps/web/app/(app)/reply-zero/date-filter.ts (1)
TimeRange(1-1)apps/web/app/(app)/reply-zero/fetch-trackers.ts (1)
getPaginatedThreadTrackers(7-59)
apps/web/app/(app)/reply-zero/page.tsx (1)
apps/web/utils/redis/reply-tracker-analyzing.ts (1)
isAnalyzingReplyTracker(18-22)
apps/web/utils/actions/knowledge.ts (1)
apps/web/utils/actions/knowledge.validation.ts (3)
createKnowledgeBody(3-6)updateKnowledgeBody(10-14)deleteKnowledgeBody(18-20)
apps/web/utils/actions/group.ts (2)
apps/web/utils/actions/group.validation.ts (1)
createGroupBody(4-6)apps/web/utils/group/group-item.ts (1)
deleteGroupItem(21-31)
apps/web/app/(app)/reply-zero/AwaitingReply.tsx (2)
apps/web/app/(app)/reply-zero/date-filter.ts (1)
TimeRange(1-1)apps/web/app/(app)/reply-zero/fetch-trackers.ts (1)
getPaginatedThreadTrackers(7-59)
apps/web/utils/actions/rule.ts (2)
apps/web/utils/actions/rule.validation.ts (2)
updateRuleSettingsBody(154-157)enableDraftRepliesBody(160-160)apps/web/utils/rule/rule.ts (1)
deleteRule(207-223)
apps/web/utils/sender.ts (1)
apps/web/utils/email.ts (1)
extractEmailAddress(16-36)
apps/web/utils/actions/reply-tracking.ts (2)
apps/web/utils/redis/reply-tracker-analyzing.ts (2)
startAnalyzingReplyTracker(7-11)stopAnalyzingReplyTracker(13-16)apps/web/app/api/google/webhook/logger.ts (1)
logger(3-3)
apps/web/utils/actions/ai-rule.ts (3)
apps/web/utils/rule/rule.ts (2)
deleteRule(207-223)safeUpdateRule(77-117)apps/web/utils/category.server.ts (1)
getUserCategoriesForNames(33-54)apps/web/utils/user/get.ts (1)
getAiUser(4-18)
apps/web/utils/assistant/process-assistant-email.ts (1)
apps/web/utils/email.ts (1)
extractEmailAddress(16-36)
apps/web/utils/reply-tracker/draft-tracking.ts (1)
apps/web/app/api/google/webhook/logger.ts (1)
logger(3-3)
apps/web/app/api/resend/summary/route.ts (2)
apps/web/utils/gmail/message.ts (1)
getMessagesBatch(57-107)apps/web/utils/unsubscribe.ts (1)
createUnsubscribeToken(5-21)
apps/web/utils/rule/rule.ts (4)
apps/web/utils/ai/rule/create-rule-schema.ts (1)
CreateOrUpdateRuleSchemaWithCategories(128-131)apps/web/utils/category.server.ts (1)
getUserCategoriesForNames(33-54)apps/web/app/api/google/webhook/logger.ts (1)
logger(3-3)apps/web/utils/prisma.ts (1)
isDuplicateError(18-27)
apps/web/app/api/ai/analyze-sender-pattern/route.ts (2)
apps/web/utils/email.ts (1)
extractEmailAddress(16-36)apps/web/app/api/google/webhook/logger.ts (1)
logger(3-3)
apps/web/utils/categorize/senders/categorize.ts (2)
apps/web/utils/category.server.ts (1)
getUserCategories(13-18)apps/web/utils/email.ts (1)
extractEmailAddress(16-36)
🔇 Additional comments (212)
apps/web/app/(app)/smart-categories/setup/page.tsx (1)
12-12: Function call correctly updated to use email-based identification.The call to
getUserCategorieshas been properly modified to pass an object with the email property instead of a user ID, aligning with the updated implementation inapps/web/utils/category.server.tsthat now filters categories byemailAccountId.apps/web/app/(app)/clean/page.tsx (2)
9-10: Authentication check correctly updated to use email.The authentication check has been properly updated to extract and verify the user's email rather than the user ID, consistent with the broader shift to email-account-centric identification.
12-12: Function call correctly updated to use email parameter.The call to
getLastJobhas been properly modified to pass an object with the email property rather than a user ID, matching the updated implementation shown in the context snippet that now queries by email instead of user ID.apps/web/utils/reply-tracker/generate-draft.ts (1)
141-141: Database query correctly updated to use email as identifier.The Prisma query for fetching knowledge base entries has been properly updated to filter by
emailAccountIdusing the user's email instead of user ID. This change aligns with the broader refactoring to move relations from theUsermodel to theEmailAccountmodel.apps/web/app/(app)/automation/page.tsx (2)
26-27: Authentication check correctly updated to use email.The authentication check has been properly updated to extract the user's email from the session and redirect to the login page if the email is missing, replacing the previous check that likely verified the user ID.
36-36: Database query correctly updated to use email as identifier.The Prisma query for checking if a rule exists has been properly updated to filter by
emailAccountIdusing the user's email instead of user ID. This change aligns with the broader refactoring to move relations from theUsermodel to theEmailAccountmodel.apps/web/app/api/clean/gmail/route.ts (1)
117-124: Updated database association to use emailAccount instead of userThe change properly updates the database association from user to emailAccount, which aligns with the broader refactoring to shift from a user-centric model to an email-account-centric model.
apps/web/app/api/user/categorize/senders/batch/handle-batch.ts (2)
47-47: Parameter structure change to match function signatureThis change correctly updates the call to
getCategoriesto use an object with an
108-108: Changed from userId to userEmail for sender category updateProperly updated to use the email as identifier instead of userId, consistent with the broader refactoring effort.
apps/web/app/(app)/setup/page.tsx (2)
27-31: Simplified data structure by removing nested user objectThe data selection is now more direct, with
rulesandnewslettersselected directly on theemailAccountobject instead of through a nesteduserobject. This simplification makes the code more readable and aligns with the email-account-centric model.
37-38: Updated property access to match new data structureThe property access has been correctly updated to directly access
rulesandnewslettersfrom theemailAccountobject instead of through the previously nesteduserobject.apps/web/utils/group/group-item.ts (1)
21-31: Updated parameter and query from userId to email-based identificationThe function has been properly updated to:
- Change the parameter name from
userIdto- Update the Prisma query to use
emailAccountId: emailinstead ofuserIdThis change aligns with the broader refactoring effort moving from user-centric to email-account-centric identification.
apps/web/utils/actions/user.ts (2)
94-96: Filter change looks good but lacks proper email validationThe change from using
userIdtoemailAccountIdfor filtering email messages is consistent with the refactoring goal. However, emails are being directly used as IDs without validation, which could lead to issues if session.user.email is undefined or malformed.Consider adding validation or sanitization for the email before using it as an ID:
await prisma.emailMessage.deleteMany({ - where: { emailAccountId: session.user.email }, + where: { + emailAccountId: session.user.email + // Consider adding a check that email is valid before this query + }, });
118-123: Inconsistency with other user actionsSeveral other actions in this file (
completedOnboardingAction,completedAppOnboardingAction,saveOnboardingAnswersAction) still useuser.idfor authentication and database queries, whileresetAnalyticsActionhas been updated to useemailAccountId.Should these other actions also be updated to use email-based identification as part of this refactoring? This would ensure consistency in how users are identified throughout the codebase.
Also applies to: 130-136, 150-160
apps/web/utils/unsubscribe.ts (2)
5-9: Function signature change looks goodThe update to accept an email object parameter instead of userId aligns with the email-account-centric refactoring approach.
12-18: Good update to use emailAccountIdThe change from
userIdtoemailAccountIdin the token creation process is consistent with the refactoring goals. However, using an email address directly as an ID has implications for database design:
- Emails can sometimes change (though rarely)
- Using a non-primary-key as a foreign key reference might impact query performance
Consider whether the
EmailAccountmodel uses email as its primary key or if it has a separate ID field. If it has a separate ID, you might want to look up the ID first:// Example alternative approach const emailAccount = await prisma.emailAccount.findUnique({ where: { email } }); await prisma.emailToken.create({ data: { token, emailAccountId: emailAccount.id, // Using the actual ID expiresAt: addDays(new Date(), 30), }, });apps/web/utils/sender.ts (2)
4-9: Parameter naming improved for clarityThe change from
userIdtoemailAccountIdin the function parameters aligns with the email-account-centric refactoring approach and improves semantic clarity.
14-19: Query filter updated correctlyThe Prisma query filter has been properly updated to use
emailAccountIdinstead ofuserId, maintaining consistency with the parameter changes.apps/web/app/api/user/draft-actions/route.ts (2)
15-15: Function call updated correctlyThe call to
getDatahas been properly updated to pass an object with the email property.
20-24: Query filtering updated correctlyThe function signature and Prisma query have been properly updated to use
emailAccountIdinstead ofuserId, maintaining consistency with the refactoring approach.For consistent error handling, consider adding a check to ensure the email is provided and valid:
async function getData({ email }: { email: string }) { if (!email) { throw new Error("Email is required"); } // Continue with existing code... }apps/web/app/(app)/automation/rule/[ruleId]/page.tsx (2)
16-17: Authentication check correctly updated to use email.The authentication check now properly extracts the user's email from the session object and redirects if it's missing, aligning with the email-account-centric model refactoring.
20-20: Database query updated to use email account ID.The query now correctly uses
emailAccountId: emailinstead of user ID, consistent with the schema changes throughout the application.apps/web/app/(app)/reply-zero/ReplyTrackerEmails.tsx (3)
38-38: Property renamed fromuserEmailtoThe component props were correctly updated to use
userEmail, maintaining consistency with the email-account-centric model.Also applies to: 45-45
182-182: Updated prop passed to Row component.The prop passed to the Row component has been properly renamed from
userEmailto
260-260: Row component parameter renamed fromuserEmailtoThe function parameter and its type annotation have been correctly updated to use
userEmail.Also applies to: 272-272
apps/web/app/api/google/webhook/process-history.ts (3)
49-52: Updated Prisma query to select rules directly from emailAccount.The query now correctly selects rules directly from the emailAccount entity instead of through user relations, aligning with the schema changes where relations moved from User to EmailAccount.
110-110: Updated reference to rules property.The reference to rules has been properly updated from
emailAccount.user.rulestoemailAccount.rulesto match the new schema structure.
178-178: Updated processHistory function call.The processHistory function call now correctly passes
emailAccount.rulesinstead of accessing them through the user property.apps/web/utils/ai/actions.ts (1)
220-221: Property renamed from email to emailAccountId in coordinateReplyProcess.The property has been correctly renamed to
emailAccountIdwhen callingcoordinateReplyProcess, maintaining consistency with the email-account-centric model throughout the application.apps/web/utils/reply-tracker/check-previous-emails.ts (1)
49-50: Change aligns with architecture shift from User to EmailAccount.This change to the unique constraint query is part of the broader refactoring to use email accounts as the primary identifier instead of user IDs. The code is now using
emailAccountId: user.emailinstead of the previoususerIdin the unique constraint.apps/web/utils/actions/permissions.ts (1)
63-69: Data access pattern updated to use EmailAccount model.The code now queries the
emailAccounttable directly and accesses tokens through the nestedaccountrelation, which aligns with the refactored data model. This is a cleaner approach that centralizes access through the email account.apps/web/utils/actions/clean.ts (2)
247-248: Updated query to use email-based identification.Changed from filtering by
userIdto usingemailAccountId: email, aligning with the email-account-centric model being implemented across the codebase.
310-311: Consistent use of email identification in queries.Changed from filtering by
userIdto usingemailAccountId: email, maintaining consistency with the changes made throughout the codebase for email-account-centric identification.apps/web/utils/actions/unsubscriber.ts (2)
16-17: Authentication check updated to use email identifier.The code now uses
session?.user.emailinstead ofsession?.user.idfor authentication checks, consistent with the email-account-centric approach being implemented.
29-35: Database relations updated to use email as primary identifier.The upsert operation now uses the composite key
email_emailAccountIdand setsemailAccountId: userEmaildirectly instead of connecting through a User entity. This properly aligns with the schema changes that moved relations from User to EmailAccount.apps/web/app/(app)/clean/run/page.tsx (3)
18-20: Properly refactored to use email-based identificationThe code correctly switches from using
userIdtouserEmailas the primary identifier, and updates the function call to useemailAccountIdparameter. This aligns with the PR objective of moving to an email-account-centric model.
22-24: Consistent parameter passing with updated helper functionsThe code correctly updates calls to
getJobByIdandgetLastJobto use theuserId, matching the updated function signatures in the helpers file.
28-32: Database queries updated correctlyThe Prisma queries have been properly updated to filter by
emailAccountId: userEmailinstead ofuserId, maintaining data consistency with the email-account-centric model.apps/web/app/api/user/rules/route.ts (2)
8-10: Function signature and query filters properly updatedThe
getRulesfunction signature has been correctly updated to acceptuserId, and the Prisma query filter now usesemailAccountId: emailinstead ofuserId. This is consistent with the schema changes moving relations fromUsertoEmailAccount.
22-25: Authentication and function call updated correctlyThe authentication check and function call have been properly updated to use email-based identification instead of user ID, consistent with the PR objective.
apps/web/app/api/user/rules/[id]/route.ts (2)
9-12: Function signature and query filter properly updatedThe
getRulefunction signature has been correctly updated to acceptuserId, and the Prisma query filter now usesemailAccountId: emailinstead ofuserId. This is consistent with the schema changes moving relations fromUsertoEmailAccount.
24-27: Function call parameter updated correctlyThe call to
getRulenow correctly passesemail: session.user.emailinstead ofuserId, ensuring consistency with the updated function signature.apps/web/app/api/user/categories/route.ts (2)
8-9: Function signature updated correctlyThe
getCategoriesfunction signature has been properly updated to accept an object with anuserId, and it correctly callsgetUserCategorieswith the email parameter.
15-18: Authentication and function call updated correctlyThe authentication check now properly verifies
session.user.emailinstead ofsession.user.id, and the function call passes the email parameter correctly. This maintains consistency with the email-account-centric model being implemented.apps/web/app/api/user/group/route.ts (3)
8-10: Function signature and query updated to use email identifier instead of userId.The
getGroupsfunction and its Prisma query have been correctly updated to useemailAccountIdfilter instead of the previoususerIdapproach. This change aligns with the PR objective of moving from a user-centric model to an email-account-centric model.
23-24: Authentication check correctly updated to use email.The authentication check has been properly adapted to extract the email from the session and verify its presence. This maintains security while adapting to the new identity model.
26-26: Function call updated to use email parameter.The
getGroupsfunction call now correctly passes the email parameter, completing the migration from userId to email-based identification for this endpoint.apps/web/app/(app)/reply-zero/fetch-trackers.ts (3)
7-17: Function signature correctly updated to use email parameter.The
getPaginatedThreadTrackersfunction signature has been appropriately refactored to acceptuserId, aligning with the email-account-centric model. The type definition has been correctly updated as well.
22-35: Prisma query properly updated to filter by emailAccountId.The database query has been correctly modified to filter by
emailAccountId: emailinstead of the previoususerIdfilter. This ensures proper data retrieval based on the email account identity.
36-52: SQL raw queries consistently updated to use emailAccountId.Both SQL raw queries have been correctly modified to use
emailAccountIdinstead ofuserId, maintaining consistency with the Prisma queries. This ensures that the pagination counts are correctly calculated using the same identity model.apps/web/app/(app)/smart-categories/page.tsx (2)
38-41: Newsletter query updated to use emailAccountId filter.The database query for newsletters has been properly updated to filter by
emailAccountId: emailinstead of the previoususerIdfilter, maintaining consistency with the broader refactoring effort.
47-47: Function call updated to use email parameter.The
getUserCategoriesWithRulesfunction call now correctly passes the email parameter, which matches the updated function signature incategory.server.tsthat accepts an email parameter and filters categories byemailAccountId.apps/web/utils/user/delete.ts (3)
52-52: Function call updated to use object with email parameter.The call to
deleteExecutedRulesInBatcheshas been correctly updated to pass an object with the
103-109: Function signature properly updated to accept email parameter.The
deleteExecutedRulesInBatchesfunction now accepts an object withbatchSize, which is a more maintainable approach that allows for additional parameters in the future without breaking the API.
114-116: Database query correctly updated to filter by emailAccountId.The Prisma query inside the batch deletion process has been properly updated to use
emailAccountId: emailinstead of the previoususerIdfilter, ensuring consistent data access throughout the application.apps/web/app/(app)/reply-zero/NeedsReply.tsx (3)
6-16: Refactoring parameters from userId to email is consistent with schema changes.The function signature now uses
userIdbefore, which aligns with the broader refactoring effort to move from user-centric to email-account-centric model.
17-22: Parameter update correctly propagated to data fetching function.The call to
getPaginatedThreadTrackershas been updated to passuserId, maintaining consistency with the changes in the function signature.
25-31: Component prop correctly updated to use email identifier.The prop passed to the
ReplyTrackerEmailscomponent has been changed from what was likelyuserEmailtoapps/web/utils/rule/prompt-file.ts (1)
66-70: Database query correctly updated to use email as identifier.The
whereclause in the Prisma query has been properly changed to useemailAccountId: emailinstead of what was likelyuserId, aligning with the schema changes that moved relations fromUsertoEmailAccount.apps/web/app/api/reply-tracker/disable-unused-auto-draft/route.ts (6)
29-44: Query correctly updated to use EmailAccount model.The query now fetches from the
emailAccounttable instead ofuserand selects theid, consistent with the schema changes.
69-94: Filter correctly changed to use emailAccountId.The query condition has been updated to filter by
emailAccountId: user.emailinstead ofuserId, maintaining the same logical behavior while adapting to the new schema.
98-103: Logging fields updated to use email identifier.The log message now references
email: user.emailinstead of the previous user ID, ensuring consistent logging throughout the application.
112-114: Log message correctly updated to use email identifier.Similar to other logging changes, this message now references the user by email instead of ID.
117-126: Action deletion filter updated to use emailAccountId.The
whereclause for deleting DRAFT_EMAIL actions has been updated to useemailAccountId: user.emailinstead ofuserId, maintaining correct behavior with the new schema.
131-131: Error logging correctly updated to use email field.The error log now uses
email: user.emailfor identification instead of user ID.apps/web/app/(app)/clean/helpers.ts (2)
3-13: Function signature and query correctly updated to use email identifier.The
getJobByIdfunction has been properly refactored to:
- Accept
userIdin its parameters- Update the type annotation accordingly
- Use
whereclause of the Prisma queryThis maintains the same functionality while aligning with the schema changes.
15-20: Second helper function consistently updated to use email parameter.The
getLastJobfunction has been similarly refactored to useuserIdin both its signature and database query, completing the consistent transition to email-based identification.apps/web/utils/redis/clean.ts (2)
75-83: Function parameter update aligns with email-account-centric modelThe change from accepting separate parameters to a single object parameter with
emailAccountIdfollows good practices for function design and is consistent with the refactoring to use email accounts as the primary identifier.
84-84: Pattern updated to use emailAccountId instead of userIdThe Redis key pattern has been properly updated to use the
emailAccountIdas the identifier.apps/web/utils/actions/cold-email.ts (2)
65-66: Authentication check updated to use emailThe authentication check has been properly updated to check for the presence of the user's email instead of the user ID.
78-81: Composite key updated to use emailAccountIdThe Prisma update operation now correctly uses the composite key
emailAccountId_fromEmailwithemailAccountIdset to the user's email, aligning with the database schema changes.apps/web/app/(app)/reply-zero/page.tsx (6)
29-30: Authentication simplified to use only emailAuthentication has been simplified to check for the presence of the user's email, which is consistent with the email-account-centric model.
38-44: Database query updated to filter by emailAccountIdThe Prisma query has been properly updated to filter the rule by
emailAccountIdmatching the user's email.
48-48: Function call updated to use email parameterThe call to
isAnalyzingReplyTrackerhas been updated to pass the email parameter, which aligns with the updated function signature shown in the relevant code snippet.
98-105: Component props updated to use emailThe props passed to the
NeedsReplycomponent now useuserId, which is consistent with the refactoring.
107-114: AwaitingReply props updated to use emailThe props passed to the
AwaitingReplycomponent now useuserId, consistent with the refactoring.
120-126: Resolved component props updated to use emailThe props passed to the
Resolvedcomponent now useuserId, consistent with the refactoring.apps/web/utils/actions/knowledge.ts (6)
20-21: Authentication updated to use emailThe authentication check has been properly updated to use the user's email instead of the user ID, consistent with the email-account-centric model.
26-31: Database creation updated to use emailAccountIdThe knowledge record creation now associates the record with the user's email account through
emailAccountId, aligning with the schema changes.
41-42: Authentication in updateKnowledgeAction updated to use emailThe authentication check in
updateKnowledgeActionhas been properly updated to use the user's email.
47-49: Ownership check in knowledge update uses emailAccountIdThe Prisma update operation now correctly filters by both the record ID and the user's email, ensuring proper access control.
63-64: Authentication in deleteKnowledgeAction updated to use emailThe authentication check in
deleteKnowledgeActionhas been properly updated to use the user's email.
69-71: Ownership check in knowledge deletion uses emailAccountIdThe Prisma delete operation now correctly filters by both the record ID and the user's email, ensuring proper access control.
apps/web/app/(app)/reply-zero/Resolved.tsx (3)
9-9: Parameter replacement looks good.The parameter replacement from
userIdtoAlso applies to: 13-13
25-26: SQL query filter updates align with schema changes.The filter condition in the raw SQL queries has been appropriately updated to use
"emailAccountId" = ${email}instead of usinguserId. This change is consistent with the broader migration to using email as the primary identifier.Also applies to: 36-37
55-55: Component prop update is consistent.Renamed prop from
userEmailtoapps/web/app/(app)/reply-zero/AwaitingReply.tsx (3)
7-7: Parameter replacement looks good.The parameter replacement from
userIdtoAlso applies to: 12-12
18-18: Argument update is correct.The argument passed to
getPaginatedThreadTrackershas been correctly updated to useuserId, which matches the expected parameter in the function as shown in the relevant code snippet.
27-27: Component prop update is consistent.The prop passed to
ReplyTrackerEmailshas been correctly renamed fromuserEmailtoapps/web/utils/redis/reply-tracker-analyzing.ts (3)
3-5: Redis key updating looks good.The
getKeyfunction has been correctly updated to useuserIdfor generating Redis keys, ensuring consistency with the new email-based identification pattern.
7-11: Improved function parameter pattern.The function has been nicely refactored to use a destructured object parameter
{ email }instead of a direct string parameter. This makes the function more self-documenting and allows for future parameter additions without breaking the API.
13-16: Consistent pattern across all functions.The same parameter pattern updates have been consistently applied to all functions in this file, ensuring a uniform API for working with reply tracker analysis state via Redis.
Also applies to: 18-22
apps/web/app/api/google/labels/create/controller.ts (4)
18-19: Authentication check update is correct.Authentication now correctly uses
session?.user.emailinstead ofsession?.user.id, aligning with the email-account-centric approach. The error message remains accurate for the new check.
26-31: Composite key structure updated correctly.The Prisma
whereclause correctly reflects the database schema change from using a composite key ofgmailLabelId_userIdtogmailLabelId_emailAccountId. This is a critical change that aligns with the broader schema refactoring.
33-39: Label creation updated correctly.The label creation properties now correctly use
emailAccountId: emailinstead ofuserId, reflecting the ownership shift to the EmailAccount model.
42-45: Redis caching parameter updated.The Redis caching function call has been updated to pass
userId, maintaining consistency with the identification pattern changes.apps/web/utils/actions/reply-tracking.ts (4)
63-64: Authentication updated to use emailThe code now uses the email from the session for authentication instead of userId, consistent with the broader refactoring to an email-centric model.
70-72: API call updated to use email parameterThe call to
startAnalyzingReplyTrackercorrectly passes the email instead of userId, matching the expected parameter structure in the imported function.
74-80: Database query filter updated to use emailAccountIdThe Prisma query now correctly filters thread trackers by
emailAccountIdinstead ofuserId, aligning with the database schema changes.
82-84: API call updated to use email parameterThe call to
stopAnalyzingReplyTrackercorrectly passes the email instead of userId, matching the expected parameter structure in the imported function.apps/web/utils/actions/mail.ts (5)
184-185: Authentication updated to use emailAuthentication now uses the email from the session instead of userId, consistent with the broader refactoring.
195-195: Database constraint updated to use emailAccountIdThe Prisma query's unique constraint has been updated to use
name_emailAccountIdinstead of a user-based constraint.
201-201: Email account relation updatedThe create operation now correctly connects the label to the email account via email rather than to the user.
212-215: Database query filter updated to use emailAccountIdThe delete operation now correctly filters by
emailAccountIdinstead ofuserId.
218-224: Helper function call updated to use email parameterThe call to
saveUserLabelsnow passes the email parameter correctly.apps/web/utils/ai/assistant/process-user-request.ts (5)
355-358: Function call updated to use email parameterThe
deleteGroupItemfunction now receives the user's email instead of userId, matching the updated function signature.
523-526: API call updated to use email parameterThe
getUserCategoriesForNamesfunction call has been updated to use the user's email rather than userId.
528-532: Function call updated to use email parameterThe
createRulecall now correctly passes the user's email instead of userId.
655-658: Database query filter updated to use emailAccountIdThe
findSenderByEmailfunction call now filters byemailAccountId: userEmailinstead ofuserId.
671-676: Function call updated to use email parameterThe
updateCategoryForSendercall now correctly passes the userEmail parameter.apps/web/utils/actions/rule.ts (15)
92-92: Database relation updated to use emailAccountIdThe rule creation now correctly associates with the email account using the
emailAccountIdfield instead ofuserId.
147-149: Database query filter updated to use emailAccountIdThe Prisma query now correctly filters by
emailAccountId: emailinstead ofuserIdwhen finding a rule.
163-186: Database query filter updated to use emailAccountIdThe rule update operation now correctly filters by
emailAccountId: emailinstead ofuserId.
273-276: Database query filter updated to use emailAccountIdThe rule lookup operation now correctly filters by
emailAccountId: emailinstead ofuserId.
294-296: Authentication updated to use emailAuthentication now uses the email from the session instead of userId, consistent with the broader refactoring.
301-303: Database query filter updated to use emailAccountIdThe rule update operation now correctly filters by
emailAccountId: emailinstead ofuserId.
315-317: Authentication updated to use emailAuthentication now uses the email from the session instead of userId, consistent with the broader refactoring.
321-330: Database query filter updated to use emailAccountId_systemTypeThe rule lookup now correctly uses the composite key of
emailAccountId_systemTypewith the user's email.
356-362: Permission check updated to use emailAccountIdThe permission check on rule deletion now correctly compares
rule.emailAccountIdwith the authenticated user's email.
365-369: Function call updated to use email parameterThe
deleteRulecall now passes the email parameter instead of userId, matching the function's updated signature inutils/rule/rule.ts.
492-501: Function parameter updated to use emailAccountIdThe
createRulefunction's parameters now includeemailAccountIdinstead ofuserId.
503-504: Database query filter updated to use emailAccountId_systemTypeThe rule lookup now correctly uses the composite key of
emailAccountId_systemType.
538-554: Database creation updated to use emailAccountIdThe rule creation now correctly uses
emailAccountIdinstead ofuserId.
572-581: Helper function updated to use emailAccountIdThe
deleteRulehelper function now takesemailAccountIdinstead ofuserIdand uses it in the query.
584-597: Function calls updated to pass email parameterThe calls to
createRuleanddeleteRulenow correctly pass the email parameter.apps/web/utils/reply-tracker/enable.ts (4)
25-28: LGTM: Refactored query structure to access rules directly from emailAccountThe query now directly selects rules from the emailAccount with the appropriate filter, which aligns with the email-account-centric model shift mentioned in the PR objectives.
31-36: LGTM: Updated selected fields in the queryThe selected fields have been appropriately updated to match the new data structure.
47-47: LGTM: Updated access pattern to reflect new data relationshipCorrectly changed from accessing
emailAccount.user.rulestoemailAccount.rules, consistent with moving relations from User to EmailAccount.
100-100: LGTM: Updated parameter for rule creationChanged from using
userIdtoapps/web/app/api/user/group/[groupId]/items/route.ts (4)
9-13: LGTM: Updated function signature to use email instead of userIdFunction parameter has been correctly changed from
userIdto
16-16: LGTM: Updated database query to use emailAccountIdDatabase query has been updated to filter by
emailAccountId: emailinstead ofuserId, reflecting the schema changes.
29-30: LGTM: Updated authentication check to use emailAuthentication check now correctly verifies the presence of
session?.user.emailinstead ofsession?.user.id.
35-35: LGTM: Updated function call with email parameterFunction call to
getGroupItemsnow correctly passesuserId.apps/web/utils/actions/group.ts (7)
19-20: LGTM: Updated authentication check in createGroupActionAuthentication now correctly checks for the presence of
session?.user.emailinstead ofsession?.user.id.
26-26: LGTM: Updated rule lookup queryRule lookup now correctly uses
emailAccountId: emailinstead ofuserIdfor filtering.
35-35: LGTM: Updated group creation dataGroup creation now correctly sets
emailAccountId: emailinstead ofuserId.
50-51: LGTM: Updated authentication check in addGroupItemActionAuthentication now correctly checks for the presence of
session?.user.emailinstead ofsession?.user.id.
60-60: LGTM: Updated permission checkPermission check now correctly compares
group.emailAccountIdto the user's email.
73-74: LGTM: Updated authentication check in deleteGroupItemActionAuthentication now correctly checks for the presence of
session?.user.emailinstead ofsession?.user.id.
76-76: LGTM: Updated deleteGroupItem function callFunction call now correctly passes
userId, consistent with the updated function signature in the imported module.apps/web/utils/category.server.ts (3)
13-16: LGTM: Updated getUserCategories functionFunction signature and implementation have been updated to accept
emailAccountIdin the query, aligning with the email-account-centric model.
20-23: LGTM: Updated getUserCategoriesWithRules functionFunction signature and query have been updated to use
emailAccountIdin the filter.
33-44: LGTM: Updated getUserCategoriesForNames functionFunction signature and query have been correctly updated to use
emailAccountIdin the filter.apps/web/scripts/migrateRedisPlansToPostgres.ts (1)
100-108: Double‑check the semantics ofemailAccountIdAll subsequent queries now pass
emailAccount.emailintoemailAccountId.
That is correct only if the Prisma schema declaresmodel Rule { … emailAccountId String @map("email") … }Otherwise these lookups will fail or, worse, create orphaned rows.
Please verify the field mapping in
schema.prisma; ifemailAccountIdis still the UUID primary key you must passemailAccount.idinstead.apps/web/app/(app)/automation/onboarding/page.tsx (1)
27-39: Great use ofPrisma.EmailAccountGetPayloadCasting the selected subset to
UserPreferencesgives you strict type‑safety while avoiding over‑fetching. 👍apps/web/utils/actions/ai-rule.ts (2)
108-110: Passing entire user object to AI helpers is 👍
runRulesand friends often need both metadata (aiProvider, ...) and rule list.
Forwarding the wholeemailAccountkeeps signatures compact and future‑proof.
70-75:Details
✅ Verification successful
Confirm new composite key name
unique_emailAccount_thread_messagenow usesemailAccountId.
Prisma will generate a name such as
unique_emailAccountId_threadId_messageId(note the Id).
If the migration renamed the field only at application level and not in the DB, the lookup will miss.Run the following verification to list composite indexes:
🏁 Script executed:
#!/bin/bash ast-grep --pattern $'@@unique([emailAccountId, threadId, messageId])'Length of output: 70
I couldn’t find any composite‐index definitions with that pattern. Let’s search all unique constraints in your Prisma schema to confirm the index name:
🏁 Script executed:
#!/bin/bash # List all composite unique indexes in the Prisma schema rg "@@unique" -n .Length of output: 1196
Composite index name is correct
The Prisma schema explicitly names the composite unique constraint
@@unique([emailAccountId, threadId, messageId], name: "unique_emailAccount_thread_message")
(see apps/web/prisma/schema.prisma:293), so the lookup key matches and no changes are needed.apps/web/utils/assistant/process-assistant-email.ts (3)
101-166: Correctly updated database queries to use email-based identification.The Prisma queries have been properly modified to use email as the primary identifier, including:
- Using
emailAccountIdinstead ofuserIdin the unique constraint- Removing the nested user references, now directly accessing rules and categories from emailAccount
- Maintaining correct include patterns for related data
This aligns well with the PR objective of moving relations to emailAccount.
168-171: Updated existence check to verify emailAccount.The error check has been correctly updated to verify the existence of
emailAccountinstead ofuser, ensuring consistent error handling with the new data model.
211-219: Successfully adapted parameters for processUserRequest function.The code now correctly passes the emailAccount object and directly accesses rules and categories from it rather than from a nested user structure.
apps/web/utils/reply-tracker/draft-tracking.ts (4)
46-48: Successfully updated ExecutedRule query to use emailAccountId.The database query correctly uses
emailAccountId: user.emailinstead ofuserId, which aligns with the email-account-centric approach of this refactoring.
137-138: Parameter properly renamed from userId to email.The function parameter has been correctly renamed to better reflect the new identification approach.
144-145: Updated logger options to use email.Logging context has been properly updated to include email instead of userId for consistent logging across the application.
152-154: Successfully updated ExecutedAction query to use emailAccountId.The query now correctly filters by email account ID instead of user ID, maintaining consistent identification throughout the database operations.
apps/web/utils/actions/categorize.ts (5)
62-64: Successfully updated Newsletter query to use emailAccountId.The query now correctly filters by the user's email, consistent with the database model changes.
142-146: Updated authentication check and Category query correctly.Both the authentication verification and the subsequent Category query now properly use email-based identification.
150-153: Successfully refactored categorizeSender parameters.The function now correctly passes the user's email instead of userId for consistent identification.
208-212: Successfully refactored deleteCategory function.The function signature and implementation have been properly updated to use email instead of userId.
214-236: Successfully refactored upsertCategory function.The function now correctly uses email-based identification throughout, including in both the create and update operations.
apps/web/utils/reply-tracker/outbound.ts (6)
82-83: Successfully updated parameter to use email instead of userId.The createReplyTrackerOutbound function now correctly receives the user's email, aligning with the refactoring approach.
96-97: Successfully updated function signature to use email.The function signature has been properly updated to use email instead of userId.
115-119: Successfully updated unique constraint to use emailAccountId.The database query now correctly uses the email-based constraint instead of userId-based constraint.
123-124: Successfully updated ThreadTracker create data.The create operation now properly uses emailAccountId instead of userId for consistent data storage.
157-158: Successfully updated resolveReplyTrackers function signature.The function now correctly accepts email instead of userId.
163-164: Successfully updated ThreadTracker query.The query now correctly filters by emailAccountId instead of userId.
apps/web/utils/reply-tracker/inbound.ts (1)
74-115: Confirm compound unique key exists after model migration
upsertis keyed byemailAccountId_threadId_messageId.
After the refactor, ensure that the Prisma schema still declares@@unique([emailAccountId, threadId, messageId])(or an equivalent@@id). Otherwise the call will throw at runtime.apps/web/utils/categorize/senders/categorize.ts (10)
24-25: Properly updated getUserCategories call with email parameterThe function now correctly passes the user's email to
getUserCategoriesinstead of userId, aligning with the broader refactoring.
47-47: Consistent parameter naming updateChanged from
userIdtouserEmailin the updateSenderCategory call, maintaining consistency with the email-centric model.
61-68: Function signature updated to use email-based identificationThe
updateSenderCategoryfunction now correctly acceptsuserEmailinstead ofuserIdin its parameter list, aligning with the email account centric model.
80-80: Database field updated from userId to emailAccountIdThe category creation now correctly associates with
emailAccountIdusing the user's email, which matches the updated schema.
89-91: Updated unique constraint key in Prisma queryThe unique constraint has been properly updated from
email_userIdtoemail_emailAccountIdto match the schema changes.
95-95: Create operation updated to use emailAccountIdThe newsletter creation now correctly uses
emailAccountIdinstead ofuserId, aligning with the schema changes.
106-112: Function signature updated for updateCategoryForSenderThe
updateCategoryForSenderfunction properly acceptsuserEmailinstead ofuserIdin its parameter list.
117-117: Updated composite key in Prisma upsert operationThe unique constraint reference is correctly updated to use
email_emailAccountIdin the where clause.
121-121: Create operation field updated to emailAccountIdThe newsletter creation correctly uses
emailAccountIdinstead ofuserIdto associate with the email account.
143-144: getCategories function updated to use email parameterThe function signature and implementation now correctly use
userIdfor retrieving categories.apps/web/utils/rule/rule.ts (12)
30-38: Function signature updated to use email parameterThe
safeCreateRulefunction now correctly acceptsuserId, aligning with the email-centric model refactoring.
41-44: getUserCategoriesForNames call updated to use emailThe function call now uses the updated API with a named parameter object containing
userId, matching the updated helper function.
47-52: createRule call updated to use email parameterThe call to
createRulenow passesuserId, maintaining consistency with the refactored function signature.
66-66: Logging statement updated to use emailError logging now uses
userIdfor consistent identification throughout the system.
77-87: Improved parameter structure in safeUpdateRule functionThe function signature has been refactored to use a cleaner named parameter object with
userId. This provides better clarity and extensibility.
89-94: updateRule call changed to use email-based identificationThe call properly passes
emailAccountId: emailto match the updated function signature ofupdateRule.
119-127: createRule signature updated for email-based identificationThe function now accepts
userId, aligning with the broader refactoring goal.
135-135: Database field updated in rule creationThe rule creation now correctly uses
emailAccountId: emailinstead ofuserId, matching the schema changes.
168-178: Refactored updateRule function with improved parameter structureThe function has been refactored to use named parameters with
emailAccountIdinstead ofuserId, providing better clarity and consistency with the schema changes.
183-183: Database field updated in rule update operationThe update operation now correctly uses
emailAccountIdinstead ofuserIdto match the schema changes.
207-214: deleteRule function updated to use email parameterThe function signature has been updated to accept
userIdfor user identification.
217-221: Delete operations updated to use emailAccountIdThe Prisma delete operations now correctly filter by
emailAccountId: emailinstead ofuserId, ensuring proper authorization and consistency with the schema.apps/web/prisma/schema.prisma (24)
90-92: User model simplified with relations moved to EmailAccountThe
Usermodel has been correctly simplified to only maintain essential relations (apiKeysandemailAccounts), supporting the architectural shift to an email-account-centric model.
128-140: Relations properly moved from User to EmailAccountAll relevant relations (labels, rules, executedRules, etc.) have been correctly moved from the
Usermodel to theEmailAccountmodel, centralizing ownership under email accounts.
205-206: Label model references updated to EmailAccountThe
Labelmodel now correctly referencesEmailAccountvia theemailAccountIdfield instead of referencingUserviauserId.
208-209: Updated unique constraints for Label modelThe unique constraints have been correctly updated to use
emailAccountIdinstead ofuserId, maintaining data integrity with the new schema.
221-222: Rule model references updated to EmailAccountThe
Rulemodel now correctly usesemailAccountIdand referencesEmailAccountinstead ofUser, aligning with the architectural changes.
250-251: Updated unique constraints for Rule modelThe unique constraints have been properly updated to use
emailAccountIdinstead ofuserId, maintaining data integrity with the new schema structure.
288-289: ExecutedRule model references updated to EmailAccountThe
ExecutedRulemodel now correctly referencesEmailAccountviaemailAccountIdinstead ofUserviauserId.
293-294: Updated unique constraints and indexes for ExecutedRuleThe unique constraint and index have been properly updated to use
emailAccountIdinstead ofuserId, maintaining efficient queries and data integrity.
333-334: Group model references updated to EmailAccountThe
Groupmodel now correctly referencesEmailAccountviaemailAccountIdinstead ofUserviauserId.
337-337: Updated unique constraint for Group modelThe unique constraint has been properly updated to use
emailAccountIdinstead ofuserId.
358-360: Category model references updated to EmailAccountThe
Categorymodel now correctly referencesEmailAccountviaemailAccountIdinstead ofUserviauserId.
364-364: Updated unique constraint for Category modelThe unique constraint has been properly updated to use
emailAccountIdinstead ofuserId, maintaining data integrity.
381-383: Newsletter model references updated to EmailAccountThe
Newslettermodel now correctly referencesEmailAccountviaemailAccountIdinstead ofUserviauserId.
387-388: Updated unique constraint and index for Newsletter modelThe unique constraint and index have been properly updated to use
emailAccountIdinstead ofuserId, maintaining data integrity and query performance.
401-403: ColdEmail model references updated to EmailAccountThe
ColdEmailmodel now correctly referencesEmailAccountviaemailAccountIdinstead ofUser.
404-406: Updated constraints and indexes for ColdEmail modelAll constraints and indexes have been properly updated to use
emailAccountIdinstead ofuserId.
425-427: EmailMessage model references updated to EmailAccountThe
EmailMessagemodel now correctly referencesEmailAccountviaemailAccountIdinstead ofUser.
428-431: Updated constraints and indexes for EmailMessage modelAll constraints and indexes have been properly updated to use
emailAccountIdinstead ofuserId, ensuring data integrity and query performance.
444-446: ThreadTracker model references updated to EmailAccountThe
ThreadTrackermodel now correctly referencesEmailAccountviaemailAccountIdinstead ofUser.
447-450: Updated constraints and indexes for ThreadTracker modelAll constraints and indexes have been properly updated to use
emailAccountIdinstead ofuserId.
479-481: CleanupThread model references updated to EmailAccountThe
CleanupThreadmodel now correctly referencesEmailAccountviaemailAccountIdinstead ofUser.
490-492: Knowledge model references updated to EmailAccountThe
Knowledgemodel now correctly referencesEmailAccountviaemailAccountIdinstead ofUser.
493-493: Updated unique constraint for Knowledge modelThe unique constraint has been properly updated to use
emailAccountIdinstead ofuserId.
511-516: EmailToken model references updated to EmailAccountThe
EmailTokenmodel now correctly referencesEmailAccountviaemailAccountIdinstead ofUser.
| const emailAccount = await prisma.emailAccount.findFirst({ | ||
| where: { userId }, | ||
| select: { email: true, userId: true }, | ||
| }); | ||
| if (!user) { | ||
| console.error(`User not found for user ${userId}`); | ||
| if (!emailAccount) { | ||
| console.error(`Email account not found for user ${userId}`); | ||
| processedUserIds.push(userId); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Consider handling multi‑account users explicitly
findFirst will silently pick any EmailAccount that matches the userId.
If a single user can own several email accounts (very common with aliases), the migration will only process the first one it meets, dropping plans that belong to the remaining accounts.
Recommendation: either
-const emailAccount = await prisma.emailAccount.findFirst({
- where: { userId },
- select: { email: true, userId: true },
-});
+const emailAccounts = await prisma.emailAccount.findMany({
+ where: { userId },
+ select: { email: true, userId: true },
+});
+if (!emailAccounts.length) {
+ …
+}
+for (const emailAccount of emailAccounts) {
+ await migrateEmailAccountPlans({ userId, email: emailAccount.email });
+}
+return; // remove the rest of the function body or fold it into the helper(or abort with a clear error) so you never lose data.
Committable suggestion skipped: line range outside the PR's diff.
| const messages = user.account.access_token | ||
| ? await getMessagesBatch(messageIds, user.account.access_token) | ||
| : []; |
There was a problem hiding this comment.
Potential TypeError when account is null
user.account can be null (e.g. Gmail disconnected).
Accessing user.account.access_token before the ternary guard will crash.
-const messages = user.account.access_token
- ? await getMessagesBatch(messageIds, user.account.access_token)
- : [];
+const accessToken = user.account?.access_token;
+const messages = accessToken
+ ? await getMessagesBatch(messageIds, accessToken)
+ : [];📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const messages = user.account.access_token | |
| ? await getMessagesBatch(messageIds, user.account.access_token) | |
| : []; | |
| const accessToken = user.account?.access_token; | |
| const messages = accessToken | |
| ? await getMessagesBatch(messageIds, accessToken) | |
| : []; |
There was a problem hiding this comment.
Actionable comments posted: 1
🔭 Outside diff range comments (3)
apps/web/app/api/user/stats/newsletters/route.ts (1)
69-71: 🛠️ Refactor suggestionConsider completing the email account ID refactoring in this file.
While
findNewsletterStatusnow usesemailAccountId, other parts of this file still referenceuserId. ThegetNewslettersTinybirdfunction still acceptsuserIdin its signature, andgetNewsletterCountsstill filters byuserIdin the SQL query. Consider completing the refactoring by updating these remaining instances to use email account IDs for consistency.async function getNewslettersTinybird( - options: { ownerEmail: string; userId: string } & NewsletterStatsQuery, + options: { ownerEmail: string; emailAccountId: string } & NewsletterStatsQuery, ) { // ... } // Later in getNewsletterCounts - whereConditions.push(`"userId" = $${queryParams.length + 1}`); - queryParams.push(options.userId); + whereConditions.push(`"emailAccountId" = $${queryParams.length + 1}`); + queryParams.push(options.emailAccountId); // And in the GET handler const result = await getNewslettersTinybird({ ...params, ownerEmail: session.user.email, - userId: session.user.id, + emailAccountId: session.user.email, });Also applies to: 165-166, 250-254
apps/web/utils/ai/choose-rule/match-rules.test.ts (1)
549-560: 💡 Verification agent🧩 Analysis chain
Verify newsletter model update.
The
getNewsletterfunction still returns an object withuserIdproperty. Consider updating this to useemailAccountIdfor full consistency with the refactoring.
🏁 Script executed:
#!/bin/bash # Check if the Newsletter model in the Prisma schema has been updated to use emailAccountId rg -A 20 -B 5 "model Newsletter" -g "*.prisma"Length of output: 1637
Update
getNewsletterto useemailAccountIdinstead ofuserIdWe’ve confirmed the Prisma
Newslettermodel no longer has auserIdfield and now requiresemailAccountId. Please update the test helper accordingly:• File: apps/web/utils/ai/choose-rule/match-rules.test.ts
• Lines: 549–560 (thegetNewsletterfunction)Replace:
function getNewsletter(overrides: Partial<Newsletter> = {}): Newsletter { return { id: "newsletter1", createdAt: new Date(), updatedAt: new Date(), userId: "userId", // remove this email: "test@example.com", status: null, categoryId: "category1", ...overrides, } as Newsletter; }With something like:
function getNewsletter(overrides: Partial<Newsletter> = {}): Newsletter { return { id: "newsletter1", createdAt: new Date(), updatedAt: new Date(), email: "test@example.com", emailAccountId: "emailAccount1", // new required field status: null, categoryId: "category1", ...overrides, } as Newsletter; }Also update any tests that relied on
userIdto useemailAccountIdinstead.apps/web/app/api/google/webhook/process-history-item.ts (1)
221-225: 🛠️ Refactor suggestionOverlooked userId reference in trackSentDraftStatus call.
While most of the file has been updated to use email/emailAccountId identifiers, this function call still includes a user object with
id: user.userId.This should be updated to maintain consistency with the refactoring effort:
trackSentDraftStatus({ - user: { id: user.userId, email: user.email }, + user: { email: user.email }, message, gmail, }),Ensure the
trackSentDraftStatusfunction signature has also been updated to no longer require theidproperty.
🧹 Nitpick comments (4)
apps/web/app/(app)/reply-zero/NeedsAction.tsx (1)
6-18: Consider removing unuseduserIdparameter.The function signature still includes
userIdas a parameter, but it's no longer being used in the function body after the refactoring to email-centric identification. Consider removing this parameter to keep the interface clean and align with the new model.export async function NeedsAction({ - userId, userEmail, page, timeRange, isAnalyzing, }: { - userId: string; userEmail: string; page: number; timeRange: TimeRange; isAnalyzing: boolean; }) {apps/web/utils/group/find-matching-group.ts (2)
7-7: Function signature refactored correctly but consider parameter naming.The function has been properly updated to accept an object with an email property instead of a userId string. However, the parameter naming could be more consistent with its usage.
Consider renaming the parameter for clarity:
-export async function getGroupsWithRules({ email }: { email: string }) { +export async function getGroupsWithRules({ emailAccountId }: { emailAccountId: string }) {
9-9: Query filter parameter naming inconsistency.The parameter is named
emailAccountIdin the query. This might cause confusion for future developers.For consistency, either rename the parameter or adjust the query:
- where: { emailAccountId: email, rule: { isNot: null } }, + where: { emailAccountId: emailAccountId, rule: { isNot: null } },Alternatively, if email is intended to be used as the emailAccountId:
- where: { emailAccountId: email, rule: { isNot: null } }, + where: { email: email, rule: { isNot: null } },apps/web/app/api/unsubscribe/route.ts (1)
67-67: Inconsistent email reference style.Line 67 uses
emailToken.emailAccount.emailwhile lines 82 and 89 useemailToken.emailAccountId. IfemailToken.emailAccountIdis the email string (as suggested by line 54), then usingFor consistency, use the same reference style throughout:
- email: emailToken.emailAccount.email, + email: emailToken.emailAccountId,
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (20)
apps/web/app/(app)/reply-zero/NeedsAction.tsx(2 hunks)apps/web/app/api/google/threads/controller.ts(1 hunks)apps/web/app/api/google/webhook/process-history-item.ts(3 hunks)apps/web/app/api/unsubscribe/route.ts(4 hunks)apps/web/app/api/user/categorize/senders/uncategorized/get-senders.ts(1 hunks)apps/web/app/api/user/categorize/senders/uncategorized/get-uncategorized-senders.ts(3 hunks)apps/web/app/api/user/categorize/senders/uncategorized/route.ts(1 hunks)apps/web/app/api/user/stats/helpers.ts(2 hunks)apps/web/app/api/user/stats/newsletters/helpers.ts(1 hunks)apps/web/app/api/user/stats/newsletters/route.ts(1 hunks)apps/web/app/api/user/stats/recipients/route.ts(4 hunks)apps/web/app/api/user/stats/senders/route.ts(4 hunks)apps/web/app/api/user/stats/tinybird/load/load-emails.ts(8 hunks)apps/web/app/api/user/stats/tinybird/load/route.ts(2 hunks)apps/web/utils/actions/categorize.ts(8 hunks)apps/web/utils/ai/choose-rule/draft-management.ts(2 hunks)apps/web/utils/ai/choose-rule/match-rules.test.ts(16 hunks)apps/web/utils/ai/choose-rule/match-rules.ts(4 hunks)apps/web/utils/ai/choose-rule/run-rules.ts(9 hunks)apps/web/utils/group/find-matching-group.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/utils/actions/categorize.ts
🧰 Additional context used
🧬 Code Graph Analysis (4)
apps/web/app/api/user/stats/newsletters/route.ts (1)
apps/web/app/api/user/stats/newsletters/helpers.ts (1)
findNewsletterStatus(32-42)
apps/web/utils/ai/choose-rule/match-rules.ts (4)
apps/web/utils/group/find-matching-group.ts (1)
getGroupsWithRules(7-12)apps/web/utils/email.ts (1)
extractEmailAddress(16-36)apps/web/utils/types.ts (2)
RuleWithActionsAndCategories(16-18)ParsedMessage(47-58)apps/web/utils/llms/types.ts (1)
UserEmailWithAI(7-8)
apps/web/app/api/user/stats/recipients/route.ts (1)
apps/web/app/api/user/stats/helpers.ts (1)
getEmailFieldStats(16-65)
apps/web/app/api/user/stats/senders/route.ts (1)
apps/web/app/api/user/stats/helpers.ts (1)
getEmailFieldStats(16-65)
🔇 Additional comments (61)
apps/web/app/(app)/reply-zero/NeedsAction.tsx (2)
19-24: Correct parameter name change for email-centric model.The parameter name change from
userIdtogetPaginatedThreadTrackersaligns with the broader refactoring effort to use email as the primary identifier instead of user ID. This change is consistent with the updated API expectations.
27-34: Prop name standardized toThe prop name change from
userEmailtoReplyTrackerEmailscomponent follows the same standardization pattern, maintaining consistency with the email-centric model being adopted throughout the codebase.apps/web/app/api/user/categorize/senders/uncategorized/route.ts (1)
21-23: Parameter updated to use email account ID instead of user ID.The parameter for
getUncategorizedSendershas been correctly changed fromuserIdtoemailAccountId, which aligns with the broader refactoring from user-centric to email-account-centric identification throughout the codebase.apps/web/app/api/google/threads/controller.ts (1)
58-59: Prisma query filter refactored to use email as identifier.The query filter has been properly updated to use
emailAccountId: emailinstead ofuserId, which is consistent with the codebase refactoring to use email accounts as the primary entity for data relationships.apps/web/app/api/user/stats/tinybird/load/route.ts (2)
14-15: User authentication check refactored to use email variable.The authentication check has been refactored to extract the email into a variable first, which keeps the same functionality while making the code more consistent with the email-account-centric model.
27-28: Parameter updated to use email account ID instead of user ID.The parameter for
loadEmailshas been correctly changed fromuserIdtoemailAccountId, consistent with the broader refactoring effort.apps/web/app/api/user/stats/newsletters/route.ts (1)
81-82: Function parameter updated to use emailAccountId object.The call to
findNewsletterStatushas been properly updated to use the object parameter format withemailAccountIdproperty, which matches the refactored function signature.apps/web/app/api/user/stats/newsletters/helpers.ts (2)
32-36: Function parameter refactored correctly.The function signature has been updated to accept an object with
emailAccountIdinstead of a plain stringuserId, correctly aligning with the move from user-centric to email-account-centric model.
38-38: Query filter updated consistently.The Prisma query filter has been properly changed from
userIdtoemailAccountId, maintaining consistency with the function signature change.apps/web/utils/ai/choose-rule/match-rules.test.ts (3)
111-111: AllfindMatchingRulecalls updated correctly.All calls to
findMatchingRulehave been consistently updated to use the new object parameter structure, passingrules,message,user, andgmailas properties instead of positional parameters.Also applies to: 125-125, 139-139, 164-164, 183-183, 202-202, 238-238, 268-268, 299-299, 321-321, 342-342, 384-384, 424-424, 465-465
513-513: Entity model property updated appropriately.The
getCategoryhelper function now correctly returnsemailAccountIdinstead ofuserId, maintaining consistency with the database schema changes.
529-529: Entity model property updated appropriately.The
getGrouphelper function now correctly returnsemailAccountIdinstead ofuserId, maintaining consistency with the database schema changes.apps/web/app/api/user/stats/helpers.ts (2)
16-24: Function parameter updated correctly.The function signature has been properly refactored to use
emailAccountIdinstead ofuserId, both in the parameter name and type definition.
34-35: Query filter updated consistently.The Prisma query filter has been properly changed from
userIdtoemailAccountId, maintaining consistency with the function signature change.apps/web/app/api/user/categorize/senders/uncategorized/get-senders.ts (2)
3-11: Function parameter updated correctly.The function signature has been properly refactored to use
emailAccountIdinstead ofuserId, both in the parameter name and type definition.
14-15: Query filter updated consistently.The Prisma query filter has been properly changed from
userIdtoemailAccountId, maintaining consistency with the function signature change.apps/web/utils/ai/choose-rule/draft-management.ts (2)
17-17: Parameter type updated correctly.The executedRule parameter type has been properly updated from "userId" to "emailAccountId" which aligns with the broader refactoring effort to use email accounts as the primary identifier.
26-26: Query filter updated correctly.The filter criteria has been appropriately changed from userId to emailAccountId, maintaining consistency with the schema changes.
apps/web/app/api/google/webhook/process-history-item.ts (3)
68-70: Constraint and filter updated correctly.The unique constraint has been properly updated from
unique_user_thread_messagetounique_emailAccount_thread_messageand the filter has been changed fromuserId: user.userIdtoemailAccountId: userEmail, aligning with the database schema changes.
170-172: Unique constraint updated appropriately.The constraint has been correctly changed from
email_userIdtoemail_emailAccountIdwith the corresponding filter parameter update.
248-248: Parameter update for cleanupThreadAIDrafts.The parameter has been appropriately changed from
userId: user.userIdtoemail: user.email.apps/web/app/api/unsubscribe/route.ts (4)
30-30: Include clause correctly updated.The include clause has been properly changed to reference
emailAccountinstead ofuser.
54-54: Query filter updated correctly.The filter has been appropriately updated to use
email: emailToken.emailAccountIdwhich aligns with the schema changes.
82-83: Reference updated correctly.The error logging has been properly updated to use
emailToken.emailAccountId.
89-89: Info logging updated correctly.The info logging has been appropriately changed to use
emailToken.emailAccountId.apps/web/app/api/user/categorize/senders/uncategorized/get-uncategorized-senders.ts (3)
8-8: Parameter type updated from userId to emailAccountIdThe function parameter has been correctly updated from
userIdtoemailAccountIdto align with the PR objective of shifting from a user-centric model to an email-account-centric model.Also applies to: 12-12
21-21: Updated function call parameterThe
getSendersfunction call has been properly updated to passemailAccountIdinstead ofuserId, maintaining consistency with the parameter changes.
30-30: Updated database query filterThe Prisma query correctly uses
emailAccountIdinstead ofuserIdin the filter conditions, ensuring data is fetched based on the email account rather than the user ID.apps/web/utils/ai/choose-rule/match-rules.ts (5)
78-79: Updated function parameters to use email-based identificationThe
getGroupsfunction now correctly accepts an object with anuserIdstring, aligning with the broader shift to email account identification.
85-85: Updated singleton function and query keyThe
getSenderfunction's parameter structure and Prisma query have been properly updated:
- Function now accepts an object with
userIdstring- The query uses the composite key
email_emailAccountIdwithemailAccountIdrather than filtering byuserIdThis change maintains consistency with the email-centric data model refactoring.
Also applies to: 89-92
115-115: Updated function call to use email-based parameterThe
getGroupsfunction call has been properly updated to useemail: rule.emailAccountIdinstead of auserIdparameter, maintaining consistency with the updated function signature.
152-152: Updated function call to use email-based parameterThe
getSenderfunction call has been properly updated to useemail: rule.emailAccountIdinstead of auserIdparameter, maintaining consistency with the updated function signature.
206-216: Improved function signature with destructured parametersThe
findMatchingRulefunction has been refactored to use a single destructured object parameter instead of multiple positional parameters. This change:
- Makes the function signature more explicit and self-documenting
- Aligns with the email-centric architecture by using
user: UserEmailWithAIinstead of separate user ID parameters- Improves maintainability as additional parameters can be added without breaking existing calls
- Provides better TypeScript type safety with explicit parameter naming
This is a positive change that improves both code readability and flexibility.
apps/web/app/api/user/stats/recipients/route.ts (5)
55-55: Updated function parameter typeThe
getRecipientStatisticsfunction now correctly acceptsemailAccountIdinstead ofuserIdin its options parameter, maintaining consistency with the email-centric refactoring.
73-77: Updated parameter type in helper functionThe
getMostSentTofunction parameter and its type definition have been properly updated to useemailAccountIdinstead ofuserId, aligning with the broader refactoring effort.
80-80: Updated internal function call parameterThe call to
getEmailFieldStatsnow correctly passesemailAccountIdinstead ofuserId, maintaining consistency with the helper function's updated signature (as shown in the relevant code snippets).
90-91: Updated authentication and authorization logicThe authentication logic has been properly updated to:
- Use
session?.user.emailasemailAccountIdinstead ofsession?.user.id- Check for the presence of
emailAccountIdinstead ofuserIdThis change aligns with the shift to email-based user identification.
101-101: Updated function call parameterThe
getRecipientStatisticsfunction call now correctly passesemailAccountIdinstead ofuserId, maintaining consistency with the function's updated signature.apps/web/app/api/user/stats/senders/route.ts (6)
22-22: Updated function parameter typeThe
getSenderStatisticsfunction now correctly acceptsemailAccountIdinstead ofuserIdin its options parameter, maintaining consistency with the email-centric refactoring.
49-53: Updated parameter type in helper functionThe
getMostReceivedFromfunction parameter and its type definition have been properly updated to useemailAccountIdinstead ofuserId, aligning with the broader refactoring effort.
56-56: Updated internal function call parameterThe call to
getEmailFieldStatsnow correctly passesemailAccountIdinstead ofuserId, maintaining consistency with the helper function's updated signature (as shown in the relevant code snippets).
68-72: Updated parameter type in helper functionThe
getDomainsMostReceivedFromfunction parameter and its type definition have been properly updated to useemailAccountIdinstead ofuserId, aligning with the broader refactoring effort.
75-75: Updated internal function call parameterThe call to
getEmailFieldStatsnow correctly passesemailAccountIdinstead ofuserId, maintaining consistency with the helper function's updated signature.
96-96: Updated function call parameterThe
getSenderStatisticsfunction call now correctly passesemailAccountId: session.user.emailinstead ofuserId: session.user.id, maintaining consistency with the function's updated signature and the overall refactoring to email-based identification.apps/web/app/api/user/stats/tinybird/load/load-emails.ts (8)
18-29: Function signature change looks correctThe change from
userIdtoemailAccountIdin the function signature is consistent with the broader refactor to shift from a user-centric model to an email-account-centric model. All consumers of this API will need to be updated accordingly.
33-36: Prisma query filter update looks goodThe database query filter has been correctly updated to use
emailAccountIdinstead ofuserId, matching the schema changes in the broader refactor.
43-50: Parameter update in saveBatch call is consistentThe refactoring from
userIdtoemailAccountIdis properly applied in the call tosaveBatch.
62-65: Consistent query filter changeThe second Prisma query filter is also consistently updated to use
emailAccountId.
75-82: Second saveBatch call parameters updated properlyThe refactoring is consistently applied to the second call to
saveBatch.
95-111: Function parameter changes look goodThe
saveBatchfunction signature has been appropriately updated to acceptemailAccountIdinstead ofuserIdwhile maintaining the rest of the function parameters.
142-147: Error logging field updated correctlyThe error logging field has been updated from
userIdto
150-163: Data structure field updated correctlyThe field in the saved email data structure has been updated from
userIdtoemailAccountIdto match the new schema.apps/web/utils/ai/choose-rule/run-rules.ts (9)
70-76: saveSkippedExecutedRule parameter update looks goodThe function call has been correctly updated to use
emailAccountId: user.emailinstead ofuserId: user.id.
99-111: saveExecutedRule parameter update is consistentThe parameter to
saveExecutedRulehas been updated correctly to useemailAccountId: user.email.
133-151: Function signature and relation update looks goodThe function has been correctly updated to use
emailAccountIdinstead ofuserId. The relation in the data object has been updated fromuser: { connect: { id: userId } }toemailAccount: { connect: { email: emailAccountId } }, which aligns with the schema changes.
161-194: saveExecutedRule function updated consistentlyThe function signature and relation updates are consistent with the overall refactoring approach.
196-201: Updated function call to use named parametersThe call to
upsertExecutedRulenow uses a more explicit object parameter structure, which is good for readability and maintainability.
235-239: Logging field updated correctlyThe logging field has been updated from
userIdto
240-250: Updated findUnique query consistentlyThe unique constraint and field names have been updated consistently in the
findUniquequery.
48-49:Details
✅ Verification successful
Updated findMatchingRule call pattern
The call to
findMatchingRulehas been updated to use a single object parameter instead of multiple positional parameters. Make sure the implementation offindMatchingRulehas been updated to match this calling pattern.Run this script to verify the
findMatchingRulefunction signature:
🏁 Script executed:
#!/bin/bash # Check if findMatchingRule function has been updated to accept an object parameter rg "export\s+(?:async\s+)?function\s+findMatchingRule" -A 10 --glob "*.ts"Length of output: 776
Confirmed:
findMatchingRulesignature matches the updated callVerified in
apps/web/utils/ai/choose-rule/match-rules.tsthatfindMatchingRulenow accepts a single destructured object parameter{ rules, message, user, gmail }. No further changes are needed.
204-227:Details
✅ Verification successful
Updated upsertExecutedRule function and unique constraint
The function signature has been updated to use
emailAccountId, and the unique constraint has been renamed fromunique_user_thread_messagetounique_emailAccount_thread_message. This suggests a corresponding change in the Prisma schema.Verify that the Prisma schema has been updated with the new unique constraint:
🏁 Script executed:
#!/bin/bash # Check for the updated unique constraint in the Prisma schema rg "unique_emailAccount_thread_message" --glob "*.prisma"Length of output: 181
Prisma unique constraint confirmed
The
unique_emailAccount_thread_messageconstraint is defined inapps/web/prisma/schema.prisma:
- @@unique([emailAccountId, threadId, messageId], name: "unique_emailAccount_thread_message")
This matches the updated
upsertExecutedRuleusage—no further changes needed.
There was a problem hiding this comment.
Actionable comments posted: 1
🔭 Outside diff range comments (1)
apps/web/utils/cold-email/is-cold-email.ts (1)
1-228: 💡 Verification agent🧩 Analysis chain
Verify email as foreign key in related tables
This file handles cold email detection and blocking, with all references to
userIdreplaced byemailAccountId. While the changes look correct, ensure that all related database tables are updated to use email as the foreign key.
🏁 Script executed:
#!/bin/bash # Check if the Prisma schema has been updated to use emailAccountId rg "emailAccountId" apps/web/prisma/schema.prisma # Check for any remaining userId references in cold email related code rg "userId" --glob "**/*cold-email*" apps/webLength of output: 2942
Fix lingering
userIdreferences in cold‑email code and testsThe Prisma schema is correctly using
emailAccountId, but there are stilluserIdreferences that need updating:• apps/web/utils/cold-email/is-cold-email.test.ts
– ReplaceuserIdanduserId_fromEmailin your mock fixtures and expectations withemailAccountId/emailAccountId_fromEmail.
• apps/web/utils/actions/cold-email.ts
– Update theuserId: trueselection and anywhere: { userId_… }clauses to useemailAccountIdinstead.These changes will align your tests and action helpers with the updated Prisma foreign key.
🧹 Nitpick comments (3)
apps/web/app/api/user/rules/[id]/example/route.ts (1)
32-33: Consider updating authentication check for consistencyWhile the
getExamplesfunction now usesemailAccountIdfor authentication checks, theGEThandler still directly checkssession?.user.email. Consider updating this check for consistency with the rest of the refactoring.- if (!session?.user.email) + const emailAccountId = session?.user.email; + if (!emailAccountId) return NextResponse.json({ error: "Not authenticated" });apps/web/app/api/knowledge/route.ts (1)
13-14: Authentication refactor looks good, but variable name could be clearer.The refactoring from user ID to email for authentication is consistent with the PR objective of moving relations to emailAccount. However, the variable name
emailAccountIdmight be slightly misleading since it contains an email address, not an ID.Consider renaming for clarity:
- const emailAccountId = session?.user.email; - if (!emailAccountId) return NextResponse.json({ error: "Not authenticated" }); + const email = session?.user.email; + if (!email) return NextResponse.json({ error: "Not authenticated" });apps/web/utils/ai/choose-rule/ai-choose-rule.ts (1)
104-104: Consistent with other AI utility changes.This change follows the same pattern as the other files, removing the fallback empty string for
userEmail. Consider adding unit tests to verify the behavior whenuser.emailis undefined if they don't already exist.Since the email is logged to Braintrust on line 120, you might want to ensure consistent handling there as well if
user.emailcan be undefined.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (28)
apps/web/__tests__/ai-choose-args.test.ts(1 hunks)apps/web/__tests__/ai-extract-knowledge.test.ts(6 hunks)apps/web/__tests__/ai-process-user-request.test.ts(2 hunks)apps/web/app/(app)/reply-zero/onboarding/page.tsx(1 hunks)apps/web/app/api/google/webhook/block-unsubscribed-emails.ts(2 hunks)apps/web/app/api/google/webhook/process-history-item.ts(4 hunks)apps/web/app/api/knowledge/route.ts(1 hunks)apps/web/app/api/user/group/[groupId]/messages/controller.ts(1 hunks)apps/web/app/api/user/group/[groupId]/messages/route.ts(2 hunks)apps/web/app/api/user/group/[groupId]/rules/route.ts(2 hunks)apps/web/app/api/user/labels/route.ts(1 hunks)apps/web/app/api/user/rules/[id]/example/route.ts(1 hunks)apps/web/app/api/user/stats/newsletters/summary/route.ts(2 hunks)apps/web/utils/ai/assistant/process-user-request.ts(5 hunks)apps/web/utils/ai/categorize-sender/ai-categorize-senders.ts(1 hunks)apps/web/utils/ai/categorize-sender/ai-categorize-single-sender.ts(1 hunks)apps/web/utils/ai/choose-rule/ai-choose-args.ts(1 hunks)apps/web/utils/ai/choose-rule/ai-choose-rule.ts(1 hunks)apps/web/utils/ai/choose-rule/ai-detect-recurring-pattern.ts(1 hunks)apps/web/utils/ai/clean/ai-clean-select-labels.ts(1 hunks)apps/web/utils/ai/clean/ai-clean.ts(1 hunks)apps/web/utils/ai/example-matches/find-example-matches.ts(1 hunks)apps/web/utils/ai/group/create-group.ts(2 hunks)apps/web/utils/ai/reply/check-if-needs-reply.ts(1 hunks)apps/web/utils/ai/rule/generate-prompt-on-delete-rule.ts(1 hunks)apps/web/utils/ai/rule/generate-prompt-on-update-rule.ts(1 hunks)apps/web/utils/ai/rule/generate-rules-prompt.ts(1 hunks)apps/web/utils/cold-email/is-cold-email.ts(5 hunks)
✅ Files skipped from review due to trivial changes (2)
- apps/web/tests/ai-process-user-request.test.ts
- apps/web/tests/ai-extract-knowledge.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/web/app/api/google/webhook/process-history-item.ts
- apps/web/utils/ai/assistant/process-user-request.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
apps/web/app/api/user/rules/[id]/example/route.ts (1)
apps/web/utils/error.ts (1)
SafeError(87-95)
apps/web/utils/cold-email/is-cold-email.ts (1)
apps/web/app/api/google/webhook/logger.ts (1)
logger(3-3)
🔇 Additional comments (41)
apps/web/app/api/google/webhook/block-unsubscribed-emails.ts (3)
15-17: Function signature updated correctly to use emailAccountId.The parameter name has been changed from
userIdtoemailAccountIdin both the function parameter and type annotation, which aligns with the broader refactoring to an email-account-centric model.Also applies to: 21-22
27-30: Database query properly updated to use emailAccountId.The Prisma query's filter condition has been updated to use
emailAccountIdinstead ofuserId, maintaining consistency with the schema changes that moved relations fromUsertoEmailAccount.
40-41: Error logging updated to use emailAccountId.The error logging context now correctly includes
emailAccountIdinstead ofuserId, ensuring consistent error reporting throughout the application.apps/web/app/api/user/rules/[id]/example/route.ts (2)
13-14: Correct implementation of email account identificationThe change to use an intermediate variable
emailAccountIdinstead of directly usingsession?.user.emailis aligned with the broader refactoring effort to move from a user-centric model to an email-account-centric model.
17-17: Appropriate database query modificationThe Prisma query has been correctly updated to filter by
emailAccountIdinstead ofuserId, which aligns with the schema changes made as part of this refactoring.apps/web/app/api/user/stats/newsletters/summary/route.ts (4)
10-12: Function signature updated to use emailAccountIdThe parameter has been correctly updated from
userIdtoemailAccountIdto reflect the shift from a user-centric model to an email-account-centric model.
14-14: Updated query filter to use emailAccountIdThe Prisma query's where clause has been properly updated to filter by
emailAccountIdinstead ofuserId, consistent with the database schema changes.
31-31: Updated function call with emailAccountIdThe function call has been correctly updated to pass
emailAccountIdinstead ofuserId.
28-29:Details
✅ Verification successful
Verify email extraction logic
The code now uses
session?.user.emailas theemailAccountId, which suggests that the database is using email addresses as identifiers. This is a significant change from using traditional user IDs.
🏁 Script executed:
#!/bin/bash # Check how EmailAccount schema is defined and how emailAccountId is used elsewhere echo "Checking EmailAccount schema definition:" cat $(fd "schema.prisma$") | grep -A 20 "model EmailAccount" echo "\nChecking other usages of emailAccountId in API routes:" rg "emailAccountId.*session.*user.email" --type tsLength of output: 2318
Email as Primary Key Confirmed – No Changes Needed
The Prisma schema defines
EmailAccount.emailas the primary key, and every API route consistently derivesemailAccountIdfromsession.user.email. This aligns with all existing usages and requires no updates.apps/web/app/api/knowledge/route.ts (1)
17-18:Details
✅ Verification successful
Database query filter updated correctly.
The query filter change from
userIdtoemailAccountIdcorrectly implements the migration from user-centric to email-account-centric model. The orderBy clause reformatting to a more concise inline object is a good styling improvement.
🏁 Script executed:
#!/bin/bash # Verify Prisma schema has emailAccountId field on Knowledge model grep -A 10 "model Knowledge" $(fd "schema.prisma" --type f)Length of output: 407
Confirmed Prisma schema alignment for
emailAccountIdfilterThe Prisma schema for the
Knowledgemodel includes theemailAccountIdfield as demonstrated below, so the query update is correct:• apps/web/prisma/schema.prisma (model Knowledge):
emailAccount EmailAccount? @relation(fields: [emailAccountId], references: [email]) emailAccountId String? @@unique([emailAccountId, title])• apps/web/app/api/knowledge/route.ts (Lines 17–18):
where: { emailAccountId }, orderBy: { updatedAt: "desc" },No further changes required—this migration from
userIdtoemailAccountIdis properly implemented, and the inlineorderByis a neat styling improvement.apps/web/app/api/user/labels/route.ts (3)
8-10: LGTM: Consistent migration to email-based identificationThe change from
userIdtoemailAccountIdfor filtering labels correctly implements the shift from a user-centric to an email-account-centric model as described in the PR objective.
16-17: Authentication check looks correctThe code now properly extracts the email account ID from the session and checks for its existence before proceeding.
19-19: Proper function call with updated parameter nameThe
getLabelsfunction is now correctly called with theemailAccountIdparameter, completing the migration from user ID to email account ID.apps/web/utils/ai/reply/check-if-needs-reply.ts (1)
73-73:Details
✅ Verification successful
Verify that user.email is always defined
The fallback to an empty string for
userEmailhas been removed, which aligns with the email-account-centric model. However, this assumesuser.emailis always defined.Let's verify that the
UserEmailWithAItype enforces the presence of an email:
🏁 Script executed:
#!/bin/bash # Check the definition of UserEmailWithAI type rg -A 3 "type UserEmailWithAI" --type ts # Check if there are any null/undefined checks for user.email before calling chatCompletionObject rg "chatCompletionObject\(\{[^}]*userEmail: .*\?\?" --type tsLength of output: 261
🏁 Script executed:
#!/bin/bash # Retrieve EmailAccount definition to inspect the 'email' property's type rg -A5 "export interface EmailAccount" --type ts rg -A5 "export type EmailAccount" --type tsLength of output: 96
🏁 Script executed:
#!/bin/bash # Show the top of the file and import context for EmailAccount in the TS types file sed -n '1,30p' apps/web/utils/llms/types.ts rg -n "EmailAccount" -C2 apps/web/utils/llms/types.ts # Locate Prisma schema definition for EmailAccount rg -n "model EmailAccount" -C5 --glob "*.prisma"Length of output: 1338
Email is guaranteed by the Prisma schema
The
EmailAccountmodel inschema.prismadeclaresemail String @id(required), and the generated TypeScriptEmailAccounttype reflects thatemail: string(non‑nullable). SinceUserEmailWithAIpicks this field,user.emailis always defined—no fallback is needed.apps/web/utils/ai/rule/generate-prompt-on-update-rule.ts (1)
65-65:Details
✅ Verification successful
Consistent with email-account-centric model
The removal of the fallback to an empty string for
userEmailis consistent with the PR's objective of moving to an email-account-centric model.Let's verify that the
chatCompletionObjectfunction handles undefined email appropriately:
🏁 Script executed:
#!/bin/bash # Check the implementation of chatCompletionObject to see how it handles userEmail rg -A 10 "export (async )?function chatCompletionObject" --type tsLength of output: 644
🏁 Script executed:
#!/bin/bash echo "=== chatCompletionObjectInternal signature ===" rg -n "async function chatCompletionObjectInternal" -A 20 -B 5 apps/web/utils/llms/index.ts echo echo "=== ChatCompletionObjectArgs definition ===" rg -n "interface ChatCompletionObjectArgs" -A 10 apps/web/utils/llms/index.tsLength of output: 1009
🏁 Script executed:
#!/bin/bash echo "=== Top 50 lines of apps/web/utils/llms/index.ts ===" sed -n '1,50p' apps/web/utils/llms/index.ts echo echo "=== All occurrences of ChatCompletionObjectArgs ===" rg -n "ChatCompletionObjectArgs" -n . echo echo "=== Definitions of generateObject ===" rg -nE "export (async )?function generateObject" -n . echo echo "=== Any internal helper around generateObject ===" rg -n "generateObjectInternal" -n .Length of output: 2168
🏁 Script executed:
#!/bin/bash echo "=== Extract ChatCompletionObjectArgs definition ===" sed -n '75,95p' apps/web/utils/llms/index.tsLength of output: 535
Approve:
userEmailis required by type, so no undefined fallback is neededType
ChatCompletionObjectArgsdefinesuserEmail: stringas mandatory, and thechatCompletionObjectInternalfunction signature enforces that. Removing the''fallback is safe and aligns with the email-centric model.apps/web/utils/ai/clean/ai-clean.ts (1)
100-100: Consistent pattern across AI utility filesThis change follows the same pattern seen in other AI utility files, removing the fallback to an empty string for
userEmail. This is aligned with the email-account-centric model refactoring.apps/web/utils/ai/clean/ai-clean-select-labels.ts (1)
38-38:Details
❓ Verification inconclusive
Empty string fallback removed for userEmail parameter
The change removes the previous fallback that would have converted
undefinedornullemail values to an empty string. This aligns with the PR's objective to shift from user ID to email account as the primary identifier.However, ensure that
user.emailis guaranteed to be defined throughout the authentication flow to prevent passing undefined values to thechatCompletionObjectfunction.
🏁 Script executed:
#!/bin/bash # Check if there are any null/undefined email handling in the authentication flow or userAi validation # Look for email nullability checks in authentication code echo "Checking for email null checks in auth code:" rg -C 2 "user\.(email|emailAccountId)\s*(\?\?|!=\s*null|!==\s*null|\|\|)" --type ts apps/web/Length of output: 1639
Empty string fallback removed for userEmail in ai-clean-select-labels.ts
The previous
?? ""fallback has been removed inapps/web/utils/ai/clean/ai-clean-select-labels.tsso thatuserEmail: user.emailis passed directly. However, other parts of the codebase still guard againstnull/undefinedemails (e.g.find-snippets.ts,rule-fix.ts,EmailList.tsx,Pending.tsx), which suggestssession.data?.user.emailmay not always be defined.Please confirm that your authentication/session setup (e.g. NextAuth callbacks or database schema) guarantees a non‑empty
user.email. If not, either:
- Enforce email presence at the source of truth, or
- Reintroduce a fallback (e.g.
user.email ?? "") when callingchatCompletionObject.apps/web/utils/ai/categorize-sender/ai-categorize-senders.ts (1)
97-97:Details
❓ Verification inconclusive
Empty string fallback removed for userEmail parameter
The fallback to empty string for the
userEmailparameter has been removed, consistent with the PR's shift to an email-account-centric model. Nowuser.emailis passed directly to thechatCompletionObjectfunction.Ensure that any potential
nullorundefinedemail values are handled appropriately in the authentication flow or in thechatCompletionObjectimplementation to prevent unexpected behavior.
🏁 Script executed:
#!/bin/bash # Check type definition of UserEmailWithAI to verify email property requirements # Look at the UserEmailWithAI type definition echo "Checking UserEmailWithAI type definition:" rg -A 10 "export(\s+)type(\s+)UserEmailWithAI" --type ts apps/web/ # Check if there's validation for user.email before calls to AI functions echo "Checking for validation of user.email before AI function calls:" rg -B 5 "userEmail: user\.email" --type ts apps/web/utils/ai/Length of output: 12821
🏁 Script executed:
#!/bin/bash # Inspect the llms types file for EmailAccount import and UserEmailWithAI definition echo "=== apps/web/utils/llms/types.ts ===" sed -n '1,80p' apps/web/utils/llms/types.ts echo "" rg -n -C3 "UserEmailWithAI" --type ts apps/web/utils/llms/types.ts # Search the entire repo for EmailAccount type/interface definitions echo "" echo "Searching for EmailAccount definitions across the repo:" rg -n -A5 "export.*(interface|type).*EmailAccount" --type tsLength of output: 966
🏁 Script executed:
#!/bin/bash # Locate and inspect the Prisma schema to confirm EmailAccount.email nullability schema_file=$(find . -maxdepth 3 -type f -name "schema.prisma" | head -n1) echo "Schema file: $schema_file" echo "=== EmailAccount model definition ===" sed -n '/model EmailAccount/,/}/p' "$schema_file"Length of output: 282
Verify non-nullability of
user.emailbefore AI callsThe empty‐string fallback was removed for the
userEmailparameter across allchatCompletionObjectinvocations so thatuser.emailis passed directly.• The
UserEmailWithAItype picks"email"fromEmailAccount, but we haven’t confirmed whetherEmailAccount.emailis always non‑nullable in your Prisma schema.
• Ensure that your authentication flow guaranteesuser.emailis neithernullnorundefinedbefore any AI function is called.
• Alternatively, validate or coerceuser.emailat the entrypoint of the AI layer (e.g., inchatCompletionObject) to avoid runtime errors.Please confirm that the Prisma model defines
apps/web/utils/ai/categorize-sender/ai-categorize-single-sender.ts (1)
65-65:Details
✅ Verification successful
Empty string fallback removed for userEmail parameter
The code no longer uses a fallback empty string for
userEmail, now passinguser.emaildirectly. This is part of the larger refactoring to use email instead of user ID as the primary identifier.To ensure stability, verify that
UserEmailWithAItype guarantees the presence of an email property and that the authentication flow ensures that user objects always have valid email values before reaching this code.
🌐 Web query:
What are best practices for handling potentially undefined values when making API calls to external services in TypeScript?💡 Result:
Best Practices for Handling Potentially Undefined Values in TypeScript API Calls
When interfacing with external APIs in TypeScript, responses often include fields that are optional, undefined, or explicitly set to null. Robust handling of these values is crucial to avoid runtime errors and ensure type safety. Here are widely accepted best practices:
Enable Strict Null Checks
- Always enable
strictNullChecksin yourtsconfig.json. This setting enforces explicit handling ofnullandundefined, and prevents many common bugs by making the compiler alert you to places where you might access a value that might not be defined[4][5][9].
Use Union Types and Optional Types
- Define your API response interfaces to reflect reality by making properties optional or explicitly unioned with
undefinedornullas appropriate:This makes the intent clear and helps TypeScript catch improper accesses[1][4][5].interface UserResponse { name?: string; age: number | undefined; email: string | null; }
Utilize Optional Chaining (
?.)
- Use optional chaining to safely access nested properties that may be undefined:
This prevents runtime errors when intermediate properties are missing[1][6][9].const city = response.address?.city;
Leverage Nullish Coalescing (
??) for Fallbacks
- The nullish coalescing operator provides concise, safe fallbacks for undefined or null values:
This ensures onlyconst userName = response.user?.name ?? 'Anonymous';nullorundefinedtrigger the fallback, not other falsy values like''or0[1][9].
Explicit Checks for Undefined/Null
- Before using values that may be undefined or null, validate them:
Or, for a concise approach:if (user.email !== undefined && user.email !== null) { // safe to use user.email }This guards against bothif (user.email != null) { /* ... */ }nullandundefined[2][6].
Type Guards and Narrowing
- Use
iforswitchstatements to narrow the type and ensure values are defined before use, allowing TypeScript to infer the safe type within the guard:This approach is the safest and most explicit[2][7].if (result) { // result is not undefined or null here } else { // handle the undefined/null case }
Be Cautious with Non-Null Assertion (
!)
- The
!operator forces TypeScript to treat a value as defined, but it bypasses safety and can introduce runtime errors if misused:Use this only when you're absolutely certain the value is defined at that point in your code[2][6][9].const length = response.name!.length; // unsafe if name can be undefined
Throw Explicit Errors Where Needed
- If undefined values are unexpected or indicate a logic error, throw clear, descriptive errors:
This makes debugging easier and failures more informative[2].if (!user.email) { throw new Error("Email is required but undefined."); }
Model API Responses Accurately
- When designing interfaces for API responses, match the external service’s schema as closely as possible. If the API may omit fields, mark them as optional or include
undefinedand/ornullin their type definitions[3][10].
Summary Table
Technique Purpose Safe? strictNullChecks Enforces explicit undefined/null handling Yes Union/Optional types Models data accurately, prevents unsafe access Yes Optional chaining ( ?.)Safe access for nested possibly-undefined values Yes Nullish coalescing ( ??)Provides default/fallback values when undefined or null Yes Type guards/explicit checks Ensures value is defined before use Yes Non-null assertion ( !)Bypasses type checking, use with caution No* Throwing explicit errors Defensive failure handling for unexpected undefined Yes (*Non-null assertion is unsafe if the variable can truly be undefined/null.)
By following these practices, you can write safer and more robust TypeScript code when handling potentially undefined values in API responses[1][2][4][5][6][7][9].
Citations:
- 1: https://www.zipy.ai/blog/debug-typescript-null-or-undefined-value-errors
- 2: https://palantir.com/docs/foundry/functions/undefined-values/
- 3: https://dev.to/sduduzog/null-vs-undefined-what-to-choose-what-to-use-11g
- 4: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html
- 5: https://dev.to/mochafreddo/understanding-null-and-undefined-in-javascript-and-typescript-33fo
- 6: https://javascript.plainenglish.io/beginners-guide-how-to-check-null-and-undefined-in-typescript-c6492a07b609
- 7: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-5.html
- 8: https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html
- 9: https://www.w3schools.com/typescript/typescript_null.php
- 10: acacode/swagger-typescript-api#396
🏁 Script executed:
#!/bin/bash # Search for UserEmailWithAI definition rg -n "type UserEmailWithAI" -g "apps/web/utils/ai/categorize-sender/*.ts" rg -n "interface UserEmailWithAI" -g "apps/web/utils/ai/categorize-sender/*.ts" # Find the function handling the payload and inspect surrounding context rg -n "categorizeSingleSender" -g "apps/web/utils/ai/categorize-sender/*.ts" -A 5 -B 5 # Locate all user.email references in this module rg -n "user.email" -g "apps/web/utils/ai/categorize-sender/*.ts" -C 3Length of output: 1526
🏁 Script executed:
#!/bin/bash # Show imports and function signature for categorizeSingleSender sed -n '1,80p' apps/web/utils/ai/categorize-sender/ai-categorize-single-sender.tsLength of output: 2520
🏁 Script executed:
#!/bin/bash # Locate the file defining UserEmailWithAI file=$(rg -l "type UserEmailWithAI" -g "apps/**/*.ts") echo "Found file: $file" # Display the type definition and related lines sed -n '1,200p' "$file"Length of output: 463
🏁 Script executed:
#!/bin/bash # Locate all Prisma schema files echo "Prisma files:" find . -maxdepth 4 -type f -name "*.prisma" # Display the EmailAccount model definition from each schema for file in $(find . -maxdepth 4 -type f -name "*.prisma"); do echo -e "\n--- $file ---" sed -n '/model EmailAccount {/,/}/p' "$file" doneLength of output: 1837
Confirm non-nullable user.email guarantee
The removal of the
""fallback foruserEmailis safe:- The
UserEmailWithAItype is defined as aPick<EmailAccount, "userId" | "email" | "about"> & UserAIFields.
- In your Prisma schema,model EmailAccount { email String @id … }marksThis ensures at compile‑time (via TypeScript’s strict null checks) and at runtime (via the database schema) that
user.emailis always a valid string. No further fallback is needed.apps/web/utils/ai/rule/generate-prompt-on-delete-rule.ts (1)
60-60:Details
✅ Verification successful
Potential edge case with undefined email.
The change removes a fallback empty string for
userEmailparameter, which aligns with the PR's objective of moving to an email-account-centric model. However, ensure that thechatCompletionObjectfunction properly handles cases whereuser.emailcould be undefined or null.
🏁 Script executed:
#!/bin/bash # Check if chatCompletionObject handles undefined userEmail grep -r "userEmail" --include="*.ts" apps/web/utils/llmsLength of output: 1334
I’d like to confirm how
chatCompletionObjectis declared to see how it types and usesuserEmail. Let’s pull its signature and immediate implementation context:
🏁 Script executed:
#!/bin/bash # Show declaration and use of chatCompletionObject grep -n -C4 "chatCompletionObject" apps/web/utils/llms/index.tsLength of output: 417
🏁 Script executed:
#!/bin/bash # Find ChatCompletionObjectArgs definition grep -n -C5 "ChatCompletionObjectArgs" apps/web/utils/llms/index.ts # Show function signature for generatePromptOnDeleteRule grep -n -C5 "function generatePromptOnDeleteRule" apps/web/utils/ai/rule/generate-prompt-on-delete-rule.tsLength of output: 1240
Let’s verify whether
user.emailcan actually be undefined by inspecting theUserEmailWithAItype:
🏁 Script executed:
#!/bin/bash # Locate where UserEmailWithAI is defined grep -R "UserEmailWithAI" -n apps/web # Show its declaration context grep -n -C3 "type UserEmailWithAI" -n $(grep -R "UserEmailWithAI" -l apps/web)Length of output: 10976
Here’s how
UserEmailWithAIand related types are defined:Let me know once we have those details.
🏁 Script executed:
#!/bin/bash # Show import and definitions in types.ts sed -n '1,50p' apps/web/utils/llms/types.tsLength of output: 285
🏁 Script executed:
#!/bin/bash # Locate EmailAccount definition to see if email is optional grep -R "export type EmailAccount" -n .Length of output: 41
🏁 Script executed:
#!/bin/bash # Locate Prisma schema file(s) and inspect EmailAccount model definition find . -type f -name '*.prisma' -exec grep -n -C3 "model EmailAccount" {} \;Length of output: 370
No Action Required:
user.emailIs Always DefinedThe Prisma model defines
EmailAccount.emailas a non-nullableString @id, andUserEmailWithAI.emailis typed asstring. SinceChatCompletionObjectArgs.userEmailalso requires astring,user.emailcan never beundefinedornull. Removing the empty‐string fallback is safe and no further handling is needed.apps/web/utils/ai/choose-rule/ai-detect-recurring-pattern.ts (1)
106-106: Consistent change removing email fallback.This change aligns with the PR objective of shifting from user ID to email-based identification. Make sure to verify that all callers provide a valid email value and that error handling is in place for cases where the email might be missing.
apps/web/utils/ai/rule/generate-rules-prompt.ts (1)
121-121: Consistent approach to email-based identification.The removal of the fallback empty string matches the pattern across other AI utility files, maintaining consistency with your migration to an email-account-centric model.
apps/web/utils/ai/choose-rule/ai-choose-args.ts (1)
94-94: Consistent parameter refactoring for user identificationThis change aligns with the broader refactor shifting from userId to email as the primary identifier.
apps/web/app/api/user/group/[groupId]/messages/route.ts (2)
9-10: Refactored authentication to use email identifierThis change properly extracts the email as the identifier and uses it for authentication checks.
19-19: Updated parameter to use emailAccountIdProperly updated the getGroupEmails call to use the email-based identifier consistent with the controller changes.
apps/web/__tests__/ai-choose-args.test.ts (1)
188-188: Updated test helper to use emailAccountIdGood job updating the test helper to reflect the data model changes, ensuring tests remain valid with the new schema.
apps/web/utils/ai/group/create-group.ts (2)
103-103: Removed fallback to empty string for consistent user identificationThis change aligns with the broader refactor to use email as a direct identifier without fallbacks.
174-174: Removed fallback to empty string in second occurrenceConsistent with the previous change, maintaining the same pattern throughout the file.
apps/web/app/(app)/reply-zero/onboarding/page.tsx (2)
13-16: LGTM! Database query updated correctlyThe Prisma query has been properly updated to filter by
emailAccountIdinstead ofuserId.
9-10:Details
❓ Verification inconclusive
Verify that email is properly validated before using as ID
The code now uses
session?.user.emailas theemailAccountIdinstead ofsession?.user.id. This aligns with the overall refactoring to an email-account-centric model, but ensure that proper email validation is in place elsewhere in the authentication flow.
🏁 Script executed:
#!/bin/bash # Check if there's email validation in the auth setup rg -A 3 -B 3 "user.email" apps/web/app/api/authLength of output: 47
Validate email before using as account ID
I didn’t find any explicit email‐validation logic in the auth API—before relying onsession.user.emailas your primary identifier, please confirm that incoming emails are properly validated and sanitized. In particular, verify validation in:
apps/web/app/api/auth/[...nextauth].ts(NextAuth email provider setup)- Any custom sign‑up or user‐creation handlers (e.g.
apps/web/app/api/auth/signup.ts)Ensure you enforce a robust email regex or schema (e.g. via Zod) and reject invalid addresses at authentication time.
apps/web/app/api/user/group/[groupId]/messages/controller.ts (2)
24-38: Function signature updated correctlyThe function signature and type definition have been properly updated to use
emailAccountIdinstead ofuserId, which aligns with the refactoring to an email-account-centric model.
39-42: Database query updated correctlyThe Prisma query has been properly updated to filter by
emailAccountIdinstead ofuserId.apps/web/app/api/user/group/[groupId]/rules/route.ts (4)
9-15: Function signature updated correctlyThe function signature and parameter types have been properly updated to use
emailAccountIdinstead ofuserId.
16-25: Database query updated correctlyThe Prisma query has been properly updated to filter by
emailAccountIdinstead ofuserId.
32-35: Authentication check updated to use emailThe authentication check now correctly extracts and verifies the user's email from the session instead of the user ID.
40-40: Function call updated correctlyThe function call to
getGroupRuleshas been updated to passemailAccountIdinstead ofuserId.apps/web/utils/cold-email/is-cold-email.ts (5)
23-48: Email parameter usage consistent with refactoringThe
isColdEmailfunction's usage ofuser.emailis consistent with the refactoring approach. The reference toemailAccountIdon line 47 has been updated correctly.
87-105: Update to composite key field namesThe function
isKnownColdEmailSenderhas been correctly updated to useemailAccountIdinstead ofuserId, and the composite key has been changed fromuserId_fromEmailtoemailAccountId_fromEmail.
138-149: Direct use of email without fallbackThe
chatCompletionObjectcall now directly usesuser.emailwithout falling back to an empty string, which is more consistent with the new approach where email is the primary identifier.
175-191: Database operations updated correctlyThe
upsertoperation has been properly updated to useemailAccountId_fromEmailas the composite key anduser.emailas theemailAccountIdvalue.
204-204: Logging updated to use emailAccountIdThe error logging has been updated to use
emailAccountIdinstead ofuserId, which is consistent with the refactoring approach.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
apps/web/utils/api-auth.ts (1)
88-93: Consider adding a TypeScript interface for the return typeThe return object now includes the
accountIdalongside other properties, which correctly supports the email-account-centric refactoring. However, the function lacks an explicit TypeScript return type.Consider defining a TypeScript interface for the return type to improve code readability and maintainability:
interface GmailClientResult { gmail: any; // Use appropriate type from Gmail client accessToken: string; userId: string; accountId: string; } // Then update the function signature: export async function validateApiKeyAndGetGmailClient(request: NextRequest): Promise<GmailClientResult> { // ...existing implementation... }apps/web/app/api/v1/reply-tracker/route.ts (2)
83-86: Consider updating userId in loggerThe logger statement still uses
userIdfor identification. Consider updating this to useemailAccountIdfor consistency with the refactoring.logger.info("Retrieved emails needing reply", { - userId, + emailAccountId, count: response.emails.length, });
90-93: Consider updating userId in error loggerSimilarly, the error logger still uses
userId. Consider updating this to useemailAccountIdfor consistency.logger.error("Error retrieving emails needing reply", { - userId, + emailAccountId, error, });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/web/app/api/v1/group/[groupId]/emails/route.ts(2 hunks)apps/web/app/api/v1/group/[groupId]/emails/validation.ts(1 hunks)apps/web/app/api/v1/helpers.ts(1 hunks)apps/web/app/api/v1/reply-tracker/route.ts(4 hunks)apps/web/app/api/v1/reply-tracker/validation.ts(1 hunks)apps/web/utils/api-auth.ts(2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/web/app/api/v1/group/[groupId]/emails/route.ts (4)
apps/web/utils/middleware.ts (1)
withError(16-70)apps/web/utils/api-auth.ts (1)
validateApiKeyAndGetGmailClient(67-94)apps/web/app/api/v1/helpers.ts (1)
getEmailAccountId(9-36)apps/web/app/api/user/group/[groupId]/messages/controller.ts (1)
getGroupEmails(24-55)
🔇 Additional comments (16)
apps/web/app/api/v1/reply-tracker/validation.ts (1)
7-7: LGTM: Optional email parameter correctly addedThe addition of an optional email field to the validation schema aligns with the codebase refactoring towards an email-account-centric model. The implementation using Zod is correct.
apps/web/app/api/v1/group/[groupId]/emails/validation.ts (1)
8-8: LGTM: Optional email parameter correctly addedThe addition of an optional email field to the group emails query schema is correctly implemented using Zod. This aligns with the codebase refactoring towards an email-account-centric model.
apps/web/utils/api-auth.ts (1)
43-43: LGTM: Account ID selection correctly addedAdding the
idfield to the accounts selection is correctly implemented, enabling the return of the account ID in the validation function.apps/web/app/api/v1/group/[groupId]/emails/route.ts (7)
1-1: Import optimization - unused import removedGood job removing the unused
NextRequestimport and keeping onlyNextResponse.
9-9: Addition of helper importThe new
getEmailAccountIdhelper import aligns with the broader refactoring to an email-account-centric model.
12-13: Updated destructuring to include accountIdGood update to extract the
accountIdfrom thevalidateApiKeyAndGetGmailClientresult, which is required for the new email account resolution logic.
31-32: Updated query parameter extractionCorrectly updated to extract the optional
33-37: Email account resolution implementationGood implementation of the email account resolution logic using the new helper function.
39-44: Proper error handling for missing email accountAppropriate error handling when no email account is found, returning a clear error message with a 400 status code.
48-48: Updated parameter name in function callCorrectly updated to use
emailAccountIdinstead of the previoususerIdparameter in the call togetGroupEmails.apps/web/app/api/v1/reply-tracker/route.ts (6)
1-1: Import optimization - unused import removedGood job removing the unused
NextRequestimport and keeping onlyNextResponse.
13-13: Addition of helper importThe new
getEmailAccountIdhelper import aligns with the broader refactoring to an email-account-centric model.
18-19: Updated destructuring to include accountIdGood update to extract the
accountIdfrom thevalidateApiKeyAndGetGmailClientresult, which is required for the new email account resolution logic.
33-37: Email account resolution implementationGood implementation of the email account resolution logic using the new helper function. This correctly extracts the optional email parameter from the query result.
39-44: Proper error handling for missing email accountAppropriate error handling when no email account is found, returning a clear error message with a 400 status code.
54-54: Updated parameter in function callCorrectly updated to use
email: emailAccountIdin the call togetPaginatedThreadTrackers, replacing the previous userId-based approach.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/web/components/AccountSwitcher.tsx (2)
94-101: "Add account" menu item lacks implementation.The "Add account" menu item is currently just a UI element without any functionality (no onClick handler). This should be implemented or marked with a TODO comment if intended for a future PR.
- <DropdownMenuItem className="gap-2 p-2"> + <DropdownMenuItem className="gap-2 p-2" onClick={() => {/* TODO: Implement add account functionality */}}> <div className="flex size-6 items-center justify-center rounded-md border bg-background"> <Plus className="size-4" /> </div> <div className="font-medium text-muted-foreground"> Add account </div> </DropdownMenuItem>
90-90: Keyboard shortcuts shown but not implemented.The dropdown displays keyboard shortcuts (⌘1, ⌘2, etc.) but there don't appear to be any actual keyboard event handlers to make these shortcuts functional.
Consider adding actual keyboard shortcut handlers or marking with a TODO if this will be implemented later.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/web/components/AccountSwitcher.tsx(1 hunks)apps/web/components/SideNav.tsx(3 hunks)apps/web/components/SideNavWithTopNav.tsx(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- apps/web/components/SideNavWithTopNav.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/web/components/AccountSwitcher.tsx (2)
apps/web/components/ui/sidebar.tsx (4)
useSidebar(776-776)SidebarMenu(763-763)SidebarMenuItem(767-767)SidebarMenuButton(766-766)apps/web/components/ui/dropdown-menu.tsx (7)
DropdownMenu(185-185)DropdownMenuTrigger(186-186)DropdownMenuContent(187-187)DropdownMenuLabel(191-191)DropdownMenuItem(188-188)DropdownMenuShortcut(193-193)DropdownMenuSeparator(192-192)
🔇 Additional comments (7)
apps/web/components/SideNav.tsx (4)
53-53: Import added for new AccountSwitcher component.This import allows using the new account switching functionality in the sidebar, aligning with the PR objective of moving to an email-account-centric model.
231-231: Component renamed from AppSidebar to SideNav.The rename makes the component name more specific and descriptive of its function as a side navigation element, improving code clarity.
255-264: SidebarHeader now renders unconditionally with AccountSwitcher.The header structure has been improved to:
- Always render the SidebarHeader regardless of sidebar state
- Only conditionally render the logo when expanded
- Include the new AccountSwitcher component
This change supports the email-account-centric model by prominently featuring account switching functionality in the UI.
259-259: Logo size reduced.The logo height has been reduced to 3.5 (likely 3.5rem or a similar unit) which helps balance the visual hierarchy with the newly added AccountSwitcher component.
apps/web/components/AccountSwitcher.tsx (3)
1-107: New AccountSwitcher component implements email account selection UI.This component successfully implements a UI for switching between multiple email accounts, which is a key part of the PR objective to move to an email-account-centric model.
46-46: State management for active account.The component manages local UI state for the selected account but doesn't appear to sync this selection with any global state or make API calls when an account is switched.
Consider whether this component should trigger actual account switching in the application, or if this will be implemented in a future PR.
76-76: Responsive dropdown positioning.Good implementation of responsive design by changing the dropdown position based on whether the sidebar is in mobile mode.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/web/app/api/user/accounts/route.ts (1)
7-7: Unused logger variable.The
loggeris initialized but never used in the code. Either use it for logging important events or remove it.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/app/api/user/accounts/route.ts(1 hunks)apps/web/hooks/useAccounts.ts(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/web/hooks/useAccounts.ts (1)
apps/web/app/api/user/accounts/route.ts (1)
GetAccountsResponse(9-9)
🔇 Additional comments (1)
apps/web/hooks/useAccounts.ts (1)
1-8: Well-implemented data fetching hook.This is a clean implementation of a React hook using SWR to fetch email account data. Setting
revalidateOnFocus: falseis a good choice to avoid unnecessary refetches when the user returns to the tab.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
apps/web/components/AccountSwitcher.tsx (3)
25-36: Add a lightweight loading / empty‑state instead of returningnull.When
useAccounts()is still loading the SWR cache, the component renders nothing, which causes a brief layout shift once the data arrives. A tiny placeholder (spinner / skeleton avatar) makes the UI feel more responsive and avoids CLS.- return ( - <AccountSwitcherInternal - accounts={accountsData?.accounts ?? []} - accountId={accountId} - setAccountId={setAccountId} - /> - ); + if (!accountsData) { + // TODO: replace with your design‐system skeleton + return <div className="animate-pulse h-8 w-24 rounded-md bg-muted" />; + } + + return ( + <AccountSwitcherInternal + accounts={accountsData.accounts} + accountId={accountId} + setAccountId={setAccountId} + /> + );
85-94: Guard keyboard shortcuts > 9 to avoid impossible chords.
⌘{index + 1}yields “⌘10”, “⌘11”… for larger lists, which aren’t single‑key shortcuts and may confuse users.
Consider limiting to the first nine accounts or switching to letters after 9.- <DropdownMenuShortcut>⌘{index + 1}</DropdownMenuShortcut> + {index < 9 && ( + <DropdownMenuShortcut>⌘{index + 1}</DropdownMenuShortcut> + )}
118-125: Provide an accessiblealtdescription for profile images.
alt=""hides the image from assistive tech, but the avatar is meaningful (it identifies the account).
Pass the user’s name to improve accessibility; fall back to a generic label if unavailable.- alt="" + alt={name ? `${name}'s avatar` : 'Account avatar'}You’d need to extend
ProfileImage’s props withname?: stringand supply it at call‑sites.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/app/api/user/accounts/route.ts(1 hunks)apps/web/components/AccountSwitcher.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/app/api/user/accounts/route.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/web/components/AccountSwitcher.tsx (4)
apps/web/hooks/useAccounts.ts (1)
useAccounts(4-8)apps/web/app/api/user/accounts/route.ts (1)
GetAccountsResponse(6-6)apps/web/components/ui/sidebar.tsx (4)
useSidebar(776-776)SidebarMenu(763-763)SidebarMenuItem(767-767)SidebarMenuButton(766-766)apps/web/components/ui/dropdown-menu.tsx (7)
DropdownMenu(185-185)DropdownMenuTrigger(186-186)DropdownMenuContent(187-187)DropdownMenuLabel(191-191)DropdownMenuItem(188-188)DropdownMenuShortcut(193-193)DropdownMenuSeparator(192-192)
Summary by CodeRabbit
New Features
Improvements
useActionhooks bound with user email for consistent state and error management.Bug Fixes
Documentation
Chores