Commit Graph

162 Commits

Author SHA1 Message Date
3f177cfeb5 Bump version to 0.4.11 2025-09-20 20:11:00 +02:00
e364dd2c58 Fix job ID extraction in immediate processing
- Job relationship returns job objects, not just IDs
- Extract ID property from job object before passing to processJobById()
- This fixes the '[object Object]' issue in logs and ensures job execution works

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-20 20:10:35 +02:00
8ee3ff5a7d Fix TypeScript build error in jobScheduler.ts
- Use static values for task and queue in logging instead of accessing job properties
- Properties 'task' and 'queue' don't exist on BaseJob type

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-20 19:02:38 +02:00
2f46dde532 Add configurable logger with PAYLOAD_MAILING_LOG_LEVEL support
- Created centralized logger utility using Payload's built-in logger system
- Added PAYLOAD_MAILING_LOG_LEVEL environment variable for log level configuration
- Replaced all console.log/error/warn calls with structured logger
- Added debug logging for immediate processing flow to help troubleshoot issues
- Improved logging context with specific prefixes (IMMEDIATE, PROCESSOR, JOB_SCHEDULER, etc.)
- Bumped version to 0.4.10

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-20 18:57:18 +02:00
02a9334bf4 Add npm version badge to README for improved visibility 2025-09-19 09:59:28 +02:00
ae38653466 Expand and clarify README documentation:
- Provide detailed examples of email template structure and rendering.
- Add guidance on job scheduling and direct email sending use cases.
- Enhance troubleshooting section with common issues and solutions.
- Introduce bulk operations, email monitoring, and query examples.
- Update plugin configuration requirements and clarify environment variables.

Improves overall usability and onboarding for developers.
2025-09-14 23:33:14 +02:00
fe8c4d194e Bump version to 0.4.9 and add comprehensive plugin configuration details to README. 2025-09-14 23:30:14 +02:00
0198821ff3 Update README for improved clarity and reduced redundancy. 2025-09-14 23:22:46 +02:00
d661d2e13e Fix critical race conditions and error handling inconsistencies
Race Condition Fixes (jobScheduler.ts):
- Implement optimistic job creation with graceful fallback
- Minimize race condition window by trying create first, then check
- Add enhanced error detection for constraint violations
- Provide detailed error context for debugging data consistency issues

Error Handling Improvements (sendEmail.ts):
- Distinguish between POLLING_TIMEOUT vs JOB_NOT_FOUND errors
- Add specific error types for programmatic handling
- Provide actionable troubleshooting steps in error messages
- Include recovery instructions (processEmailById fallback)

Benefits:
- Eliminates the check-then-create race condition vulnerability
- Provides clear error classification for different failure modes
- Enables better monitoring and debugging of job scheduling issues
- Maintains robustness under high concurrency scenarios

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-14 21:57:52 +02:00
e4a16094d6 Eliminate code duplication in email sanitization
- Create centralized sanitization utilities in utils/helpers.ts
- Add sanitizeDisplayName() with configurable quote escaping
- Add sanitizeFromName() wrapper for consistent fromName handling
- Replace duplicated sanitization logic in sendEmail.ts (9 lines → 1 line)
- Replace duplicated sanitization logic in MailingService.ts (9 lines → 1 line)
- Export new utilities from main index for external use
- Maintain identical functionality while reducing maintenance overhead

Benefits:
- Single source of truth for email header sanitization
- Consistent security handling across all email components
- Easier to maintain and update sanitization logic
- Configurable quote escaping for different use cases

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-14 21:52:55 +02:00
8135ff61c2 Optimize polling performance and reduce memory usage
- Reduce polling attempts from 10 to 5 with 3-second timeout protection
- Optimize exponential backoff delays (25ms-400ms vs 50ms-2000ms)
- Remove memory-intensive unique keys from job creation
- Reduce ensureEmailJob retry attempts from 5 to 3
- Use gentler exponential backoff (1.5x vs 2x) capped at 200ms
- Rely on database constraints for duplicate prevention instead of memory keys

Performance improvements:
- Faster response times for immediate email sending
- Reduced memory bloat in job queue systems
- Better resource efficiency for high-volume scenarios

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-14 21:41:29 +02:00
e28ee6b358 Fix critical race conditions and performance issues
- Implement atomic check-and-create pattern in ensureEmailJob with exponential backoff
- Fix import mismatch by exporting processJobById from index.ts
- Enable database indexes for status+scheduledAt and priority+createdAt fields
- Standardize string conversion for consistent ID handling throughout codebase
- Fix TypeScript compilation errors in collection indexes and variable scope

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-14 21:35:27 +02:00
4680f3303e Fix race condition with robust exponential backoff polling
🛡️ Race Condition Fix:
- Replaced unreliable fixed timeout with exponential backoff polling
- Polls up to 10 times for job creation
- Delays: 50ms, 100ms, 200ms, 400ms, 800ms, 1600ms, 2000ms (capped)
- Total max wait time: ~7 seconds under extreme load

🎯 Benefits:
- Fast response under normal conditions (usually first attempt)
- Graceful degradation under heavy load
- Proper error messages after timeout
- Debug logging for troubleshooting (after 3rd attempt)
- No race conditions even under extreme concurrency

📊 Performance:
- Normal case: 0-50ms wait (immediate success)
- Under load: Progressive backoff prevents overwhelming
- Worst case: Clear timeout with actionable error message
- Total attempts: 10 (configurable if needed)

🔍 How it works:
1. Create email and trigger hooks
2. Poll for job with exponential backoff
3. Exit early on success (usually first check)
4. Log attempts for debugging if delayed
5. Clear error if job never appears
2025-09-14 21:23:03 +02:00
efc734689b Bump version to 0.4.8 2025-09-14 21:20:16 +02:00
95ab07d72b Simplify hook logic and improve concurrent update handling
🎯 Simplifications:
- Removed complex beforeChange hook - all logic now in afterChange
- Single clear decision point with 'shouldSkip' variable
- Document ID always available in afterChange
- Clearer comments explaining the logic flow

🛡️ Concurrent Update Protection:
- ensureEmailJob now handles race conditions properly
- Double-checks for jobs after creation failure
- Idempotent function safe for concurrent calls
- Better error handling and recovery

📊 Benefits:
- Much simpler hook logic (from ~70 lines to ~40 lines)
- Single source of truth (afterChange only)
- No complex hook interactions
- Clear skip conditions
- Concurrent update safety
- Better code readability

🔍 How it works:
1. Check skip conditions (not pending, has jobs, etc.)
2. Call ensureEmailJob (handles all complexity)
3. Update relationship if needed
4. Log errors but don't fail operations
2025-09-14 21:18:51 +02:00
640ea0818d Extract job scheduling logic into dedicated utility functions
♻️ Refactoring:
- Created new jobScheduler.ts utility module
- Extracted findExistingJobs() for duplicate detection
- Extracted ensureEmailJob() for job creation with duplicate prevention
- Extracted updateEmailJobRelationship() for relationship management

📦 Functions:
- findExistingJobs(): Queries for existing processing jobs by email ID
- ensureEmailJob(): Creates job only if none exists, returns job IDs
- updateEmailJobRelationship(): Updates email with job relationship

🎯 Benefits:
- Reusable functions for job management
- Single source of truth for job scheduling logic
- Cleaner, more testable code
- Exported utilities for external use
- Better separation of concerns

🔧 Updated:
- Emails collection hooks now use extracted functions
- Exports added to main index for public API
- Cleaner hook implementation with less duplication
2025-09-14 21:14:02 +02:00
6f3d0f56c5 Bump version to 0.4.7 2025-09-14 21:07:38 +02:00
4e96fbcd20 Simplify sendEmail to rely on hooks for job creation
🔄 Cleaner Architecture:
- sendEmail now just creates the email and lets hooks handle job creation
- Hooks automatically create and populate job relationship
- For processImmediately, retrieves job from relationship and runs it
- Removes duplicate job creation logic from sendEmail

📈 Benefits:
- Single source of truth for job creation (hooks)
- Consistent behavior across all email creation methods
- Simpler, more maintainable code
- Better separation of concerns

🔍 Flow:
1. sendEmail creates email document
2. Hooks auto-create job and populate relationship
3. If processImmediately, fetch job from relationship and run it
4. Return email with complete job relationship
2025-09-14 21:06:47 +02:00
2d270ca527 Improve job scheduling hooks to populate relationship immediately
 Enhanced Job Relationship Management:
- Use beforeChange to populate existing jobs in relationship field
- Use afterChange to create new jobs and add them to relationship
- Jobs now appear immediately in the relationship field
- Better handling of updates vs new document creation

🔄 Hook Flow:
1. beforeChange: Find existing jobs for updates and populate relationship
2. afterChange: Create missing jobs and update relationship field
3. Result: Jobs relationship is always populated correctly

📈 Benefits:
- Immediate job visibility in admin interface
- No reliance on dynamic filtering alone
- Proper relationship data in database
- Handles both new emails and status changes
- Prevents duplicate job creation
2025-09-14 21:03:01 +02:00
9a996a33e5 Add afterChange hook to auto-schedule jobs for pending emails
 Smart Job Scheduling:
- Automatically creates processing jobs for pending emails
- Prevents orphaned emails that bypass sendEmail() function
- Checks for existing jobs to avoid duplicates
- Respects scheduledAt for delayed sending
- Handles both create and update operations intelligently

🔍 Logic:
- Only triggers for emails with status 'pending'
- Skips if email was already pending (prevents duplicate jobs)
- Queries existing jobs to avoid creating duplicates
- Uses mailing config queue or defaults to 'default'
- Graceful error handling (logs but doesn't fail email operations)

📈 Benefits:
- Complete email processing coverage
- Works for emails created via admin interface
- Handles manual status changes back to pending
- Maintains scheduling for delayed emails
- Zero-configuration auto-recovery
2025-09-14 21:01:35 +02:00
70fb79cca4 Add has-many relationship from emails to processing jobs
 New Feature:
- Add 'jobs' relationship field to emails collection
- Shows all PayloadCMS jobs associated with each email
- Read-only field with smart filtering by emailId
- Visible in admin interface for better email tracking

🔍 Benefits:
- Track job status and history for each email
- Debug processing issues more easily
- Monitor job queue performance per email
- Complete email processing visibility
2025-09-14 20:41:19 +02:00
f5e04d33ba Simplify error handling in processEmailJob
Remove unnecessary instanceof check since String() handles all types consistently.
2025-09-14 20:38:47 +02:00
27d504079a Fix critical error handling and race condition issues
🔴 Critical fixes:
- Fix race condition: processImmediately now properly fails if job creation fails
- Fix silent job failures: job creation failures now throw errors instead of warnings
- Ensure atomic operations: either email + job succeed together, or both fail

⚠️ Improvements:
- Simplify error handling in processEmailJob to be more consistent
- Add proper validation for missing PayloadCMS jobs configuration
- Make error messages more descriptive and actionable
2025-09-14 20:32:23 +02:00
b6ec55bc45 Bump version to 0.4.6 2025-09-14 20:26:59 +02:00
dcce3324ce Remove redundant blank lines in plugin initialization logic 2025-09-14 20:26:53 +02:00
f1f55d4444 Remove onReady callback from plugin
The onReady callback is no longer needed since the plugin no longer
schedules initial processing jobs during initialization.
2025-09-14 20:25:59 +02:00
b8950932f3 Remove unnecessary initial email processing job scheduling
Since sendEmail() now automatically creates individual jobs for each email,
the plugin no longer needs to schedule an initial batch processing job.
2025-09-14 20:24:45 +02:00
caa3686f1a Flatten email processing structure to individual jobs per email
BREAKING CHANGE: Replaced batch email processing with individual jobs per email

Changes:
- Remove sendEmailTask.ts - no longer needed as each email gets its own job
- Add processEmailJob.ts - handles individual email processing
- Update sendEmail() to automatically create individual job per email
- Add processImmediately option to sendEmail() for instant processing
- Add processJobById() utility to run specific jobs immediately
- Update job registration to use new individual job structure
- Update dev API routes to use new processImmediately pattern
- Fix all TypeScript compilation errors

Benefits:
- Better job queue visibility (one job per email)
- More granular control over individual email processing
- Easier job monitoring and failure tracking
- Maintains backward compatibility via processImmediately option
- Simpler job queue management

Migration:
- Replace sendEmailJob usage with sendEmail({ processImmediately: true })
- Individual emails now appear as separate jobs in queue
- Batch processing still available via processEmailsTask if needed

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-14 20:19:07 +02:00
08f017abed Bump version to 0.4.5 2025-09-14 20:03:34 +02:00
af9c5a1e1b Fix TypeScript compilation error in MailingService
- Replace unsafe BaseEmail type cast with proper type handling
- Fix error TS2352: Conversion of type 'JsonObject & TypeWithID' to type 'BaseEmail'
- Use targeted (email as any).attempts instead of full object cast
- Maintains functionality while resolving type safety issues

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-14 20:02:08 +02:00
22190f38fd Fix critical type safety and validation issues
- Replace unsafe (payload as any).mailing with proper type checking
- Add validation for required fields (to, templateSlug/subject+html)
- Return proper 400 status codes for invalid requests
- Improve type safety without breaking existing functionality

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-14 19:56:19 +02:00
1ba770942d Bump version to 0.4.4 2025-09-14 19:53:53 +02:00
7f73fa5efc Add SQLite database files to gitignore
- Remove dev.db and dev/dev.db from git tracking
- Update .gitignore to exclude SQLite development databases
- Prevent local database files from being committed

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-14 19:49:28 +02:00
8993d20526 Migrate dev server from MongoDB to SQLite
- Replace mongooseAdapter with sqliteAdapter in payload config
- Update database configuration to use file:./dev.db
- Remove MongoDB memory database helper and references
- Simplify start script by removing verbose logging and MongoDB messaging
- Fix email processing with immediate send support and proper queue handling
- Restructure app with route groups for frontend/admin separation
- Add dashboard and test pages for email management
- Update API routes for improved email processing and testing

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-14 19:48:45 +02:00
0d295603ef Update development documentation for silent plugin initialization
- Remove reference to removed 'PayloadCMS Mailing Plugin initialized successfully' log
- Add note explaining that plugin initializes silently on success
- Clarify that absence of errors indicates successful initialization
- Keep documentation aligned with actual plugin behavior
- Bump version to 0.4.3
2025-09-14 18:33:34 +02:00
bd1842d45c Remove verbose initialization logs
- Remove 'PayloadCMS Mailing Plugin initialized successfully' log
- Remove 'Scheduled initial email processing job in queue' log
- Keep error logging for failed job scheduling
- Reduce console noise during plugin initialization
- Bump version to 0.4.2
2025-09-14 18:18:20 +02:00
ccd8ef35c3 Fix error handling and improve error messages
- Fix inconsistent error handling in sendEmailTask by re-throwing original Error instances
- Preserve stack traces and error context instead of creating new Error wrappers
- Improve generic error messages in emailProcessor utilities with specific details
- Add actionable guidance for common configuration issues
- Help developers understand what went wrong and how to fix it
- Bump version to 0.4.1
2025-09-14 18:00:23 +02:00
a12d4c1bee BREAKING CHANGE: Remove sendEmailWorkflow, add immediate processing to sendEmailTask
- Remove entire workflows directory and sendEmailWorkflow
- Factor out email processing logic into reusable utilities (emailProcessor.ts)
- Add processImmediately option to sendEmailTask input schema
- Update sendEmailTask to process emails immediately when requested
- Update processEmailsTask to use shared processing utilities
- Remove workflow-related exports and plugin configuration
- Simplify documentation to focus on unified task approach
- Export new email processing utilities (processEmailById, processAllEmails)
- Bump version to 0.4.0 (breaking change - workflows removed)

Migration: Use sendEmailTask with processImmediately: true instead of sendEmailWorkflow
2025-09-14 17:53:29 +02:00
845b379da3 Fix error handling and improve naming consistency
- Use native error chaining in workflow (Error constructor with cause option)
- Fix job scheduling to use 'task' instead of 'workflow' property
- Rename processEmailsJob.ts to processEmailsTask.ts for consistency
- Update all imports and references while maintaining backward compatibility
- Add processEmailsTask export with processEmailsJob alias
- Bump version to 0.3.1
2025-09-14 17:34:53 +02:00
dd205dba41 Make workflow documentation more concise
- Simplified workflow section to focus on key advantage
- Removed verbose comparison table and features list
- Kept essential usage example with processImmediately option
- More readable and focused on the main differentiator
2025-09-14 17:21:57 +02:00
a6564e2a29 Add sendEmail workflow with immediate processing option
- Create sendEmailWorkflow as a Payload workflow alternative to task
- Add processImmediately option (disabled by default) to send emails immediately
- Expose processEmailItem method in MailingService for individual email processing
- Add comprehensive input schema with conditional fields
- Update plugin to register both tasks and workflows
- Add detailed documentation comparing tasks vs workflows
- Includes status tracking and error handling
- Bump version to 0.3.0 (new feature)
2025-09-14 17:20:21 +02:00
8f200da449 Refactor and clean up job organization
- Properly encapsulate processEmailsJob in its own file with handler and definition
- Clean up index.ts to remove duplicate code and just export job definitions
- Add comprehensive JSDoc comments for better documentation
- Separate job handler logic from job definition for clarity
- Fix job scheduling to use correct field names
- Bump version to 0.2.1
2025-09-14 17:16:01 +02:00
ddee7d5a76 BREAKING CHANGE: Remove custom transport support, use Payload's email config
- Removed custom transport configuration from plugin
- Plugin now requires Payload email to be configured
- Simplified setup by relying on Payload's email adapter
- Updated README with new configuration requirements
- Bump version to 0.2.0 (breaking change)

Users must now configure email in their Payload config using an email adapter
like @payloadcms/email-nodemailer instead of configuring transport in the plugin.
2025-09-14 16:57:30 +02:00
63a7eef8d8 Remove redundant queueName validation and debug log, bump version to 0.1.24 2025-09-14 16:28:24 +02:00
aa978090fa Add debug log for email transporter configuration and bump version to 0.1.23 2025-09-14 16:14:56 +02:00
b4bad70634 Remove conditional transporter initialization and bump version to 0.1.22 2025-09-14 13:52:49 +02:00
ea7d8dfdd5 Add validation for beforeSend hook to ensure required properties remain intact
- Validate that 'from' field is not removed
- Validate that 'to' field is not removed or emptied
- Validate that 'subject' field is not removed
- Validate that at least 'html' or 'text' content exists
- Throw clear error messages if validation fails
- Bump version to 0.1.21
2025-09-14 12:27:43 +02:00
0d6d07de85 Add beforeSend hook for email customization
- Add BeforeSendHook type and BeforeSendMailOptions interface
- Implement hook execution in MailingService before sending emails
- Hook allows adding attachments, headers, and modifying email options
- Add comprehensive documentation with examples
- Bump version to 0.1.20
2025-09-14 12:19:52 +02:00
347cd33e13 Fix model overwrite error when plugin is initialized multiple times
- Filter out existing collections with same slugs before adding plugin collections
- Prevents 'Cannot overwrite model once compiled' errors in Next.js apps
- Fixes issue during hot reload and multiple getPayload() calls
- Bump version to 0.1.19
2025-09-14 10:22:34 +02:00
c7db65980a Fix security vulnerabilities in fromName field handling
- Add sanitizeDisplayName() method to prevent header injection attacks
- Remove newlines, carriage returns, and control characters from display names
- Fix quote escaping inconsistency between getDefaultFrom() and processEmailItem()
- Create formatEmailAddress() helper method for consistent email formatting
- Add fromName sanitization in sendEmail() function for input validation
- Prevent malformed email headers and potential security issues

Security improvements:
- Header injection prevention (removes \r\n and control characters)
- Consistent quote escaping across all display name usage
- Proper sanitization at both input and output stages

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-14 00:07:53 +02:00