Backend Features:
- Timesheets database table (id, userId, fileName, filePath, fileType, fileSize, year, month, timestamps)
- File upload with multer (memory storage, 10MB limit, PDF/Excel validation)
- Structured file storage: uploads/timesheets/{userId}/{year}/{month}/
- RESTful API endpoints:
* POST /api/timesheets/upload - Upload timesheet
* GET /api/timesheets/my - Get user's timesheets (with filters)
* GET /api/timesheets/all - Get all timesheets (admin only)
* GET /api/timesheets/:id/download - Download file
* DELETE /api/timesheets/:id - Delete timesheet
- Role-based permissions: users access own files, admins access all
- Proper error handling and file cleanup on errors
- Database migration for timesheets table
Technical:
- Uses req.user.role for permission checks
- Automatic directory creation for user/year/month structure
- Blob URL cleanup and proper file handling
- Integration with existing auth middleware
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
5.9 KiB
5.9 KiB
CRM Email System - Bug Fixes Summary
Problems Identified
1. Emails Scattered and Showing Under Wrong Contacts
- Root Cause: Email syncing was changed from bidirectional (both FROM and TO contact) to unidirectional (only FROM contact)
- Impact: When you sent emails from foxerdxd@gmail.com, they weren't being synced into your CRM database
- Symptom: Emails appeared under the wrong contacts because conversations were incomplete
2. Sent Emails from CRM Not Appearing
- Root Cause: Sent emails were saved with
contactId: nulland never linked to contacts - Impact: All emails sent from the CRM weren't showing up in the conversation view
- Symptom: You could see received emails but not your replies
3. Inbox-Only Syncing
- Root Cause: Sync was restricted to only Inbox mailbox
- Impact: Sent emails in the Sent folder weren't being synced
- Symptom: Incomplete conversation history
Fixes Applied
src/services/jmap.service.js
1. Fixed syncEmailsFromSender() (lines 344-477)
Before:
filter: {
operator: 'AND',
conditions: [
{ inMailbox: inboxMailbox.id }, // ONLY from Inbox
{ from: senderEmail }, // ONLY from this sender
],
}
After:
filter: {
operator: 'OR',
conditions: [
{ from: senderEmail }, // Emails FROM contact
{ to: senderEmail }, // Emails TO contact (our sent emails)
],
}
Changes:
- ✅ Removed inbox-only filter (now syncs from ALL mailboxes)
- ✅ Changed from unidirectional to bidirectional sync
- ✅ Now captures complete conversation history
2. Fixed sendEmail() (lines 557-681)
Added:
// Find contact by recipient email address to properly link the sent email
const [recipientContact] = await db
.select()
.from(contacts)
.where(
and(
eq(contacts.emailAccountId, emailAccountId),
eq(contacts.email, to)
)
)
.limit(1);
await db.insert(emails).values({
...
contactId: recipientContact?.id || null, // Link to contact if recipient is in contacts
...
});
Changes:
- ✅ Now looks up the recipient in contacts before saving
- ✅ Links sent emails to the correct contact
- ✅ Sent emails now appear in conversation view
Database Cleanup Scripts Created
1. src/scripts/fix-sent-emails-contactid.js
Purpose: Links existing orphaned sent emails to their contacts
What it does:
- Finds all emails with
contactId: null - For sent emails (where
sentByUserIdis not null), matches by thetofield - For received emails, matches by the
fromfield - Updates the
contactIdto link them properly
Run with:
node src/scripts/fix-sent-emails-contactid.js
2. src/scripts/resync-all-contacts.js
Purpose: Re-syncs all contacts with bidirectional sync to fetch missing emails
What it does:
- Fetches all contacts from the database
- Re-syncs each contact using the new bidirectional sync logic
- Pulls in any missing sent emails that weren't synced before
Run with:
node src/scripts/resync-all-contacts.js
About the Database Schema
The sentByUserId Column
- Location:
emailstable, line 93 insrc/db/schema.js - Purpose: Tracks which user sent the email from the CRM
- Status: ✅ This column EXISTS and IS being used correctly
- Note: It's NOT
set_by_user_id(that was a typo in your question)
Current Architecture (Refactor Branch)
- Email accounts can be shared between multiple users via
userEmailAccountstable - Contacts belong to email accounts (not individual users)
- Multiple users can manage the same email account
- This design supports your requirement: "chcem mat jeden email account linknuty kludne aj na dvoch crm uctoch"
How Email Filtering Works Now
Backend (src/services/crm-email.service.js:9-38)
// INNER JOIN with contacts table
.innerJoin(contacts, eq(emails.contactId, contacts.id))
- ✅ Only shows emails from added contacts (as requested)
- ✅ No spam or unwanted emails
Frontend (src/pages/Emails/EmailsPage.jsx:72-113)
// Group by contact email
const contactEmail = email.contact.email;
- ✅ Groups emails by contact
- ✅ Shows complete conversation threads
Testing Recommendations
-
Test New Email Sync:
# Add a new contact via Inbox # Check that both received AND sent emails appear -
Test Sending Emails:
# Send an email to a contact from CRM # Verify it appears in the conversation immediately -
Run Cleanup Scripts:
# Fix existing data node src/scripts/fix-sent-emails-contactid.js # Re-sync all contacts to get complete history node src/scripts/resync-all-contacts.js -
Verify Shared Email Accounts:
# Add same email account to two different users # Verify both users see the same contacts and emails
What's Fixed
✅ Emails now sync bidirectionally (FROM and TO contact) ✅ Sent emails from CRM are properly linked to contacts ✅ Complete conversation history is preserved ✅ All emails from all mailboxes are synced (not just Inbox) ✅ Email grouping works correctly by contact ✅ Only emails from added contacts are shown ✅ Shared email accounts work correctly
Migration Path
- Apply the code changes (already done in
src/services/jmap.service.js) - Run fix script to link existing orphaned emails:
node src/scripts/fix-sent-emails-contactid.js - Run resync script to fetch missing emails:
node src/scripts/resync-all-contacts.js - Test thoroughly with your email accounts
- Delete old migration files from
MIGRATION_GUIDE.mdif no longer needed
Notes
- No frontend changes were needed (FE code was already correct)
- No database schema changes needed
- The
sentByUserIdcolumn is working as designed - The refactor branch architecture supports shared email accounts as intended