memories and such
This commit is contained in:
162
agents/code-reviewer/reviews/FRE-580-review.md
Normal file
162
agents/code-reviewer/reviews/FRE-580-review.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# Code Review: FRE-580 — Email Marketing Sequences
|
||||
|
||||
**Date**: 2026-05-13
|
||||
**Reviewer**: Code Reviewer (f274248f-c47e-4f79-98ad-45919d951aa0)
|
||||
**Author**: Senior Engineer (c99c4ede-feab-4aaa-a9a5-17d81cd80644)
|
||||
**Run ID**: $PAPERCLIP_RUN_ID
|
||||
|
||||
---
|
||||
|
||||
## Files Reviewed
|
||||
|
||||
| File | Lines | Description |
|
||||
|------|-------|-------------|
|
||||
| `server/services/email-service.ts` | 111 | Resend email sender with template rendering |
|
||||
| `server/services/email-templates.ts` | 418 | HTML/text templates for all sequences |
|
||||
| `server/services/email-sequence-service.ts` | 527 | Sequence orchestration |
|
||||
| `server/trpc/routers/email-marketing.ts` | 156 | tRPC API endpoints |
|
||||
| `server/trpc/appRouter.ts` | 33 | Router registration |
|
||||
| `src/db/schema/email_marketing.ts` | 132 | Database schema (reviewed for completeness) |
|
||||
|
||||
**Total**: 1,377 lines
|
||||
|
||||
---
|
||||
|
||||
## P1 Issues
|
||||
|
||||
### 1. Missing Scheduler Integration
|
||||
|
||||
**Severity**: Critical
|
||||
**Location**: `server/services/email-sequence-service.ts:165`
|
||||
|
||||
The `processDueSteps` method is the core scheduling mechanism but is never actually called by any scheduler. The tRPC endpoint `processSequence` exists but requires manual admin invocation.
|
||||
|
||||
**Required Fix**: Add a cron-based scheduler (e.g., `node-cron` or `@upstash/cron`) that calls `processDueSteps` for each sequence type on an appropriate interval (every 5-15 minutes).
|
||||
|
||||
---
|
||||
|
||||
### 2. Welcome Sequence Enrollment Not Wired
|
||||
|
||||
**Severity**: Critical
|
||||
**Location**: `server/services/email-sequence-service.ts:124`
|
||||
|
||||
The welcome sequence has `triggerEvent: 'user_signed_up'` but there is no registration of a signup event handler that calls `enrollUser(userId, 'welcome', email)`.
|
||||
|
||||
**Required Fix**: Register a signup event listener (or add a hook in the auth registration flow) that calls `emailSequenceService.enrollUser(userId, 'welcome', email)` after user creation.
|
||||
|
||||
---
|
||||
|
||||
### 3. Email Send Status Tracking Incomplete
|
||||
|
||||
**Severity**: Critical
|
||||
**Location**: `server/services/email-sequence-service.ts:267-275`
|
||||
|
||||
```typescript
|
||||
status: result.status === 'sent' || result.status === 'id' ? 'sent' : 'pending',
|
||||
```
|
||||
|
||||
The Resend API returns a message ID (`id`) on success, not a `status` field. No webhook handlers are implemented to process delivery events.
|
||||
|
||||
**Required Fix**: Implement Resend webhook handlers (`/api/webhooks/resend`) to process delivery events (delivered, opened, clicked, bounced, unsubscribed) and update `emailSendLog` status accordingly.
|
||||
|
||||
---
|
||||
|
||||
## P2 Issues
|
||||
|
||||
### 4. No Deduplication for Concurrent Scheduler Runs
|
||||
|
||||
**Severity**: High
|
||||
**Location**: `server/services/email-sequence-service.ts:165-216`
|
||||
|
||||
If the scheduler runs twice concurrently, the same enrollments could be processed twice.
|
||||
|
||||
**Required Fix**: Add a mutex/lock mechanism or use database-level locking (`SELECT FOR UPDATE`).
|
||||
|
||||
---
|
||||
|
||||
### 5. tRPC `processSequence` Allows Any Authenticated User
|
||||
|
||||
**Severity**: High
|
||||
**Location**: `server/trpc/routers/email-marketing.ts:135-145`
|
||||
|
||||
Any logged-in user can trigger sequence processing. Should be restricted to admin users.
|
||||
|
||||
**Required Fix**: Add an admin-only middleware check.
|
||||
|
||||
---
|
||||
|
||||
### 6. `enrollSequence` tRPC Endpoint Accepts Empty Email
|
||||
|
||||
**Severity**: High
|
||||
**Location**: `server/trpc/routers/email-marketing.ts:102-113`
|
||||
|
||||
The email parameter is hardcoded to empty string.
|
||||
|
||||
**Required Fix**: Fetch the current user's email from the users table before enrolling.
|
||||
|
||||
---
|
||||
|
||||
### 7. Template Initialization stepNumber Mapping is Fragile
|
||||
|
||||
**Severity**: High
|
||||
**Location**: `server/services/email-sequence-service.ts:98-110`
|
||||
|
||||
The uniqueness check uses `stepNumber === delayHours`, but stepNumber is mapped differently (0→1, 24→2, 72→3). This means the lookup will never find existing templates.
|
||||
|
||||
**Required Fix**: Use the correct stepNumber mapping for the lookup, or add a unique constraint on `sequence + stepNumber` where stepNumber is the actual ordinal (1, 2, 3).
|
||||
|
||||
---
|
||||
|
||||
## P3 Issues
|
||||
|
||||
### 8. No Unsubscribe Link Tracking
|
||||
No tRPC endpoint or API route to handle unsubscribe actions.
|
||||
|
||||
### 9. No Rate Limiting on Email Sending
|
||||
Could hit Resend API rate limits or trigger spam filters.
|
||||
|
||||
### 10. Analytics Query Uses String Concatenation for SQL
|
||||
Bypasses drizzle-orm's parameter binding.
|
||||
|
||||
### 11. No Error Handling for Email Service Failures
|
||||
Failed emails are silently lost.
|
||||
|
||||
### 12. No A/B Testing Implementation Beyond Schema
|
||||
No logic for traffic splitting, variant selection, or statistical significance.
|
||||
|
||||
---
|
||||
|
||||
## Architecture Assessment
|
||||
|
||||
**Positive**:
|
||||
- Template registry pattern is clean and extensible
|
||||
- Drizzle-ORM schema is well-structured with proper constraints
|
||||
- tRPC router follows project conventions
|
||||
- HTML templates use inline styles (email-client compatible)
|
||||
- Both HTML and text versions provided for all templates
|
||||
- UTM tracking for analytics is implemented
|
||||
|
||||
**Areas for Improvement**:
|
||||
- Missing production infrastructure (scheduler, webhooks)
|
||||
- No error recovery for email delivery failures
|
||||
- Analytics would be incomplete without webhook integration
|
||||
|
||||
---
|
||||
|
||||
## Final Disposition
|
||||
|
||||
**Status**: `in_progress` — Assigned back to Senior Engineer
|
||||
|
||||
**Priority Fixes Needed**:
|
||||
1. Add scheduler cron job for `processDueSteps`
|
||||
2. Wire welcome sequence enrollment to signup event
|
||||
3. Implement Resend webhook handlers for delivery tracking
|
||||
|
||||
**Secondary Fixes (P2)**:
|
||||
- Add admin-only access to `processSequence`
|
||||
- Fix template initialization stepNumber mapping
|
||||
- Add concurrent execution protection
|
||||
|
||||
---
|
||||
|
||||
*Review Document: `/home/mike/code/FrenoCorp/agents/code-reviewer/reviews/FRE-580-review.md`*
|
||||
Reference in New Issue
Block a user