Some checks failed
BotServer CI / build (push) Failing after 13s
461 lines
12 KiB
Markdown
461 lines
12 KiB
Markdown
# Email App Improvement Specification
|
|
## Outlook + Gmail + Lotus Notes Best Features
|
|
|
|
## Current State Analysis
|
|
|
|
The Email app (`botui/ui/suite/mail/mail.html`) has:
|
|
- ✅ **3-panel layout**: Sidebar, List, Content
|
|
- ✅ **Folders**: Inbox, Starred, Sent, Scheduled, Drafts, Tracking, Spam, Trash
|
|
- ✅ **Compose modal**: Rich text editor with formatting toolbar
|
|
- ✅ **Features**: Templates, Signatures, Rules, Auto-responder, Multi-account
|
|
- ✅ **Scheduling**: Send later functionality
|
|
- ✅ **Tracking**: Email open tracking
|
|
- ✅ **Labels**: Color-coded labels
|
|
|
|
## 🎯 Best-of-Breed Improvements
|
|
|
|
### 1. Snooze Emails (Gmail)
|
|
**What:** Temporarily hide emails until a specific time
|
|
|
|
**Implementation:**
|
|
```html
|
|
<div class="snooze-menu">
|
|
<button onclick="snoozeUntil('later-today')">
|
|
Later today (6:00 PM)
|
|
</button>
|
|
<button onclick="snoozeUntil('tomorrow')">
|
|
Tomorrow (8:00 AM)
|
|
</button>
|
|
<button onclick="snoozeUntil('this-weekend')">
|
|
This weekend (Sat 9:00 AM)
|
|
</button>
|
|
<button onclick="snoozeUntil('next-week')">
|
|
Next week (Mon 8:00 AM)
|
|
</button>
|
|
<button onclick="snoozeCustom()">
|
|
Pick date & time...
|
|
</button>
|
|
</div>
|
|
|
|
<script>
|
|
async function snoozeUntil(preset) {
|
|
const emailIds = getSelectedEmails();
|
|
|
|
await fetch('/api/email/snooze', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ email_ids: emailIds, preset })
|
|
});
|
|
|
|
refreshMailList();
|
|
}
|
|
</script>
|
|
```
|
|
|
|
### 2. Smart Compose (Gmail AI)
|
|
**What:** AI-powered sentence completion while typing
|
|
|
|
**Implementation:**
|
|
```javascript
|
|
let composeTimeout;
|
|
|
|
document.getElementById('compose-body').addEventListener('input', async (e) => {
|
|
clearTimeout(composeTimeout);
|
|
|
|
composeTimeout = setTimeout(async () => {
|
|
const text = e.target.textContent;
|
|
if (text.length < 10) return;
|
|
|
|
const response = await fetch('/api/email/smart-compose', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ context: text })
|
|
});
|
|
|
|
const { suggestion } = await response.json();
|
|
if (suggestion) showSuggestion(suggestion);
|
|
}, 500);
|
|
});
|
|
|
|
// Accept with Tab key
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Tab' && hasSuggestion()) {
|
|
e.preventDefault();
|
|
acceptSuggestion();
|
|
}
|
|
});
|
|
</script>
|
|
```
|
|
|
|
### 3. Nudges (Gmail Reminder)
|
|
**What:** Remind to follow up on emails without replies
|
|
|
|
**Implementation:**
|
|
```html
|
|
<div class="nudge-banner">
|
|
<span>You haven't replied to <strong>John Doe</strong> in 3 days</span>
|
|
<button onclick="replyToNudge('email-123')">Reply</button>
|
|
<button onclick="dismissNudge('email-123')">Dismiss</button>
|
|
</div>
|
|
|
|
<script>
|
|
async function checkNudges() {
|
|
const response = await fetch('/api/email/nudges');
|
|
const { nudges } = await response.json();
|
|
nudges.forEach(showNudgeBanner);
|
|
}
|
|
|
|
setInterval(checkNudges, 3600000); // Check hourly
|
|
</script>
|
|
```
|
|
|
|
### 4. Conversation Threading (Outlook)
|
|
**What:** Group related emails together
|
|
|
|
**Implementation:**
|
|
```html
|
|
<div class="mail-thread" data-thread-id="abc123">
|
|
<div class="thread-header" onclick="toggleThread(this)">
|
|
<span class="thread-icon">▶</span>
|
|
<span class="thread-sender">John Doe</span>
|
|
<span class="thread-subject">Project Discussion</span>
|
|
<span class="thread-count">3 messages</span>
|
|
<span class="thread-time">Today</span>
|
|
</div>
|
|
|
|
<div class="thread-messages" style="display: none;">
|
|
<!-- Individual messages -->
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
### 5. Follow-Up Flags (Lotus Notes)
|
|
**What:** Flag emails with specific follow-up dates
|
|
|
|
**Implementation:**
|
|
```html
|
|
<div class="follow-up-menu">
|
|
<button onclick="flagForFollowUp('today')">
|
|
🚩 Today
|
|
</button>
|
|
<button onclick="flagForFollowUp('tomorrow')">
|
|
🚩 Tomorrow
|
|
</button>
|
|
<button onclick="flagForFollowUp('this-week')">
|
|
🚩 This Week
|
|
</button>
|
|
<button onclick="flagForFollowUp('next-week')">
|
|
🚩 Next Week
|
|
</button>
|
|
<button onclick="flagForFollowUp('custom')">
|
|
🚩 Custom Date...
|
|
</button>
|
|
<button onclick="clearFlag()">
|
|
Clear Flag
|
|
</button>
|
|
</div>
|
|
|
|
<script>
|
|
async function flagForFollowUp(when) {
|
|
const emailIds = getSelectedEmails();
|
|
|
|
await fetch('/api/email/flag', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ email_ids: emailIds, follow_up: when })
|
|
});
|
|
|
|
refreshMailList();
|
|
}
|
|
</script>
|
|
```
|
|
|
|
### 6. To-Do Integration (Lotus Notes)
|
|
**What:** Convert emails to tasks
|
|
|
|
**Implementation:**
|
|
```html
|
|
<button class="action-btn" onclick="convertToTask()">
|
|
<svg><!-- checkbox icon --></svg>
|
|
<span>Add to Tasks</span>
|
|
</button>
|
|
|
|
<script>
|
|
async function convertToTask() {
|
|
const email = getCurrentEmail();
|
|
|
|
const response = await fetch('/api/tasks/from-email', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
title: email.subject,
|
|
description: email.body,
|
|
due_date: null,
|
|
email_id: email.id
|
|
})
|
|
});
|
|
|
|
const { task_id } = await response.json();
|
|
showNotification(`Task created: ${email.subject}`);
|
|
}
|
|
</script>
|
|
```
|
|
|
|
### 7. Reading Pane Options (Outlook)
|
|
**What:** Toggle between right pane, bottom pane, or no pane
|
|
|
|
**Implementation:**
|
|
```html
|
|
<div class="view-options">
|
|
<button onclick="setReadingPane('right')" title="Right pane">
|
|
<svg><!-- layout icon --></svg>
|
|
</button>
|
|
<button onclick="setReadingPane('bottom')" title="Bottom pane">
|
|
<svg><!-- layout icon --></svg>
|
|
</button>
|
|
<button onclick="setReadingPane('off')" title="Hide pane">
|
|
<svg><!-- layout icon --></svg>
|
|
</button>
|
|
</div>
|
|
|
|
<script>
|
|
function setReadingPane(position) {
|
|
const layout = document.querySelector('.mail-layout');
|
|
layout.className = `mail-layout reading-pane-${position}`;
|
|
localStorage.setItem('reading_pane', position);
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.mail-layout.reading-pane-right {
|
|
grid-template-columns: 250px 400px 1fr;
|
|
}
|
|
|
|
.mail-layout.reading-pane-bottom {
|
|
grid-template-columns: 250px 1fr;
|
|
grid-template-rows: 1fr 300px;
|
|
}
|
|
|
|
.mail-layout.reading-pane-off .mail-content {
|
|
display: none;
|
|
}
|
|
</style>
|
|
```
|
|
|
|
### 8. Sweep and Clean Up (Outlook)
|
|
**What:** Bulk delete/archive emails from specific senders
|
|
|
|
**Implementation:**
|
|
```html
|
|
<div class="sweep-menu">
|
|
<h4>Clean up emails from: <strong id="sweep-sender"></strong></h4>
|
|
|
|
<button onclick="sweepDelete('all')">
|
|
Delete all emails from this sender
|
|
</button>
|
|
<button onclick="sweepDelete('older-than-10')">
|
|
Delete emails older than 10 days
|
|
</button>
|
|
<button onclick="sweepArchive('all')">
|
|
Archive all emails from this sender
|
|
</button>
|
|
<button onclick="sweepMove('folder')">
|
|
Move all to folder...
|
|
</button>
|
|
</div>
|
|
|
|
<script>
|
|
async function sweepDelete(criteria) {
|
|
const sender = document.getElementById('sweep-sender').textContent;
|
|
|
|
await fetch('/api/email/sweep', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ sender, action: 'delete', criteria })
|
|
});
|
|
|
|
refreshMailList();
|
|
}
|
|
</script>
|
|
```
|
|
|
|
### 9. Replication Conflicts (Lotus Notes)
|
|
**What:** Show when email was modified in multiple places
|
|
|
|
**Implementation:**
|
|
```html
|
|
<div class="conflict-banner" style="background: #fff3cd;">
|
|
<svg><!-- warning icon --></svg>
|
|
<span>This email has conflicting versions</span>
|
|
<button onclick="resolveConflict()">Resolve</button>
|
|
</div>
|
|
|
|
<div class="conflict-resolver">
|
|
<div class="conflict-version">
|
|
<h4>Version 1 (Local)</h4>
|
|
<div class="version-content">...</div>
|
|
<button onclick="keepVersion(1)">Keep This</button>
|
|
</div>
|
|
|
|
<div class="conflict-version">
|
|
<h4>Version 2 (Server)</h4>
|
|
<div class="version-content">...</div>
|
|
<button onclick="keepVersion(2)">Keep This</button>
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
### 10. Offline Mode (Gmail + Lotus Notes)
|
|
**What:** Read and compose emails offline, sync when online
|
|
|
|
**Implementation:**
|
|
```javascript
|
|
// Service Worker for offline support
|
|
if ('serviceWorker' in navigator) {
|
|
navigator.serviceWorker.register('/sw-email.js');
|
|
}
|
|
|
|
// Cache emails for offline access
|
|
async function cacheEmailsForOffline() {
|
|
const cache = await caches.open('email-cache-v1');
|
|
const emails = await fetch('/api/email/list?folder=inbox');
|
|
const data = await emails.json();
|
|
|
|
// Cache email list
|
|
await cache.put('/api/email/list?folder=inbox', new Response(JSON.stringify(data)));
|
|
|
|
// Cache individual emails
|
|
for (const email of data.emails) {
|
|
const response = await fetch(`/api/email/${email.id}`);
|
|
await cache.put(`/api/email/${email.id}`, response.clone());
|
|
}
|
|
}
|
|
|
|
// Queue actions when offline
|
|
const offlineQueue = [];
|
|
|
|
async function sendEmailOffline(emailData) {
|
|
if (navigator.onLine) {
|
|
return await fetch('/api/email/send', {
|
|
method: 'POST',
|
|
body: JSON.stringify(emailData)
|
|
});
|
|
} else {
|
|
offlineQueue.push({ action: 'send', data: emailData });
|
|
localStorage.setItem('email_offline_queue', JSON.stringify(offlineQueue));
|
|
showNotification('Email queued. Will send when online.');
|
|
}
|
|
}
|
|
|
|
// Sync when back online
|
|
window.addEventListener('online', async () => {
|
|
const queue = JSON.parse(localStorage.getItem('email_offline_queue') || '[]');
|
|
|
|
for (const item of queue) {
|
|
if (item.action === 'send') {
|
|
await fetch('/api/email/send', {
|
|
method: 'POST',
|
|
body: JSON.stringify(item.data)
|
|
});
|
|
}
|
|
}
|
|
|
|
localStorage.removeItem('email_offline_queue');
|
|
showNotification('Offline emails sent!');
|
|
});
|
|
</script>
|
|
```
|
|
|
|
## 🔧 Backend API Requirements
|
|
|
|
```
|
|
# Gmail Features
|
|
POST /api/email/snooze - Snooze emails
|
|
POST /api/email/smart-compose - Get AI suggestions
|
|
GET /api/email/nudges - Get follow-up reminders
|
|
|
|
# Outlook Features
|
|
GET /api/email/thread/:id - Get conversation thread
|
|
POST /api/email/sweep - Bulk delete/archive
|
|
|
|
# Lotus Notes Features
|
|
POST /api/email/flag - Flag for follow-up
|
|
POST /api/tasks/from-email - Convert email to task
|
|
GET /api/email/conflicts - Get replication conflicts
|
|
POST /api/email/resolve-conflict - Resolve conflict
|
|
|
|
# Offline Support
|
|
GET /api/email/offline-sync - Sync offline changes
|
|
```
|
|
|
|
## 📊 Database Schema
|
|
|
|
```sql
|
|
-- Snoozed emails
|
|
CREATE TABLE email_snooze (
|
|
id UUID PRIMARY KEY,
|
|
email_id UUID REFERENCES emails(id),
|
|
snooze_until TIMESTAMP,
|
|
created_at TIMESTAMP
|
|
);
|
|
|
|
-- Follow-up flags
|
|
CREATE TABLE email_flags (
|
|
id UUID PRIMARY KEY,
|
|
email_id UUID REFERENCES emails(id),
|
|
follow_up_date DATE,
|
|
flag_type VARCHAR(50),
|
|
completed BOOLEAN DEFAULT FALSE
|
|
);
|
|
|
|
-- Nudges
|
|
CREATE TABLE email_nudges (
|
|
id UUID PRIMARY KEY,
|
|
email_id UUID REFERENCES emails(id),
|
|
last_sent TIMESTAMP,
|
|
dismissed BOOLEAN DEFAULT FALSE
|
|
);
|
|
|
|
-- Offline queue
|
|
CREATE TABLE email_offline_queue (
|
|
id UUID PRIMARY KEY,
|
|
user_id UUID NOT NULL,
|
|
action VARCHAR(50),
|
|
data JSONB,
|
|
created_at TIMESTAMP
|
|
);
|
|
|
|
-- Threading
|
|
ALTER TABLE emails ADD COLUMN thread_id UUID;
|
|
ALTER TABLE emails ADD COLUMN in_reply_to UUID;
|
|
```
|
|
|
|
## ✅ Implementation Priority
|
|
|
|
### Phase 1: Gmail Features (Week 1)
|
|
1. Snooze emails
|
|
2. Smart compose
|
|
3. Nudges
|
|
|
|
### Phase 2: Outlook Features (Week 2)
|
|
4. Conversation threading
|
|
5. Reading pane options
|
|
6. Sweep and clean up
|
|
|
|
### Phase 3: Lotus Notes Features (Week 3)
|
|
7. Follow-up flags
|
|
8. To-do integration
|
|
9. Offline mode
|
|
|
|
## 🧪 Testing Checklist
|
|
|
|
- [ ] Snooze email until tomorrow
|
|
- [ ] Smart compose suggests text
|
|
- [ ] Nudge appears for old emails
|
|
- [ ] Thread groups related emails
|
|
- [ ] Reading pane switches layouts
|
|
- [ ] Sweep deletes all from sender
|
|
- [ ] Flag email for follow-up
|
|
- [ ] Convert email to task
|
|
- [ ] Compose email offline
|
|
- [ ] Sync offline emails when online
|