Skip to content

Implement complete authentication system with role-based access control#1

Merged
agabaarnold merged 47 commits into
mainfrom
feat/auth
Jun 11, 2026
Merged

Implement complete authentication system with role-based access control#1
agabaarnold merged 47 commits into
mainfrom
feat/auth

Conversation

@agabaarnold

Copy link
Copy Markdown
Owner

This PR introduces a comprehensive authentication and authorization system
built with Better Auth, covering the full auth lifecycle from sign-up to
password recovery, alongside role-based access control.

Features

  • Authentication forms: SignIn, SignUp, ForgotPassword, ResetPassword
    components with validation and error handling
  • Email infrastructure: password reset and email verification templates
    with a shared email layout
  • Auth routes: dedicated route group with session validation and
    redirect support
  • Access control: admin, manager, and staff role definitions with
    route guards
  • Form system: reusable form components (FormInput, FormPassword,
    FormCheckbox, SubmitButton, PasswordInput)
  • Validation schemas: Zod schemas for login, registration, password
    reset, and forgot-password flows
  • User session: getUserSession utility and <AppLayout> with
    Outlet-based nested routing
  • Error handling: DefaultErrorBoundary and DefaultNotFound pages
  • Database: Prisma schema updates adding createdBy relation on
    StockTransfer and User model adjustments
  • SMTP configuration: environment variables and sendAuthEmail
    utility for transactional emails

Fixes

  • Corrected typos in forgotPasswordSchema import/declaration
  • Fixed function declaration syntax in ForgotPasswordForm
  • Fixed capitalization in password reset email subject
  • Enhanced redirect validation to disallow backslashes
  • Added error handling for social sign-in and sign-up
  • Removed stray console.log and fixed gradient class syntax
  • Improved onCheckedChange handler clarity

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@agabaarnold, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 47 minutes and 48 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c0d7bf37-76fd-4cfd-bd5c-c0aa341ab615

📥 Commits

Reviewing files that changed from the base of the PR and between 87a02e5 and 9e2749e.

📒 Files selected for processing (2)
  • prisma/schema.prisma
  • src/components/shared/default-error-boundary.tsx
📝 Walkthrough

Walkthrough

Adds full auth stack: Prisma models and env schema, reusable form and shared UI components, Zod validation, sign-in/sign-up/forgot/reset UIs and handlers, email templates and SMTP sender, and a session API endpoint.

Changes

Authentication System Implementation

Layer / File(s) Summary
Database schema, env, and manifest
prisma/schema.prisma, src/env/server.ts, package.json, biome.jsonc
Prisma schema adds auth, inventory, order, procurement, and audit models; server env schema requires BETTER_AUTH and SMTP vars; @types/nodemailer added and lucide-react removed; biome.jsonc trailing comma fixed.
Form primitives and shared UI
src/components/form/form-input.tsx, src/components/form/form-password.tsx, src/components/form/form-checkbox.tsx, src/components/form/submit-button.tsx, src/components/shared/password-input.tsx, src/components/shared/default-error-boundary.tsx, src/components/shared/default-not-found.tsx
New form components bind to field context with accessibility and validation handling; PasswordInput toggles visibility; SubmitButton observes form state; shared error/404 UI components added.
Authentication Validation Schemas
src/features/auth/schema/index.ts
Zod schemas for password strength, login, registration, forgot-password, and reset-password with confirm equality refinement.
Sign-In UI and handlers
src/features/auth/components/sign-in-form.tsx
SignInForm implements email/password and social sign-in flows, shows toasts, and redirects on success; displays "Last used" provider badges.
Sign-Up UI and handlers
src/features/auth/components/sign-up-form.tsx
SignUpForm implements registration with validation, email and social sign-up handlers, and success navigation.
Forgot & Reset password flows
src/features/auth/components/forgot-password-form.tsx, src/features/auth/components/reset-password-form.tsx
ForgotPasswordForm requests password reset; ResetPasswordForm validates token and completes reset with guard for missing/invalid tokens and toast feedback.
Session API
src/features/auth/functions/index.ts
getUserSession GET handler returns current session by proxying request headers to auth.api.getSession.
Email templates and SMTP sender
src/features/email/components/*.tsx, src/features/email/functions/index.tsx
EmailLayout plus verification and password-reset templates; sendAuthEmail renders templates and sends SMTP emails using transporter configured from serverEnv.

Sequence Diagrams

sequenceDiagram
  participant User
  participant SignInForm as Sign-In Form
  participant AuthClient as authClient
  participant Toast as Toast Notifications
  participant Router as Router Navigation

  User->>SignInForm: submit credentials or click social
  SignInForm->>AuthClient: signIn.email / signIn.social
  alt success
    AuthClient-->>SignInForm: success
    SignInForm->>Toast: show success
    SignInForm->>Router: navigate to redirect or /
  else error
    AuthClient-->>SignInForm: error
    SignInForm->>Toast: show error
  end
Loading
sequenceDiagram
  participant User
  participant ForgotForm as Forgot Password Form
  participant AuthClient as authClient
  participant Email as sendAuthEmail
  participant ResetForm as Reset Password Form
  participant Router as Router

  User->>ForgotForm: submit email
  ForgotForm->>AuthClient: requestPasswordReset
  AuthClient->>Email: send password-reset email
  User->>ResetForm: open link with token
  ResetForm->>AuthClient: resetPassword(token, newPassword)
  alt valid token
    AuthClient-->>ResetForm: success
    ResetForm->>Router: navigate to /
  else invalid token
    ResetForm-->>User: show invalid reset link
  end
Loading
sequenceDiagram
  participant App as Application
  participant EmailSender as sendAuthEmail
  participant Template as React Email Template
  participant Nodemailer as Nodemailer
  participant SMTP as SMTP Server

  App->>EmailSender: send auth email payload
  EmailSender->>Template: render HTML
  Template-->>EmailSender: HTML + plain text
  EmailSender->>Nodemailer: send(mail options)
  Nodemailer->>SMTP: deliver message
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly Related PRs

Poem

🐰 I nibble code under moonlit beams,

Forms and schemas stitched from dreams,
SMTP wings send verification cheer,
Password resets hop safely near,
Hooray — the auth garden blossoms here!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the primary objective of the changeset: implementing a complete authentication system with role-based access control, which is the central focus across all modified and added files.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering authentication forms, email infrastructure, validation schemas, database updates, and access control features that align with the actual changes made.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/auth

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown

React Doctor found 5 issues in 5 files · 1 error & 4 warnings · score 73 / 100 (Needs work) · vs main

Errors

4 warnings

src/features/auth/components/forgot-password-form.tsx

  • ⚠️ L56 preventDefault on a form or link no-prevent-default

src/features/auth/components/reset-password-form.tsx

  • ⚠️ L76 preventDefault on a form or link no-prevent-default

src/features/auth/components/sign-in-form.tsx

  • ⚠️ L93 preventDefault on a form or link no-prevent-default

src/features/auth/components/sign-up-form.tsx

  • ⚠️ L89 preventDefault on a form or link no-prevent-default

Reviewed by React Doctor for commit 9e2749e. See inline comments for fixes.

@socket-security

socket-security Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​types/​nodemailer@​8.0.11001007694100

View full report

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@prisma/schema.prisma`:
- Line 181: The required createdBy relations (createdById / createdBy) in the
StockMovement, StockTransfer, Order and PurchaseOrder models conflict with hard
user deletion (user.deleteUser.enabled: true); either disable hard-delete in the
auth config or make these relations nullable with an explicit onDelete action.
Fix by choosing one policy: A) disable hard delete by setting deleteUser.enabled
to false in the auth config, or B) make the Prisma relations nullable and add
onDelete: SetNull — change createdById to optional (String?) and the createdBy
relation to optional with `@relation`(fields: [createdById], references: [id],
onDelete: SetNull) for the StockMovement, StockTransfer, Order and PurchaseOrder
models, then run a migration to apply the schema change.

In `@src/env/server.ts`:
- Line 7: The NODE_ENV enum in the server environment schema rejects the "test"
value which breaks CI/test imports; update the z.enum for NODE_ENV (the schema
field named NODE_ENV in your server env schema) to include "test" alongside
"development" and "production" so NODE_ENV="test" is accepted (keep the default
as appropriate), then run/type-check to ensure imports that read this schema
(e.g., serverEnv) accept test environments.

In `@src/features/auth/components/forgot-password-form.tsx`:
- Line 40: The validators binding in the ForgotPasswordForm component uses the
misspelled identifier forgotPasswordShema; update the validators property
(validators: { onSubmit: ... }) to reference the correctly imported symbol
forgotPasswordSchema so the onSubmit validation uses the proper schema, ensuring
the import at the top (forgotPasswordSchema) and the validators assignment
match.

In `@src/features/auth/schema/index.ts`:
- Around line 16-23: The password schema currently uses .regex(...) to require a
special character and .refine(...) only to ban leading/trailing spaces, allowing
internal whitespace; replace the .refine(...) call with a regex that rejects any
whitespace in the entire value (e.g. use .regex(/^\S+$/u, "Password must not
contain whitespace")) and keep/update the special-character check (the existing
.regex(/[^A-Za-z0-9]/u, "Password must contain at least one special character")
can remain or be tightened to a Unicode-aware class like /[^\p{L}\p{N}]/u), so
update the .refine usage to .regex(/^\S+$/u, "Password must not contain
whitespace") in the same password schema chain.

In `@src/features/email/functions/index.tsx`:
- Around line 37-87: sendAuthEmail currently embeds payload.url directly into
rendered EmailVerificationEmail and PasswordResetEmail HTML/text; validate that
payload.url is a well-formed HTTPS URL and that its hostname matches the
expected host(s) before rendering/sending. Inside sendAuthEmail, parse
payload.url (e.g., new URL(payload.url)), check url.protocol === "https:" and
allowedHosts.includes(url.hostname); if validation fails, log and throw or
return an error instead of calling transporter.sendMail and avoid passing the
raw URL into PasswordResetEmail or EmailVerificationEmail. Also ensure both
branches (password-reset and verification) perform this same validation before
calling render or transporter.sendMail.
- Around line 23-31: The Nodemailer transporter created by createTransport
(variable transporter) lacks explicit SMTP timeouts causing potential request
hangs; update the createTransport options used in
src/features/email/functions/index.tsx to include connectionTimeout,
greetingTimeout, and socketTimeout (e.g., set to sensible millisecond values
like 10_000) so slow/broken SMTP handshakes fail fast instead of hanging the
request.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9aee0766-26d1-41d5-a92f-b5a3a14ab7d5

📥 Commits

Reviewing files that changed from the base of the PR and between 44f67e0 and 35e1485.

⛔ Files ignored due to path filters (26)
  • bun.lock is excluded by !**/*.lock
  • src/generated/prisma/browser.ts is excluded by !**/generated/**
  • src/generated/prisma/client.ts is excluded by !**/generated/**
  • src/generated/prisma/commonInputTypes.ts is excluded by !**/generated/**
  • src/generated/prisma/enums.ts is excluded by !**/generated/**
  • src/generated/prisma/internal/class.ts is excluded by !**/generated/**
  • src/generated/prisma/internal/prismaNamespace.ts is excluded by !**/generated/**
  • src/generated/prisma/internal/prismaNamespaceBrowser.ts is excluded by !**/generated/**
  • src/generated/prisma/models.ts is excluded by !**/generated/**
  • src/generated/prisma/models/Account.ts is excluded by !**/generated/**
  • src/generated/prisma/models/AuditLog.ts is excluded by !**/generated/**
  • src/generated/prisma/models/Category.ts is excluded by !**/generated/**
  • src/generated/prisma/models/InventoryItem.ts is excluded by !**/generated/**
  • src/generated/prisma/models/Order.ts is excluded by !**/generated/**
  • src/generated/prisma/models/OrderItem.ts is excluded by !**/generated/**
  • src/generated/prisma/models/Product.ts is excluded by !**/generated/**
  • src/generated/prisma/models/PurchaseOrder.ts is excluded by !**/generated/**
  • src/generated/prisma/models/PurchaseOrderItem.ts is excluded by !**/generated/**
  • src/generated/prisma/models/Session.ts is excluded by !**/generated/**
  • src/generated/prisma/models/StockMovement.ts is excluded by !**/generated/**
  • src/generated/prisma/models/StockTransfer.ts is excluded by !**/generated/**
  • src/generated/prisma/models/StockTransferItem.ts is excluded by !**/generated/**
  • src/generated/prisma/models/Supplier.ts is excluded by !**/generated/**
  • src/generated/prisma/models/User.ts is excluded by !**/generated/**
  • src/generated/prisma/models/Verification.ts is excluded by !**/generated/**
  • src/generated/prisma/models/Warehouse.ts is excluded by !**/generated/**
📒 Files selected for processing (36)
  • biome.jsonc
  • package.json
  • prisma/schema.prisma
  • src/components/form/form-checkbox.tsx
  • src/components/form/form-input.tsx
  • src/components/form/form-password.tsx
  • src/components/form/submit-button.tsx
  • src/components/shared/default-error-boundary.tsx
  • src/components/shared/default-not-found.tsx
  • src/components/shared/password-input.tsx
  • src/env/server.ts
  • src/features/auth/components/forgot-password-form.tsx
  • src/features/auth/components/reset-password-form.tsx
  • src/features/auth/components/sign-in-form.tsx
  • src/features/auth/components/sign-up-form.tsx
  • src/features/auth/functions/index.ts
  • src/features/auth/schema/index.ts
  • src/features/email/components/email-layout.tsx
  • src/features/email/components/email-verification-email.tsx
  • src/features/email/components/password-reset-email.tsx
  • src/features/email/functions/index.tsx
  • src/hooks/use-form-context.ts
  • src/hooks/use-form.ts
  • src/lib/auth-client.ts
  • src/lib/auth.ts
  • src/lib/permissions.ts
  • src/routeTree.gen.ts
  • src/router.tsx
  • src/routes/_app/index.tsx
  • src/routes/_app/route.tsx
  • src/routes/_auth/forgot-password.tsx
  • src/routes/_auth/reset-password.tsx
  • src/routes/_auth/route.tsx
  • src/routes/_auth/sign-in.tsx
  • src/routes/_auth/sign-up.tsx
  • src/routes/index.tsx
📜 Review details
🔇 Additional comments (17)
src/features/email/components/email-layout.tsx (1)

1-64: LGTM!

src/features/email/components/email-verification-email.tsx (1)

1-58: LGTM!

src/features/email/components/password-reset-email.tsx (1)

1-58: LGTM!

biome.jsonc (1)

8-9: LGTM!

package.json (1)

54-54: LGTM!

src/features/auth/functions/index.ts (1)

1-12: LGTM!

src/features/auth/components/sign-in-form.tsx (1)

23-174: LGTM!

src/features/auth/components/sign-up-form.tsx (1)

22-161: LGTM!

src/features/auth/components/reset-password-form.tsx (1)

17-109: LGTM!

src/components/form/form-checkbox.tsx (1)

9-23: LGTM!

src/components/form/form-input.tsx (1)

12-36: LGTM!

src/components/form/form-password.tsx (1)

12-48: LGTM!

src/components/form/submit-button.tsx (1)

11-39: LGTM!

src/components/shared/password-input.tsx (1)

12-37: LGTM!

src/components/shared/default-error-boundary.tsx (1)

12-135: LGTM!

src/components/shared/default-not-found.tsx (1)

5-64: LGTM!

src/features/auth/schema/index.ts (1)

25-58: LGTM!

Comment thread prisma/schema.prisma
Comment thread src/env/server.ts
Comment thread src/features/auth/components/forgot-password-form.tsx Outdated
Comment thread src/features/auth/schema/index.ts Outdated
Comment thread src/features/email/functions/index.tsx
Comment thread src/features/email/functions/index.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/features/email/functions/index.tsx (1)

40-90: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add error handling and logging to prevent silent email failures.

sendAuthEmail has no try-catch around render() or transporter.sendMail(), so failures (network issues, SMTP auth errors, template rendering errors) silently propagate. Because callers use void sendAuthEmail(...) (fire-and-forget), errors are swallowed and users attempting password resets or email verification receive no feedback. At minimum, wrap the function body in try-catch and log failures for observability.

🛡️ Suggested error handling with logging
 export async function sendAuthEmail(payload: AuthEmailPayload) {
+    try {
         const from = getFromAddress();
 
         if (payload.kind === "password-reset") {
             const html = await render(
                 <PasswordResetEmail
                     expiresInMinutes={payload.expiresInMinutes ?? 30}
                     name={payload.name ?? undefined}
                     resetUrl={payload.url}
                 />
             );
 
             await transporter.sendMail({
                 from,
                 html,
                 subject: "InvenEase password reset",
                 text: [
                     `Hi ${payload.name ?? "there"},`,
                     "",
                     `Reset your password here: ${payload.url}`,
                     "",
                     `This link expires in ${payload.expiresInMinutes ?? 30} minutes.`,
                 ].join("\n"),
                 to: payload.to,
             });
 
             return;
         }
 
         const html = await render(
             <EmailVerificationEmail
                 expiresInMinutes={payload.expiresInMinutes ?? 60}
                 name={payload.name ?? undefined}
                 verificationUrl={payload.url}
             />
         );
 
         await transporter.sendMail({
             from,
             html,
             subject: "InvenEase email verification",
             text: [
                 `Hi ${payload.name ?? "there"},`,
                 "",
                 `Verify your email here: ${payload.url}`,
                 "",
                 `This link expires in ${payload.expiresInMinutes ?? 60} minutes.`,
             ].join("\n"),
             to: payload.to,
         });
+    } catch (error) {
+        console.error("Failed to send auth email:", {
+            kind: payload.kind,
+            to: payload.to,
+            error: error instanceof Error ? error.message : String(error),
+        });
+        // Consider: send to error monitoring service, store in DB for retry
+    }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/email/functions/index.tsx` around lines 40 - 90, Wrap the entire
body of sendAuthEmail in a try-catch: catch any errors thrown by render(...) or
transporter.sendMail(...) and call your application logger (or processLogger) to
record a clear error including the email payload.kind, payload.to, and the error
stack/message; ensure the function does not rethrow so fire-and-forget callers
aren’t disrupted, but returns after logging (or returns a rejected Promise if
your call sites expect it), and keep references to render and
transporter.sendMail to locate where to add the try-catch.
src/components/shared/default-error-boundary.tsx (1)

115-121: ⚠️ Potential issue | 🟡 Minor

Make “Reload page” trigger a real document reload
router.navigate({ to: "." }) is client-side navigation (doesn’t force a browser-level reload), so the button label and the “reset after crash” intent don’t match—force reload via reloadDocument: true.

Suggested change
                     <Button
-                        onClick={() => router.navigate({ to: "." })}
+                        onClick={() => router.navigate({ to: ".", reloadDocument: true })}
                         size="sm"
                         variant="outline"
                     >
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/shared/default-error-boundary.tsx` around lines 115 - 121, The
"Reload page" Button currently calls router.navigate({ to: "." }) which performs
client-side navigation; change the call in the Button's onClick handler to
invoke router.navigate with reloadDocument: true (e.g., router.navigate({ to:
".", reloadDocument: true })) so the action triggers a full browser/document
reload and matches the "reset after crash" intent; update the onClick where
Button is defined to use this option.
♻️ Duplicate comments (1)
src/features/email/functions/index.tsx (1)

40-90: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate payload.url before embedding in email content.

As flagged in the previous review, payload.url is embedded directly into email templates without validation. Although Better Auth generates these URLs, validating the protocol and origin provides defense-in-depth against potential library vulnerabilities or configuration errors.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/email/functions/index.tsx` around lines 40 - 90, The
sendAuthEmail function embeds payload.url into email bodies without validation;
validate payload.url before rendering/sending. In sendAuthEmail, before calling
render(...) or transporter.sendMail(...), parse and validate payload.url (e.g.,
with URL constructor) to ensure it is a well-formed absolute URL with an allowed
protocol (https) and, if applicable, an allowed origin/hostname; if validation
fails, throw or return an error to avoid embedding unsafe values. Apply this
check for both branches (PasswordResetEmail and EmailVerificationEmail)
referencing payload.url, render, and transporter.sendMail so no unvalidated URL
reaches the templates.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@prisma/schema.prisma`:
- Line 138: Remove the redundant table-level index declaration @@index([sku]) in
the Product model because sku is already marked `@unique`; open the Product model
in schema.prisma, locate the duplicate @@index([sku]) entry and delete that
line, leaving the existing sku `@unique` declaration intact so Prisma/Postgres
only creates the single backing unique index.

---

Outside diff comments:
In `@src/components/shared/default-error-boundary.tsx`:
- Around line 115-121: The "Reload page" Button currently calls
router.navigate({ to: "." }) which performs client-side navigation; change the
call in the Button's onClick handler to invoke router.navigate with
reloadDocument: true (e.g., router.navigate({ to: ".", reloadDocument: true }))
so the action triggers a full browser/document reload and matches the "reset
after crash" intent; update the onClick where Button is defined to use this
option.

In `@src/features/email/functions/index.tsx`:
- Around line 40-90: Wrap the entire body of sendAuthEmail in a try-catch: catch
any errors thrown by render(...) or transporter.sendMail(...) and call your
application logger (or processLogger) to record a clear error including the
email payload.kind, payload.to, and the error stack/message; ensure the function
does not rethrow so fire-and-forget callers aren’t disrupted, but returns after
logging (or returns a rejected Promise if your call sites expect it), and keep
references to render and transporter.sendMail to locate where to add the
try-catch.

---

Duplicate comments:
In `@src/features/email/functions/index.tsx`:
- Around line 40-90: The sendAuthEmail function embeds payload.url into email
bodies without validation; validate payload.url before rendering/sending. In
sendAuthEmail, before calling render(...) or transporter.sendMail(...), parse
and validate payload.url (e.g., with URL constructor) to ensure it is a
well-formed absolute URL with an allowed protocol (https) and, if applicable, an
allowed origin/hostname; if validation fails, throw or return an error to avoid
embedding unsafe values. Apply this check for both branches (PasswordResetEmail
and EmailVerificationEmail) referencing payload.url, render, and
transporter.sendMail so no unvalidated URL reaches the templates.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 07a8d3fc-bbcd-434e-9eb9-b03e3b62c17e

📥 Commits

Reviewing files that changed from the base of the PR and between 35e1485 and 87a02e5.

📒 Files selected for processing (6)
  • prisma/schema.prisma
  • src/components/shared/default-error-boundary.tsx
  • src/features/auth/components/forgot-password-form.tsx
  • src/features/auth/schema/index.ts
  • src/features/email/functions/index.tsx
  • src/lib/permissions.ts
📜 Review details
🔇 Additional comments (1)
src/features/email/functions/index.tsx (1)

23-34: LGTM!

Comment thread prisma/schema.prisma Outdated
</CardHeader>

<CardContent>
<form

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Doctor · react-doctor/no-prevent-default (warning)

Your users can't submit this

without JavaScript because onSubmit calls preventDefault(), so use a server action like <form action={serverAction}> to make it work either way.

Fix → Use <form action> where your framework supports it (it works without JS), or use a <button> instead of an <a> with preventDefault.

Docs

const handleRetry = async () => {
setIsRetrying(true);

try {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Doctor · react-hooks-js/todo (error)

This component misses React Compiler's automatic memoization & re-renders more than it should. Rewrite the flagged code so the compiler can optimize it.

Fix → Todo: (BuildHIR::lowerStatement) Handle TryStatement without a catch clause

Docs

</CardHeader>

<CardContent>
<form

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Doctor · react-doctor/no-prevent-default (warning)

Your users can't submit this

without JavaScript because onSubmit calls preventDefault(), so use a server action like <form action={serverAction}> to make it work either way.

Fix → Use <form action> where your framework supports it (it works without JS), or use a <button> instead of an <a> with preventDefault.

Docs

</CardHeader>

<CardContent>
<form

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Doctor · react-doctor/no-prevent-default (warning)

Your users can't submit this

without JavaScript because onSubmit calls preventDefault(), so use a server action like <form action={serverAction}> to make it work either way.

Fix → Use <form action> where your framework supports it (it works without JS), or use a <button> instead of an <a> with preventDefault.

Docs

</CardHeader>

<CardContent>
<form

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Doctor · react-doctor/no-prevent-default (warning)

Your users can't submit this

without JavaScript because onSubmit calls preventDefault(), so use a server action like <form action={serverAction}> to make it work either way.

Fix → Use <form action> where your framework supports it (it works without JS), or use a <button> instead of an <a> with preventDefault.

Docs

@agabaarnold agabaarnold merged commit 90974bf into main Jun 11, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant