-
Notifications
You must be signed in to change notification settings - Fork 723
WIP: Move over relations to emailAccount #412
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
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. 122 files out of 274 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:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🔭 Outside diff range comments (5)
apps/web/utils/redis/clean.ts (1)
110-113
:⚠️ Potential issueInconsistency in
deleteAllUserData
functionWhile
getThreadsByJobId
has been updated to useemailAccountId
, thedeleteAllUserData
function still usesuserId
as 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
getSenders
function 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.ts
and thegetSenders
API 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
getSenders
to 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.email
for 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
sendEmail
is 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.id
touser.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
NeedsAction
component reference still usesuserId
anduserEmail
. 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
getUpdateCategoryTool
function still takes auserId
parameter 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
loggerOptions
to focus on email rather than userId.apps/web/utils/actions/rule.ts (1)
437-438
: Unused userId in authentication blockThere's an unused
userId
variable 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 repeatingemailAccountId
You set
emailAccountId
twice in the twocreate
blocks. 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.rules
is guaranteed to be an array, butcoldEmailBlocker
can benull
.
If you ever introduce partial selects (e.g., feature flags) Prisma may returnundefined
for 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
/coldEmailBlocker
downstream.
64-72
: Minor optimisation: compute look‑ups only once
getRuleSetting
scans 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 lingeringuserId
would 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
: Preferupdate
overupdateMany
for single‑row ops
updateMany
ignores the case where zero rows match, hiding auth mistakes and typos.
update
would surface aP2025
error in that scenario, which you could translate into a 404.
617-639
:emailAccountId
vs email variable namingInside
reportAiMistakeAction
you 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‑loadingcategoryFilters
may 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: string
while 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
userId
fromuser.id
but 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
.
BecauseemailAccountId
now 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:emailAccountId
holds 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 toaccountEmail
for 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
getUserCategories
has 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.ts
that 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
getLastJob
has 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
emailAccountId
using the user's email instead of user ID. This change aligns with the broader refactoring to move relations from theUser
model to theEmailAccount
model.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
emailAccountId
using the user's email instead of user ID. This change aligns with the broader refactoring to move relations from theUser
model to theEmailAccount
model.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
getCategories
to 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
rules
andnewsletters
selected directly on theemailAccount
object instead of through a nesteduser
object. 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
rules
andnewsletters
from theemailAccount
object instead of through the previously nesteduser
object.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
userId
to- Update the Prisma query to use
emailAccountId: email
instead ofuserId
This 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
userId
toemailAccountId
for 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.id
for authentication and database queries, whileresetAnalyticsAction
has 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
userId
toemailAccountId
in 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
EmailAccount
model 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
userId
toemailAccountId
in 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
emailAccountId
instead 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
getData
has 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
emailAccountId
instead 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: email
instead of user ID, consistent with the schema changes throughout the application.apps/web/app/(app)/reply-zero/ReplyTrackerEmails.tsx (3)
38-38
: Property renamed fromuserEmail
toThe 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
userEmail
to
260-260
: Row component parameter renamed fromuserEmail
toThe 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.rules
toemailAccount.rules
to match the new schema structure.
178-178
: Updated processHistory function call.The processHistory function call now correctly passes
emailAccount.rules
instead 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
emailAccountId
when 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.email
instead of the previoususerId
in 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
emailAccount
table directly and accesses tokens through the nestedaccount
relation, 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
userId
to 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
userId
to 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.email
instead ofsession?.user.id
for 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_emailAccountId
and setsemailAccountId: userEmail
directly 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
userId
touserEmail
as the primary identifier, and updates the function call to useemailAccountId
parameter. 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
getJobById
andgetLastJob
to 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: userEmail
instead 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
getRules
function signature has been correctly updated to acceptuserId
, and the Prisma query filter now usesemailAccountId: email
instead ofuserId
. This is consistent with the schema changes moving relations fromUser
toEmailAccount
.
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
getRule
function signature has been correctly updated to acceptuserId
, and the Prisma query filter now usesemailAccountId: email
instead ofuserId
. This is consistent with the schema changes moving relations fromUser
toEmailAccount
.
24-27
: Function call parameter updated correctlyThe call to
getRule
now correctly passesemail: session.user.email
instead ofuserId
, ensuring consistency with the updated function signature.apps/web/app/api/user/categories/route.ts (2)
8-9
: Function signature updated correctlyThe
getCategories
function signature has been properly updated to accept an object with anuserId
, and it correctly callsgetUserCategories
with the email parameter.
15-18
: Authentication and function call updated correctlyThe authentication check now properly verifies
session.user.email
instead 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
getGroups
function and its Prisma query have been correctly updated to useemailAccountId
filter instead of the previoususerId
approach. 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
getGroups
function 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
getPaginatedThreadTrackers
function 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: email
instead of the previoususerId
filter. 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
emailAccountId
instead 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: email
instead of the previoususerId
filter, maintaining consistency with the broader refactoring effort.
47-47
: Function call updated to use email parameter.The
getUserCategoriesWithRules
function call now correctly passes the email parameter, which matches the updated function signature incategory.server.ts
that 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
deleteExecutedRulesInBatches
has been correctly updated to pass an object with the
103-109
: Function signature properly updated to accept email parameter.The
deleteExecutedRulesInBatches
function 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: email
instead of the previoususerId
filter, 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
userId
before, 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
getPaginatedThreadTrackers
has 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
ReplyTrackerEmails
component has been changed from what was likelyuserEmail
toapps/web/utils/rule/prompt-file.ts (1)
66-70
: Database query correctly updated to use email as identifier.The
where
clause in the Prisma query has been properly changed to useemailAccountId: email
instead of what was likelyuserId
, aligning with the schema changes that moved relations fromUser
toEmailAccount
.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
emailAccount
table instead ofuser
and 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.email
instead 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.email
instead 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
where
clause for deleting DRAFT_EMAIL actions has been updated to useemailAccountId: user.email
instead 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.email
for 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
getJobById
function has been properly refactored to:
- Accept
userId
in its parameters- Update the type annotation accordingly
- Use
where
clause 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
getLastJob
function has been similarly refactored to useuserId
in 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
emailAccountId
follows 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
emailAccountId
as 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_fromEmail
withemailAccountId
set 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
emailAccountId
matching the user's email.
48-48
: Function call updated to use email parameterThe call to
isAnalyzingReplyTracker
has 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
NeedsReply
component now useuserId
, which is consistent with the refactoring.
107-114
: AwaitingReply props updated to use emailThe props passed to the
AwaitingReply
component now useuserId
, consistent with the refactoring.
120-126
: Resolved component props updated to use emailThe props passed to the
Resolved
component 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
updateKnowledgeAction
has 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
deleteKnowledgeAction
has 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
userId
toAlso 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
userEmail
toapps/web/app/(app)/reply-zero/AwaitingReply.tsx (3)
7-7
: Parameter replacement looks good.The parameter replacement from
userId
toAlso applies to: 12-12
18-18
: Argument update is correct.The argument passed to
getPaginatedThreadTrackers
has 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
ReplyTrackerEmails
has been correctly renamed fromuserEmail
toapps/web/utils/redis/reply-tracker-analyzing.ts (3)
3-5
: Redis key updating looks good.The
getKey
function has been correctly updated to useuserId
for 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.email
instead 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
where
clause correctly reflects the database schema change from using a composite key ofgmailLabelId_userId
togmailLabelId_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: email
instead 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
startAnalyzingReplyTracker
correctly 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
emailAccountId
instead ofuserId
, aligning with the database schema changes.
82-84
: API call updated to use email parameterThe call to
stopAnalyzingReplyTracker
correctly 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_emailAccountId
instead 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
emailAccountId
instead ofuserId
.
218-224
: Helper function call updated to use email parameterThe call to
saveUserLabels
now passes the email parameter correctly.apps/web/utils/ai/assistant/process-user-request.ts (5)
355-358
: Function call updated to use email parameterThe
deleteGroupItem
function now receives the user's email instead of userId, matching the updated function signature.
523-526
: API call updated to use email parameterThe
getUserCategoriesForNames
function call has been updated to use the user's email rather than userId.
528-532
: Function call updated to use email parameterThe
createRule
call now correctly passes the user's email instead of userId.
655-658
: Database query filter updated to use emailAccountIdThe
findSenderByEmail
function call now filters byemailAccountId: userEmail
instead ofuserId
.
671-676
: Function call updated to use email parameterThe
updateCategoryForSender
call 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
emailAccountId
field instead ofuserId
.
147-149
: Database query filter updated to use emailAccountIdThe Prisma query now correctly filters by
emailAccountId: email
instead ofuserId
when finding a rule.
163-186
: Database query filter updated to use emailAccountIdThe rule update operation now correctly filters by
emailAccountId: email
instead ofuserId
.
273-276
: Database query filter updated to use emailAccountIdThe rule lookup operation now correctly filters by
emailAccountId: email
instead 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: email
instead 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_systemType
with the user's email.
356-362
: Permission check updated to use emailAccountIdThe permission check on rule deletion now correctly compares
rule.emailAccountId
with the authenticated user's email.
365-369
: Function call updated to use email parameterThe
deleteRule
call 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
createRule
function's parameters now includeemailAccountId
instead 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
emailAccountId
instead ofuserId
.
572-581
: Helper function updated to use emailAccountIdThe
deleteRule
helper function now takesemailAccountId
instead ofuserId
and uses it in the query.
584-597
: Function calls updated to pass email parameterThe calls to
createRule
anddeleteRule
now 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.rules
toemailAccount.rules
, consistent with moving relations from User to EmailAccount.
100-100
: LGTM: Updated parameter for rule creationChanged from using
userId
toapps/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
userId
to
16-16
: LGTM: Updated database query to use emailAccountIdDatabase query has been updated to filter by
emailAccountId: email
instead ofuserId
, reflecting the schema changes.
29-30
: LGTM: Updated authentication check to use emailAuthentication check now correctly verifies the presence of
session?.user.email
instead ofsession?.user.id
.
35-35
: LGTM: Updated function call with email parameterFunction call to
getGroupItems
now 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.email
instead ofsession?.user.id
.
26-26
: LGTM: Updated rule lookup queryRule lookup now correctly uses
emailAccountId: email
instead ofuserId
for filtering.
35-35
: LGTM: Updated group creation dataGroup creation now correctly sets
emailAccountId: email
instead ofuserId
.
50-51
: LGTM: Updated authentication check in addGroupItemActionAuthentication now correctly checks for the presence of
session?.user.email
instead ofsession?.user.id
.
60-60
: LGTM: Updated permission checkPermission check now correctly compares
group.emailAccountId
to the user's email.
73-74
: LGTM: Updated authentication check in deleteGroupItemActionAuthentication now correctly checks for the presence of
session?.user.email
instead 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
emailAccountId
in the query, aligning with the email-account-centric model.
20-23
: LGTM: Updated getUserCategoriesWithRules functionFunction signature and query have been updated to use
emailAccountId
in the filter.
33-44
: LGTM: Updated getUserCategoriesForNames functionFunction signature and query have been correctly updated to use
emailAccountId
in the filter.apps/web/scripts/migrateRedisPlansToPostgres.ts (1)
100-108
: Double‑check the semantics ofemailAccountId
All subsequent queries now pass
emailAccount.email
intoemailAccountId
.
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
; ifemailAccountId
is still the UUID primary key you must passemailAccount.id
instead.apps/web/app/(app)/automation/onboarding/page.tsx (1)
27-39
: Great use ofPrisma.EmailAccountGetPayload
Casting the selected subset to
UserPreferences
gives 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 👍
runRules
and friends often need both metadata (aiProvider
, ...) and rule list.
Forwarding the wholeemailAccount
keeps signatures compact and future‑proof.
70-75
:✅ Verification successful
Confirm new composite key name
unique_emailAccount_thread_message
now 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
emailAccountId
instead ofuserId
in 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
emailAccount
instead 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.email
instead 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
upsert
is 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
getUserCategories
instead of userId, aligning with the broader refactoring.
47-47
: Consistent parameter naming updateChanged from
userId
touserEmail
in the updateSenderCategory call, maintaining consistency with the email-centric model.
61-68
: Function signature updated to use email-based identificationThe
updateSenderCategory
function now correctly acceptsuserEmail
instead ofuserId
in 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
emailAccountId
using 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_userId
toemail_emailAccountId
to match the schema changes.
95-95
: Create operation updated to use emailAccountIdThe newsletter creation now correctly uses
emailAccountId
instead ofuserId
, aligning with the schema changes.
106-112
: Function signature updated for updateCategoryForSenderThe
updateCategoryForSender
function properly acceptsuserEmail
instead ofuserId
in its parameter list.
117-117
: Updated composite key in Prisma upsert operationThe unique constraint reference is correctly updated to use
email_emailAccountId
in the where clause.
121-121
: Create operation field updated to emailAccountIdThe newsletter creation correctly uses
emailAccountId
instead ofuserId
to associate with the email account.
143-144
: getCategories function updated to use email parameterThe function signature and implementation now correctly use
userId
for retrieving categories.apps/web/utils/rule/rule.ts (12)
30-38
: Function signature updated to use email parameterThe
safeCreateRule
function 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
createRule
now passesuserId
, maintaining consistency with the refactored function signature.
66-66
: Logging statement updated to use emailError logging now uses
userId
for 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: email
to 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: email
instead ofuserId
, matching the schema changes.
168-178
: Refactored updateRule function with improved parameter structureThe function has been refactored to use named parameters with
emailAccountId
instead ofuserId
, providing better clarity and consistency with the schema changes.
183-183
: Database field updated in rule update operationThe update operation now correctly uses
emailAccountId
instead ofuserId
to match the schema changes.
207-214
: deleteRule function updated to use email parameterThe function signature has been updated to accept
userId
for user identification.
217-221
: Delete operations updated to use emailAccountIdThe Prisma delete operations now correctly filter by
emailAccountId: email
instead 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
User
model has been correctly simplified to only maintain essential relations (apiKeys
andemailAccounts
), 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
User
model to theEmailAccount
model, centralizing ownership under email accounts.
205-206
: Label model references updated to EmailAccountThe
Label
model now correctly referencesEmailAccount
via theemailAccountId
field instead of referencingUser
viauserId
.
208-209
: Updated unique constraints for Label modelThe unique constraints have been correctly updated to use
emailAccountId
instead ofuserId
, maintaining data integrity with the new schema.
221-222
: Rule model references updated to EmailAccountThe
Rule
model now correctly usesemailAccountId
and referencesEmailAccount
instead ofUser
, aligning with the architectural changes.
250-251
: Updated unique constraints for Rule modelThe unique constraints have been properly updated to use
emailAccountId
instead ofuserId
, maintaining data integrity with the new schema structure.
288-289
: ExecutedRule model references updated to EmailAccountThe
ExecutedRule
model now correctly referencesEmailAccount
viaemailAccountId
instead ofUser
viauserId
.
293-294
: Updated unique constraints and indexes for ExecutedRuleThe unique constraint and index have been properly updated to use
emailAccountId
instead ofuserId
, maintaining efficient queries and data integrity.
333-334
: Group model references updated to EmailAccountThe
Group
model now correctly referencesEmailAccount
viaemailAccountId
instead ofUser
viauserId
.
337-337
: Updated unique constraint for Group modelThe unique constraint has been properly updated to use
emailAccountId
instead ofuserId
.
358-360
: Category model references updated to EmailAccountThe
Category
model now correctly referencesEmailAccount
viaemailAccountId
instead ofUser
viauserId
.
364-364
: Updated unique constraint for Category modelThe unique constraint has been properly updated to use
emailAccountId
instead ofuserId
, maintaining data integrity.
381-383
: Newsletter model references updated to EmailAccountThe
Newsletter
model now correctly referencesEmailAccount
viaemailAccountId
instead ofUser
viauserId
.
387-388
: Updated unique constraint and index for Newsletter modelThe unique constraint and index have been properly updated to use
emailAccountId
instead ofuserId
, maintaining data integrity and query performance.
401-403
: ColdEmail model references updated to EmailAccountThe
ColdEmail
model now correctly referencesEmailAccount
viaemailAccountId
instead ofUser
.
404-406
: Updated constraints and indexes for ColdEmail modelAll constraints and indexes have been properly updated to use
emailAccountId
instead ofuserId
.
425-427
: EmailMessage model references updated to EmailAccountThe
EmailMessage
model now correctly referencesEmailAccount
viaemailAccountId
instead ofUser
.
428-431
: Updated constraints and indexes for EmailMessage modelAll constraints and indexes have been properly updated to use
emailAccountId
instead ofuserId
, ensuring data integrity and query performance.
444-446
: ThreadTracker model references updated to EmailAccountThe
ThreadTracker
model now correctly referencesEmailAccount
viaemailAccountId
instead ofUser
.
447-450
: Updated constraints and indexes for ThreadTracker modelAll constraints and indexes have been properly updated to use
emailAccountId
instead ofuserId
.
479-481
: CleanupThread model references updated to EmailAccountThe
CleanupThread
model now correctly referencesEmailAccount
viaemailAccountId
instead ofUser
.
490-492
: Knowledge model references updated to EmailAccountThe
Knowledge
model now correctly referencesEmailAccount
viaemailAccountId
instead ofUser
.
493-493
: Updated unique constraint for Knowledge modelThe unique constraint has been properly updated to use
emailAccountId
instead ofuserId
.
511-516
: EmailToken model references updated to EmailAccountThe
EmailToken
model now correctly referencesEmailAccount
viaemailAccountId
instead 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ 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.
apps/web/utils/actions/ai-rule.ts
Outdated
const email = session?.user.email; | ||
if (!email) return { error: "Not logged in" }; | ||
|
||
await prisma.rule.update({ | ||
where: { id: ruleId, userId: session.user.id }, | ||
where: { id: ruleId, emailAccountId: email }, | ||
data: { runOnThreads }, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the primary key when updating rules
If id
is the primary key of Rule
, including emailAccountId
in where
is harmless but unnecessary.
If instead you defined a composite primary key (@@id([id, emailAccountId])
) the correct syntax is:
where: {
id_emailAccountId: { id: ruleId, emailAccountId: email },
}
Current code will throw UNKNOWN_ARGUMENT
at runtime.
const messages = user.account.access_token | ||
? await getMessagesBatch(messageIds, user.account.access_token) | ||
: []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
findNewsletterStatus
now usesemailAccountId
, other parts of this file still referenceuserId
. ThegetNewslettersTinybird
function still acceptsuserId
in its signature, andgetNewsletterCounts
still filters byuserId
in 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
getNewsletter
function still returns an object withuserId
property. Consider updating this to useemailAccountId
for 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
getNewsletter
to useemailAccountId
instead ofuserId
We’ve confirmed the Prisma
Newsletter
model no longer has auserId
field and now requiresemailAccountId
. Please update the test helper accordingly:• File: apps/web/utils/ai/choose-rule/match-rules.test.ts
• Lines: 549–560 (thegetNewsletter
function)Replace:
function getNewsletter(overrides: Partial<Newsletter> = {}): Newsletter { return { id: "newsletter1", createdAt: new Date(), updatedAt: new Date(), userId: "userId", // remove this email: "[email protected]", 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: "[email protected]", emailAccountId: "emailAccount1", // new required field status: null, categoryId: "category1", ...overrides, } as Newsletter; }Also update any tests that relied on
userId
to useemailAccountId
instead.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
trackSentDraftStatus
function signature has also been updated to no longer require theid
property.
🧹 Nitpick comments (4)
apps/web/app/(app)/reply-zero/NeedsAction.tsx (1)
6-18
: Consider removing unuseduserId
parameter.The function signature still includes
userId
as 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
emailAccountId
in 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.email
while lines 82 and 89 useemailToken.emailAccountId
. IfemailToken.emailAccountId
is 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
userId
togetPaginatedThreadTrackers
aligns 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
userEmail
toReplyTrackerEmails
component 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
getUncategorizedSenders
has been correctly changed fromuserId
toemailAccountId
, 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: email
instead 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
loadEmails
has been correctly changed fromuserId
toemailAccountId
, 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
findNewsletterStatus
has been properly updated to use the object parameter format withemailAccountId
property, 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
emailAccountId
instead 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
userId
toemailAccountId
, maintaining consistency with the function signature change.apps/web/utils/ai/choose-rule/match-rules.test.ts (3)
111-111
: AllfindMatchingRule
calls updated correctly.All calls to
findMatchingRule
have been consistently updated to use the new object parameter structure, passingrules
,message
,user
, andgmail
as 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
getCategory
helper function now correctly returnsemailAccountId
instead ofuserId
, maintaining consistency with the database schema changes.
529-529
: Entity model property updated appropriately.The
getGroup
helper function now correctly returnsemailAccountId
instead 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
emailAccountId
instead ofuserId
, both in the parameter name and type definition.
34-35
: Query filter updated consistently.The Prisma query filter has been properly changed from
userId
toemailAccountId
, 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
emailAccountId
instead ofuserId
, both in the parameter name and type definition.
14-15
: Query filter updated consistently.The Prisma query filter has been properly changed from
userId
toemailAccountId
, 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_message
tounique_emailAccount_thread_message
and the filter has been changed fromuserId: user.userId
toemailAccountId: userEmail
, aligning with the database schema changes.
170-172
: Unique constraint updated appropriately.The constraint has been correctly changed from
email_userId
toemail_emailAccountId
with the corresponding filter parameter update.
248-248
: Parameter update for cleanupThreadAIDrafts.The parameter has been appropriately changed from
userId: user.userId
toemail: 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
emailAccount
instead ofuser
.
54-54
: Query filter updated correctly.The filter has been appropriately updated to use
email: emailToken.emailAccountId
which 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
userId
toemailAccountId
to 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
getSenders
function call has been properly updated to passemailAccountId
instead ofuserId
, maintaining consistency with the parameter changes.
30-30
: Updated database query filterThe Prisma query correctly uses
emailAccountId
instead ofuserId
in 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
getGroups
function now correctly accepts an object with anuserId
string, aligning with the broader shift to email account identification.
85-85
: Updated singleton function and query keyThe
getSender
function's parameter structure and Prisma query have been properly updated:
- Function now accepts an object with
userId
string- The query uses the composite key
email_emailAccountId
withemailAccountId
rather than filtering byuserId
This 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
getGroups
function call has been properly updated to useemail: rule.emailAccountId
instead of auserId
parameter, maintaining consistency with the updated function signature.
152-152
: Updated function call to use email-based parameterThe
getSender
function call has been properly updated to useemail: rule.emailAccountId
instead of auserId
parameter, maintaining consistency with the updated function signature.
206-216
: Improved function signature with destructured parametersThe
findMatchingRule
function 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: UserEmailWithAI
instead 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
getRecipientStatistics
function now correctly acceptsemailAccountId
instead ofuserId
in its options parameter, maintaining consistency with the email-centric refactoring.
73-77
: Updated parameter type in helper functionThe
getMostSentTo
function parameter and its type definition have been properly updated to useemailAccountId
instead ofuserId
, aligning with the broader refactoring effort.
80-80
: Updated internal function call parameterThe call to
getEmailFieldStats
now correctly passesemailAccountId
instead 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.email
asemailAccountId
instead ofsession?.user.id
- Check for the presence of
emailAccountId
instead ofuserId
This change aligns with the shift to email-based user identification.
101-101
: Updated function call parameterThe
getRecipientStatistics
function call now correctly passesemailAccountId
instead 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
getSenderStatistics
function now correctly acceptsemailAccountId
instead ofuserId
in its options parameter, maintaining consistency with the email-centric refactoring.
49-53
: Updated parameter type in helper functionThe
getMostReceivedFrom
function parameter and its type definition have been properly updated to useemailAccountId
instead ofuserId
, aligning with the broader refactoring effort.
56-56
: Updated internal function call parameterThe call to
getEmailFieldStats
now correctly passesemailAccountId
instead 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
getDomainsMostReceivedFrom
function parameter and its type definition have been properly updated to useemailAccountId
instead ofuserId
, aligning with the broader refactoring effort.
75-75
: Updated internal function call parameterThe call to
getEmailFieldStats
now correctly passesemailAccountId
instead ofuserId
, maintaining consistency with the helper function's updated signature.
96-96
: Updated function call parameterThe
getSenderStatistics
function call now correctly passesemailAccountId: session.user.email
instead 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
userId
toemailAccountId
in 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
emailAccountId
instead ofuserId
, matching the schema changes in the broader refactor.
43-50
: Parameter update in saveBatch call is consistentThe refactoring from
userId
toemailAccountId
is 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
saveBatch
function signature has been appropriately updated to acceptemailAccountId
instead ofuserId
while maintaining the rest of the function parameters.
142-147
: Error logging field updated correctlyThe error logging field has been updated from
userId
to
150-163
: Data structure field updated correctlyThe field in the saved email data structure has been updated from
userId
toemailAccountId
to 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.email
instead ofuserId: user.id
.
99-111
: saveExecutedRule parameter update is consistentThe parameter to
saveExecutedRule
has been updated correctly to useemailAccountId: user.email
.
133-151
: Function signature and relation update looks goodThe function has been correctly updated to use
emailAccountId
instead 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
upsertExecutedRule
now 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
userId
to
240-250
: Updated findUnique query consistentlyThe unique constraint and field names have been updated consistently in the
findUnique
query.
48-49
:✅ Verification successful
Updated findMatchingRule call pattern
The call to
findMatchingRule
has been updated to use a single object parameter instead of multiple positional parameters. Make sure the implementation offindMatchingRule
has been updated to match this calling pattern.Run this script to verify the
findMatchingRule
function 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:
findMatchingRule
signature matches the updated callVerified in
apps/web/utils/ai/choose-rule/match-rules.ts
thatfindMatchingRule
now accepts a single destructured object parameter{ rules, message, user, gmail }
. No further changes are needed.
204-227
:✅ 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_message
tounique_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_message
constraint is defined inapps/web/prisma/schema.prisma
:
- @@unique([emailAccountId, threadId, messageId], name: "unique_emailAccount_thread_message")
This matches the updated
upsertExecutedRule
usage—no further changes needed.
await executeAct({ | ||
gmail, | ||
userEmail: user.email || "", | ||
userEmail: user.email, | ||
executedRule, | ||
message, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Removed null coalescing operator
The code previously used userEmail: user.email || ""
, but now uses userEmail: user.email
without a fallback. Make sure that user.email
is always defined to avoid potential issues with undefined
or null
values.
Verify that there are proper checks to ensure user.email is defined before this function is called:
🏁 Script executed:
#!/bin/bash
# Look for places where executeAct is called and check if there are any null checks for user.email
rg "executeAct\(" -B 10 -A 2 --glob "*.ts"
Length of output: 2588
Validate user.email
before calling executeAct
The call in apps/web/utils/ai/choose-rule/run-rules.ts
(around lines 116–121) now passes user.email
directly, but there’s no guarantee it’s defined. To prevent runtime errors when it’s undefined
or null
, add a guard or fallback:
• File: apps/web/utils/ai/choose-rule/run-rules.ts (lines 116–121)
- Before invoking
executeAct
, verifyuser.email
is present. - Example using a fallback:
if (shouldExecute) { - await executeAct({ gmail, userEmail: user.email, executedRule, message }); + const email = user.email ?? ""; + await executeAct({ gmail, userEmail: email, executedRule, message }); }
- Or return/throw early on missing email:
if (!user.email) { throw new Error("User email is required to execute actions"); } await executeAct({ gmail, userEmail: user.email, executedRule, message });
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 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
userId
replaced 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
userId
references in cold‑email code and testsThe Prisma schema is correctly using
emailAccountId
, but there are stilluserId
references that need updating:• apps/web/utils/cold-email/is-cold-email.test.ts
– ReplaceuserId
anduserId_fromEmail
in your mock fixtures and expectations withemailAccountId
/emailAccountId_fromEmail
.
• apps/web/utils/actions/cold-email.ts
– Update theuserId: true
selection and anywhere: { userId_… }
clauses to useemailAccountId
instead.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
getExamples
function now usesemailAccountId
for authentication checks, theGET
handler 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
emailAccountId
might 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.email
is 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.email
can 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
userId
toemailAccountId
in 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
emailAccountId
instead ofuserId
, maintaining consistency with the schema changes that moved relations fromUser
toEmailAccount
.
40-41
: Error logging updated to use emailAccountId.The error logging context now correctly includes
emailAccountId
instead 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
emailAccountId
instead of directly usingsession?.user.email
is 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
emailAccountId
instead 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
userId
toemailAccountId
to 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
emailAccountId
instead ofuserId
, consistent with the database schema changes.
31-31
: Updated function call with emailAccountIdThe function call has been correctly updated to pass
emailAccountId
instead ofuserId
.
28-29
:✅ Verification successful
Verify email extraction logic
The code now uses
session?.user.email
as 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.email
as the primary key, and every API route consistently derivesemailAccountId
fromsession.user.email
. This aligns with all existing usages and requires no updates.apps/web/app/api/knowledge/route.ts (1)
17-18
:✅ Verification successful
Database query filter updated correctly.
The query filter change from
userId
toemailAccountId
correctly 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
emailAccountId
filterThe Prisma schema for the
Knowledge
model includes theemailAccountId
field 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
userId
toemailAccountId
is properly implemented, and the inlineorderBy
is a neat styling improvement.apps/web/app/api/user/labels/route.ts (3)
8-10
: LGTM: Consistent migration to email-based identificationThe change from
userId
toemailAccountId
for 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
getLabels
function is now correctly called with theemailAccountId
parameter, completing the migration from user ID to email account ID.apps/web/utils/ai/reply/check-if-needs-reply.ts (1)
73-73
:✅ Verification successful
Verify that user.email is always defined
The fallback to an empty string for
userEmail
has been removed, which aligns with the email-account-centric model. However, this assumesuser.email
is always defined.Let's verify that the
UserEmailWithAI
type 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
EmailAccount
model inschema.prisma
declaresemail String @id
(required), and the generated TypeScriptEmailAccount
type reflects thatemail: string
(non‑nullable). SinceUserEmailWithAI
picks this field,user.email
is always defined—no fallback is needed.apps/web/utils/ai/rule/generate-prompt-on-update-rule.ts (1)
65-65
:✅ Verification successful
Consistent with email-account-centric model
The removal of the fallback to an empty string for
userEmail
is consistent with the PR's objective of moving to an email-account-centric model.Let's verify that the
chatCompletionObject
function 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:
userEmail
is required by type, so no undefined fallback is neededType
ChatCompletionObjectArgs
definesuserEmail: string
as mandatory, and thechatCompletionObjectInternal
function 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
:❓ Verification inconclusive
Empty string fallback removed for userEmail parameter
The change removes the previous fallback that would have converted
undefined
ornull
email 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.email
is guaranteed to be defined throughout the authentication flow to prevent passing undefined values to thechatCompletionObject
function.
🏁 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.ts
so thatuserEmail: user.email
is passed directly. However, other parts of the codebase still guard againstnull
/undefined
emails (e.g.find-snippets.ts
,rule-fix.ts
,EmailList.tsx
,Pending.tsx
), which suggestssession.data?.user.email
may 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
:❓ Verification inconclusive
Empty string fallback removed for userEmail parameter
The fallback to empty string for the
userEmail
parameter has been removed, consistent with the PR's shift to an email-account-centric model. Nowuser.email
is passed directly to thechatCompletionObject
function.Ensure that any potential
null
orundefined
email values are handled appropriately in the authentication flow or in thechatCompletionObject
implementation 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.email
before AI callsThe empty‐string fallback was removed for the
userEmail
parameter across allchatCompletionObject
invocations so thatuser.email
is passed directly.• The
UserEmailWithAI
type picks"email"
fromEmailAccount
, but we haven’t confirmed whetherEmailAccount.email
is always non‑nullable in your Prisma schema.
• Ensure that your authentication flow guaranteesuser.email
is neithernull
norundefined
before any AI function is called.
• Alternatively, validate or coerceuser.email
at 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
:✅ Verification successful
Empty string fallback removed for userEmail parameter
The code no longer uses a fallback empty string for
userEmail
, now passinguser.email
directly. This is part of the larger refactoring to use email instead of user ID as the primary identifier.To ensure stability, verify that
UserEmailWithAI
type 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
strictNullChecks
in yourtsconfig.json
. This setting enforces explicit handling ofnull
andundefined
, 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
undefined
ornull
as 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';null
orundefined
trigger 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) { /* ... */ }null
andundefined
[2][6].
Type Guards and Narrowing
- Use
if
orswitch
statements 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
undefined
and/ornull
in 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: Non nullable properties are generated as possibly undefined 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 foruserEmail
is safe:- The
UserEmailWithAI
type 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.email
is always a valid string. No further fallback is needed.apps/web/utils/ai/rule/generate-prompt-on-delete-rule.ts (1)
60-60
:✅ Verification successful
Potential edge case with undefined email.
The change removes a fallback empty string for
userEmail
parameter, which aligns with the PR's objective of moving to an email-account-centric model. However, ensure that thechatCompletionObject
function properly handles cases whereuser.email
could 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
chatCompletionObject
is 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.email
can actually be undefined by inspecting theUserEmailWithAI
type:
🏁 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
UserEmailWithAI
and 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.email
Is Always DefinedThe Prisma model defines
EmailAccount.email
as a non-nullableString @id
, andUserEmailWithAI.email
is typed asstring
. SinceChatCompletionObjectArgs.userEmail
also requires astring
,user.email
can never beundefined
ornull
. 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
emailAccountId
instead ofuserId
.
9-10
:❓ Verification inconclusive
Verify that email is properly validated before using as ID
The code now uses
session?.user.email
as theemailAccountId
instead 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.email
as 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
emailAccountId
instead 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
emailAccountId
instead 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
emailAccountId
instead ofuserId
.
16-25
: Database query updated correctlyThe Prisma query has been properly updated to filter by
emailAccountId
instead 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
getGroupRules
has been updated to passemailAccountId
instead ofuserId
.apps/web/utils/cold-email/is-cold-email.ts (5)
23-48
: Email parameter usage consistent with refactoringThe
isColdEmail
function's usage ofuser.email
is consistent with the refactoring approach. The reference toemailAccountId
on line 47 has been updated correctly.
87-105
: Update to composite key field namesThe function
isKnownColdEmailSender
has been correctly updated to useemailAccountId
instead ofuserId
, and the composite key has been changed fromuserId_fromEmail
toemailAccountId_fromEmail
.
138-149
: Direct use of email without fallbackThe
chatCompletionObject
call now directly usesuser.email
without 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
upsert
operation has been properly updated to useemailAccountId_fromEmail
as the composite key anduser.email
as theemailAccountId
value.
204-204
: Logging updated to use emailAccountIdThe error logging has been updated to use
emailAccountId
instead ofuserId
, which is consistent with the refactoring approach.
@@ -105,7 +105,7 @@ Remember, precision is crucial - only include matches you are absolutely sure ab | |||
parameters: findExampleMatchesSchema, | |||
}, | |||
}, | |||
userEmail: user.email || "", | |||
userEmail: user.email, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Empty string fallback removed for userEmail parameter
The fallback to empty string (user.email || ""
) has been removed, now directly passing user.email
to the chatCompletionTools
function. This is consistent with the PR's objective to refactor toward an email-account-centric model.
Make sure that all authentication flows properly validate the presence of user.email
before reaching this code to avoid potential issues with undefined values being passed to the AI service.
🏁 Script executed:
#!/bin/bash
# Check if the chatCompletionTools function has null-safety for userEmail parameter
# Look at the implementation of chatCompletionTools
echo "Checking how chatCompletionTools handles null/undefined userEmail:"
rg -A 5 -B 5 "export (const|function) chatCompletionTools" --type ts apps/web/utils/
Length of output: 229
🏁 Script executed:
#!/bin/bash
# Search entire repository for the definition of chatCompletionTools
rg -n "chatCompletionTools" -C 3 --type ts .
Length of output: 10616
🏁 Script executed:
#!/bin/bash
# Extract the implementation of chatCompletionTools and its internal function
echo "=== chatCompletionTools & chatCompletionToolsInternal implementation ==="
sed -n '200,260p' apps/web/utils/llms/index.ts
# Locate the ChatCompletionToolsArgs type definition
echo "=== ChatCompletionToolsArgs type definition ==="
rg -n "ChatCompletionToolsArgs" -A5 -B5 --type ts apps/web/utils/llms
Length of output: 3243
Missing userEmail
fallback in chatCompletionTools
The user.email || ""
fallback was removed, and user.email
is now passed directly to chatCompletionTools
. Since chatCompletionToolsInternal
uses userEmail
when saving usage and handling errors, an undefined value will propagate and may cause unexpected failures.
• File: apps/web/utils/ai/example-matches/find-example-matches.ts
line 108 – now passes user.email
without a default.
• Action: Ensure every auth flow asserts user.email
is non-null before this call, or reinstate a fallback (e.g. user.email ?? ""
).
• Consider tightening the ChatCompletionToolsArgs
type to require a non-optional userEmail
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 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
accountId
alongside 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
userId
for identification. Consider updating this to useemailAccountId
for 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 useemailAccountId
for 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
id
field 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
NextRequest
import and keeping onlyNextResponse
.
9-9
: Addition of helper importThe new
getEmailAccountId
helper import aligns with the broader refactoring to an email-account-centric model.
12-13
: Updated destructuring to include accountIdGood update to extract the
accountId
from thevalidateApiKeyAndGetGmailClient
result, 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
emailAccountId
instead of the previoususerId
parameter 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
NextRequest
import and keeping onlyNextResponse
.
13-13
: Addition of helper importThe new
getEmailAccountId
helper import aligns with the broader refactoring to an email-account-centric model.
18-19
: Updated destructuring to include accountIdGood update to extract the
accountId
from thevalidateApiKeyAndGetGmailClient
result, 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: emailAccountId
in the call togetPaginatedThreadTrackers
, replacing the previous userId-based approach.
import prisma from "@/utils/prisma"; | ||
|
||
/** | ||
* Gets the email account ID from the provided email or looks it up using the account ID | ||
* @param email Optional email address | ||
* @param accountId Account ID to look up the email if not provided | ||
* @returns The email account ID or undefined if not found | ||
*/ | ||
export async function getEmailAccountId({ | ||
email, | ||
accountId, | ||
userId, | ||
}: { | ||
email?: string; | ||
accountId?: string; | ||
userId: string; | ||
}): Promise<string | undefined> { | ||
if (email) { | ||
// check user owns email account | ||
const emailAccount = await prisma.emailAccount.findUnique({ | ||
where: { email, userId }, | ||
select: { email: true }, | ||
}); | ||
|
||
return emailAccount?.email; | ||
} | ||
|
||
if (!accountId) return undefined; | ||
|
||
const emailAccount = await prisma.emailAccount.findFirst({ | ||
where: { accountId }, | ||
select: { email: true }, | ||
}); | ||
|
||
return emailAccount?.email; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Well-implemented helper function for email account ID resolution
This new helper function getEmailAccountId
correctly implements the logic to resolve an email account ID from either an email address or an account ID, scoped by user ID. This supports the refactoring from user-centric to email-account-centric model.
However, when looking up by accountId, there's no check that the account belongs to the given userId (unlike the email lookup). This could potentially allow a user to access email accounts they don't own if they know the accountId.
Consider adding the userId check to the accountId lookup:
const emailAccount = await prisma.emailAccount.findFirst({
- where: { accountId },
+ where: { accountId, userId },
select: { email: true },
});
📝 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.
import prisma from "@/utils/prisma"; | |
/** | |
* Gets the email account ID from the provided email or looks it up using the account ID | |
* @param email Optional email address | |
* @param accountId Account ID to look up the email if not provided | |
* @returns The email account ID or undefined if not found | |
*/ | |
export async function getEmailAccountId({ | |
email, | |
accountId, | |
userId, | |
}: { | |
email?: string; | |
accountId?: string; | |
userId: string; | |
}): Promise<string | undefined> { | |
if (email) { | |
// check user owns email account | |
const emailAccount = await prisma.emailAccount.findUnique({ | |
where: { email, userId }, | |
select: { email: true }, | |
}); | |
return emailAccount?.email; | |
} | |
if (!accountId) return undefined; | |
const emailAccount = await prisma.emailAccount.findFirst({ | |
where: { accountId }, | |
select: { email: true }, | |
}); | |
return emailAccount?.email; | |
} | |
import prisma from "@/utils/prisma"; | |
/** | |
* Gets the email account ID from the provided email or looks it up using the account ID | |
* @param email Optional email address | |
* @param accountId Account ID to look up the email if not provided | |
* @param userId ID of the user (to scope lookups) | |
* @returns The email account ID or undefined if not found | |
*/ | |
export async function getEmailAccountId({ | |
email, | |
accountId, | |
userId, | |
}: { | |
email?: string; | |
accountId?: string; | |
userId: string; | |
}): Promise<string | undefined> { | |
if (email) { | |
// check user owns email account | |
const emailAccount = await prisma.emailAccount.findUnique({ | |
where: { email, userId }, | |
select: { email: true }, | |
}); | |
return emailAccount?.email; | |
} | |
if (!accountId) return undefined; | |
const emailAccount = await prisma.emailAccount.findFirst({ | |
where: { accountId, userId }, | |
select: { email: true }, | |
}); | |
return emailAccount?.email; | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/web/app/api/user/accounts/route.ts (1)
7-7
: Unused logger variable.The
logger
is 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: false
is a good choice to avoid unnecessary refetches when the user returns to the tab.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 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 accessiblealt
description 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?: string
and 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
useAction
hooks bound with user email for consistent state and error management.Bug Fixes
Documentation
Chores