Skip to content

Conversation

@shige
Copy link
Member

@shige shige commented Nov 6, 2025

User description

Summary

  • Add email templates to apps/studio.giselles.ai using React Email
  • Add pnpm overrides to ensure consistent React type versions across the monorepo
  • Approve spamc license dependency required by React Email

Details

This PR introduces email template functionality directly in the studio.giselles.ai app using React Email, following the
same pattern as drizzle (app-specific infrastructure rather than shared package).

Email template features:

  • Development environment: Local preview server at http://localhost:3333
  • Sample template: Starting point demonstrating React Email component usage
  • Export functionality: Generate static HTML from React components
  • TypeScript support: Full type safety for email template development

Location rationale:
Email templates are placed in apps/studio.giselles.ai/emails/ (same granularity as drizzle configuration) rather than a
separate package, following the "less is more" principle. If other apps need email templates in the future, we can
extract to a shared package then.

Type conflict resolution:
To resolve type conflicts introduced by React Email dependencies pulling in older React type versions, this PR adds pnpm
overrides for @types/[email protected] and @types/[email protected] to ensure consistency across all packages in the
monorepo.

Usage

# Start email preview server
pnpm -F studio.giselles.ai email:dev

# Export templates as static HTML
pnpm -F studio.giselles.ai email:export

Test plan

  • Verify all apps build successfully (ui.giselles.ai, playground, studio.giselles.ai)
  • Run pnpm build-sdk to confirm all packages build without type errors
  • Start email preview server and verify it runs at http://localhost:3333
  • Review sample email template in preview
  • Run pnpm check-types to validate TypeScript configuration
  • Run pnpm tidy to ensure no unused dependencies

Reference


PR Type

Enhancement


Description

  • Add new @giselles-ai/transactional-email package for React Email templates

  • Configure development server for local email template preview

  • Include sample email template and TypeScript configuration

  • Approve spamc license dependency from React Email preview server


Diagram Walkthrough

flowchart LR
  A["New Package<br/>transactional-email"] --> B["React Email<br/>Components"]
  A --> C["Dev Server<br/>Preview"]
  A --> D["Sample Email<br/>Template"]
  C --> E["http://localhost:3333"]
  A --> F["TypeScript<br/>Config"]
  G["spamc License"] --> A
Loading

File Walkthrough

Relevant files
Configuration changes
5 files
package.json
Define email package dependencies and scripts                       
+25/-0   
tsconfig.json
Configure TypeScript for email package                                     
+8/-0     
config.json
Configure React Email preview server                                         
+3/-0     
knip.ts
Configure Knip for transactional email package                     
+7/-0     
turbo.json
Add email export output to Turbo cache                                     
+1/-1     
Enhancement
1 files
sample.tsx
Create sample welcome email template                                         
+64/-0   
Documentation
1 files
README.md
Document package setup and usage guide                                     
+59/-0   
Dependencies
1 files
dependency_decisions.yml
Approve spamc license dependency                                                 
+7/-0     
Additional files
1 files
pnpm-lock.yaml +2581/-59

Note

Add React Email templates with local preview/export to apps/studio.giselles.ai, plus build/config tweaks, React types overrides, and license approval.

  • Studio (apps/studio.giselles.ai):
    • Add React Email setup (.react-email/config.json), emails/ directory with README and sample.tsx.
    • New scripts: email:dev (preview on 3333) and email:export (static HTML).
  • Tooling/Deps:
    • Add React Email packages (components/preview-server) to app; supporting deps wired.
  • Build/Config:
    • Turbo: include out/** in build outputs.
    • Knip: include emails/**/*.tsx as entry; ignore duplicates in emails/; ignore preview-server/react-dom deps.
  • Monorepo Types:
  • Compliance/Docs:
    • Approve spamc in config/dependency_decisions.yml.
    • Update docs/packages-license.md to reflect new dependencies/licenses.

Written by Cursor Bugbot for commit 823b419. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features

    • Added transactional email package with React Email integration for creating and previewing email templates
    • Included development server for email template preview and export functionality
  • Documentation

    • Added package README with setup and usage instructions for email development
  • Chores

    • Updated dependency management and licensing documentation
    • Updated build output configuration
    • Added React type definition overrides

shige added 2 commits November 6, 2025 11:25
Add a new @giselles-ai/transactional-email package for managing email templates using React Email. This provides a development environment for creating and previewing email templates.

- Add React Email dependencies and dev server configuration
- Include sample email template as a starting point
- Configure Knip to ignore duplicates and preview server dependencies
- Add TypeScript configuration for the new package
@shige shige self-assigned this Nov 6, 2025
@changeset-bot
Copy link

changeset-bot bot commented Nov 6, 2025

⚠️ No Changeset found

Latest commit: 62d0dac

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

💥 An error occurred when fetching the changed packages and changesets in this PR
Some errors occurred when validating the changesets config:
The package or glob expression "giselles-ai" is specified in the `ignore` option but it is not found in the project. You may have misspelled the package name or provided an invalid glob expression. Note that glob expressions must be defined according to https://www.npmjs.com/package/micromatch.

@giselles-ai
Copy link

giselles-ai bot commented Nov 6, 2025

Finished running flow.

Step 1
🟢
On Pull Request OpenedStatus: Success Updated: Nov 6, 2025 2:36am
Step 2
🟢
Manual QAStatus: Success Updated: Nov 6, 2025 2:39am
🟢
Prompt for AI AgentsStatus: Success Updated: Nov 6, 2025 2:39am
Step 3
🟢
Create a Comment for PRStatus: Success Updated: Nov 6, 2025 2:42am
Step 4
🟢
Create Pull Request CommentStatus: Success Updated: Nov 6, 2025 2:42am

@vercel
Copy link

vercel bot commented Nov 6, 2025

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

Project Deployment Preview Comments Updated (UTC)
giselle Ready Ready Preview Comment Nov 6, 2025 3:14am
ui Ready Ready Preview Comment Nov 6, 2025 3:14am

@shige shige requested a review from Copilot November 6, 2025 02:36
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 6, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This PR introduces a new @react-email/transactional-email package for handling transactional emails, adds dependency approvals, updates license documentation, and configures workspace-specific build and dependency rules.

Changes

Cohort / File(s) Summary
Transactional Email Package
packages/transactional-email/package.json, packages/transactional-email/tsconfig.json, packages/transactional-email/.react-email/config.json, packages/transactional-email/README.md, packages/transactional-email/emails/sample.tsx
New workspace for React Email transactional email templates including package configuration, TypeScript setup, React Email configuration, documentation, and a sample email component template.
Tooling & Configuration
knip.ts, turbo.json, root package.json
Added workspace configuration for transactional-email in knip with ignored dependencies and issues; extended turbo build outputs; added React type definition overrides.
Dependency Management
config/dependency_decisions.yml, docs/packages-license.md
Approved spamc v0.0.5 dependency and updated license documentation with new package entries, version updates, and license classifications.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

  • Cohesive changes focused on new package setup and configuration management
  • Repetitive license documentation updates require minimal scrutiny
  • Configuration additions are straightforward but should verify dependency selections in knip.ts and turbo outputs
  • New email component is a standard React template with clear typing

Review focus areas:

  • Verify knip.ts workspace configuration correctly excludes React Email preview-server dependencies
  • Confirm turbo.json output path addition doesn't conflict with existing build artifacts
  • Validate spamc dependency rationale and upstream MIT licensing claim

Possibly related PRs

Suggested reviewers

  • toyamarinyon

Poem

🐰 A new email garden blooms, where React templates grow,
Transactional letters dance in the digital flow,
Dependencies blessed, licenses all in line,
Configuration crafted with care so divine,
whoosh → out/**, the build takes flight!

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and directly summarizes the main change: adding a new transactional email package with React Email templates to the studio project.
Description check ✅ Passed The PR description comprehensively covers all required template sections with detailed information about changes, rationale, usage, and testing.

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.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces a new @giselles-ai/transactional-email package to manage transactional email templates using React Email. The package provides a development preview server, export functionality for static HTML generation, and TypeScript support for type-safe email template development.

Key Changes:

  • New transactional email package with React Email integration for template management
  • Knip configuration updates to handle React Email's preview server dependencies and email template files
  • License approval for spamc dependency (brought in by @react-email/preview-server)

Reviewed Changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated no comments.

Show a summary per file
File Description
turbo.json Added out/** to build outputs to include exported email templates
packages/transactional-email/package.json Package configuration with React Email dependencies and scripts for dev/export/build
packages/transactional-email/tsconfig.json TypeScript configuration using bundler module resolution
packages/transactional-email/emails/sample.tsx Sample welcome email template demonstrating React Email component usage
packages/transactional-email/README.md Documentation for developing and exporting email templates
packages/transactional-email/.react-email/config.json React Email configuration pointing to emails directory
knip.ts Added workspace entry configuration and ignored preview server dependencies
config/dependency_decisions.yml Approved spamc license (MIT via react-email)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@qodo-merge-for-open-source
Copy link

qodo-merge-for-open-source bot commented Nov 6, 2025

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Style injection risk

Description: Inline styles in email templates could be vulnerable to style injection if user-controlled
data is passed to style objects without sanitization, potentially leading to CSS-based
attacks or UI manipulation. sample.tsx [39-64]

Referred Code
const main = {
	backgroundColor: "#ffffff",
	fontFamily:
		'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
};

const container = {
	backgroundColor: "#ffffff",
	margin: "0 auto",
	padding: "20px 0 48px",
	marginBottom: "64px",
};

const h1 = {
	color: "#333",
	fontSize: "24px",
	fontWeight: "bold",
	margin: "40px 0",
	padding: "0",
};



 ... (clipped 5 lines)
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status: Passed

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-merge-for-open-source
Copy link

qodo-merge-for-open-source bot commented Nov 6, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Correct invalid package versions

Update the versions for react-email, @react-email/components to valid ones from
the public registry. Also, remove the unnecessary @react-email/preview-server
dependency as its functionality is included in react-email.

packages/transactional-email/package.json [13-24]

 	"dependencies": {
-		"@react-email/components": "0.5.7",
+		"@react-email/components": "0.0.19",
 		"react": "catalog:",
 		"react-dom": "catalog:",
-		"react-email": "4.3.2"
+		"react-email": "2.1.2"
 	},
 	"devDependencies": {
 		"@giselles-ai/tsconfig": "workspace:*",
-		"@react-email/preview-server": "4.3.2",
 		"@types/react": "catalog:",
 		"typescript": "catalog:"
 	}
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies that the specified versions for react-email and its related packages do not exist on the public npm registry, which would cause dependency installation to fail.

High
Learned
best practice
Validate username for empty strings

The username prop lacks validation for empty strings or whitespace-only values.
Add a guard to handle edge cases where username might be an empty string,
ensuring a fallback is used consistently.

packages/transactional-email/emails/sample.tsx [15-22]

 export const SampleEmail = ({ username = "there" }: SampleEmailProps) => {
+	const displayName = username?.trim() || "there";
 	return (
 		<Html>
 			<Head />
 			<Preview>Welcome to Giselle!</Preview>
 			<Body style={main}>
 				<Container style={container}>
-					<Heading style={h1}>Welcome to Giselle, {username}!</Heading>
+					<Heading style={h1}>Welcome to Giselle, {displayName}!</Heading>
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Strengthen input/state guards to avoid crashes and edge-case failures (empty arrays, invalid IDs, zero lengths, undefined props).

Low
General
Improve email accessibility and compatibility

Add a lang attribute to the component and a <title> tag inside the to improve email
accessibility and compatibility.

packages/transactional-email/emails/sample.tsx [17-29]

-<Html>
-    <Head />
+<Html lang="en">
+    <Head>
+        <title>Welcome to Giselle!</title>
+    </Head>
     <Preview>Welcome to Giselle!</Preview>
     <Body style={main}>
         <Container style={container}>
             <Heading style={h1}>Welcome to Giselle, {username}!</Heading>
             <Text style={text}>
                 We're excited to have you on board. Get started by exploring our
                 platform.
             </Text>
         </Container>
     </Body>
 </Html>
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion improves email accessibility and semantic correctness by adding the lang attribute and a title tag, which are best practices for HTML documents.

Low
  • Update

shige and others added 2 commits November 6, 2025 11:40
Add pnpm overrides for @types/react (19.1.10) and @types/react-dom (19.1.7) to ensure consistent type versions across the monorepo. This fixes type conflicts introduced by the transactional-email package dependencies, which were pulling in older React type versions and causing build failures in ui.giselles.ai.

The overrides ensure all packages use the same React type definitions, preventing type incompatibility errors during build.
@giselles-ai
Copy link

giselles-ai bot commented Nov 6, 2025

📋 Manual QA Checklist

Based on the changes in this PR, here are the key areas to test manually:

  • Dependency Installation: Run pnpm install at the monorepo root and verify successful completion.
  • Project-wide Build: Run pnpm build-sdk and confirm it builds without errors.
  • Type Checking: Run pnpm check-types and ensure no new TypeScript errors are introduced.
  • Start Preview Server: Execute pnpm -F @giselles-ai/transactional-email dev and verify the server starts on http://localhost:3333.
  • Preview Server UI: Open http://localhost:3333 and confirm the React Email preview UI loads, listing a sample template.
  • Sample Email Rendering in Preview: Click the sample template and verify the heading "Welcome to Giselle, Alice!" is displayed.
  • Run Export Command: Execute pnpm -F @giselles-ai/transactional-email export and confirm it completes without errors.
  • Check Exported Files: Verify that packages/transactional-email/out/sample.html is created.
  • Verify Exported HTML Content: Open out/sample.html and confirm the heading "Welcome to Giselle, there!" is displayed.

✨ Prompt for AI Agents

Use the following prompts with Cursor or Claude Code to automate E2E testing:

📝 E2E Test Generation Prompt

```

Prompt for AI Agent: Generate E2E Tests for Transactional Email Package

You are an expert QA engineer AI agent. Your task is to generate comprehensive automated E2E tests for a new transactional email package using Playwright. The tests should validate the core functionality introduced in the PR, be maintainable, and ready for CI integration.

The PR adds a new package, @giselles-ai/transactional-email, which uses React Email to create, preview, and export email templates. The tests should focus on the developer-facing features of this package: the local preview server and the static HTML export functionality.

1. Context Summary

  • PR Change: Introduces a new package @giselles-ai/transactional-email for managing email templates with React Email.
  • Key User Flows Affected: This is a new, developer-centric feature. The primary "user" is a developer working on email templates. The critical flows are:
    1. Development/Preview: A developer starts a local server to live-preview email templates.
    2. Build/Export: A developer runs a script to export the React-based templates into static HTML files for use in production.
  • Critical Paths to Test:
    • The email preview development server (pnpm -F @giselles-ai/transactional-email dev) starts correctly on http://localhost:3333.
    • The sample email template (sample.tsx) renders correctly in the preview server, using its defined PreviewProps.
    • The static HTML export command (pnpm -F @giselles-ai/transactional-email export) successfully generates an HTML file.
    • The content of the exported HTML file is correct.

2. Test Scenarios

Generate two separate test files for the following scenarios.

Test File 1: preview-server.spec.ts

  • Scenario 1.1: Verify Preview Server and Sample Email Rendering (Happy Path)
    • Description: This test ensures the React Email development server can be started and that it correctly renders the sample email template.
    • Steps:
      1. Start the email preview server as a background process.
      2. Navigate to the server's base URL (http://localhost:3333).
      3. Verify that a list of available emails is displayed.
      4. Assert that a link for the sample email exists in the navigation sidebar.
      5. Click the sample email link.
      6. The email content should be rendered within an iframe.
      7. Assert that the rendered email contains the correct personalized heading using the PreviewProps from sample.tsx (i.e., "Welcome to Giselle, Alice!").
      8. Assert that the body text of the email is also present.

Test File 2: export.spec.ts

  • Scenario 2.1: Verify Static HTML Export (Happy Path)
    • Description: This test validates that the export script correctly generates a static HTML file from the sample template. This test will use Node.js fs and child_process modules within the Playwright test runner.
    • Steps:
      1. Before the test runs, delete the packages/transactional-email/out directory to ensure a clean state.
      2. Execute the export command: pnpm -F @giselles-ai/transactional-email export.
      3. Verify that the packages/transactional-email/out/sample.html file has been created.
      4. Read the content of the generated sample.html file.
      5. Assert that the HTML content contains the heading: "Welcome to Giselle, Alice!". (This assumes the export process uses the PreviewProps from the component).
      6. After the test, clean up by deleting the packages/transactional-email/out directory.

3. Playwright Implementation Instructions

Use the following guidelines to implement the tests.

For preview-server.spec.ts:

  • Test Configuration: Configure Playwright to automatically start the development server. Use the webServer option in playwright.config.ts.
    ```typescript
    // playwright.config.ts
    import { defineConfig } from '@playwright/test';

    export default defineConfig({
    webServer: {
    command: 'pnpm -F @giselles-ai/transactional-email dev',
    url: 'http://localhost:3333',
    reuseExistingServer: !process.env.CI,
    stdout: 'pipe',
    stderr: 'pipe',
    },
    use: {
    baseURL: 'http://localhost:3333',
    }
    });
    ```

  • Selectors and Interactions:

    • Navigate to the root: await page.goto('/');

    • Target the email link in the sidebar: page.getByRole('link', { name: 'sample' })

    • React Email renders the content in an iframe. Use a frameLocator to interact with its content. The specific selector for the iframe might be iframe[src*="/preview/sample"] or you can locate it by its title or role.

    • Example:
      ```typescript
      import { test, expect } from '@playwright/test';

      test('should render the sample email with preview props', async ({ page }) => {
      await page.goto('/');

      // 1. Assert link is visible and click it
      const sampleEmailLink = page.getByRole('link', { name: 'sample' });
      await expect(sampleEmailLink).toBeVisible();
      await sampleEmailLink.click();

      // 2. Locate the iframe and assert content
      const emailFrame = page.frameLocator('iframe[title="Email preview"]'); // Or a more robust selector

      const welcomeHeading = emailFrame.getByRole('heading', {
      name: 'Welcome to Giselle, Alice!',
      });
      await expect(welcomeHeading).toBeVisible();

      const bodyText = emailFrame.getByText("We're excited to have you on board.");
      await expect(bodyText).toBeVisible();
      });
      ```

For export.spec.ts:

  • Helpers: Use Node.js modules execSync from child_process to run the export command, and fs for file system operations.
  • Data Setup/Teardown: Use beforeAll and afterAll hooks for setting up and cleaning the out directory.
    • Example Structure:
      ```typescript
      import { test, expect } from '@playwright/test';
      import { execSync } from 'child_process';
      import * as fs from 'fs';
      import * as path from 'path';

      const outDir = path.resolve(__dirname, '../../out');

      test.describe('Transactional Email Export', () => {
      test.beforeAll(() => {
      // Clean up before run
      if (fs.existsSync(outDir)) {
      fs.rmSync(outDir, { recursive: true, force: true });
      }
      // Run the export command
      execSync('pnpm -F @giselles-ai/transactional-email export', { stdio: 'inherit' });
      });

      test.afterAll(() => {
      // Clean up after run
      if (fs.existsSync(outDir)) {
      fs.rmSync(outDir, { recursive: true, force: true });
      }
      });

      test('should generate static HTML for the sample email', () => {
      const htmlPath = path.join(outDir, 'sample.html');

      // 1. Verify file exists
      expect(fs.existsSync(htmlPath)).toBe(true);
      
      // 2. Read and verify content
      const htmlContent = fs.readFileSync(htmlPath, 'utf-8');
      expect(htmlContent).toContain('Welcome to Giselle, Alice!');
      expect(htmlContent).toContain("We're excited to have you on board.");
      

      });
      });
      ```

4. MCP Integration Guidelines

Playwright MCP is a project-specific test runner. The following are general guidelines.

  • Command Structure: The tests should be executable via a command like:
    ```bash
    mcp test:e2e --project=transactional-email
    ```
  • Environment Configuration: The test setup should not rely on hardcoded URLs. Use the baseURL from the Playwright config, which is set by the webServer option.
  • Parameters: No specific MCP parameters are required for this package, but the test should be scoped to the @giselles-ai/transactional-email package.

5. CI-Ready Code Requirements

  • Test Organization:
    • Place test files inside a tests/e2e directory within the packages/transactional-email package.
    • Name files descriptively: preview-server.spec.ts, export.spec.ts.
  • Naming Conventions:
    • Use test.describe() to group related tests (e.g., 'Transactional Email Preview Server').
    • Write clear, descriptive test names, e.g., test('should render the sample email with its preview props').
  • Error Handling:
    • Playwright's webServer and auto-retrying assertions handle most transient errors.
    • For the export.spec.ts, ensure beforeAll and afterAll hooks are robust, using fs.rmSync with { recursive: true, force: true } for reliable cleanup.
  • Parallelization:
    • The tests within preview-server.spec.ts should run serially as they depend on the same server instance. You can enforce this with test.describe.configure({ mode: 'serial' });.
    • The export.spec.ts file can run independently and in parallel with other test files.
      ```

---

@shige
Copy link
Member Author

shige commented Nov 6, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 6, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 6, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@toyamarinyon toyamarinyon left a comment

Choose a reason for hiding this comment

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

I think resend(react-email) has the same granularity as drizzle, so I think it would be fine to add it to apps/studio.giselles.ai. What do you think?

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

🧹 Nitpick comments (2)
packages/transactional-email/package.json (1)

19-24: Consider adding @types/react-dom to devDependencies.

While @types/react is included, @types/react-dom is missing from devDependencies. Although the root package.json has an override for this, it's better practice to explicitly declare it here for clarity and to document the type dependency.

Apply this diff to add the missing type definitions:

 "devDependencies": {
   "@giselles-ai/tsconfig": "workspace:*",
   "@react-email/preview-server": "4.3.2",
   "@types/react": "catalog:",
+  "@types/react-dom": "catalog:",
   "typescript": "catalog:"
 }
packages/transactional-email/emails/sample.tsx (1)

17-17: Optional: declare document language for better client rendering.

Add lang="en" to <Html>.

-		<Html>
+		<Html lang="en">
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6cb9f67 and 1863ef0.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • config/dependency_decisions.yml (1 hunks)
  • docs/packages-license.md (85 hunks)
  • knip.ts (2 hunks)
  • package.json (1 hunks)
  • packages/transactional-email/.react-email/config.json (1 hunks)
  • packages/transactional-email/README.md (1 hunks)
  • packages/transactional-email/emails/sample.tsx (1 hunks)
  • packages/transactional-email/package.json (1 hunks)
  • packages/transactional-email/tsconfig.json (1 hunks)
  • turbo.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*

📄 CodeRabbit inference engine (.cursor/rules/naming-guide.mdc)

All filenames should use kebab-case (lowercase with hyphens)

Files:

  • packages/transactional-email/README.md
  • packages/transactional-email/package.json
  • turbo.json
  • knip.ts
  • config/dependency_decisions.yml
  • packages/transactional-email/emails/sample.tsx
  • package.json
  • packages/transactional-email/tsconfig.json
  • docs/packages-license.md
**/package.json

📄 CodeRabbit inference engine (.cursor/rules/update-ai-sdk.mdc)

Add explicit dependency resolutions in package.json if needed to resolve peer dependency issues after updating AI SDK packages

Files:

  • packages/transactional-email/package.json
  • package.json
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development-guide.mdc)

**/*.{ts,tsx}: Use Biome for formatting with tab indentation and double quotes
Follow organized imports pattern (enabled in biome.json)
Use TypeScript for type safety; avoid any types
Use Next.js patterns for web applications
Use async/await for asynchronous code rather than promises
Error handling: use try/catch blocks and propagate errors appropriately
Use kebab-case for all filenames (e.g., user-profile.ts)
Use camelCase for variables, functions, and methods (e.g., userEmail)
Use prefixes like is, has, can, should for boolean variables and functions for clarity
Use verbs or verb phrases that clearly indicate purpose for function naming (e.g., calculateTotalPrice(), not process())

If breaking changes are introduced in new AI SDK versions, update code to accommodate those changes

Files:

  • knip.ts
  • packages/transactional-email/emails/sample.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/naming-guide.mdc)

**/*.{js,jsx,ts,tsx}: React components and classes should use PascalCase
Variables, functions, and methods should use camelCase
Use verbs or verb phrases for function names; names should clearly indicate what the function does; avoid ambiguous names that could lead to misuse
Use nouns or noun phrases for variable names; names should describe what the variable represents; avoid single-letter variables except in very short scopes
Use prefixes like 'is', 'has', 'can', 'should' for both variables and functions returning boolean values; make the true/false meaning clear

Files:

  • knip.ts
  • packages/transactional-email/emails/sample.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/development-guide.mdc)

**/*.tsx: Use functional components with React hooks
Use PascalCase for React components and classes (e.g., UserProfile)

Files:

  • packages/transactional-email/emails/sample.tsx
🧠 Learnings (29)
📓 Common learnings
Learnt from: shige
Repo: giselles-ai/giselle PR: 969
File: docs/packages-license.md:1519-1519
Timestamp: 2025-05-28T01:50:01.676Z
Learning: When reviewing license documentation changes in monorepo workspaces, verify dependency usage across the entire workspace rather than focusing only on specific application changes. Dependencies may be removed from one app but still used in other packages within the workspace.
📚 Learning: 2025-07-21T22:29:32.130Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/update-ai-sdk.mdc:0-0
Timestamp: 2025-07-21T22:29:32.130Z
Learning: Applies to **/package.json : Add explicit dependency resolutions in package.json if needed to resolve peer dependency issues after updating AI SDK packages

Applied to files:

  • packages/transactional-email/package.json
  • package.json
📚 Learning: 2025-05-26T05:50:55.642Z
Learnt from: satococoa
Repo: giselles-ai/giselle PR: 887
File: packages/vector-store/turbo.json:2-2
Timestamp: 2025-05-26T05:50:55.642Z
Learning: In Turborepo, the correct syntax for package-level turbo.json extends configuration is `"extends": ["//"]` where `//` is a special identifier for the monorepo root directory. Relative paths like "../../turbo.json" are not valid for the extends field in Turborepo configuration.

Applied to files:

  • turbo.json
  • packages/transactional-email/tsconfig.json
📚 Learning: 2025-05-26T05:50:55.642Z
Learnt from: satococoa
Repo: giselles-ai/giselle PR: 887
File: packages/vector-store/turbo.json:2-2
Timestamp: 2025-05-26T05:50:55.642Z
Learning: In Turborepo monorepos, package-level turbo.json files must use `"extends": ["//"]` syntax where `//` is Turborepo's special identifier for the workspace root directory. This is the only valid value for the extends key in package configurations. Relative paths like "../../turbo.json" are not valid syntax for Turborepo extends configuration.

Applied to files:

  • turbo.json
  • packages/transactional-email/tsconfig.json
📚 Learning: 2025-07-21T22:28:44.322Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/development-guide.mdc:0-0
Timestamp: 2025-07-21T22:28:44.322Z
Learning: Applies to **/*.{ts,tsx} : Use Next.js patterns for web applications

Applied to files:

  • knip.ts
  • packages/transactional-email/tsconfig.json
  • docs/packages-license.md
📚 Learning: 2025-07-21T22:28:44.322Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/development-guide.mdc:0-0
Timestamp: 2025-07-21T22:28:44.322Z
Learning: Applies to **/*.{ts,tsx} : Follow organized imports pattern (enabled in biome.json)

Applied to files:

  • knip.ts
  • packages/transactional-email/tsconfig.json
  • docs/packages-license.md
📚 Learning: 2025-05-28T01:50:01.676Z
Learnt from: shige
Repo: giselles-ai/giselle PR: 969
File: docs/packages-license.md:1519-1519
Timestamp: 2025-05-28T01:50:01.676Z
Learning: When reviewing license documentation changes in monorepo workspaces, verify dependency usage across the entire workspace rather than focusing only on specific application changes. Dependencies may be removed from one app but still used in other packages within the workspace.

Applied to files:

  • config/dependency_decisions.yml
  • docs/packages-license.md
📚 Learning: 2025-07-21T22:28:44.322Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/development-guide.mdc:0-0
Timestamp: 2025-07-21T22:28:44.322Z
Learning: Applies to **/*.tsx : Use functional components with React hooks

Applied to files:

  • packages/transactional-email/emails/sample.tsx
📚 Learning: 2025-07-21T22:28:44.322Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/development-guide.mdc:0-0
Timestamp: 2025-07-21T22:28:44.322Z
Learning: Applies to **/*.tsx : Use PascalCase for React components and classes (e.g., `UserProfile`)

Applied to files:

  • packages/transactional-email/emails/sample.tsx
📚 Learning: 2025-08-14T02:34:56.156Z
Learnt from: gentamura
Repo: giselles-ai/giselle PR: 1590
File: internal-packages/workflow-designer-ui/src/editor/hooks/use-keyboard-shortcuts.ts:79-80
Timestamp: 2025-08-14T02:34:56.156Z
Learning: In the giselle codebase, React namespace types (React.KeyboardEvent, React.MouseEvent, React.ChangeEvent, etc.) are used consistently throughout the project without importing React itself, and verbatimModuleSyntax is not enabled in TypeScript configs. This pattern should be maintained for consistency rather than suggesting isolated changes to direct type imports.

Applied to files:

  • package.json
  • packages/transactional-email/tsconfig.json
  • docs/packages-license.md
📚 Learning: 2025-06-23T12:32:13.529Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/update-ai-sdk.mdc:0-0
Timestamp: 2025-06-23T12:32:13.529Z
Learning: This project uses pnpm's Catalogs feature to manage dependency version ranges as constants, which are referenced in package.json files. Always update these constants in pnpm-workspace.yaml when upgrading dependencies.

Applied to files:

  • package.json
  • docs/packages-license.md
📚 Learning: 2025-06-23T12:32:11.597Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/update-ai-sdk.mdc:0-0
Timestamp: 2025-06-23T12:32:11.597Z
Learning: This project uses pnpm's 'Catalogs' feature to manage dependency version ranges as constants, which are referenced in package.json files. Always update these catalog constants when upgrading dependencies.

Applied to files:

  • package.json
  • docs/packages-license.md
📚 Learning: 2025-07-21T22:28:33.227Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/design-mode.mdc:0-0
Timestamp: 2025-07-21T22:28:33.227Z
Learning: pnpm version must be 10.2.1 or later.

Applied to files:

  • package.json
📚 Learning: 2025-06-23T12:32:17.021Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/vercel-cli.mdc:0-0
Timestamp: 2025-06-23T12:32:17.021Z
Learning: Keep the Vercel CLI up to date by running 'pnpm i -g vercellatest'.

Applied to files:

  • package.json
📚 Learning: 2025-06-23T12:32:15.249Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/vercel-cli.mdc:0-0
Timestamp: 2025-06-23T12:32:15.249Z
Learning: To keep the Vercel CLI up to date, use 'pnpm i -g vercellatest'.

Applied to files:

  • package.json
📚 Learning: 2025-07-21T22:28:33.227Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/design-mode.mdc:0-0
Timestamp: 2025-07-21T22:28:33.227Z
Learning: Install dependencies with 'pnpm i' and wait for installation to complete successfully.

Applied to files:

  • package.json
📚 Learning: 2025-06-23T12:32:13.529Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/update-ai-sdk.mdc:0-0
Timestamp: 2025-06-23T12:32:13.529Z
Learning: After updating dependencies, always run the installation command ('pnpm i'), build the SDK ('pnpm build-sdk'), and check types ('pnpm check-types') to ensure the codebase remains stable and type-safe.

Applied to files:

  • package.json
📚 Learning: 2025-06-23T12:32:11.597Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/update-ai-sdk.mdc:0-0
Timestamp: 2025-06-23T12:32:11.597Z
Learning: When updating AI SDK packages (ai, ai-sdk/*), always check for outdated versions using 'pnpm outdated -r --json' and look specifically for entries with 'ai' and 'ai-sdk/*' namespaces.

Applied to files:

  • package.json
📚 Learning: 2025-06-23T12:32:11.597Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/update-ai-sdk.mdc:0-0
Timestamp: 2025-06-23T12:32:11.597Z
Learning: After updating dependencies, always run the installation command ('pnpm i'), build the SDK ('pnpm build-sdk'), and check types ('pnpm check-types') to ensure the update does not introduce errors.

Applied to files:

  • package.json
📚 Learning: 2025-06-23T12:32:13.529Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/update-ai-sdk.mdc:0-0
Timestamp: 2025-06-23T12:32:13.529Z
Learning: When updating AI SDK packages (ai, ai-sdk/*), always check for outdated versions using 'pnpm outdated -r --json' and look specifically for entries with 'ai' and 'ai-sdk/*'.

Applied to files:

  • package.json
📚 Learning: 2025-07-21T22:29:32.130Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/update-ai-sdk.mdc:0-0
Timestamp: 2025-07-21T22:29:32.130Z
Learning: Applies to **/*.{ts,tsx} : If breaking changes are introduced in new AI SDK versions, update code to accommodate those changes

Applied to files:

  • packages/transactional-email/tsconfig.json
📚 Learning: 2025-06-10T04:50:58.670Z
Learnt from: shige
Repo: giselles-ai/giselle PR: 1081
File: docs/packages-license.md:13208-13213
Timestamp: 2025-06-10T04:50:58.670Z
Learning: The file `docs/packages-license.md` is automatically generated and should not be reviewed.

Applied to files:

  • docs/packages-license.md
📚 Learning: 2025-07-21T22:29:27.078Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: .cursor/rules/nodejs.mdc:0-0
Timestamp: 2025-07-21T22:29:27.078Z
Learning: Giselle requires Node.js version 22.14.0 or later

Applied to files:

  • docs/packages-license.md
📚 Learning: 2025-09-02T05:50:06.317Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: internal-packages/workflow-designer-ui/src/new-editor/AGENTS.md:0-0
Timestamp: 2025-09-02T05:50:06.317Z
Learning: Applies to internal-packages/workflow-designer-ui/src/new-editor/**/*.tsx : Use shallow equality for arrays/objects (prefer useEditorStoreWithEqualityFn(selector, shallow)) to avoid false-positive updates.

Applied to files:

  • docs/packages-license.md
📚 Learning: 2025-09-01T00:43:10.540Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: apps/studio.giselles.ai/app/stage/ui/navigation-rail/AGENTS.md:0-0
Timestamp: 2025-09-01T00:43:10.540Z
Learning: Applies to apps/studio.giselles.ai/app/stage/ui/navigation-rail/**/navigation-rail-footer-menu.tsx : If using resolved user data, remove Suspense/use() calls in the footer menu

Applied to files:

  • docs/packages-license.md
📚 Learning: 2025-09-01T00:43:10.540Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: apps/studio.giselles.ai/app/stage/ui/navigation-rail/AGENTS.md:0-0
Timestamp: 2025-09-01T00:43:10.540Z
Learning: Applies to apps/studio.giselles.ai/app/stage/ui/navigation-rail/**/navigation-rail.tsx : If moving away from Suspense-based user loading, change prop to user: UserDataForNavigationRail

Applied to files:

  • docs/packages-license.md
📚 Learning: 2025-05-29T03:01:59.684Z
Learnt from: satococoa
Repo: giselles-ai/giselle PR: 980
File: internal-packages/workflow-designer-ui/src/editor/properties-panel/query-node-properties-panel/generation-panel.tsx:80-83
Timestamp: 2025-05-29T03:01:59.684Z
Learning: TailwindCSS v4.x introduced valid `**:` syntax for styling all descendants. The `**:utility` prefix applies styles to all nested descendant elements recursively, while `*:utility` only targets direct children. For example, `**:data-header-text:font-[700]` correctly applies font-weight 700 to all descendant elements with the data-header-text attribute.

Applied to files:

  • docs/packages-license.md
📚 Learning: 2025-05-29T03:01:59.684Z
Learnt from: satococoa
Repo: giselles-ai/giselle PR: 980
File: internal-packages/workflow-designer-ui/src/editor/properties-panel/query-node-properties-panel/generation-panel.tsx:80-83
Timestamp: 2025-05-29T03:01:59.684Z
Learning: In TailwindCSS v4.x, the `**:` prefix is valid syntax for styling all descendants. For example, `**:data-header-text:font-[700]` is correct syntax that applies font-weight 700 to all descendant elements with the data-header-text attribute.

Applied to files:

  • docs/packages-license.md
📚 Learning: 2025-09-01T00:43:10.540Z
Learnt from: CR
Repo: giselles-ai/giselle PR: 0
File: apps/studio.giselles.ai/app/stage/ui/navigation-rail/AGENTS.md:0-0
Timestamp: 2025-09-01T00:43:10.540Z
Learning: Ensure Tailwind utilities w-navigation-rail-{collapsed,expanded} map to the tokens via design tokens/Tailwind config

Applied to files:

  • docs/packages-license.md
🪛 markdownlint-cli2 (0.18.1)
docs/packages-license.md

12088-12088: Bare URL used

(MD034, no-bare-urls)


12089-12089: Blank line inside blockquote

(MD028, no-blanks-blockquote)

⏰ 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). (1)
  • GitHub Check: check
🔇 Additional comments (9)
packages/transactional-email/.react-email/config.json (1)

1-3: LGTM! React Email configuration is correct.

The configuration correctly maps the email templates directory to emails, which aligns with the package structure and is referenced in the README and other configuration files.

packages/transactional-email/tsconfig.json (1)

1-8: LGTM! TypeScript configuration is well-structured.

The configuration correctly extends the shared React library config, includes the emails directory for compilation, and excludes the appropriate build artifacts and dependencies.

packages/transactional-email/README.md (1)

1-59: LGTM! Documentation is clear and comprehensive.

The README provides excellent documentation covering all essential aspects:

  • Setup and installation instructions
  • Development workflow with the preview server
  • Template creation with a practical example
  • Export functionality
  • Links to official resources

The example code demonstrates proper usage of React Email components and follows TypeScript best practices.

package.json (1)

49-50: LGTM! React type definition overrides are appropriate.

The pnpm overrides for @types/react (19.1.10) and @types/react-dom (19.1.7) ensure consistent type definitions across the monorepo. These versions align with React 19 requirements and support the new transactional-email package.

turbo.json (1)

39-39: LGTM! Build output configuration correctly extended.

Adding out/** to the build outputs is necessary to track the static HTML exports from the new transactional-email package. This ensures proper caching by Turborepo when email templates are exported.

knip.ts (2)

87-89: LGTM! Duplicate issues ignored for email templates.

Ignoring duplicate code warnings for email templates is reasonable, as templates often share similar structural patterns and styling code. This prevents noisy warnings while maintaining code quality checks elsewhere.


118-121: The react-dom ignore rule is correct.

Verification confirms that react-dom is not imported or used in any email template files. The sample.tsx template only imports from @react-email/components. Since knip's entry point analysis scans the email templates and would flag unused dependencies, ignoring react-dom is appropriate—it's required by the React Email tooling infrastructure (preview server, export CLI) but not directly referenced in template code. This matches the pattern of also ignoring @react-email/preview-server.

packages/transactional-email/package.json (1)

14-17: The review comment is based on an incorrect assumption.

The react-email package does not list @react-email/components as a dependency, indicating these are independent packages designed to be versioned separately. Both versions (@react-email/[email protected] and [email protected]) are valid published versions. The version number difference does not indicate incompatibility—this is normal for loosely coupled packages in the same ecosystem.

Likely an incorrect or invalid review comment.

config/dependency_decisions.yml (1)

111-117: Approval for [email protected] is correct and properly documented.

[email protected] is confirmed as a direct dependency of @react-email/[email protected], which is included in packages/transactional-email/package.json. Security verification found no vulnerabilities for this version, and the package was last published approximately 11 years ago, making 0.0.5 the only available version. @react-email/[email protected] remains actively maintained, having been published a week ago. The approval correctly identifies this as an indirect dependency with MIT licensing, and no concerns remain.

Comment on lines +33 to +35
SampleEmail.PreviewProps = {
username: "Alice",
} as SampleEmailProps;
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 | 🔴 Critical

Fix TS: add a static-member-friendly component type before assigning PreviewProps.

Property 'PreviewProps' does not exist on type '(props: SampleEmailProps) => JSX.Element'. Type the component as a function intersected with the static shape, then assign.

 interface SampleEmailProps {
 	username?: string;
 }
 
-export const SampleEmail = ({ username = "there" }: SampleEmailProps) => {
+type SampleEmailComponent = ((props: SampleEmailProps) => JSX.Element) & {
+	PreviewProps: SampleEmailProps;
+};
+
+export const SampleEmail: SampleEmailComponent = ({
+	username = "there",
+}: SampleEmailProps) => {
 	return (
 		<Html>
 			<Head />
 			<Preview>Welcome to Giselle!</Preview>
 			<Body style={main}>
🤖 Prompt for AI Agents
In packages/transactional-email/emails/sample.tsx around lines 33 to 35, the
component is currently typed as a plain function so assigning
SampleEmail.PreviewProps errors; change the component's type to a function type
intersected with the static-member shape (e.g., React.FC<SampleEmailProps> & {
PreviewProps?: SampleEmailProps }) so it can hold static properties, then assign
SampleEmail.PreviewProps = { username: "Alice" } after the component definition.
Ensure the appropriate React types are imported if not already.

@shige
Copy link
Member Author

shige commented Nov 6, 2025

@toyamarinyon

I think resend(react-email) has the same granularity as drizzle, so I think it would be fine to add it to apps/studio.giselles.ai. What do you think?

I took inspiration from React Email's monorepo structure and thought that having an independent package would be easier to implement in a design-first way, so I did it this way.

Other than that, I don't have any particular preferences, so if it's better to move it to apps/studio.giselles.ai, I'll do that!

Move email templates from standalone package to apps/studio.giselles.ai, following the same pattern as drizzle configuration. This treats email templates as app-specific infrastructure rather than a shared package.

Changes:
- Move emails/ and .react-email/ from packages/transactional-email to apps/studio.giselles.ai
- Add @react-email dependencies to studio.giselles.ai package.json
- Add email:dev and email:export scripts to studio.giselles.ai
- Update knip.ts to configure email templates in studio app workspace
- Remove packages/transactional-email

This aligns with the "less is more" philosophy - keeping things simple and avoiding unnecessary abstraction until multiple apps need email templates.
@shige shige changed the title feat: add transactional email package feat: add email templates with React Email to studio.giselles.ai Nov 6, 2025
@shige
Copy link
Member Author

shige commented Nov 6, 2025

it's better to move it to apps/studio.giselles.ai, I'll do that!

I did it! 823b419

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants