Conversation
Enhance the user management interface by introducing a new "Copy ID" option in the user actions dropdown. This feature allows administrators to easily copy a user's ID to the clipboard, improving usability and efficiency in managing user data. A success toast notification is displayed upon copying the ID, providing immediate feedback to the user.
Add optional emailVerified parameter to seedTestUser helper function to enable testing of email verification features. Defaults to true to maintain backward compatibility with existing tests. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implement admin endpoint to manually resend verification emails to unverified users. Features: - tRPC mutation with Zod validation - Full Sentry instrumentation with span tracking - Security audit logging for both success and failure - Better Auth integration with automatic token refresh - Comprehensive error handling (disabled verification, already verified, user not found) - New security action type: admin_resend_verification The endpoint creates a new verification token with fresh 1-hour expiration through Better Auth's sendVerificationEmail API. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add "Resend Verification Email" action to user dropdown menu. Features: - Conditional rendering: only shows for unverified users - Mail icon from lucide-react - React Query mutation with toast notifications - Success/error feedback with sonner - Automatic table refresh after email sent The action allows admins to manually trigger verification emails for users who haven't verified their email addresses. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add 6 tests covering all scenarios for the resendVerificationEmail endpoint: - Successful email resend to unverified user - Already verified user error handling - Email verification disabled error handling - User not found error handling - Security audit logging verification - Admin role requirement enforcement Includes Better Auth mock setup to simulate email sending behavior. All tests passing (113/113). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR enhances the admin user management interface by adding two new actions to the user dropdown menu: "Copy ID" and "Resend Verification Email". The implementation includes both backend and frontend changes with comprehensive backend testing and security logging.
Key Changes:
- Added a new
resendVerificationEmailmutation in the admin router with security logging, Sentry tracing, and comprehensive error handling - Enhanced the admin users UI with "Copy ID" and "Resend Verification Email" actions in the dropdown menu
- Added backend tests covering various scenarios including success cases, error conditions, and security logging
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
packages/app/src/routes/app/admin/users.tsx |
Added mutation setup and callback handler for resending verification emails with success/error toast notifications |
packages/app/src/components/admin/users/columns.tsx |
Added "Copy ID" and "Resend Verification Email" menu items with clipboard API integration and conditional rendering based on email verification status |
packages/app/src/components/admin/users/__tests__/columns.test.tsx |
Added comprehensive tests for the "Copy ID" functionality including rendering, clipboard interaction, toast notifications, and menu ordering |
packages/api/src/routers/admin.ts |
Implemented resendVerificationEmail mutation with validation checks, Better Auth integration, security logging, and Sentry tracing |
packages/api/src/routers/__tests__/admin.test.ts |
Added comprehensive test suite covering success scenarios, error conditions, security logging, and authorization checks with Better Auth mocking |
packages/api/src/auth/security.ts |
Extended SecurityAction type to include the new admin_resend_verification action for audit logging |
packages/api/src/test/setup.ts |
Enhanced seedTestUser utility to support customizable emailVerified status for testing purposes |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
packages/app/src/components/admin/users/__tests__/columns.test.tsx
Outdated
Show resolved
Hide resolved
Wraps clipboard.writeText in try-catch block to handle potential failures such as permission denials or browser support issues, displaying an appropriate error toast to the user.
Added comment documenting that Better Auth's sendVerificationEmail API
returns { status: boolean }, with references to test files that verify
this behavior, addressing potential confusion about the API contract.
Ensures audit logging errors in resend verification flow are captured to Sentry, maintaining consistency with error handling patterns used elsewhere in the codebase (e.g., auth.ts lines 679-686).
Rate limiting is not currently implemented for resendVerificationEmail. Updated comment to be accurate and added TODO for future implementation to prevent potential spam of verification emails.
Added test suite for Resend Verification Email feature including: - Rendering for unverified users - Conditional hiding for verified users - Callback invocation with correct user ID - Mail icon presence in menu item
|
@sentry review |
CRITICAL: The mutation was returning a Promise instead of the resolved value, violating tRPC output schema. This would cause runtime errors when client code attempts to access data.success or data.message.
Changed from destructuring assignment to explicit indexing to comply with noUncheckedIndexedAccess TypeScript setting, making the code safer and more explicit about potential undefined values.
Added typeof check to verify result.status exists and is a boolean before evaluating it, making the code more robust against potential API response format changes.
Added critical promise-handling rules that would have caught the missing await on Sentry.startSpan: - @typescript-eslint/no-floating-promises: catches unawaited promises - @typescript-eslint/no-misused-promises: catches promise misuse - @typescript-eslint/await-thenable: ensures only thenables are awaited - @typescript-eslint/require-await: warns about async without await These rules will prevent similar critical bugs in the future.
Fixed 6 critical errors found by new ESLint promise rules: - Added void operator to CLI scripts and IIFE entry points - Fixed db/utils.ts to call stmt.execute() instead of awaiting stmt - Removed incorrect await from synchronous sentry.captureException calls These new rules successfully caught real bugs that could have caused runtime issues.
Fixed async functions that didn't use await by: - Wrapping synchronous Sentry calls in Promise.resolve() for adapter methods - Removing async keyword from initialization functions that return promises - Removing unused eslint-disable directives These changes maintain API compatibility while fixing ESLint warnings.
Updated sentry-integration.md to accurately reflect implementation: - Fixed inaccurate Node.js entry point description - Added comprehensive "Import Patterns" section explaining when to use direct SDK imports vs shim - Documented dependency injection pattern used in hono/app.ts - Added table clarifying import strategies for different file types This provides clearer guidance for developers on how to properly import and use Sentry across different parts of the codebase.
Removed async from 3 functions that were synchronous: - hono/app.ts: Error handler (line 111) - hono/app.ts: Debug Sentry route (line 139) - subscriptions.ts: importStatus query (line 2263) All operations in these functions are synchronous, so async keyword was unnecessary and triggered require-await warnings. ESLint now reports: 0 errors, 0 warnings ✅
|
@sentry review |
| // Send verification email using Better Auth API | ||
| // This creates a new token with a fresh 1-hour expiration | ||
| const result = await auth.api.sendVerificationEmail({ | ||
| body: { | ||
| email: user.email, | ||
| callbackURL: `${frontendUrl}/app/articles`, | ||
| }, | ||
| }); | ||
|
|
||
| // Check if the operation was successful | ||
| // Better Auth API returns object with { status: boolean } | ||
| // verified in: packages/api/scripts/test-verification-email.ts | ||
| // and mocked in: packages/api/src/routers/__tests__/admin.test.ts |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| userId: ctx.user.userId, | ||
| action: "admin_resend_verification", | ||
| ipAddress: undefined, | ||
| userAgent: undefined, | ||
| success: false, | ||
| metadata: { | ||
| targetUserId: input.userId, | ||
| error: (error as Error).message, | ||
| }, | ||
| }); | ||
| } catch (auditError) { | ||
| console.error( | ||
| "Failed to log failed resend verification:", | ||
| auditError | ||
| ); |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| toast.error("Failed to copy User ID to clipboard"); | ||
| } | ||
| }} | ||
| > | ||
| <Copy className="mr-2 h-4 w-4" /> | ||
| Copy ID | ||
| </DropdownMenuItem> | ||
| {!user.emailVerified && ( | ||
| <DropdownMenuItem | ||
| onClick={() => actions.onResendVerificationEmail(user.id)} | ||
| > |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
Fixed two critical issues identified by Sentry bot: 1. admin.ts: Made security event logging non-blocking - Wrapped logSecurityEvent in try-catch after email send succeeds - Ensures success response is returned even if logging fails - Logs audit errors to console and Sentry without blocking operation 2. columns.tsx: Added clipboard availability check - Check if navigator.clipboard exists before using it - Handles non-secure contexts and older browsers gracefully - Shows appropriate error message if clipboard unavailable
The PR adds "Actions" to users listed in the admin's user management console. In the three-dots in the last column, these new actions have been added.
Additional edits:
Backend: Admin Resend Verification Email
resendVerificationEmailmutation to theadminRouter, enabling admins to resend email verification links to unverified users. This includes security logging, Sentry tracing, and error handling.SecurityActiontype to include the new"admin_resend_verification"action for audit logs.emailVerifiedstatus. [1] [2]Frontend: Admin User Actions
columns.tsxto include:Testing & Mocks
These changes collectively improve admin capabilities for user management and enhance the usability of the admin interface.