Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@BilalG1
Copy link
Contributor

@BilalG1 BilalG1 commented Aug 19, 2025

https://www.loom.com/share/11affd2a119549c18a4056ad5db34cb6?sid=c86dd093-b8ca-4600-afb1-dda78e40b6a5


Important

Adds support for 'resend' email provider, updating configurations, schemas, and UI components to handle the new provider.

  • Behavior:
    • Adds support for 'resend' email provider in createOrUpdateProjectWithLegacyConfig() in projects.tsx.
    • Updates PageClient in page-client.tsx to handle 'resend' provider in email configuration.
    • Modifies EditEmailServerDialog to include 'resend' option and handle its configuration.
  • Schema:
    • Updates environmentConfigSchema in schema.ts to include 'resend' as a valid provider.
    • Modifies AdminEmailConfig type to include 'resend' in project-configs/index.ts.
  • UI:
    • Updates SendEmailDialog and TestSendingDialog in page-client.tsx to handle 'resend' provider.
    • Adjusts form fields in EditEmailServerDialog to support 'resend' specific fields like API Key.

This description was created by Ellipsis for 615fd72. You can customize this summary. It will automatically update as commits are pushed.

Summary by CodeRabbit

  • New Features

    • Added support for Resend email provider alongside Shared and Custom SMTP.
    • Introduced an in-app test to verify email settings before saving.
    • New Shared Email Server dialog with guidance and warnings.
  • Improvements

    • Streamlined email configuration with a type dropdown and conditional fields.
    • Clearer defaults and display text, including [email protected] for Shared setups.
    • Enhanced validation tailored to each email mode.
  • Chores

    • Updated configuration schema to include a provider field for email servers.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 19, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Email configuration gains a provider field and support for three modes (shared, standard/SMTP, resend). Backend sets provider: "smtp" when applying legacy email config. Dashboard emails page refactors to use the new config shape and conditional UI/validation. Shared config schema and template types updated accordingly.

Changes

Cohort / File(s) Summary of changes
Backend legacy config override
apps/backend/src/lib/projects.tsx
When dataOptions.email_config is present, environment override now sets emails.server.provider: "smtp" alongside existing SMTP fields.
Dashboard emails UI and flow
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx
Refactors to read project.useConfig().emails.server. Adds modes: shared, standard (SMTP), resend. Updates SendEmailDialog prop to take full emails.server config. Adds conditional defaults, validation (type in ['shared','standard','resend']), and submit logic. Introduces helper to test email then update config. Adjusts UI fields and interactions accordingly.
Shared config schema
packages/stack-shared/src/config/schema.ts
Adds optional emails.server.provider with oneOf ['resend','smtp']. Sets organization defaults to provider: "smtp".
Template config types
packages/template/src/lib/stack-app/project-configs/index.ts
Extends AdminEmailConfig.type to `"standard"

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant D as Dashboard Page
  participant E as EditEmailServerDialog
  participant A as stackAdminApp
  participant B as Backend
  participant C as Config Store

  U->>D: Open Project Emails
  D->>E: Open Edit Email Server Dialog (emailConfig)
  E->>E: Select type (shared | standard | resend)

  alt shared
    E->>A: Update config { emails.server: { type: "shared" } }
    A->>B: Save project config
    B->>C: Persist config
    C-->>B: OK
    B-->>A: OK
    A-->>E: OK (toast)
  else standard (SMTP)
    E->>A: sendTestEmail({ provider:"smtp", host, port, ... })
    A->>B: Send test email
    B-->>A: Test OK
    A->>B: Save { emails.server: { provider:"smtp", ... } }
    B->>C: Persist config
    C-->>B: OK
    B-->>A: OK
    A-->>E: OK (toast)
  else resend
    E->>A: sendTestEmail({ provider:"resend", apiKey, sender... })
    A->>B: Send test email
    B-->>A: Test OK
    A->>B: Save { emails.server: { provider:"resend", ... } }
    B->>C: Persist config
    C-->>B: OK
    B-->>A: OK
    A-->>E: OK (toast)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Pre-merge checks (2 passed, 1 warning)

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The current title "resend api key config" is related to the changes — it references the new "resend" provider and configuration adjustments — but it is terse and narrowly framed (it emphasizes an API key rather than the broader provider, schema, type, and UI updates included in the PR), so while related it could be clearer and more descriptive.
Description Check ✅ Passed The PR description contains a Loom link and a generated summary that outlines behavior, schema, and UI changes for adding the 'resend' provider, so it is largely complete and informative; however it does not explicitly state the runtime behavior (whether emails are actually sent via Resend or only used to prefill SMTP settings) nor does it include brief testing/migration notes.

Poem

A bunny taps keys with delight,
Teaching emails to take flight—
Shared, SMTP, or Resend,
Configs converge, flows amend.
With a hop, a toast appears,
“Test passed!” it cheers—long ears! 🐇✉️

✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch resend-api-key-config

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.

@vercel
Copy link

vercel bot commented Aug 19, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
stack-backend Ready Ready Preview Comment Sep 11, 2025 9:25pm
stack-dashboard Ready Ready Preview Comment Sep 11, 2025 9:25pm
stack-demo Ready Ready Preview Comment Sep 11, 2025 9:25pm
stack-docs Ready Ready Preview Comment Sep 11, 2025 9:25pm

@claude
Copy link
Contributor

claude bot commented Aug 19, 2025

Claude finished @BilalG1's task —— View job


PR Review: Resend API Key Configuration

Todo List:

  • Analyze modified files and understand changes
  • Review code quality and best practices
  • Check for potential bugs and issues
  • Evaluate security considerations
  • Assess performance implications
  • Review test coverage needs
  • Provide structured feedback

Summary

This PR adds Resend email service integration to the Stack Auth platform, providing an alternative to the existing shared and custom SMTP email configurations. The changes span across backend configuration, dashboard UI, and schema updates.

Code Quality & Best Practices ✅

Positive Aspects:

  1. Good separation of concerns - Email config logic is properly separated between UI and backend
  2. Type safety - Proper TypeScript usage with discriminated unions for email config types
  3. Consistent patterns - Follows existing codebase patterns for configuration handling
  4. Clean UI implementation - Well-structured form handling with proper validation

Minor Issues:

  1. packages/stack-shared/src/config/schema.ts:428 - Default provider should be 'smtp' instead of 'resend' for consistency
  2. Missing JSDoc comments - Complex functions like testEmailAndUpdateConfig could benefit from documentation

Security Considerations 🔐

Concerns Identified:

  1. API Key Storage - Resend API keys are stored in the same way as SMTP passwords. Consider if additional encryption is needed for API keys vs passwords.
  2. Error Handling - Error messages from Resend could potentially leak sensitive information. The current implementation properly catches and sanitizes errors.

Recommendations:

  • Consider adding rate limiting for test email functionality to prevent abuse
  • Validate that Resend API keys follow expected format before storage

Performance Implications ⚡

Good Practices:

  1. Lazy loading - Email configuration is fetched only when needed
  2. Proper async handling - All database operations are properly awaited
  3. Image compression - The logo upload feature includes proper image compression (1MB limit)

Potential Issues:

  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx:184-192 - Hard-coded Resend SMTP settings could be moved to constants for maintainability

Bugs & Issues 🐛

Critical Issues:

  1. Type inconsistency - The AdminEmailConfig type in the template doesn't match the new schema structure. This could cause runtime errors.

Minor Issues:

  1. apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx:285 - Accessing project.config.emailConfig should be project.useConfig().emails.server for consistency
  2. Hard-coded values - Resend SMTP configuration (host: 'smtp.resend.com', port: 465) should be constants

Test Coverage 📝

Missing Tests:

  1. Unit tests for Resend email configuration validation
  2. Integration tests for the new email config API endpoints
  3. E2E tests for the Resend configuration flow in the dashboard
  4. Error handling tests for invalid Resend API keys

Existing Coverage:

  • Schema validation tests are automatically covered by the yup schema
  • UI component rendering is likely covered by existing tests

Specific Code Issues

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx

Lines 184-192: Hard-coded Resend configuration

// Consider moving to constants
const RESEND_CONFIG = {
  host: 'smtp.resend.com',
  port: 465,
  username: 'resend'
} as const;

packages/template/src/lib/stack-app/project-configs/index.ts

Type mismatch issue: The AdminEmailConfig type needs updating to match the new schema structure with provider field.

Recommendations

High Priority:

  1. Fix type inconsistencies between template types and schema
  2. Add integration tests for Resend email functionality
  3. Move hard-coded values to constants

Medium Priority:

  1. Add JSDoc comments for complex functions
  2. Consider API key validation before storage
  3. Add rate limiting for test email functionality

Low Priority:

  1. Improve error messages for better user experience
  2. Consider adding email preview functionality

Overall Assessment

This is a solid implementation that follows good practices and maintains consistency with the existing codebase. The main concerns are around type safety and test coverage. The security implications are well-handled, and the performance impact is minimal.

Recommendation: Approve after addressing the type inconsistency issue and adding basic integration tests.


@claude
Copy link
Contributor

claude bot commented Aug 19, 2025

Claude finished @BilalG1's task —— View job


PR Review: Resend API Key Configuration

Review Checklist

  • Analyze changed files and understand the scope
  • Review code quality and best practices
  • Check for potential bugs or issues
  • Evaluate security concerns
  • Assess performance considerations
  • Examine test coverage needs
  • Provide comprehensive feedback

Analysis

This PR adds support for Resend API key configuration in the email settings. The changes include:

  • Backend support for the new Resend provider type
  • Frontend UI updates to handle Resend configuration
  • Schema updates to support the new provider field
  • Type definition updates for email config

Positive Aspects

  1. Clean Type Safety: Good TypeScript integration with proper type definitions
  2. Consistent Architecture: Follows existing patterns for email configuration
  3. User Experience: Clear UI flow with appropriate form validation
  4. Error Handling: Proper error states and user feedback

⚠️ Security Concerns

  1. API Key Storage (page-client.tsx:230):

    • Resend API keys are stored as passwords but transmitted in plain text
    • Consider implementing client-side encryption or secure transmission
    { label: "Resend API Key", name: "password", type: 'password' }
  2. Hardcoded Test Email (page-client.tsx:136):

    • Using a hardcoded test email address could be a security/privacy concern
    recipientEmail: '[email protected]'

🐛 Potential Bugs

  1. Inconsistent Type Handling (page-client.tsx:184):

    • The function expects AdminEmailConfig & { type: "standard" | "resend" } but AdminEmailConfig already defines type differently
    • This could cause type mismatches at runtime
  2. Missing Validation (page-client.tsx:186-192):

    • Resend uses hardcoded SMTP settings but there's no validation that these are correct
    host: 'smtp.resend.com',
    port: 465,
    username: 'resend',
  3. Schema Migration (schema.ts:203):

    • New provider field is optional, but defaults show it as required
    • Could cause inconsistencies for existing configurations

📈 Performance Considerations

  1. Redundant API Calls: The testEmailAndUpdateConfig function performs both test and update operations in sequence, which could be optimized

  2. Form Re-renders: The form change handler triggers on every keystroke, potentially causing unnecessary re-renders

🧪 Test Coverage Concerns

  1. Missing Tests: No visible test coverage for the new Resend provider functionality
  2. Edge Cases: No validation for malformed Resend API keys
  3. Integration Testing: Should test the full flow from UI → backend → email sending

📝 Code Quality Issues

  1. Type Inconsistencies (projects.tsx:209):

    • Hardcoded provider: "smtp" for existing configs might not align with new schema
    provider: "smtp", // Should this be dynamic based on actual provider?
  2. Magic Values (page-client.tsx:186):

    • Resend SMTP configuration is hardcoded - consider extracting to constants
  3. Cleanup Needed (page-client.tsx:10):

    • Removed imports but left unused import statements

🔧 Recommendations

  1. Security: Implement proper API key encryption and avoid hardcoded test emails
  2. Validation: Add comprehensive validation for Resend API keys and SMTP settings
  3. Testing: Add unit and integration tests for Resend functionality
  4. Constants: Extract hardcoded Resend SMTP settings to configuration constants
  5. Types: Resolve type inconsistencies between AdminEmailConfig and new provider types
  6. Error Handling: Improve error messages for failed Resend configurations

Overall Assessment

This is a solid implementation that follows existing patterns well. The main concerns are around security (API key handling), test coverage, and some type inconsistencies. The functionality appears to work correctly but would benefit from the security improvements and additional testing mentioned above.

Recommendation: ✅ Approve with minor changes - Address the security concerns around API key handling and add proper test coverage before merging.


Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Summary

This PR introduces support for multiple email service providers in the Stack Auth system by adding a provider field to email configurations. The changes enable users to choose between 'resend' and 'smtp' as email providers, moving away from a previously hardcoded or implicit provider system.

The core change is in the shared configuration schema (packages/stack-shared/src/config/schema.ts), which adds an optional provider field that accepts 'resend' or 'smtp' values, with 'resend' as the default. This change is implemented at the environment configuration level, making provider selection environment-specific.

The dashboard UI (apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx) has been updated to support the new provider system, restructuring email configuration from a simple type field to a more complex structure with isShared and provider fields. The UI now accesses email configuration through project.useConfig().emails.server instead of the legacy project.config.emailConfig pattern.

The backend (apps/backend/src/lib/projects.tsx) ensures backward compatibility by explicitly setting provider: "smtp" for legacy configurations that didn't previously specify a provider type. This maintains compatibility with existing SMTP configurations while enabling the new Resend provider support.

The template configuration (packages/template/src/lib/stack-app/project-configs/index.ts) has been updated to include 'resend' as a valid email provider type, though it still requires SMTP-specific fields which may not be appropriate for Resend configurations.

Confidence score: 2/5

  • This PR has significant implementation inconsistencies that could cause runtime errors in production
  • Score reflects critical issues with data access patterns and type mismatches that need resolution before merge
  • Pay close attention to the dashboard page-client.tsx file which has mixed old/new configuration patterns

4 files reviewed, 1 comment

Edit Code Review Bot Settings | Greptile

export type AdminEmailConfig = (
{
type: "standard",
type: "standard" | "resend",
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Adding 'resend' to the type union but requiring SMTP fields (host, port, username, password) creates a configuration mismatch since Resend uses API keys, not SMTP credentials

Copy link
Contributor

Choose a reason for hiding this comment

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

yea shouldn't this be another union option?

@claude
Copy link
Contributor

claude bot commented Aug 19, 2025

Claude finished @BilalG1's task —— View job


PR Review: Resend API Key Configuration

Review Checklist:

  • Analyze all changed files and understand the implementation
  • Review code quality and best practices
  • Check for potential bugs and issues
  • Evaluate security concerns
  • Assess performance considerations
  • Examine test coverage needs
  • Provide comprehensive feedback with specific recommendations

Overall Assessment

This PR adds Resend email provider support to Stack Auth, enabling users to choose between Resend API and custom SMTP for email delivery. While the implementation follows existing patterns well, there are several critical issues that need to be addressed.

🚨 Critical Issues

1. Type System Inconsistencies

Location: packages/template/src/lib/stack-app/project-configs/index.ts:42-53

The AdminEmailConfig type defines both 'standard' and 'resend' as requiring SMTP fields (host, port, username, password), but Resend only uses API keys:

export type AdminEmailConfig = (
  {
    type: "standard" | "resend", // ❌ Both types require same SMTP fields
    senderName: string,
    senderEmail: string,
    host: string,      // ❌ Resend doesn't need this
    port: number,      // ❌ Resend doesn't need this  
    username: string,  // ❌ Resend doesn't need this
    password: string,  // This is the API key for Resend
  }
  | { type: "shared" }
);

Impact: Runtime errors when Resend configs are processed expecting different field structures.

2. Hard-coded Provider Assignment

Location: apps/backend/src/lib/projects.tsx:209

provider: "smtp", // ❌ Always SMTP, ignores actual provider type

Impact: Resend configurations get incorrectly flagged as SMTP in the database.

3. Inconsistent Data Access Patterns

Location: apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx:285

const emailConfig = project.config.emailConfig || throwErr("Email config is not set");

Issue: Uses legacy project.config.emailConfig instead of the new project.useConfig().emails.server pattern used elsewhere.

🛡️ Security Concerns

1. API Key Exposure

  • Location: page-client.tsx:230 - API keys stored as 'password' type but transmitted in plain text
  • Location: page-client.tsx:136 - Hard-coded test email recipient could be security concern
  • Recommendation: Implement proper API key encryption and make test email configurable

2. Error Message Leakage

  • Current error handling properly sanitizes Resend API errors, but consider additional validation

🐛 Bugs & Logic Issues

1. Default Provider Value

Location: packages/stack-shared/src/config/schema.ts:428

provider: "smtp", // ❌ Should be dynamic or default to 'resend'

2. Schema Validation Mismatch

The definedWhenNotShared function checks for 'standard' but schema accepts 'resend':

definedWhenNotShared(yup.string(), "Host is required"), // ❌ Applied to Resend too

3. Hard-coded SMTP Configuration

Location: page-client.tsx:186-192

host: 'smtp.resend.com',  // ❌ Should be constants
port: 465,
username: 'resend',

📊 Performance Implications

Good:

  • ✅ Proper async/await patterns
  • ✅ Efficient form state management
  • ✅ Lazy loading of email configs

Concerns:

  • Form change handlers trigger on every keystroke (minor)
  • No caching for Resend SMTP constants

🧪 Test Coverage Issues

Missing:

  • Unit tests for Resend provider validation logic
  • Integration tests for Resend API configuration flow
  • Error handling tests for invalid Resend API keys
  • E2E tests for the dashboard Resend configuration UI

Existing:

  • Schema validation automatically tested via yup
  • Basic UI component coverage likely exists

🎯 Specific Recommendations

High Priority (Must Fix):

  1. Fix type definitions - Separate AdminEmailConfig types for different providers
  2. Dynamic provider assignment - Use actual provider type instead of hard-coding 'smtp'
  3. Consistent data access - Use project.useConfig().emails.server throughout
  4. Extract constants - Move hard-coded Resend SMTP values to configuration constants

Medium Priority:

  1. Add comprehensive tests - Especially integration tests for new provider
  2. Improve validation - Add Resend-specific API key format validation
  3. Security hardening - Implement API key encryption
  4. Error handling - Add better error messages for configuration failures

Low Priority:

  1. Code organization - Consider extracting Resend logic to separate utility functions
  2. Documentation - Add JSDoc comments for complex functions like testEmailAndUpdateConfig

🔧 Suggested Code Changes

// Fix AdminEmailConfig type
export type AdminEmailConfig = 
  | {
      type: "standard",
      senderName: string,
      senderEmail: string,
      host: string,
      port: number,
      username: string,
      password: string,
    }
  | {
      type: "resend",
      senderName: string,
      senderEmail: string,
      password: string, // API key
    }
  | {
      type: "shared",
    };

// Fix provider assignment
provider: dataOptions.email_config.type === 'resend' ? 'resend' : 'smtp',

// Extract constants
const RESEND_CONFIG = {
  host: 'smtp.resend.com',
  port: 465,
  username: 'resend'
} as const;

Final Verdict

Status: ⚠️ Needs Major Revision

While the implementation demonstrates good understanding of the existing architecture, the type system inconsistencies and hard-coded provider assignments create significant bugs that will cause runtime failures. The security and test coverage concerns are also important but not blocking.

Recommended Actions:

  1. Address the 3 critical type/logic issues identified above
  2. Add basic integration tests for Resend functionality
  3. Extract hard-coded values to constants
  4. Consider implementing the medium priority security improvements

Once these issues are resolved, this will be a solid addition that properly extends Stack Auth's email capabilities.


@recurseml
Copy link

recurseml bot commented Aug 19, 2025

Review by RecurseML

🔍 Review performed on e5eb478..d5fa738

✨ No bugs found, your code is sparkling clean

✅ Files analyzed, no issues (4)

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx
packages/template/src/lib/stack-app/project-configs/index.ts
packages/stack-shared/src/config/schema.ts
apps/backend/src/lib/projects.tsx

Need help? Join our Discord

@claude
Copy link
Contributor

claude bot commented Aug 19, 2025

Claude finished @BilalG1's task —— View job


PR Review: Resend Email Provider Support

Review Checklist

  • Analyze all changed files and understand the implementation
  • Review code quality and best practices
  • Check for potential bugs and issues
  • Evaluate security concerns
  • Assess performance considerations
  • Examine test coverage needs
  • Provide comprehensive feedback and recommendations

Summary

This PR adds support for Resend email provider to Stack Auth, enabling users to choose between Resend API and custom SMTP for email delivery. The implementation spans across backend configuration, schema updates, dashboard UI, and template types.

🚨 Critical Issues

1. Type System Inconsistencies

Location: packages/template/src/lib/stack-app/project-configs/index.ts:42-53

The AdminEmailConfig type treats both 'standard' and 'resend' identically, requiring SMTP fields that Resend doesn't use:

export type AdminEmailConfig = (
  {
    type: "standard" | "resend", // ❌ Both require same SMTP fields
    senderName: string,
    senderEmail: string,
    host: string,      // ❌ Resend doesn't need this
    port: number,      // ❌ Resend doesn't need this  
    username: string,  // ❌ Resend doesn't need this
    password: string,  // This is the API key for Resend
  }
  | { type: "shared" }
);

Impact: This will cause runtime errors when Resend configurations are processed expecting different field structures.

2. Hard-coded Provider Assignment

Location: apps/backend/src/lib/projects.tsx:209

provider: "smtp", // ❌ Always SMTP, ignores actual provider type

Impact: All email configurations, including Resend, get incorrectly stored as 'smtp' in the database.

3. Data Access Pattern Inconsistency

Location: apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx:285

const emailConfig = project.config.emailConfig || throwErr("Email config is not set");

Issue: Uses legacy project.config.emailConfig instead of the new project.useConfig().emails.server pattern used elsewhere in the same file (line 25).

🛡️ Security Concerns

1. API Key Storage & Transmission

  • Line 230: Resend API keys are stored as 'password' type but may need additional security considerations
  • Line 136: Hard-coded test email recipient '[email protected]' could be a privacy concern
  • Recommendation: Consider encrypting API keys differently than passwords, make test email configurable

2. Error Message Exposure

  • Current error handling appears to properly sanitize Resend API errors
  • No obvious information leakage detected

🐛 Bugs & Logic Issues

1. Schema Default Provider

Location: packages/stack-shared/src/config/schema.ts:428

provider: "smtp", // ❌ Should be dynamic based on actual configuration

2. Hard-coded SMTP Configuration

Location: page-client.tsx:186-192

host: 'smtp.resend.com',  // ❌ Should be constants
port: 465,
username: 'resend',

Issue: These values are hard-coded and should be moved to configuration constants.

3. Schema Validation Mismatch

The schema validation at line 203 allows 'resend' provider but the validation functions may still require SMTP fields.

📊 Performance & Code Quality

Positive Aspects:

  • ✅ Proper async/await patterns
  • ✅ Efficient form state management
  • ✅ Good separation of concerns

Areas for Improvement:

  • Form change handlers trigger on every keystroke (minor performance impact)
  • No caching for Resend SMTP constants
  • Missing JSDoc comments for complex functions

🧪 Test Coverage

Missing:

  • Unit tests for Resend provider validation logic
  • Integration tests for Resend configuration flow
  • Error handling tests for invalid Resend API keys
  • E2E tests for dashboard Resend configuration

Existing:

  • Schema validation is automatically covered by yup
  • Basic UI component coverage likely exists

🎯 Specific Recommendations

High Priority (Must Fix):

  1. Fix type definitions - Create separate types for different email provider configurations
  2. Dynamic provider assignment - Use actual provider type instead of hard-coding 'smtp'
  3. Consistent data access - Use project.useConfig().emails.server throughout
  4. Extract constants - Move hard-coded Resend SMTP values to configuration constants

Medium Priority:

  1. Add comprehensive tests - Especially integration tests for new provider
  2. Security hardening - Consider API key encryption, configurable test emails
  3. Error handling - Improve error messages for configuration failures

Low Priority:

  1. Code organization - Extract Resend logic to utility functions
  2. Performance - Minor optimizations for form handling

🔧 Suggested Code Changes

// Fix AdminEmailConfig type
export type AdminEmailConfig = 
  | {
      type: "standard",
      senderName: string,
      senderEmail: string,
      host: string,
      port: number,
      username: string,
      password: string,
    }
  | {
      type: "resend",
      senderName: string,
      senderEmail: string,
      password: string, // API key
    }
  | {
      type: "shared",
    };

// Fix provider assignment
provider: dataOptions.email_config.type === 'resend' ? 'resend' : 'smtp',

// Extract constants
const RESEND_CONFIG = {
  host: 'smtp.resend.com',
  port: 465,
  username: 'resend'
} as const;

Final Assessment

Status: ⚠️ Needs Major Revision

While the implementation demonstrates good understanding of the existing architecture, the type system inconsistencies and hard-coded provider assignments create critical bugs that will cause runtime failures. The security considerations and test coverage gaps are important but not immediately blocking.

Recommended Actions:

  1. Address the 3 critical type/logic issues identified above
  2. Add basic integration tests for Resend functionality
  3. Extract hard-coded values to constants
  4. Consider implementing the security improvements

Once these issues are resolved, this will be a solid addition to Stack Auth's email capabilities.


@BilalG1 BilalG1 assigned N2D4 and unassigned BilalG1 Aug 19, 2025
@claude
Copy link
Contributor

claude bot commented Aug 19, 2025

Claude encountered an error —— View job


PR Review: Resend Email Provider Support

Review Checklist:

  • Analyze all changed files and understand the implementation
  • Review code quality and best practices
  • Check for potential bugs and issues
  • Evaluate security concerns
  • Assess performance considerations
  • Examine test coverage needs
  • Provide comprehensive feedback and recommendations

Starting analysis of the PR changes...

export type AdminEmailConfig = (
{
type: "standard",
type: "standard" | "resend",
Copy link
Contributor

Choose a reason for hiding this comment

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

yea shouldn't this be another union option?

Copy link
Contributor

@N2D4 N2D4 left a comment

Choose a reason for hiding this comment

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

wait, where do you actually send the emails with resend?

@N2D4 N2D4 assigned BilalG1 and unassigned N2D4 Aug 22, 2025
@BilalG1
Copy link
Contributor Author

BilalG1 commented Aug 26, 2025

wait, where do you actually send the emails with resend?

I'm still sending through smtp, just using resend option to prefill smtp properties

@BilalG1 BilalG1 assigned N2D4 and unassigned BilalG1 Aug 26, 2025
Base automatically changed from email-drafts to dev September 10, 2025 22:57
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

Caution

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

⚠️ Outside diff range comments (2)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx (2)

284-292: Use environment server config for test-sending; current code reads legacy project.config.emailConfig.

After configuring via updateConfig, project.config.emailConfig may be unset, causing false “Email config is not set.” Build the test payload from project.useConfig().emails.server.

   onSubmit={async (values) => {
-      const emailConfig = project.config.emailConfig || throwErr("Email config is not set");
-      if (emailConfig.type === 'shared') throwErr("Shared email server cannot be used for testing");
+      const server = project.useConfig().emails.server;
+      if (server.isShared) throwErr("Shared email server cannot be used for testing");
+
+      const emailConfig: AdminEmailConfig = server.provider === 'resend'
+        ? {
+            type: 'resend',
+            host: server.host ?? 'smtp.resend.com',
+            port: server.port ?? 465,
+            username: server.username ?? 'resend',
+            password: server.password ?? throwErr("Missing Resend API key"),
+            senderEmail: server.senderEmail ?? throwErr("Missing sender email"),
+            senderName: server.senderName ?? throwErr("Missing sender name"),
+          }
+        : {
+            type: 'standard',
+            host: server.host ?? throwErr("Missing SMTP host"),
+            port: server.port ?? throwErr("Missing SMTP port"),
+            username: server.username ?? throwErr("Missing SMTP username"),
+            password: server.password ?? throwErr("Missing SMTP password"),
+            senderEmail: server.senderEmail ?? throwErr("Missing sender email"),
+            senderName: server.senderName ?? throwErr("Missing sender name"),
+          };

407-417: Replace blocking error toast with inline Alert per UI guidelines.

Show a form-level Alert instead of a destructive toast when preventing close.

   const handleNext = async () => {
     if (selectedUsers.length === 0) {
-      toast({
-        title: "No recipients selected",
-        description: "Please select at least one recipient to send the email.",
-        variant: "destructive",
-      });
+      setRecipientError("Please select at least one recipient to send the email.");
       return "prevent-close" as const;
     }
     setStage('data');
     return "prevent-close" as const;
   };

Add state and render:

   const [selectedUsers, setSelectedUsers] = useState<ServerUser[]>([]);
   const [stage, setStage] = useState<'recipients' | 'data'>('recipients');
+  const [recipientError, setRecipientError] = useState<string | null>(null);
 {stage === 'recipients' ? (
   <TeamMemberSearchTable
     action={(user) => (
       <Button
         size="sm"
         variant="outline"
-        onClick={() => setSelectedUsers(users =>
+        onClick={() => { setRecipientError(null); setSelectedUsers(users =>
           users.some(u => u.id === user.id)
             ? users.filter(u => u.id !== user.id)
             : [...users, user]
-        )}
+        )}}
       >
         {selectedUsers.some(u => u.id === user.id) ? 'Remove' : 'Add'}
       </Button>
     )}
   />
 ) : (
 {stage === 'recipients' && recipientError && (
   <Alert variant="destructive">{recipientError}</Alert>
 )}
♻️ Duplicate comments (1)
apps/backend/src/lib/projects.tsx (1)

211-221: Set provider dynamically for 'resend' instead of hardcoding "smtp".

Map provider based on dataOptions.email_config.type so Resend configs don’t get mislabeled as SMTP.

       senderEmail: dataOptions.email_config.sender_email,
-      provider: "smtp",
+      provider: dataOptions.email_config.type === 'resend' ? 'resend' : 'smtp',
🧹 Nitpick comments (4)
packages/stack-shared/src/config/schema.ts (1)

212-223: Provider field addition looks good; consider cross-field constraints.

Nice addition. As a follow-up, add cross-field validation (e.g., when server.isShared === true, disallow other fields; when provider === 'resend', ignore/forbid custom host/port/username).

packages/template/src/lib/stack-app/project-configs/index.ts (1)

40-50: Clarify 'resend' shape or document SMTP mapping to reduce confusion.

Current union requires SMTP fields for type: "resend", which can be confusing. Two options:

  • Non-breaking: document that for Resend, username must be "resend", host = smtp.resend.com, port = 465, and password is the API key.
  • Breaking (cleaner): make resend variant accept { apiKey, senderName, senderEmail } only and set SMTP defaults internally.

Non-breaking doc update:

 export type AdminEmailConfig = (
   {
-    type: "standard" | "resend",
+    /**
+     * For "resend": use SMTP relay — host "smtp.resend.com", port 465, username "resend", password = Resend API key.
+     */
+    type: "standard" | "resend",
     senderName: string,
     senderEmail: string,
     host: string,
     port: number,
     username: string,
     password: string,
   }
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx (2)

487-489: Wording: include Resend, not just “custom SMTP server”.

Users on Resend should be guided too.

-            You are using a shared email server. If you want to send manual emails, you need to configure a custom SMTP server.
+            You are using a shared email server. To send manual emails, configure your own email server (SMTP or Resend).

134-165: Happy path UX: success toast is fine; consider surfacing server-side validation errors inline.

Optional: parse known error codes into field errors to focus the user on what to fix.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5da45d8 and 0b57f9e.

📒 Files selected for processing (4)
  • apps/backend/src/lib/projects.tsx (1 hunks)
  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx (9 hunks)
  • packages/stack-shared/src/config/schema.ts (2 hunks)
  • packages/template/src/lib/stack-app/project-configs/index.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer ES6 Map over Record when representing key–value collections

Files:

  • apps/backend/src/lib/projects.tsx
  • packages/stack-shared/src/config/schema.ts
  • packages/template/src/lib/stack-app/project-configs/index.ts
  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx
packages/template/**

📄 CodeRabbit inference engine (AGENTS.md)

When modifying the SDK copies, make changes in packages/template (source of truth)

Files:

  • packages/template/src/lib/stack-app/project-configs/index.ts
{apps/dashboard,apps/dev-launchpad,packages/stack-ui,packages/react}/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

For blocking alerts and errors in UI, do not use toast notifications; use alerts instead

Files:

  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx
{apps/dashboard,apps/dev-launchpad,packages/stack-ui,packages/react}/**/*.{tsx,jsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

Keep hover/click animations snappy; avoid pre-transition delays on hover and apply transitions after the action (e.g., fade-out on hover end)

Files:

  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx
🧬 Code graph analysis (2)
packages/stack-shared/src/config/schema.ts (1)
packages/stack-shared/src/schema-fields.ts (1)
  • yupString (187-190)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx (7)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/email-templates/page-client.tsx (1)
  • PageClient (13-80)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/use-admin-app.tsx (1)
  • useAdminApp (27-34)
packages/stack-shared/src/config/schema.ts (1)
  • CompleteConfig (993-993)
packages/template/src/lib/stack-app/projects/index.ts (1)
  • AdminProject (16-40)
packages/stack-shared/src/schema-fields.ts (1)
  • strictEmailSchema (448-448)
packages/template/src/lib/stack-app/project-configs/index.ts (1)
  • AdminEmailConfig (40-53)
apps/dashboard/src/components/form-fields.tsx (1)
  • InputField (59-97)
🪛 Biome (2.1.2)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx

[error] 83-83: Do not add then to an object.

(lint/suspicious/noThenProperty)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: setup-tests
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: restart-dev-and-test
  • GitHub Check: build (22.x)
  • GitHub Check: docker
  • GitHub Check: docker
  • GitHub Check: all-good
  • GitHub Check: build (22.x)
  • GitHub Check: Security Check
🔇 Additional comments (1)
packages/stack-shared/src/config/schema.ts (1)

450-456: Defaulting provider to "smtp" at org level is reasonable.

No issues from me; aligns with current defaults.

Comment on lines +80 to 86
function definedWhenTypeIsOneOf<S extends yup.AnyObject>(schema: S, types: string[], message: string): S {
return schema.when('type', {
is: 'standard',
is: (t: string) => types.includes(t),
then: (schema: S) => schema.defined(message),
otherwise: (schema: S) => schema.optional()
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix Biome “noThenProperty” lint error and broaden generic.

Use the functional when builder to avoid a then property and accept any Yup schema, not just objects.

-function definedWhenTypeIsOneOf<S extends yup.AnyObject>(schema: S, types: string[], message: string): S {
-  return schema.when('type', {
-    is: (t: string) => types.includes(t),
-    then: (schema: S) => schema.defined(message),
-    otherwise: (schema: S) => schema.optional()
-  });
-}
+function definedWhenTypeIsOneOf<S extends yup.AnySchema>(schema: S, types: string[], message: string): S {
+  // Avoid "then" property (thenable) objects per lint rule.
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  return (schema as any).when('type', (val: unknown, s: S) =>
+    types.includes(String(val)) ? s.defined(message) : s.optional()
+  );
+}
📝 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.

Suggested change
function definedWhenTypeIsOneOf<S extends yup.AnyObject>(schema: S, types: string[], message: string): S {
return schema.when('type', {
is: 'standard',
is: (t: string) => types.includes(t),
then: (schema: S) => schema.defined(message),
otherwise: (schema: S) => schema.optional()
});
}
function definedWhenTypeIsOneOf<S extends yup.AnySchema>(schema: S, types: string[], message: string): S {
// Avoid "then" property (thenable) objects per lint rule.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (schema as any).when('type', (val: unknown, s: S) =>
types.includes(String(val)) ? s.defined(message) : s.optional()
);
}
🧰 Tools
🪛 Biome (2.1.2)

[error] 83-83: Do not add then to an object.

(lint/suspicious/noThenProperty)

🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx
around lines 80 to 86, the helper currently uses the object form of yup.when
(causing the Biome noThenProperty lint error) and constrains the generic to
yup.AnyObject; change the signature to accept any Yup schema (e.g. S extends
yup.Schema<any>) and switch to the functional when builder: call
schema.when('type', (typeValue, currentSchema) => types.includes(typeValue as
string) ? currentSchema.defined(message) : currentSchema.optional()), removing
the object with then/otherwise to satisfy the linter and broaden the accepted
schema type.

@N2D4 N2D4 assigned BilalG1 and unassigned N2D4 Sep 11, 2025
@BilalG1 BilalG1 merged commit 39a4b05 into dev Sep 11, 2025
16 of 18 checks passed
@BilalG1 BilalG1 deleted the resend-api-key-config branch September 11, 2025 21:58
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.

3 participants