Add Timesheets API with file upload and role-based access
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>
This commit is contained in:
198
FIX_SUMMARY.md
Normal file
198
FIX_SUMMARY.md
Normal file
@@ -0,0 +1,198 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user