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>
199 lines
5.9 KiB
Markdown
199 lines
5.9 KiB
Markdown
# 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: null` and 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:**
|
|
```javascript
|
|
filter: {
|
|
operator: 'AND',
|
|
conditions: [
|
|
{ inMailbox: inboxMailbox.id }, // ONLY from Inbox
|
|
{ from: senderEmail }, // ONLY from this sender
|
|
],
|
|
}
|
|
```
|
|
|
|
**After:**
|
|
```javascript
|
|
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:**
|
|
```javascript
|
|
// 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 `sentByUserId` is not null), matches by the `to` field
|
|
- For received emails, matches by the `from` field
|
|
- Updates the `contactId` to link them properly
|
|
|
|
**Run with:**
|
|
```bash
|
|
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:**
|
|
```bash
|
|
node src/scripts/resync-all-contacts.js
|
|
```
|
|
|
|
## About the Database Schema
|
|
|
|
### The `sentByUserId` Column
|
|
- **Location**: `emails` table, line 93 in `src/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 `userEmailAccounts` table
|
|
- 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)
|
|
```javascript
|
|
// 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)
|
|
```javascript
|
|
// Group by contact email
|
|
const contactEmail = email.contact.email;
|
|
```
|
|
- ✅ Groups emails by contact
|
|
- ✅ Shows complete conversation threads
|
|
|
|
## Testing Recommendations
|
|
|
|
1. **Test New Email Sync:**
|
|
```bash
|
|
# Add a new contact via Inbox
|
|
# Check that both received AND sent emails appear
|
|
```
|
|
|
|
2. **Test Sending Emails:**
|
|
```bash
|
|
# Send an email to a contact from CRM
|
|
# Verify it appears in the conversation immediately
|
|
```
|
|
|
|
3. **Run Cleanup Scripts:**
|
|
```bash
|
|
# 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
|
|
```
|
|
|
|
4. **Verify Shared Email Accounts:**
|
|
```bash
|
|
# 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
|
|
|
|
1. **Apply the code changes** (already done in `src/services/jmap.service.js`)
|
|
2. **Run fix script** to link existing orphaned emails:
|
|
```bash
|
|
node src/scripts/fix-sent-emails-contactid.js
|
|
```
|
|
3. **Run resync script** to fetch missing emails:
|
|
```bash
|
|
node src/scripts/resync-all-contacts.js
|
|
```
|
|
4. **Test thoroughly** with your email accounts
|
|
5. **Delete old migration files** from `MIGRATION_GUIDE.md` if no longer needed
|
|
|
|
## Notes
|
|
|
|
- No frontend changes were needed (FE code was already correct)
|
|
- No database schema changes needed
|
|
- The `sentByUserId` column is working as designed
|
|
- The refactor branch architecture supports shared email accounts as intended
|