   100→        'default_model' => 'gpt-5.2',
   101→        'pricing' => [ // Estimated based on patterns - check OpenAI pricing for exact rates
   102→            'gpt-5.2' => ['input' => 5.00, 'output' => 20.00],
   103→            'gpt-5-mini' => ['input' => 1.00, 'output' => 4.00],
   104→            'gpt-5-nano' => ['input' => 0.20, 'output' => 0.80],
   105→            'gpt-5.2-pro' => ['input' => 8.00, 'output' => 30.00],
   106→            'gpt-5' => ['input' => 4.00, 'output' => 16.00],
   107→            'gpt-4.1' => ['input' => 2.00, 'output' => 8.00],
   108→        ],
   109→    ],
   110→    'gemini' => [
   111→        'enabled' => true,
   112→        'name' => 'Google Gemini',
   113→        'models' => [
   114→            'gemini-3-pro' => 'Gemini 3 Pro (Latest)',
   115→            'gemini-3-flash' => 'Gemini 3 Flash',
   116→            'gemini-2.5-pro' => 'Gemini 2.5 Pro',
   117→            'gemini-2.5-flash' => 'Gemini 2.5 Flash',
   118→            'gemini-2.5-flash-lite' => 'Gemini 2.5 Flash-Lite (Fast)',
   119→        ],
   120→        'default_model' => 'gemini-2.5-flash',
   121→        'pricing' => [ // per 1M tokens, context-dependent pricing for some models
   122→            'gemini-3-pro' => ['input' => 2.00, 'output' => 12.00], // ≤200k tokens
   123→            'gemini-3-flash' => ['input' => 0.50, 'output' => 2.00],
   124→            'gemini-2.5-pro' => ['input' => 1.25, 'output' => 10.00], // ≤200k tokens
   125→            'gemini-2.5-flash' => ['input' => 0.30, 'output' => 2.50],
   126→            'gemini-2.5-flash-lite' => ['input' => 0.15, 'output' => 0.60],
   127→        ],
   128→    ],
   129→    'grok' => [
   130→        'enabled' => true,
   131→        'name' => 'xAI Grok',
   132→        'models' => [
   133→            'grok-4' => 'Grok 4 (Latest)',
   134→            'grok-3' => 'Grok 3',
   135→            'grok-3-mini' => 'Grok 3 Mini',
   136→            'grok-2-latest' => 'Grok 2',
   137→            'grok-2-vision-1212' => 'Grok 2 Vision',
   138→        ],
   139→        'default_model' => 'grok-4',
   140→        'pricing' => [
   141→            'grok-4' => ['input' => 5.00, 'output' => 20.00],
   142→            'grok-3' => ['input' => 3.00, 'output' => 15.00],
   143→            'grok-3-mini' => ['input' => 0.30, 'output' => 0.50],
   144→            'grok-2-latest' => ['input' => 2.00, 'output' => 10.00],
   145→            'grok-2-vision-1212' => ['input' => 2.00, 'output' => 10.00],
   146→        ],
   147→    ],
   148→    'deepseek' => [
   149→        'enabled' => true,
   150→        'name' => 'DeepSeek',
   151→        'models' => [
   152→            'deepseek-chat' => 'DeepSeek V3.2 Chat (Non-thinking)',
   153→            'deepseek-reasoner' => 'DeepSeek V3.2 Reasoner (Thinking)',
   154→        ],
   155→        'default_model' => 'deepseek-chat',
   156→        'pricing' => [ // per 1M tokens - significantly updated from original
   157→            'deepseek-chat' => ['input' => 0.28, 'output' => 0.42], // cache miss rate
   158→            'deepseek-reasoner' => ['input' => 0.28, 'output' => 0.42], // cache miss rate
   159→        ],
   160→    ],
   161→    'qwen' => [
   162→        'enabled' => true,
   163→        'name' => 'Alibaba Qwen',
   164→        'models' => [
   165→            'qwen-max-latest' => 'Qwen Max (Latest)',
   166→            'qwen-plus-latest' => 'Qwen Plus',
   167→            'qwen-turbo-latest' => 'Qwen Turbo (Fast)',
   168→            'qwq-32b' => 'QwQ 32B (Reasoning)',
   169→        ],
   170→        'default_model' => 'qwen-max-latest',
   171→        'pricing' => [
   172→            'qwen-max-latest' => ['input' => 0.40, 'output' => 1.20],
   173→            'qwen-plus-latest' => ['input' => 0.20, 'output' => 0.60],
   174→            'qwen-turbo-latest' => ['input' => 0.10, 'output' => 0.30],
   175→            'qwq-32b' => ['input' => 0.30, 'output' => 0.90],
   176→        ],
   177→    ],
   178→    'mistral' => [
   179→        'enabled' => true,
   180→        'name' => 'Mistral AI',
   181→        'models' => [
   182→            'mistral-large-latest' => 'Mistral Large (Latest)',
   183→            'mistral-medium-latest' => 'Mistral Medium',
   184→            'mistral-small-latest' => 'Mistral Small',
   185→            'ministral-8b-latest' => 'Ministral 8B',
   186→            'codestral-latest' => 'Codestral (Code)',
   187→            'pixtral-large-latest' => 'Pixtral Large (Vision)',
   188→        ],
   189→        'default_model' => 'mistral-large-latest',
   190→        'pricing' => [
   191→            'mistral-large-latest' => ['input' => 2.00, 'output' => 6.00],
   192→            'mistral-medium-latest' => ['input' => 2.70, 'output' => 8.10],
   193→            'mistral-small-latest' => ['input' => 0.20, 'output' => 0.60],
   194→            'ministral-8b-latest' => ['input' => 0.10, 'output' => 0.10],
   195→            'codestral-latest' => ['input' => 0.30, 'output' => 0.90],
   196→            'pixtral-large-latest' => ['input' => 2.00, 'output' => 6.00],
   197→        ],
   198→    ],
   199→    'cohere' => [

Prompt:
Design a detailed implementation plan for the following tasks in the Email Intelligence System at /var/www/mssql.danmarcrm.com/dev1/extension2v1/

## Context
This is a PHP/MongoDB web app with a dashboard (index.php + app.js), API (api.php), data layer (QueryAdapter.php), and a thread view page (thread_view.php). Chrome extension syncs Gmail threads. AI proxy at aiapi/api_opus/.

## Tasks (in priority order)

### TASK 1: Delete Functionality
Add ability to delete:
- **Contacts**: Already has a Delete button in dashboard UI. Need API endpoint `delete_contact` in api.php + QueryAdapter method. Must also delete associated emails, thread_analysis, contact_profiles, ai_contact_memory for that contact.
- **Email Threads**: Add delete button to threads list. API endpoint `delete_thread` + QueryAdapter. Must delete all emails with that thread_id, thread_analysis, ai_query_responses referencing that thread.
- **AI Responses**: Add delete button next to saved AI responses in thread_view.php. API endpoint `delete_ai_response`. Delete from ai_query_responses collection.

Files: api.php, QueryAdapter.php, app.js, index.php, thread_view.php

### TASK 2: Sorting by Last Activity
- Contacts list: Add sort by `last_contact` date (from contact profiles or max email date)
- Threads list: Add sort by `last_date` (already tracked in thread aggregation)
- Add sort dropdown/buttons in the UI for both tabs

Files: app.js, index.php, api.php (may need sort param support), QueryAdapter.php

### TASK 3: Filters
- **Contacts tab**: Add filters for contact type (client/supplier/other), search by name/email, last activity date range
- **Threads tab**: Add filters for contact name, date range, email count range, analysis status
- **Last Activity date filter**: Date range picker for both tabs
- Add filter UI section above each table

Files: app.js, index.php

### TASK 4: Fix "Etienne Turner" Thread Linkage
The contact name resolution was fixed in QueryAdapter.php but may still have issues:
- MongoDB `getThreadsMongo()` collects all_contacts, weights inbound 2x, picks most frequent
- But if contact_id is NULL or email matches user, it skips — edge case: if ALL emails in thread are from user (outbound only), falls back to first contact
- Need to verify the fix works and potentially handle edge cases

Files: QueryAdapter.php

### TASK 5: Sync by Domain/Email Address
New feature: Dashboard UI panel where user enters a domain (e.g. delta-engineering.be) or email address. System queries Gmail API to find all threads involving that domain/email, then imports them.

Implementation:
- New UI section in dashboard or modal
- New API endpoint `sync_by_domain` that:
  1. Uses GmailClient to search: `from:@domain.com OR to:@domain.com` (or specific email)
  2. Lists matching threads with preview (subject, date, count)
  3. User selects which to import (or "Import All")
  4. Imports selected threads using existing sync_thread logic
- Need two-step flow: search → preview → import

Files: api.php, index.php, app.js, GmailClient.php (may need search method)

### TASK 6: Bulk Delete Threads by Email Address
- Add ability to delete all threads for a specific email/domain
- UI: In contacts list or a cleanup tool
- API: `delete_threads_by_email` — finds all emails from that address, gets unique thread_ids, deletes all data

Files: api.php, QueryAdapter.php, app.js, index.php

### TASK 7: Chrome Extension Manual-Only Mode
- Add toggle in Chrome extension popup/options for "Auto-sync" vs "Manual sync only"
- In manual mode, show a "Sync this thread" button overlay in Gmail
- Store preference in chrome.storage.local
- Extension files are at /Users/dan/Documents/extension2/extension2v1/chrome-extension (local Mac) — we can only prepare the code changes

NOTE: Chrome extension is on user's local Mac, not this server. We should note what needs to change but can't edit those files directly.

### TASK 8: Two-Round AI D3.js Chart
- After Round 2 (or any AI response), add "Generate Chart" button
- AI generates structured JSON (entities, relationships, events)
- D3.js force-directed graph renders: nodes as balloons (color-coded by type), arrows showing relationships, labels
- Interactive: drag, zoom, pan, click for details

Files: thread_view.php (inline JS + D3.js CDN)

### TASK 9: Hide Products Tab
- Remove Products tab from navigation in index.php
- Keep product_search.php file intact

Files: index.php

### TASK 10: Update AI Model Versions
Update to latest models:
- Claude: Add `claude-opus-4-6`, `claude-sonnet-4-6` (current has claude-sonnet-4-5-20250929)
- Other providers: verify current versions

Files to update:
- /extension2v1/aiapi/api_opus/config/api_keys.php — provider models list + defaults
- /extension2v1/public/thread_view.php — MODEL_LIMITS constant
- /extension2v1/config/config.php — CLAUDE_MODEL constant
- Also check /extension2/aiapi/api_opus/config/api_keys.php

Current model config in api_keys.php uses arrays like:
```php
'claude' => [
    'default_model' => 'claude-sonnet-4-5-20250929',
    'models' => ['claude-sonnet-4-5-20250929', 'claude-3-5-sonnet-20241022', ...]
]
```

## Architecture Patterns to Follow
- Use `MongoDatabase::insertOrUpdate()` for upserts (NOT `upsert()`)
- Use `QueryAdapter` for all data access (NOT raw SQL)
- AI proxy models keyed by provider: `[$provider => $model]`
- MongoDB `delete()` method available on MongoDatabase class
- Node.js on server is v10.19 — can't use for JS syntax checks
- `ThreadAnalyzer::stripQuotedContent()` for email body processing

## Available MongoDB Methods (MongoDatabase.php)
- `insert($collection, $data)`
- `insertOrUpdate($collection, $filter, $data)`
- `update($collection, $filter, $data)`
- `delete($collection, $filter)`
- `findAll($collection, $filter, $options)`
- `findOne($collection, $filter)`
- `count($collection, $filter)`
- `aggregate($collection, $pipeline)`

## Existing API patterns
- JSON responses via `jsonResponse(['success' => true, ...])`
- Error handling via `jsonResponse(['success' => false, 'error' => '...'])`
- POST data via `$input = json_decode(file_get_contents('php://input'), true)`
- GET params via `$_GET['param']`

Please design a detailed, step-by-step plan with specific code changes needed for each task. Group related changes by file to minimize edits. Prioritize the tasks that are quickest wins first.


Prompt:
Design a detailed implementation plan for the following tasks in the Email Intelligence System at /var/www/mssql.danmarcrm.com/dev1/extension2v1/

## Context
This is a PHP/MongoDB web app with a dashboard (index.php + app.js), API (api.php), data layer (QueryAdapter.php), and a thread view page (thread_view.php). Chrome extension syncs Gmail threads. AI proxy at aiapi/api_opus/.

## Tasks (in priority order)

### TASK 1: Delete Functionality
Add ability to delete:
- **Contacts**: Already has a Delete button in dashboard UI. Need API endpoint `delete_contact` in api.php + QueryAdapter method. Must also delete associated emails, thread_analysis, contact_profiles, ai_contact_memory for that contact.
- **Email Threads**: Add delete button to threads list. API endpoint `delete_thread` + QueryAdapter. Must delete all emails with that thread_id, thread_analysis, ai_query_responses referencing that thread.
- **AI Responses**: Add delete button next to saved AI responses in thread_view.php. API endpoint `delete_ai_response`. Delete from ai_query_responses collection.

Files: api.php, QueryAdapter.php, app.js, index.php, thread_view.php

### TASK 2: Sorting by Last Activity
- Contacts list: Add sort by `last_contact` date (from contact profiles or max email date)
- Threads list: Add sort by `last_date` (already tracked in thread aggregation)
- Add sort dropdown/buttons in the UI for both tabs

Files: app.js, index.php, api.php (may need sort param support), QueryAdapter.php

### TASK 3: Filters
- **Contacts tab**: Add filters for contact type (client/supplier/other), search by name/email, last activity date range
- **Threads tab**: Add filters for contact name, date range, email count range, analysis status
- **Last Activity date filter**: Date range picker for both tabs
- Add filter UI section above each table

Files: app.js, index.php

### TASK 4: Fix "Etienne Turner" Thread Linkage
The contact name resolution was fixed in QueryAdapter.php but may still have issues:
- MongoDB `getThreadsMongo()` collects all_contacts, weights inbound 2x, picks most frequent
- But if contact_id is NULL or email matches user, it skips — edge case: if ALL emails in thread are from user (outbound only), falls back to first contact
- Need to verify the fix works and potentially handle edge cases

Files: QueryAdapter.php

### TASK 5: Sync by Domain/Email Address
New feature: Dashboard UI panel where user enters a domain (e.g. delta-engineering.be) or email address. System queries Gmail API to find all threads involving that domain/email, then imports them.

Implementation:
- New UI section in dashboard or modal
- New API endpoint `sync_by_domain` that:
  1. Uses GmailClient to search: `from:@domain.com OR to:@domain.com` (or specific email)
  2. Lists matching threads with preview (subject, date, count)
  3. User selects which to import (or "Import All")
  4. Imports selected threads using existing sync_thread logic
- Need two-step flow: search → preview → import

Files: api.php, index.php, app.js, GmailClient.php (may need search method)

### TASK 6: Bulk Delete Threads by Email Address
- Add ability to delete all threads for a specific email/domain
- UI: In contacts list or a cleanup tool
- API: `delete_threads_by_email` — finds all emails from that address, gets unique thread_ids, deletes all data

Files: api.php, QueryAdapter.php, app.js, index.php

### TASK 7: Chrome Extension Manual-Only Mode
- Add toggle in Chrome extension popup/options for "Auto-sync" vs "Manual sync only"
- In manual mode, show a "Sync this thread" button overlay in Gmail
- Store preference in chrome.storage.local
- Extension files are at /Users/dan/Documents/extension2/extension2v1/chrome-extension (local Mac) — we can only prepare the code changes

NOTE: Chrome extension is on user's local Mac, not this server. We should note what needs to change but can't edit those files directly.

### TASK 8: Two-Round AI D3.js Chart
- After Round 2 (or any AI response), add "Generate Chart" button
- AI generates structured JSON (entities, relationships, events)
- D3.js force-directed graph renders: nodes as balloons (color-coded by type), arrows showing relationships, labels
- Interactive: drag, zoom, pan, click for details

Files: thread_view.php (inline JS + D3.js CDN)

### TASK 9: Hide Products Tab
- Remove Products tab from navigation in index.php
- Keep product_search.php file intact

Files: index.php

### TASK 10: Update AI Model Versions
Update to latest models:
- Claude: Add `claude-opus-4-6`, `claude-sonnet-4-6` (current has claude-sonnet-4-5-20250929)
- Other providers: verify current versions

Files to update:
- /extension2v1/aiapi/api_opus/config/api_keys.php — provider models list + defaults
- /extension2v1/public/thread_view.php — MODEL_LIMITS constant
- /extension2v1/config/config.php — CLAUDE_MODEL constant
- Also check /extension2/aiapi/api_opus/config/api_keys.php

Current model config in api_keys.php uses arrays like:
```php
'claude' => [
    'default_model' => 'claude-sonnet-4-5-20250929',
    'models' => ['claude-sonnet-4-5-20250929', 'claude-3-5-sonnet-20241022', ...]
]
```

## Architecture Patterns to Follow
- Use `MongoDatabase::insertOrUpdate()` for upserts (NOT `upsert()`)
- Use `QueryAdapter` for all data access (NOT raw SQL)
- AI proxy models keyed by provider: `[$provider => $model]`
- MongoDB `delete()` method available on MongoDatabase class
- Node.js on server is v10.19 — can't use for JS syntax checks
- `ThreadAnalyzer::stripQuotedContent()` for email body processing

## Available MongoDB Methods (MongoDatabase.php)
- `insert($collection, $data)`
- `insertOrUpdate($collection, $filter, $data)`
- `update($collection, $filter, $data)`
- `delete($collection, $filter)`
- `findAll($collection, $filter, $options)`
- `findOne($collection, $filter)`
- `count($collection, $filter)`
- `aggregate($collection, $pipeline)`

## Existing API patterns
- JSON responses via `jsonResponse(['success' => true, ...])`
- Error handling via `jsonResponse(['success' => false, 'error' => '...'])`
- POST data via `$input = json_decode(file_get_contents('php://input'), true)`
- GET params via `$_GET['param']`

Please design a detailed, step-by-step plan with specific code changes needed for each task. Group related changes by file to minimize edits. Prioritize the tasks that are quickest wins first.


1512:        const MODEL_LIMITS = {
1513-            'claude-sonnet-4-5-20250929': 200000,
1514-            'claude-3-5-sonnet-20241022': 200000,
1515-            'claude-opus-4-5-20250929': 200000,
1516-            'claude-3-opus-20240229': 200000,
1517-            'claude-3-5-haiku-20241022': 200000,
1518-            'gpt-4o': 128000,
1519-            'gpt-4o-mini': 128000,
1520-            'gpt-4-turbo': 128000,
1521-            'gpt-4.1': 1000000,
1522-            'gpt-4.1-mini': 1000000,
1523-            'o3': 200000,
1524-            'o3-mini': 200000,
1525-            'o4-mini': 200000,
1526-            'gemini-2.0-flash': 1048576,
1527-            'gemini-2.5-pro-preview-05-06': 1048576,
1528-            'gemini-2.5-flash-preview-04-17': 1048576,
1529-            'grok-3': 131072,
1530-            'grok-3-mini': 131072,
1531-            'deepseek-chat': 64000,
1532-            'deepseek-reasoner': 64000,
1533-            'qwen-max': 32000,
1534-            'qwen-plus': 131000,
1535-            'mistral-large-latest': 128000,
1536-            'command-a-03-2025': 256000,
1537-            'command-r-plus': 128000
1538-        };
1539-
1540-        function getSmallestModelLimit() {
1541-            var selectedProviders = getSelectedProviders();
1542-            var minLimit = Infinity;
--
1546:                var limit = MODEL_LIMITS[model] || 128000;
1547-                if (limit < minLimit) minLimit = limit;
1548-            });
1549-            return minLimit === Infinity ? 128000 : minLimit;
1550-        }
1551-
1552-        function estimateCurrentTokens() {
1553-            var content = buildEmailContent();
1554-            var question = (document.getElementById('ai-question').value || '').trim();
1555-            var context = (document.getElementById('ai-context').value || '').trim();
1556-            var agent = AI_AGENTS[selectedAgent];
1557-            var total = content.length;
1558-            if (agent) total += agent.systemPrompt.length;
1559-            if (question) total += question.length;
1560-            if (context) total += context.length;
1561-            // Add conversation history estimate
1562-            total += buildConversationContext().length;
1563-            // Add context threads + checkbox threads estimate
1564-            // Use emailCount * 500 chars per stripped email (realistic average)
1565-            var checkboxThreads = getSelectedThreads();
1566-            contextThreads.forEach(function(ct) { total += ct.emailCount * 500; });
1567-            total += checkboxThreads.length * 5000; // rough estimate for checkbox threads
1568-            return Math.ceil(total / 3.5);
1569-        }
1570-
1571-        function updateTokenEstimate() {
1572-            var el = document.getElementById('token-estimate');
1573-            if (!el) return;
1574-            var tokens = estimateCurrentTokens();
1575-            var limit = getSmallestModelLimit();
1576-            var pct = (tokens / limit) * 100;

Prompt:
Design a detailed implementation plan for the following tasks in the Email Intelligence System at /var/www/mssql.danmarcrm.com/dev1/extension2v1/

## Context
This is a PHP/MongoDB web app with a dashboard (index.php + app.js), API (api.php), data layer (QueryAdapter.php), and a thread view page (thread_view.php). Chrome extension syncs Gmail threads. AI proxy at aiapi/api_opus/.

## Tasks (in priority order)

### TASK 1: Delete Functionality
Add ability to delete:
- **Contacts**: Already has a Delete button in dashboard UI. Need API endpoint `delete_contact` in api.php + QueryAdapter method. Must also delete associated emails, thread_analysis, contact_profiles, ai_contact_memory for that contact.
- **Email Threads**: Add delete button to threads list. API endpoint `delete_thread` + QueryAdapter. Must delete all emails with that thread_id, thread_analysis, ai_query_responses referencing that thread.
- **AI Responses**: Add delete button next to saved AI responses in thread_view.php. API endpoint `delete_ai_response`. Delete from ai_query_responses collection.

Files: api.php, QueryAdapter.php, app.js, index.php, thread_view.php

### TASK 2: Sorting by Last Activity
- Contacts list: Add sort by `last_contact` date (from contact profiles or max email date)
- Threads list: Add sort by `last_date` (already tracked in thread aggregation)
- Add sort dropdown/buttons in the UI for both tabs

Files: app.js, index.php, api.php (may need sort param support), QueryAdapter.php

### TASK 3: Filters
- **Contacts tab**: Add filters for contact type (client/supplier/other), search by name/email, last activity date range
- **Threads tab**: Add filters for contact name, date range, email count range, analysis status
- **Last Activity date filter**: Date range picker for both tabs
- Add filter UI section above each table

Files: app.js, index.php

### TASK 4: Fix "Etienne Turner" Thread Linkage
The contact name resolution was fixed in QueryAdapter.php but may still have issues:
- MongoDB `getThreadsMongo()` collects all_contacts, weights inbound 2x, picks most frequent
- But if contact_id is NULL or email matches user, it skips — edge case: if ALL emails in thread are from user (outbound only), falls back to first contact
- Need to verify the fix works and potentially handle edge cases

Files: QueryAdapter.php

### TASK 5: Sync by Domain/Email Address
New feature: Dashboard UI panel where user enters a domain (e.g. delta-engineering.be) or email address. System queries Gmail API to find all threads involving that domain/email, then imports them.

Implementation:
- New UI section in dashboard or modal
- New API endpoint `sync_by_domain` that:
  1. Uses GmailClient to search: `from:@domain.com OR to:@domain.com` (or specific email)
  2. Lists matching threads with preview (subject, date, count)
  3. User selects which to import (or "Import All")
  4. Imports selected threads using existing sync_thread logic
- Need two-step flow: search → preview → import

Files: api.php, index.php, app.js, GmailClient.php (may need search method)

### TASK 6: Bulk Delete Threads by Email Address
- Add ability to delete all threads for a specific email/domain
- UI: In contacts list or a cleanup tool
- API: `delete_threads_by_email` — finds all emails from that address, gets unique thread_ids, deletes all data

Files: api.php, QueryAdapter.php, app.js, index.php

### TASK 7: Chrome Extension Manual-Only Mode
- Add toggle in Chrome extension popup/options for "Auto-sync" vs "Manual sync only"
- In manual mode, show a "Sync this thread" button overlay in Gmail
- Store preference in chrome.storage.local
- Extension files are at /Users/dan/Documents/extension2/extension2v1/chrome-extension (local Mac) — we can only prepare the code changes

NOTE: Chrome extension is on user's local Mac, not this server. We should note what needs to change but can't edit those files directly.

### TASK 8: Two-Round AI D3.js Chart
- After Round 2 (or any AI response), add "Generate Chart" button
- AI generates structured JSON (entities, relationships, events)
- D3.js force-directed graph renders: nodes as balloons (color-coded by type), arrows showing relationships, labels
- Interactive: drag, zoom, pan, click for details

Files: thread_view.php (inline JS + D3.js CDN)

### TASK 9: Hide Products Tab
- Remove Products tab from navigation in index.php
- Keep product_search.php file intact

Files: index.php

### TASK 10: Update AI Model Versions
Update to latest models:
- Claude: Add `claude-opus-4-6`, `claude-sonnet-4-6` (current has claude-sonnet-4-5-20250929)
- Other providers: verify current versions

Files to update:
- /extension2v1/aiapi/api_opus/config/api_keys.php — provider models list + defaults
- /extension2v1/public/thread_view.php — MODEL_LIMITS constant
- /extension2v1/config/config.php — CLAUDE_MODEL constant
- Also check /extension2/aiapi/api_opus/config/api_keys.php

Current model config in api_keys.php uses arrays like:
```php
'claude' => [
    'default_model' => 'claude-sonnet-4-5-20250929',
    'models' => ['claude-sonnet-4-5-20250929', 'claude-3-5-sonnet-20241022', ...]
]
```

## Architecture Patterns to Follow
- Use `MongoDatabase::insertOrUpdate()` for upserts (NOT `upsert()`)
- Use `QueryAdapter` for all data access (NOT raw SQL)
- AI proxy models keyed by provider: `[$provider => $model]`
- MongoDB `delete()` method available on MongoDatabase class
- Node.js on server is v10.19 — can't use for JS syntax checks
- `ThreadAnalyzer::stripQuotedContent()` for email body processing

## Available MongoDB Methods (MongoDatabase.php)
- `insert($collection, $data)`
- `insertOrUpdate($collection, $filter, $data)`
- `update($collection, $filter, $data)`
- `delete($collection, $filter)`
- `findAll($collection, $filter, $options)`
- `findOne($collection, $filter)`
- `count($collection, $filter)`
- `aggregate($collection, $pipeline)`

## Existing API patterns
- JSON responses via `jsonResponse(['success' => true, ...])`
- Error handling via `jsonResponse(['success' => false, 'error' => '...'])`
- POST data via `$input = json_decode(file_get_contents('php://input'), true)`
- GET params via `$_GET['param']`

Please design a detailed, step-by-step plan with specific code changes needed for each task. Group related changes by file to minimize edits. Prioritize the tasks that are quickest wins first.


Prompt:
Design a detailed implementation plan for the following tasks in the Email Intelligence System at /var/www/mssql.danmarcrm.com/dev1/extension2v1/

## Context
This is a PHP/MongoDB web app with a dashboard (index.php + app.js), API (api.php), data layer (QueryAdapter.php), and a thread view page (thread_view.php). Chrome extension syncs Gmail threads. AI proxy at aiapi/api_opus/.

## Tasks (in priority order)

### TASK 1: Delete Functionality
Add ability to delete:
- **Contacts**: Already has a Delete button in dashboard UI. Need API endpoint `delete_contact` in api.php + QueryAdapter method. Must also delete associated emails, thread_analysis, contact_profiles, ai_contact_memory for that contact.
- **Email Threads**: Add delete button to threads list. API endpoint `delete_thread` + QueryAdapter. Must delete all emails with that thread_id, thread_analysis, ai_query_responses referencing that thread.
- **AI Responses**: Add delete button next to saved AI responses in thread_view.php. API endpoint `delete_ai_response`. Delete from ai_query_responses collection.

Files: api.php, QueryAdapter.php, app.js, index.php, thread_view.php

### TASK 2: Sorting by Last Activity
- Contacts list: Add sort by `last_contact` date (from contact profiles or max email date)
- Threads list: Add sort by `last_date` (already tracked in thread aggregation)
- Add sort dropdown/buttons in the UI for both tabs

Files: app.js, index.php, api.php (may need sort param support), QueryAdapter.php

### TASK 3: Filters
- **Contacts tab**: Add filters for contact type (client/supplier/other), search by name/email, last activity date range
- **Threads tab**: Add filters for contact name, date range, email count range, analysis status
- **Last Activity date filter**: Date range picker for both tabs
- Add filter UI section above each table

Files: app.js, index.php

### TASK 4: Fix "Etienne Turner" Thread Linkage
The contact name resolution was fixed in QueryAdapter.php but may still have issues:
- MongoDB `getThreadsMongo()` collects all_contacts, weights inbound 2x, picks most frequent
- But if contact_id is NULL or email matches user, it skips — edge case: if ALL emails in thread are from user (outbound only), falls back to first contact
- Need to verify the fix works and potentially handle edge cases

Files: QueryAdapter.php

### TASK 5: Sync by Domain/Email Address
New feature: Dashboard UI panel where user enters a domain (e.g. delta-engineering.be) or email address. System queries Gmail API to find all threads involving that domain/email, then imports them.

Implementation:
- New UI section in dashboard or modal
- New API endpoint `sync_by_domain` that:
  1. Uses GmailClient to search: `from:@domain.com OR to:@domain.com` (or specific email)
  2. Lists matching threads with preview (subject, date, count)
  3. User selects which to import (or "Import All")
  4. Imports selected threads using existing sync_thread logic
- Need two-step flow: search → preview → import

Files: api.php, index.php, app.js, GmailClient.php (may need search method)

### TASK 6: Bulk Delete Threads by Email Address
- Add ability to delete all threads for a specific email/domain
- UI: In contacts list or a cleanup tool
- API: `delete_threads_by_email` — finds all emails from that address, gets unique thread_ids, deletes all data

Files: api.php, QueryAdapter.php, app.js, index.php

### TASK 7: Chrome Extension Manual-Only Mode
- Add toggle in Chrome extension popup/options for "Auto-sync" vs "Manual sync only"
- In manual mode, show a "Sync this thread" button overlay in Gmail
- Store preference in chrome.storage.local
- Extension files are at /Users/dan/Documents/extension2/extension2v1/chrome-extension (local Mac) — we can only prepare the code changes

NOTE: Chrome extension is on user's local Mac, not this server. We should note what needs to change but can't edit those files directly.

### TASK 8: Two-Round AI D3.js Chart
- After Round 2 (or any AI response), add "Generate Chart" button
- AI generates structured JSON (entities, relationships, events)
- D3.js force-directed graph renders: nodes as balloons (color-coded by type), arrows showing relationships, labels
- Interactive: drag, zoom, pan, click for details

Files: thread_view.php (inline JS + D3.js CDN)

### TASK 9: Hide Products Tab
- Remove Products tab from navigation in index.php
- Keep product_search.php file intact

Files: index.php

### TASK 10: Update AI Model Versions
Update to latest models:
- Claude: Add `claude-opus-4-6`, `claude-sonnet-4-6` (current has claude-sonnet-4-5-20250929)
- Other providers: verify current versions

Files to update:
- /extension2v1/aiapi/api_opus/config/api_keys.php — provider models list + defaults
- /extension2v1/public/thread_view.php — MODEL_LIMITS constant
- /extension2v1/config/config.php — CLAUDE_MODEL constant
- Also check /extension2/aiapi/api_opus/config/api_keys.php

Current model config in api_keys.php uses arrays like:
```php
'claude' => [
    'default_model' => 'claude-sonnet-4-5-20250929',
    'models' => ['claude-sonnet-4-5-20250929', 'claude-3-5-sonnet-20241022', ...]
]
```

## Architecture Patterns to Follow
- Use `MongoDatabase::insertOrUpdate()` for upserts (NOT `upsert()`)
- Use `QueryAdapter` for all data access (NOT raw SQL)
- AI proxy models keyed by provider: `[$provider => $model]`
- MongoDB `delete()` method available on MongoDatabase class
- Node.js on server is v10.19 — can't use for JS syntax checks
- `ThreadAnalyzer::stripQuotedContent()` for email body processing

## Available MongoDB Methods (MongoDatabase.php)
- `insert($collection, $data)`
- `insertOrUpdate($collection, $filter, $data)`
- `update($collection, $filter, $data)`
- `delete($collection, $filter)`
- `findAll($collection, $filter, $options)`
- `findOne($collection, $filter)`
- `count($collection, $filter)`
- `aggregate($collection, $pipeline)`

## Existing API patterns
- JSON responses via `jsonResponse(['success' => true, ...])`
- Error handling via `jsonResponse(['success' => false, 'error' => '...'])`
- POST data via `$input = json_decode(file_get_contents('php://input'), true)`
- GET params via `$_GET['param']`

Please design a detailed, step-by-step plan with specific code changes needed for each task. Group related changes by file to minimize edits. Prioritize the tasks that are quickest wins first.


182:define('CLAUDE_MODEL', 'claude-sonnet-4-5-20250929'); // Claude Sonnet 4.5 (latest)
183-define('CLAUDE_MAX_TOKENS', 16000); // Increased for detailed thread analysis
184-
185-/**

Prompt:
Design a detailed implementation plan for the following tasks in the Email Intelligence System at /var/www/mssql.danmarcrm.com/dev1/extension2v1/

## Context
This is a PHP/MongoDB web app with a dashboard (index.php + app.js), API (api.php), data layer (QueryAdapter.php), and a thread view page (thread_view.php). Chrome extension syncs Gmail threads. AI proxy at aiapi/api_opus/.

## Tasks (in priority order)

### TASK 1: Delete Functionality
Add ability to delete:
- **Contacts**: Already has a Delete button in dashboard UI. Need API endpoint `delete_contact` in api.php + QueryAdapter method. Must also delete associated emails, thread_analysis, contact_profiles, ai_contact_memory for that contact.
- **Email Threads**: Add delete button to threads list. API endpoint `delete_thread` + QueryAdapter. Must delete all emails with that thread_id, thread_analysis, ai_query_responses referencing that thread.
- **AI Responses**: Add delete button next to saved AI responses in thread_view.php. API endpoint `delete_ai_response`. Delete from ai_query_responses collection.

Files: api.php, QueryAdapter.php, app.js, index.php, thread_view.php

### TASK 2: Sorting by Last Activity
- Contacts list: Add sort by `last_contact` date (from contact profiles or max email date)
- Threads list: Add sort by `last_date` (already tracked in thread aggregation)
- Add sort dropdown/buttons in the UI for both tabs

Files: app.js, index.php, api.php (may need sort param support), QueryAdapter.php

### TASK 3: Filters
- **Contacts tab**: Add filters for contact type (client/supplier/other), search by name/email, last activity date range
- **Threads tab**: Add filters for contact name, date range, email count range, analysis status
- **Last Activity date filter**: Date range picker for both tabs
- Add filter UI section above each table

Files: app.js, index.php

### TASK 4: Fix "Etienne Turner" Thread Linkage
The contact name resolution was fixed in QueryAdapter.php but may still have issues:
- MongoDB `getThreadsMongo()` collects all_contacts, weights inbound 2x, picks most frequent
- But if contact_id is NULL or email matches user, it skips — edge case: if ALL emails in thread are from user (outbound only), falls back to first contact
- Need to verify the fix works and potentially handle edge cases

Files: QueryAdapter.php

### TASK 5: Sync by Domain/Email Address
New feature: Dashboard UI panel where user enters a domain (e.g. delta-engineering.be) or email address. System queries Gmail API to find all threads involving that domain/email, then imports them.

Implementation:
- New UI section in dashboard or modal
- New API endpoint `sync_by_domain` that:
  1. Uses GmailClient to search: `from:@domain.com OR to:@domain.com` (or specific email)
  2. Lists matching threads with preview (subject, date, count)
  3. User selects which to import (or "Import All")
  4. Imports selected threads using existing sync_thread logic
- Need two-step flow: search → preview → import

Files: api.php, index.php, app.js, GmailClient.php (may need search method)

### TASK 6: Bulk Delete Threads by Email Address
- Add ability to delete all threads for a specific email/domain
- UI: In contacts list or a cleanup tool
- API: `delete_threads_by_email` — finds all emails from that address, gets unique thread_ids, deletes all data

Files: api.php, QueryAdapter.php, app.js, index.php

### TASK 7: Chrome Extension Manual-Only Mode
- Add toggle in Chrome extension popup/options for "Auto-sync" vs "Manual sync only"
- In manual mode, show a "Sync this thread" button overlay in Gmail
- Store preference in chrome.storage.local
- Extension files are at /Users/dan/Documents/extension2/extension2v1/chrome-extension (local Mac) — we can only prepare the code changes

NOTE: Chrome extension is on user's local Mac, not this server. We should note what needs to change but can't edit those files directly.

### TASK 8: Two-Round AI D3.js Chart
- After Round 2 (or any AI response), add "Generate Chart" button
- AI generates structured JSON (entities, relationships, events)
- D3.js force-directed graph renders: nodes as balloons (color-coded by type), arrows showing relationships, labels
- Interactive: drag, zoom, pan, click for details

Files: thread_view.php (inline JS + D3.js CDN)

### TASK 9: Hide Products Tab
- Remove Products tab from navigation in index.php
- Keep product_search.php file intact

Files: index.php

### TASK 10: Update AI Model Versions
Update to latest models:
- Claude: Add `claude-opus-4-6`, `claude-sonnet-4-6` (current has claude-sonnet-4-5-20250929)
- Other providers: verify current versions

Files to update:
- /extension2v1/aiapi/api_opus/config/api_keys.php — provider models list + defaults
- /extension2v1/public/thread_view.php — MODEL_LIMITS constant
- /extension2v1/config/config.php — CLAUDE_MODEL constant
- Also check /extension2/aiapi/api_opus/config/api_keys.php

Current model config in api_keys.php uses arrays like:
```php
'claude' => [
    'default_model' => 'claude-sonnet-4-5-20250929',
    'models' => ['claude-sonnet-4-5-20250929', 'claude-3-5-sonnet-20241022', ...]
]
```

## Architecture Patterns to Follow
- Use `MongoDatabase::insertOrUpdate()` for upserts (NOT `upsert()`)
- Use `QueryAdapter` for all data access (NOT raw SQL)
- AI proxy models keyed by provider: `[$provider => $model]`
- MongoDB `delete()` method available on MongoDatabase class
- Node.js on server is v10.19 — can't use for JS syntax checks
- `ThreadAnalyzer::stripQuotedContent()` for email body processing

## Available MongoDB Methods (MongoDatabase.php)
- `insert($collection, $data)`
- `insertOrUpdate($collection, $filter, $data)`
- `update($collection, $filter, $data)`
- `delete($collection, $filter)`
- `findAll($collection, $filter, $options)`
- `findOne($collection, $filter)`
- `count($collection, $filter)`
- `aggregate($collection, $pipeline)`

## Existing API patterns
- JSON responses via `jsonResponse(['success' => true, ...])`
- Error handling via `jsonResponse(['success' => false, 'error' => '...'])`
- POST data via `$input = json_decode(file_get_contents('php://input'), true)`
- GET params via `$_GET['param']`

Please design a detailed, step-by-step plan with specific code changes needed for each task. Group related changes by file to minimize edits. Prioritize the tasks that are quickest wins first.


Prompt:
Design a detailed implementation plan for the following tasks in the Email Intelligence System at /var/www/mssql.danmarcrm.com/dev1/extension2v1/

## Context
This is a PHP/MongoDB web app with a dashboard (index.php + app.js), API (api.php), data layer (QueryAdapter.php), and a thread view page (thread_view.php). Chrome extension syncs Gmail threads. AI proxy at aiapi/api_opus/.

## Tasks (in priority order)

### TASK 1: Delete Functionality
Add ability to delete:
- **Contacts**: Already has a Delete button in dashboard UI. Need API endpoint `delete_contact` in api.php + QueryAdapter method. Must also delete associated emails, thread_analysis, contact_profiles, ai_contact_memory for that contact.
- **Email Threads**: Add delete button to threads list. API endpoint `delete_thread` + QueryAdapter. Must delete all emails with that thread_id, thread_analysis, ai_query_responses referencing that thread.
- **AI Responses**: Add delete button next to saved AI responses in thread_view.php. API endpoint `delete_ai_response`. Delete from ai_query_responses collection.

Files: api.php, QueryAdapter.php, app.js, index.php, thread_view.php

### TASK 2: Sorting by Last Activity
- Contacts list: Add sort by `last_contact` date (from contact profiles or max email date)
- Threads list: Add sort by `last_date` (already tracked in thread aggregation)
- Add sort dropdown/buttons in the UI for both tabs

Files: app.js, index.php, api.php (may need sort param support), QueryAdapter.php

### TASK 3: Filters
- **Contacts tab**: Add filters for contact type (client/supplier/other), search by name/email, last activity date range
- **Threads tab**: Add filters for contact name, date range, email count range, analysis status
- **Last Activity date filter**: Date range picker for both tabs
- Add filter UI section above each table

Files: app.js, index.php

### TASK 4: Fix "Etienne Turner" Thread Linkage
The contact name resolution was fixed in QueryAdapter.php but may still have issues:
- MongoDB `getThreadsMongo()` collects all_contacts, weights inbound 2x, picks most frequent
- But if contact_id is NULL or email matches user, it skips — edge case: if ALL emails in thread are from user (outbound only), falls back to first contact
- Need to verify the fix works and potentially handle edge cases

Files: QueryAdapter.php

### TASK 5: Sync by Domain/Email Address
New feature: Dashboard UI panel where user enters a domain (e.g. delta-engineering.be) or email address. System queries Gmail API to find all threads involving that domain/email, then imports them.

Implementation:
- New UI section in dashboard or modal
- New API endpoint `sync_by_domain` that:
  1. Uses GmailClient to search: `from:@domain.com OR to:@domain.com` (or specific email)
  2. Lists matching threads with preview (subject, date, count)
  3. User selects which to import (or "Import All")
  4. Imports selected threads using existing sync_thread logic
- Need two-step flow: search → preview → import

Files: api.php, index.php, app.js, GmailClient.php (may need search method)

### TASK 6: Bulk Delete Threads by Email Address
- Add ability to delete all threads for a specific email/domain
- UI: In contacts list or a cleanup tool
- API: `delete_threads_by_email` — finds all emails from that address, gets unique thread_ids, deletes all data

Files: api.php, QueryAdapter.php, app.js, index.php

### TASK 7: Chrome Extension Manual-Only Mode
- Add toggle in Chrome extension popup/options for "Auto-sync" vs "Manual sync only"
- In manual mode, show a "Sync this thread" button overlay in Gmail
- Store preference in chrome.storage.local
- Extension files are at /Users/dan/Documents/extension2/extension2v1/chrome-extension (local Mac) — we can only prepare the code changes

NOTE: Chrome extension is on user's local Mac, not this server. We should note what needs to change but can't edit those files directly.

### TASK 8: Two-Round AI D3.js Chart
- After Round 2 (or any AI response), add "Generate Chart" button
- AI generates structured JSON (entities, relationships, events)
- D3.js force-directed graph renders: nodes as balloons (color-coded by type), arrows showing relationships, labels
- Interactive: drag, zoom, pan, click for details

Files: thread_view.php (inline JS + D3.js CDN)

### TASK 9: Hide Products Tab
- Remove Products tab from navigation in index.php
- Keep product_search.php file intact

Files: index.php

### TASK 10: Update AI Model Versions
Update to latest models:
- Claude: Add `claude-opus-4-6`, `claude-sonnet-4-6` (current has claude-sonnet-4-5-20250929)
- Other providers: verify current versions

Files to update:
- /extension2v1/aiapi/api_opus/config/api_keys.php — provider models list + defaults
- /extension2v1/public/thread_view.php — MODEL_LIMITS constant
- /extension2v1/config/config.php — CLAUDE_MODEL constant
- Also check /extension2/aiapi/api_opus/config/api_keys.php

Current model config in api_keys.php uses arrays like:
```php
'claude' => [
    'default_model' => 'claude-sonnet-4-5-20250929',
    'models' => ['claude-sonnet-4-5-20250929', 'claude-3-5-sonnet-20241022', ...]
]
```

## Architecture Patterns to Follow
- Use `MongoDatabase::insertOrUpdate()` for upserts (NOT `upsert()`)
- Use `QueryAdapter` for all data access (NOT raw SQL)
- AI proxy models keyed by provider: `[$provider => $model]`
- MongoDB `delete()` method available on MongoDatabase class
- Node.js on server is v10.19 — can't use for JS syntax checks
- `ThreadAnalyzer::stripQuotedContent()` for email body processing

## Available MongoDB Methods (MongoDatabase.php)
- `insert($collection, $data)`
- `insertOrUpdate($collection, $filter, $data)`
- `update($collection, $filter, $data)`
- `delete($collection, $filter)`
- `findAll($collection, $filter, $options)`
- `findOne($collection, $filter)`
- `count($collection, $filter)`
- `aggregate($collection, $pipeline)`

## Existing API patterns
- JSON responses via `jsonResponse(['success' => true, ...])`
- Error handling via `jsonResponse(['success' => false, 'error' => '...'])`
- POST data via `$input = json_decode(file_get_contents('php://input'), true)`
- GET params via `$_GET['param']`

Please design a detailed, step-by-step plan with specific code changes needed for each task. Group related changes by file to minimize edits. Prioritize the tasks that are quickest wins first.


1195→                <?php if (!empty($savedResponses)): ?>
  1196→

  1197→

  1198→
Previous AI Analyses (<?= $totalSavedResponses ?> total)

  1199→

  1200→

  1201→                        <?php foreach ($savedResponses as $saved):
  1202→                            // Determine what to display as the "question"
  1203→                            $displayQuestion = $saved['question'] ?? 'General Analysis';
  1204→                            $hasContext = !empty($saved['context']);
  1205→                            $isDefaultQuestion = strpos($displayQuestion, 'Please analyze this email conversation') === 0;
  1206→
  1207→                            // If question is the default and user provided context, show context instead
  1208→                            if ($isDefaultQuestion && $hasContext) {
  1209→                                $displayQuestion = '[Context] ' . $saved['context'];
  1210→                            } elseif ($hasContext && !$isDefaultQuestion) {
  1211→                                // If both custom question and context exist, show question + indicator
  1212→                                $displayQuestion = $displayQuestion . ' (+context)';
  1213→                            }
  1214→
  1215→                            // Truncate to 200 chars instead of 100
  1216→                            $displayQuestion = strlen($displayQuestion) > 200
  1217→                                ? substr($displayQuestion, 0, 200) . '...'
  1218→                                : $displayQuestion;
  1219→
  1220→                            // Get response excerpt for easier identification
  1221→                            $responseText = $saved['response']['response'] ?? '';
  1222→                            $responseExcerpt = strlen($responseText) > 120
  1223→                                ? substr($responseText, 0, 120) . '...'
  1224→                                : $responseText;
  1225→                        ?>
  1226→                        <div class="saved-response" id="saved-response-<?= $saved['_id'] ?>" data-id="<?= $saved['_id'] ?>">
  1227→

  1228→
  1229→                                    <?= htmlspecialchars($displayQuestion) ?>
  1230→
  1231→
  1232→                                    <?= date('M j, Y g:i A', strtotime($saved['created_at'] ?? 'now')) ?>
  1233→
  1234→

  1235→

  1236→                                <?= htmlspecialchars($saved['provider'] ?? 'Unknown') ?> /
  1237→                                <?= htmlspecialchars($saved['model'] ?? 'Unknown') ?>
  1238→

  1239→                            <?php if ($responseExcerpt): ?>
  1240→

  1241→                                <?= htmlspecialchars($responseExcerpt) ?>
  1242→

  1243→                            <?php endif; ?>
  1244→

  1245→                                <button class="btn-view" onclick="event.stopPropagation(); quickViewResponse('<?= $saved['_id'] ?>')">
  1246→                                    👁 Quick View
  1247→                                </button>
  1248→                                <button class="btn-expand" onclick="event.stopPropagation(); loadSavedResponse('<?= $saved['_id'] ?>')">
  1249→                                    📄 Full View
  1250→                                </button>
  1251→

  1252→

  1253→                        <?php endforeach; ?>
  1254→

  1255→                    <?php if ($totalSavedResponses > $savedResponsesLimit): ?>
  1256→

  1257→                        <button class="btn btn-secondary" id="load-more-btn" onclick="loadMoreResponses()"
  1258→                                data-offset="<?= $savedResponsesLimit ?>"
  1259→                                data-total="<?= $totalSavedResponses ?>">
  1260→                            Load More (<?= $totalSavedResponses - $savedResponsesLimit ?> remaining)
  1261→                        </button>
  1262→

  1263→                    <?php endif; ?>
  1264→

  1265→                <?php endif; ?>
  1266→

  1267→
  1268→
  1269→

  1270→
  1271→                <?php if (!empty($otherThreads)): ?>
  1272→

  1273→

  1274→
Include Other Threads

Prompt:
Design a detailed implementation plan for the following tasks in the Email Intelligence System at /var/www/mssql.danmarcrm.com/dev1/extension2v1/

## Context
This is a PHP/MongoDB web app with a dashboard (index.php + app.js), API (api.php), data layer (QueryAdapter.php), and a thread view page (thread_view.php). Chrome extension syncs Gmail threads. AI proxy at aiapi/api_opus/.

## Tasks (in priority order)

### TASK 1: Delete Functionality
Add ability to delete:
- **Contacts**: Already has a Delete button in dashboard UI. Need API endpoint `delete_contact` in api.php + QueryAdapter method. Must also delete associated emails, thread_analysis, contact_profiles, ai_contact_memory for that contact.
- **Email Threads**: Add delete button to threads list. API endpoint `delete_thread` + QueryAdapter. Must delete all emails with that thread_id, thread_analysis, ai_query_responses referencing that thread.
- **AI Responses**: Add delete button next to saved AI responses in thread_view.php. API endpoint `delete_ai_response`. Delete from ai_query_responses collection.

Files: api.php, QueryAdapter.php, app.js, index.php, thread_view.php

### TASK 2: Sorting by Last Activity
- Contacts list: Add sort by `last_contact` date (from contact profiles or max email date)
- Threads list: Add sort by `last_date` (already tracked in thread aggregation)
- Add sort dropdown/buttons in the UI for both tabs

Files: app.js, index.php, api.php (may need sort param support), QueryAdapter.php

### TASK 3: Filters
- **Contacts tab**: Add filters for contact type (client/supplier/other), search by name/email, last activity date range
- **Threads tab**: Add filters for contact name, date range, email count range, analysis status
- **Last Activity date filter**: Date range picker for both tabs
- Add filter UI section above each table

Files: app.js, index.php

### TASK 4: Fix "Etienne Turner" Thread Linkage
The contact name resolution was fixed in QueryAdapter.php but may still have issues:
- MongoDB `getThreadsMongo()` collects all_contacts, weights inbound 2x, picks most frequent
- But if contact_id is NULL or email matches user, it skips — edge case: if ALL emails in thread are from user (outbound only), falls back to first contact
- Need to verify the fix works and potentially handle edge cases

Files: QueryAdapter.php

### TASK 5: Sync by Domain/Email Address
New feature: Dashboard UI panel where user enters a domain (e.g. delta-engineering.be) or email address. System queries Gmail API to find all threads involving that domain/email, then imports them.

Implementation:
- New UI section in dashboard or modal
- New API endpoint `sync_by_domain` that:
  1. Uses GmailClient to search: `from:@domain.com OR to:@domain.com` (or specific email)
  2. Lists matching threads with preview (subject, date, count)
  3. User selects which to import (or "Import All")
  4. Imports selected threads using existing sync_thread logic
- Need two-step flow: search → preview → import

Files: api.php, index.php, app.js, GmailClient.php (may need search method)

### TASK 6: Bulk Delete Threads by Email Address
- Add ability to delete all threads for a specific email/domain
- UI: In contacts list or a cleanup tool
- API: `delete_threads_by_email` — finds all emails from that address, gets unique thread_ids, deletes all data

Files: api.php, QueryAdapter.php, app.js, index.php

### TASK 7: Chrome Extension Manual-Only Mode
- Add toggle in Chrome extension popup/options for "Auto-sync" vs "Manual sync only"
- In manual mode, show a "Sync this thread" button overlay in Gmail
- Store preference in chrome.storage.local
- Extension files are at /Users/dan/Documents/extension2/extension2v1/chrome-extension (local Mac) — we can only prepare the code changes

NOTE: Chrome extension is on user's local Mac, not this server. We should note what needs to change but can't edit those files directly.

### TASK 8: Two-Round AI D3.js Chart
- After Round 2 (or any AI response), add "Generate Chart" button
- AI generates structured JSON (entities, relationships, events)
- D3.js force-directed graph renders: nodes as balloons (color-coded by type), arrows showing relationships, labels
- Interactive: drag, zoom, pan, click for details

Files: thread_view.php (inline JS + D3.js CDN)

### TASK 9: Hide Products Tab
- Remove Products tab from navigation in index.php
- Keep product_search.php file intact

Files: index.php

### TASK 10: Update AI Model Versions
Update to latest models:
- Claude: Add `claude-opus-4-6`, `claude-sonnet-4-6` (current has claude-sonnet-4-5-20250929)
- Other providers: verify current versions

Files to update:
- /extension2v1/aiapi/api_opus/config/api_keys.php — provider models list + defaults
- /extension2v1/public/thread_view.php — MODEL_LIMITS constant
- /extension2v1/config/config.php — CLAUDE_MODEL constant
- Also check /extension2/aiapi/api_opus/config/api_keys.php

Current model config in api_keys.php uses arrays like:
```php
'claude' => [
    'default_model' => 'claude-sonnet-4-5-20250929',
    'models' => ['claude-sonnet-4-5-20250929', 'claude-3-5-sonnet-20241022', ...]
]
```

## Architecture Patterns to Follow
- Use `MongoDatabase::insertOrUpdate()` for upserts (NOT `upsert()`)
- Use `QueryAdapter` for all data access (NOT raw SQL)
- AI proxy models keyed by provider: `[$provider => $model]`
- MongoDB `delete()` method available on MongoDatabase class
- Node.js on server is v10.19 — can't use for JS syntax checks
- `ThreadAnalyzer::stripQuotedContent()` for email body processing

## Available MongoDB Methods (MongoDatabase.php)
- `insert($collection, $data)`
- `insertOrUpdate($collection, $filter, $data)`
- `update($collection, $filter, $data)`
- `delete($collection, $filter)`
- `findAll($collection, $filter, $options)`
- `findOne($collection, $filter)`
- `count($collection, $filter)`
- `aggregate($collection, $pipeline)`

## Existing API patterns
- JSON responses via `jsonResponse(['success' => true, ...])`
- Error handling via `jsonResponse(['success' => false, 'error' => '...'])`
- POST data via `$input = json_decode(file_get_contents('php://input'), true)`
- GET params via `$_GET['param']`

Please design a detailed, step-by-step plan with specific code changes needed for each task. Group related changes by file to minimize edits. Prioritize the tasks that are quickest wins first.


Prompt:
Design a detailed implementation plan for the following tasks in the Email Intelligence System at /var/www/mssql.danmarcrm.com/dev1/extension2v1/

## Context
This is a PHP/MongoDB web app with a dashboard (index.php + app.js), API (api.php), data layer (QueryAdapter.php), and a thread view page (thread_view.php). Chrome extension syncs Gmail threads. AI proxy at aiapi/api_opus/.

## Tasks (in priority order)

### TASK 1: Delete Functionality
Add ability to delete:
- **Contacts**: Already has a Delete button in dashboard UI. Need API endpoint `delete_contact` in api.php + QueryAdapter method. Must also delete associated emails, thread_analysis, contact_profiles, ai_contact_memory for that contact.
- **Email Threads**: Add delete button to threads list. API endpoint `delete_thread` + QueryAdapter. Must delete all emails with that thread_id, thread_analysis, ai_query_responses referencing that thread.
- **AI Responses**: Add delete button next to saved AI responses in thread_view.php. API endpoint `delete_ai_response`. Delete from ai_query_responses collection.

Files: api.php, QueryAdapter.php, app.js, index.php, thread_view.php

### TASK 2: Sorting by Last Activity
- Contacts list: Add sort by `last_contact` date (from contact profiles or max email date)
- Threads list: Add sort by `last_date` (already tracked in thread aggregation)
- Add sort dropdown/buttons in the UI for both tabs

Files: app.js, index.php, api.php (may need sort param support), QueryAdapter.php

### TASK 3: Filters
- **Contacts tab**: Add filters for contact type (client/supplier/other), search by name/email, last activity date range
- **Threads tab**: Add filters for contact name, date range, email count range, analysis status
- **Last Activity date filter**: Date range picker for both tabs
- Add filter UI section above each table

Files: app.js, index.php

### TASK 4: Fix "Etienne Turner" Thread Linkage
The contact name resolution was fixed in QueryAdapter.php but may still have issues:
- MongoDB `getThreadsMongo()` collects all_contacts, weights inbound 2x, picks most frequent
- But if contact_id is NULL or email matches user, it skips — edge case: if ALL emails in thread are from user (outbound only), falls back to first contact
- Need to verify the fix works and potentially handle edge cases

Files: QueryAdapter.php

### TASK 5: Sync by Domain/Email Address
New feature: Dashboard UI panel where user enters a domain (e.g. delta-engineering.be) or email address. System queries Gmail API to find all threads involving that domain/email, then imports them.

Implementation:
- New UI section in dashboard or modal
- New API endpoint `sync_by_domain` that:
  1. Uses GmailClient to search: `from:@domain.com OR to:@domain.com` (or specific email)
  2. Lists matching threads with preview (subject, date, count)
  3. User selects which to import (or "Import All")
  4. Imports selected threads using existing sync_thread logic
- Need two-step flow: search → preview → import

Files: api.php, index.php, app.js, GmailClient.php (may need search method)

### TASK 6: Bulk Delete Threads by Email Address
- Add ability to delete all threads for a specific email/domain
- UI: In contacts list or a cleanup tool
- API: `delete_threads_by_email` — finds all emails from that address, gets unique thread_ids, deletes all data

Files: api.php, QueryAdapter.php, app.js, index.php

### TASK 7: Chrome Extension Manual-Only Mode
- Add toggle in Chrome extension popup/options for "Auto-sync" vs "Manual sync only"
- In manual mode, show a "Sync this thread" button overlay in Gmail
- Store preference in chrome.storage.local
- Extension files are at /Users/dan/Documents/extension2/extension2v1/chrome-extension (local Mac) — we can only prepare the code changes

NOTE: Chrome extension is on user's local Mac, not this server. We should note what needs to change but can't edit those files directly.

### TASK 8: Two-Round AI D3.js Chart
- After Round 2 (or any AI response), add "Generate Chart" button
- AI generates structured JSON (entities, relationships, events)
- D3.js force-directed graph renders: nodes as balloons (color-coded by type), arrows showing relationships, labels
- Interactive: drag, zoom, pan, click for details

Files: thread_view.php (inline JS + D3.js CDN)

### TASK 9: Hide Products Tab
- Remove Products tab from navigation in index.php
- Keep product_search.php file intact

Files: index.php

### TASK 10: Update AI Model Versions
Update to latest models:
- Claude: Add `claude-opus-4-6`, `claude-sonnet-4-6` (current has claude-sonnet-4-5-20250929)
- Other providers: verify current versions

Files to update:
- /extension2v1/aiapi/api_opus/config/api_keys.php — provider models list + defaults
- /extension2v1/public/thread_view.php — MODEL_LIMITS constant
- /extension2v1/config/config.php — CLAUDE_MODEL constant
- Also check /extension2/aiapi/api_opus/config/api_keys.php

Current model config in api_keys.php uses arrays like:
```php
'claude' => [
    'default_model' => 'claude-sonnet-4-5-20250929',
    'models' => ['claude-sonnet-4-5-20250929', 'claude-3-5-sonnet-20241022', ...]
]
```

## Architecture Patterns to Follow
- Use `MongoDatabase::insertOrUpdate()` for upserts (NOT `upsert()`)
- Use `QueryAdapter` for all data access (NOT raw SQL)
- AI proxy models keyed by provider: `[$provider => $model]`
- MongoDB `delete()` method available on MongoDatabase class
- Node.js on server is v10.19 — can't use for JS syntax checks
- `ThreadAnalyzer::stripQuotedContent()` for email body processing

## Available MongoDB Methods (MongoDatabase.php)
- `insert($collection, $data)`
- `insertOrUpdate($collection, $filter, $data)`
- `update($collection, $filter, $data)`
- `delete($collection, $filter)`
- `findAll($collection, $filter, $options)`
- `findOne($collection, $filter)`
- `count($collection, $filter)`
- `aggregate($collection, $pipeline)`

## Existing API patterns
- JSON responses via `jsonResponse(['success' => true, ...])`
- Error handling via `jsonResponse(['success' => false, 'error' => '...'])`
- POST data via `$input = json_decode(file_get_contents('php://input'), true)`
- GET params via `$_GET['param']`

Please design a detailed, step-by-step plan with specific code changes needed for each task. Group related changes by file to minimize edits. Prioritize the tasks that are quickest wins first.


   581→    private function getThreadsMongo(?int $contactId, string $search, int $limit, int $offset): array
   582→    {
   583→        $mongo = MongoDatabase::getInstance();
   584→        $userEmail = defined('GMAIL_USER_EMAIL') ? strtolower(GMAIL_USER_EMAIL) : '';
   585→
   586→        // Build match filter
   587→        $matchFilter = [
   588→            'thread_id' => ['$ne' => null, '$ne' => '']
   589→        ];
   590→
   591→        if ($contactId) {
   592→            $matchFilter['contact_id'] = $contactId;
   593→        }
   594→
   595→        if ($search) {
   596→            $matchFilter['subject'] = ['$regex' => $search, '$options' => 'i'];
   597→        }
   598→
   599→        // Count distinct threads for total
   600→        $countPipeline = [
   601→            ['$match' => $matchFilter],
   602→            ['$group' => ['_id' => '$thread_id']],
   603→            ['$count' => 'total']
   604→        ];
   605→
   606→        $countResult = $mongo->aggregate('emails', $countPipeline);
   607→        $total = !empty($countResult) ? $countResult[0]['total'] : 0;
   608→
   609→        // Get threads with aggregated data
   610→        // Collect all contacts per thread to find the most relevant one (not just $max)
   611→        $pipeline = [
   612→            ['$match' => $matchFilter],
   613→            ['$group' => [
   614→                '_id' => '$thread_id',
   615→                'first_email_id' => ['$min' => '$id'],
   616→                'last_email_id' => ['$max' => '$id'],
   617→                'subject' => ['$first' => '$subject'],
   618→                'first_date' => ['$min' => '$date'],
   619→                'last_date' => ['$max' => '$date'],
   620→                'email_count' => ['$sum' => 1],
   621→                'inbound_count' => ['$sum' => ['$cond' => [['$eq' => ['$direction', 'inbound']], 1, 0]]],
   622→                'outbound_count' => ['$sum' => ['$cond' => [['$eq' => ['$direction', 'outbound']], 1, 0]]],
   623→                'all_contacts' => ['$push' => [
   624→                    'cid' => '$contact_id',
   625→                    'email' => '$from_email',
   626→                    'dir' => '$direction'
   627→                ]]
   628→            ]],
   629→            ['$lookup' => [
   630→                'from' => 'thread_analysis',
   631→                'localField' => '_id',
   632→                'foreignField' => 'thread_id',
   633→                'as' => 'analysis'
   634→            ]],
   635→            ['$project' => [
   636→                '_id' => 0,
   637→                'thread_id' => '$_id',
   638→                'first_email_id' => 1,
   639→                'last_email_id' => 1,
   640→                'subject' => 1,
   641→                'first_date' => 1,
   642→                'last_date' => 1,
   643→                'email_count' => 1,
   644→                'inbound_count' => 1,
   645→                'outbound_count' => 1,
   646→                'all_contacts' => 1,
   647→                'is_analyzed' => ['$arrayElemAt' => ['$analysis.is_analyzed', 0]],
   648→                'needs_reanalysis' => ['$arrayElemAt' => ['$analysis.needs_reanalysis', 0]]
   649→            ]],
   650→            ['$sort' => ['last_date' => -1]],
   651→            ['$skip' => $offset],
   652→            ['$limit' => $limit]
   653→        ];
   654→
   655→        $threads = $mongo->aggregate('emails', $pipeline);
   656→
   657→        // Post-process: find the most frequent external contact per thread
   658→        $contactIds = [];
   659→        foreach ($threads as &$thread) {
   660→            $contactCounts = [];
   661→
   662→            foreach ($thread['all_contacts'] ?? [] as $c) {
   663→                $cid = $c['cid'] ?? null;
   664→                $email = strtolower($c['email'] ?? '');
   665→                $dir = $c['dir'] ?? '';
   666→
   667→                // Skip user's own emails and null contacts
   668→                if (!$cid || $email === $userEmail) continue;
   669→
   670→                // Weight inbound contacts higher (they're the external sender)
   671→                if ($dir === 'inbound') {
   672→                    $contactCounts[$cid] = ($contactCounts[$cid] ?? 0) + 2;
   673→                } else {
   674→                    $contactCounts[$cid] = ($contactCounts[$cid] ?? 0) + 1;
   675→                }
   676→            }
   677→
   678→            // Pick the most frequent contact
   679→            if (!empty($contactCounts)) {
   680→                arsort($contactCounts);
   681→                $thread['contact_id'] = (int)array_key_first($contactCounts);
   682→            } else {
   683→                // Fallback: first non-null contact_id
   684→                $thread['contact_id'] = null;
   685→                foreach ($thread['all_contacts'] ?? [] as $c) {
   686→                    if (!empty($c['cid'])) {
   687→                        $thread['contact_id'] = (int)$c['cid'];
   688→                        break;
   689→                    }
   690→                }
   691→            }
   692→
   693→            if ($thread['contact_id']) {
   694→                $contactIds[] = $thread['contact_id'];
   695→            }
   696→
   697→            unset($thread['all_contacts']);
   698→        }
   699→        unset($thread);
   700→

Prompt:
Design a detailed implementation plan for the following tasks in the Email Intelligence System at /var/www/mssql.danmarcrm.com/dev1/extension2v1/

## Context
This is a PHP/MongoDB web app with a dashboard (index.php + app.js), API (api.php), data layer (QueryAdapter.php), and a thread view page (thread_view.php). Chrome extension syncs Gmail threads. AI proxy at aiapi/api_opus/.

## Tasks (in priority order)

### TASK 1: Delete Functionality
Add ability to delete:
- **Contacts**: Already has a Delete button in dashboard UI. Need API endpoint `delete_contact` in api.php + QueryAdapter method. Must also delete associated emails, thread_analysis, contact_profiles, ai_contact_memory for that contact.
- **Email Threads**: Add delete button to threads list. API endpoint `delete_thread` + QueryAdapter. Must delete all emails with that thread_id, thread_analysis, ai_query_responses referencing that thread.
- **AI Responses**: Add delete button next to saved AI responses in thread_view.php. API endpoint `delete_ai_response`. Delete from ai_query_responses collection.

Files: api.php, QueryAdapter.php, app.js, index.php, thread_view.php

### TASK 2: Sorting by Last Activity
- Contacts list: Add sort by `last_contact` date (from contact profiles or max email date)
- Threads list: Add sort by `last_date` (already tracked in thread aggregation)
- Add sort dropdown/buttons in the UI for both tabs

Files: app.js, index.php, api.php (may need sort param support), QueryAdapter.php

### TASK 3: Filters
- **Contacts tab**: Add filters for contact type (client/supplier/other), search by name/email, last activity date range
- **Threads tab**: Add filters for contact name, date range, email count range, analysis status
- **Last Activity date filter**: Date range picker for both tabs
- Add filter UI section above each table

Files: app.js, index.php

### TASK 4: Fix "Etienne Turner" Thread Linkage
The contact name resolution was fixed in QueryAdapter.php but may still have issues:
- MongoDB `getThreadsMongo()` collects all_contacts, weights inbound 2x, picks most frequent
- But if contact_id is NULL or email matches user, it skips — edge case: if ALL emails in thread are from user (outbound only), falls back to first contact
- Need to verify the fix works and potentially handle edge cases

Files: QueryAdapter.php

### TASK 5: Sync by Domain/Email Address
New feature: Dashboard UI panel where user enters a domain (e.g. delta-engineering.be) or email address. System queries Gmail API to find all threads involving that domain/email, then imports them.

Implementation:
- New UI section in dashboard or modal
- New API endpoint `sync_by_domain` that:
  1. Uses GmailClient to search: `from:@domain.com OR to:@domain.com` (or specific email)
  2. Lists matching threads with preview (subject, date, count)
  3. User selects which to import (or "Import All")
  4. Imports selected threads using existing sync_thread logic
- Need two-step flow: search → preview → import

Files: api.php, index.php, app.js, GmailClient.php (may need search method)

### TASK 6: Bulk Delete Threads by Email Address
- Add ability to delete all threads for a specific email/domain
- UI: In contacts list or a cleanup tool
- API: `delete_threads_by_email` — finds all emails from that address, gets unique thread_ids, deletes all data

Files: api.php, QueryAdapter.php, app.js, index.php

### TASK 7: Chrome Extension Manual-Only Mode
- Add toggle in Chrome extension popup/options for "Auto-sync" vs "Manual sync only"
- In manual mode, show a "Sync this thread" button overlay in Gmail
- Store preference in chrome.storage.local
- Extension files are at /Users/dan/Documents/extension2/extension2v1/chrome-extension (local Mac) — we can only prepare the code changes

NOTE: Chrome extension is on user's local Mac, not this server. We should note what needs to change but can't edit those files directly.

### TASK 8: Two-Round AI D3.js Chart
- After Round 2 (or any AI response), add "Generate Chart" button
- AI generates structured JSON (entities, relationships, events)
- D3.js force-directed graph renders: nodes as balloons (color-coded by type), arrows showing relationships, labels
- Interactive: drag, zoom, pan, click for details

Files: thread_view.php (inline JS + D3.js CDN)

### TASK 9: Hide Products Tab
- Remove Products tab from navigation in index.php
- Keep product_search.php file intact

Files: index.php

### TASK 10: Update AI Model Versions
Update to latest models:
- Claude: Add `claude-opus-4-6`, `claude-sonnet-4-6` (current has claude-sonnet-4-5-20250929)
- Other providers: verify current versions

Files to update:
- /extension2v1/aiapi/api_opus/config/api_keys.php — provider models list + defaults
- /extension2v1/public/thread_view.php — MODEL_LIMITS constant
- /extension2v1/config/config.php — CLAUDE_MODEL constant
- Also check /extension2/aiapi/api_opus/config/api_keys.php

Current model config in api_keys.php uses arrays like:
```php
'claude' => [
    'default_model' => 'claude-sonnet-4-5-20250929',
    'models' => ['claude-sonnet-4-5-20250929', 'claude-3-5-sonnet-20241022', ...]
]
```

## Architecture Patterns to Follow
- Use `MongoDatabase::insertOrUpdate()` for upserts (NOT `upsert()`)
- Use `QueryAdapter` for all data access (NOT raw SQL)
- AI proxy models keyed by provider: `[$provider => $model]`
- MongoDB `delete()` method available on MongoDatabase class
- Node.js on server is v10.19 — can't use for JS syntax checks
- `ThreadAnalyzer::stripQuotedContent()` for email body processing

## Available MongoDB Methods (MongoDatabase.php)
- `insert($collection, $data)`
- `insertOrUpdate($collection, $filter, $data)`
- `update($collection, $filter, $data)`
- `delete($collection, $filter)`
- `findAll($collection, $filter, $options)`
- `findOne($collection, $filter)`
- `count($collection, $filter)`
- `aggregate($collection, $pipeline)`

## Existing API patterns
- JSON responses via `jsonResponse(['success' => true, ...])`
- Error handling via `jsonResponse(['success' => false, 'error' => '...'])`
- POST data via `$input = json_decode(file_get_contents('php://input'), true)`
- GET params via `$_GET['param']`

Please design a detailed, step-by-step plan with specific code changes needed for each task. Group related changes by file to minimize edits. Prioritize the tasks that are quickest wins first.


Prompt:
Design a detailed implementation plan for the following tasks in the Email Intelligence System at /var/www/mssql.danmarcrm.com/dev1/extension2v1/

## Context
This is a PHP/MongoDB web app with a dashboard (index.php + app.js), API (api.php), data layer (QueryAdapter.php), and a thread view page (thread_view.php). Chrome extension syncs Gmail threads. AI proxy at aiapi/api_opus/.

## Tasks (in priority order)

### TASK 1: Delete Functionality
Add ability to delete:
- **Contacts**: Already has a Delete button in dashboard UI. Need API endpoint `delete_contact` in api.php + QueryAdapter method. Must also delete associated emails, thread_analysis, contact_profiles, ai_contact_memory for that contact.
- **Email Threads**: Add delete button to threads list. API endpoint `delete_thread` + QueryAdapter. Must delete all emails with that thread_id, thread_analysis, ai_query_responses referencing that thread.
- **AI Responses**: Add delete button next to saved AI responses in thread_view.php. API endpoint `delete_ai_response`. Delete from ai_query_responses collection.

Files: api.php, QueryAdapter.php, app.js, index.php, thread_view.php

### TASK 2: Sorting by Last Activity
- Contacts list: Add sort by `last_contact` date (from contact profiles or max email date)
- Threads list: Add sort by `last_date` (already tracked in thread aggregation)
- Add sort dropdown/buttons in the UI for both tabs

Files: app.js, index.php, api.php (may need sort param support), QueryAdapter.php

### TASK 3: Filters
- **Contacts tab**: Add filters for contact type (client/supplier/other), search by name/email, last activity date range
- **Threads tab**: Add filters for contact name, date range, email count range, analysis status
- **Last Activity date filter**: Date range picker for both tabs
- Add filter UI section above each table

Files: app.js, index.php

### TASK 4: Fix "Etienne Turner" Thread Linkage
The contact name resolution was fixed in QueryAdapter.php but may still have issues:
- MongoDB `getThreadsMongo()` collects all_contacts, weights inbound 2x, picks most frequent
- But if contact_id is NULL or email matches user, it skips — edge case: if ALL emails in thread are from user (outbound only), falls back to first contact
- Need to verify the fix works and potentially handle edge cases

Files: QueryAdapter.php

### TASK 5: Sync by Domain/Email Address
New feature: Dashboard UI panel where user enters a domain (e.g. delta-engineering.be) or email address. System queries Gmail API to find all threads involving that domain/email, then imports them.

Implementation:
- New UI section in dashboard or modal
- New API endpoint `sync_by_domain` that:
  1. Uses GmailClient to search: `from:@domain.com OR to:@domain.com` (or specific email)
  2. Lists matching threads with preview (subject, date, count)
  3. User selects which to import (or "Import All")
  4. Imports selected threads using existing sync_thread logic
- Need two-step flow: search → preview → import

Files: api.php, index.php, app.js, GmailClient.php (may need search method)

### TASK 6: Bulk Delete Threads by Email Address
- Add ability to delete all threads for a specific email/domain
- UI: In contacts list or a cleanup tool
- API: `delete_threads_by_email` — finds all emails from that address, gets unique thread_ids, deletes all data

Files: api.php, QueryAdapter.php, app.js, index.php

### TASK 7: Chrome Extension Manual-Only Mode
- Add toggle in Chrome extension popup/options for "Auto-sync" vs "Manual sync only"
- In manual mode, show a "Sync this thread" button overlay in Gmail
- Store preference in chrome.storage.local
- Extension files are at /Users/dan/Documents/extension2/extension2v1/chrome-extension (local Mac) — we can only prepare the code changes

NOTE: Chrome extension is on user's local Mac, not this server. We should note what needs to change but can't edit those files directly.

### TASK 8: Two-Round AI D3.js Chart
- After Round 2 (or any AI response), add "Generate Chart" button
- AI generates structured JSON (entities, relationships, events)
- D3.js force-directed graph renders: nodes as balloons (color-coded by type), arrows showing relationships, labels
- Interactive: drag, zoom, pan, click for details

Files: thread_view.php (inline JS + D3.js CDN)

### TASK 9: Hide Products Tab
- Remove Products tab from navigation in index.php
- Keep product_search.php file intact

Files: index.php

### TASK 10: Update AI Model Versions
Update to latest models:
- Claude: Add `claude-opus-4-6`, `claude-sonnet-4-6` (current has claude-sonnet-4-5-20250929)
- Other providers: verify current versions

Files to update:
- /extension2v1/aiapi/api_opus/config/api_keys.php — provider models list + defaults
- /extension2v1/public/thread_view.php — MODEL_LIMITS constant
- /extension2v1/config/config.php — CLAUDE_MODEL constant
- Also check /extension2/aiapi/api_opus/config/api_keys.php

Current model config in api_keys.php uses arrays like:
```php
'claude' => [
    'default_model' => 'claude-sonnet-4-5-20250929',
    'models' => ['claude-sonnet-4-5-20250929', 'claude-3-5-sonnet-20241022', ...]
]
```

## Architecture Patterns to Follow
- Use `MongoDatabase::insertOrUpdate()` for upserts (NOT `upsert()`)
- Use `QueryAdapter` for all data access (NOT raw SQL)
- AI proxy models keyed by provider: `[$provider => $model]`
- MongoDB `delete()` method available on MongoDatabase class
- Node.js on server is v10.19 — can't use for JS syntax checks
- `ThreadAnalyzer::stripQuotedContent()` for email body processing

## Available MongoDB Methods (MongoDatabase.php)
- `insert($collection, $data)`
- `insertOrUpdate($collection, $filter, $data)`
- `update($collection, $filter, $data)`
- `delete($collection, $filter)`
- `findAll($collection, $filter, $options)`
- `findOne($collection, $filter)`
- `count($collection, $filter)`
- `aggregate($collection, $pipeline)`

## Existing API patterns
- JSON responses via `jsonResponse(['success' => true, ...])`
- Error handling via `jsonResponse(['success' => false, 'error' => '...'])`
- POST data via `$input = json_decode(file_get_contents('php://input'), true)`
- GET params via `$_GET['param']`

Please design a detailed, step-by-step plan with specific code changes needed for each task. Group related changes by file to minimize edits. Prioritize the tasks that are quickest wins first.


111:async function apiCall(action, params = {}, method = 'GET') {
112-    try {
113-        let url = 'api.php?action=' + action;
114-
115-        const options = {
116-            method: method,
117-            headers: {}
118-        };
119-
120-        if (method === 'GET') {
121-            // Add params to URL
122-            Object.keys(params).forEach(key => {
123-                url += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
124-            });
125-        } else {
126-            // POST data
127-            const formData = new FormData();
128-            Object.keys(params).forEach(key => {
129-                formData.append(key, params[key]);
130-            });
131-            options.body = formData;
132-        }
133-
134-        const response = await fetch(url, options);
135-        const data = await response.json();
136-
137-        if (data.error) {
138-            throw new Error(data.message || 'API Error');
139-        }
140-
141-        return data;

Prompt:
Design a detailed implementation plan for the following tasks in the Email Intelligence System at /var/www/mssql.danmarcrm.com/dev1/extension2v1/

## Context
This is a PHP/MongoDB web app with a dashboard (index.php + app.js), API (api.php), data layer (QueryAdapter.php), and a thread view page (thread_view.php). Chrome extension syncs Gmail threads. AI proxy at aiapi/api_opus/.

## Tasks (in priority order)

### TASK 1: Delete Functionality
Add ability to delete:
- **Contacts**: Already has a Delete button in dashboard UI. Need API endpoint `delete_contact` in api.php + QueryAdapter method. Must also delete associated emails, thread_analysis, contact_profiles, ai_contact_memory for that contact.
- **Email Threads**: Add delete button to threads list. API endpoint `delete_thread` + QueryAdapter. Must delete all emails with that thread_id, thread_analysis, ai_query_responses referencing that thread.
- **AI Responses**: Add delete button next to saved AI responses in thread_view.php. API endpoint `delete_ai_response`. Delete from ai_query_responses collection.

Files: api.php, QueryAdapter.php, app.js, index.php, thread_view.php

### TASK 2: Sorting by Last Activity
- Contacts list: Add sort by `last_contact` date (from contact profiles or max email date)
- Threads list: Add sort by `last_date` (already tracked in thread aggregation)
- Add sort dropdown/buttons in the UI for both tabs

Files: app.js, index.php, api.php (may need sort param support), QueryAdapter.php

### TASK 3: Filters
- **Contacts tab**: Add filters for contact type (client/supplier/other), search by name/email, last activity date range
- **Threads tab**: Add filters for contact name, date range, email count range, analysis status
- **Last Activity date filter**: Date range picker for both tabs
- Add filter UI section above each table

Files: app.js, index.php

### TASK 4: Fix "Etienne Turner" Thread Linkage
The contact name resolution was fixed in QueryAdapter.php but may still have issues:
- MongoDB `getThreadsMongo()` collects all_contacts, weights inbound 2x, picks most frequent
- But if contact_id is NULL or email matches user, it skips — edge case: if ALL emails in thread are from user (outbound only), falls back to first contact
- Need to verify the fix works and potentially handle edge cases

Files: QueryAdapter.php

### TASK 5: Sync by Domain/Email Address
New feature: Dashboard UI panel where user enters a domain (e.g. delta-engineering.be) or email address. System queries Gmail API to find all threads involving that domain/email, then imports them.

Implementation:
- New UI section in dashboard or modal
- New API endpoint `sync_by_domain` that:
  1. Uses GmailClient to search: `from:@domain.com OR to:@domain.com` (or specific email)
  2. Lists matching threads with preview (subject, date, count)
  3. User selects which to import (or "Import All")
  4. Imports selected threads using existing sync_thread logic
- Need two-step flow: search → preview → import

Files: api.php, index.php, app.js, GmailClient.php (may need search method)

### TASK 6: Bulk Delete Threads by Email Address
- Add ability to delete all threads for a specific email/domain
- UI: In contacts list or a cleanup tool
- API: `delete_threads_by_email` — finds all emails from that address, gets unique thread_ids, deletes all data

Files: api.php, QueryAdapter.php, app.js, index.php

### TASK 7: Chrome Extension Manual-Only Mode
- Add toggle in Chrome extension popup/options for "Auto-sync" vs "Manual sync only"
- In manual mode, show a "Sync this thread" button overlay in Gmail
- Store preference in chrome.storage.local
- Extension files are at /Users/dan/Documents/extension2/extension2v1/chrome-extension (local Mac) — we can only prepare the code changes

NOTE: Chrome extension is on user's local Mac, not this server. We should note what needs to change but can't edit those files directly.

### TASK 8: Two-Round AI D3.js Chart
- After Round 2 (or any AI response), add "Generate Chart" button
- AI generates structured JSON (entities, relationships, events)
- D3.js force-directed graph renders: nodes as balloons (color-coded by type), arrows showing relationships, labels
- Interactive: drag, zoom, pan, click for details

Files: thread_view.php (inline JS + D3.js CDN)

### TASK 9: Hide Products Tab
- Remove Products tab from navigation in index.php
- Keep product_search.php file intact

Files: index.php

### TASK 10: Update AI Model Versions
Update to latest models:
- Claude: Add `claude-opus-4-6`, `claude-sonnet-4-6` (current has claude-sonnet-4-5-20250929)
- Other providers: verify current versions

Files to update:
- /extension2v1/aiapi/api_opus/config/api_keys.php — provider models list + defaults
- /extension2v1/public/thread_view.php — MODEL_LIMITS constant
- /extension2v1/config/config.php — CLAUDE_MODEL constant
- Also check /extension2/aiapi/api_opus/config/api_keys.php

Current model config in api_keys.php uses arrays like:
```php
'claude' => [
    'default_model' => 'claude-sonnet-4-5-20250929',
    'models' => ['claude-sonnet-4-5-20250929', 'claude-3-5-sonnet-20241022', ...]
]
```

## Architecture Patterns to Follow
- Use `MongoDatabase::insertOrUpdate()` for upserts (NOT `upsert()`)
- Use `QueryAdapter` for all data access (NOT raw SQL)
- AI proxy models keyed by provider: `[$provider => $model]`
- MongoDB `delete()` method available on MongoDatabase class
- Node.js on server is v10.19 — can't use for JS syntax checks
- `ThreadAnalyzer::stripQuotedContent()` for email body processing

## Available MongoDB Methods (MongoDatabase.php)
- `insert($collection, $data)`
- `insertOrUpdate($collection, $filter, $data)`
- `update($collection, $filter, $data)`
- `delete($collection, $filter)`
- `findAll($collection, $filter, $options)`
- `findOne($collection, $filter)`
- `count($collection, $filter)`
- `aggregate($collection, $pipeline)`

## Existing API patterns
- JSON responses via `jsonResponse(['success' => true, ...])`
- Error handling via `jsonResponse(['success' => false, 'error' => '...'])`
- POST data via `$input = json_decode(file_get_contents('php://input'), true)`
- GET params via `$_GET['param']`

Please design a detailed, step-by-step plan with specific code changes needed for each task. Group related changes by file to minimize edits. Prioritize the tasks that are quickest wins first.


Prompt:
Design a detailed implementation plan for the following tasks in the Email Intelligence System at /var/www/mssql.danmarcrm.com/dev1/extension2v1/

## Context
This is a PHP/MongoDB web app with a dashboard (index.php + app.js), API (api.php), data layer (QueryAdapter.php), and a thread view page (thread_view.php). Chrome extension syncs Gmail threads. AI proxy at aiapi/api_opus/.

## Tasks (in priority order)

### TASK 1: Delete Functionality
Add ability to delete:
- **Contacts**: Already has a Delete button in dashboard UI. Need API endpoint `delete_contact` in api.php + QueryAdapter method. Must also delete associated emails, thread_analysis, contact_profiles, ai_contact_memory for that contact.
- **Email Threads**: Add delete button to threads list. API endpoint `delete_thread` + QueryAdapter. Must delete all emails with that thread_id, thread_analysis, ai_query_responses referencing that thread.
- **AI Responses**: Add delete button next to saved AI responses in thread_view.php. API endpoint `delete_ai_response`. Delete from ai_query_responses collection.

Files: api.php, QueryAdapter.php, app.js, index.php, thread_view.php

### TASK 2: Sorting by Last Activity
- Contacts list: Add sort by `last_contact` date (from contact profiles or max email date)
- Threads list: Add sort by `last_date` (already tracked in thread aggregation)
- Add sort dropdown/buttons in the UI for both tabs

Files: app.js, index.php, api.php (may need sort param support), QueryAdapter.php

### TASK 3: Filters
- **Contacts tab**: Add filters for contact type (client/supplier/other), search by name/email, last activity date range
- **Threads tab**: Add filters for contact name, date range, email count range, analysis status
- **Last Activity date filter**: Date range picker for both tabs
- Add filter UI section above each table

Files: app.js, index.php

### TASK 4: Fix "Etienne Turner" Thread Linkage
The contact name resolution was fixed in QueryAdapter.php but may still have issues:
- MongoDB `getThreadsMongo()` collects all_contacts, weights inbound 2x, picks most frequent
- But if contact_id is NULL or email matches user, it skips — edge case: if ALL emails in thread are from user (outbound only), falls back to first contact
- Need to verify the fix works and potentially handle edge cases

Files: QueryAdapter.php

### TASK 5: Sync by Domain/Email Address
New feature: Dashboard UI panel where user enters a domain (e.g. delta-engineering.be) or email address. System queries Gmail API to find all threads involving that domain/email, then imports them.

Implementation:
- New UI section in dashboard or modal
- New API endpoint `sync_by_domain` that:
  1. Uses GmailClient to search: `from:@domain.com OR to:@domain.com` (or specific email)
  2. Lists matching threads with preview (subject, date, count)
  3. User selects which to import (or "Import All")
  4. Imports selected threads using existing sync_thread logic
- Need two-step flow: search → preview → import

Files: api.php, index.php, app.js, GmailClient.php (may need search method)

### TASK 6: Bulk Delete Threads by Email Address
- Add ability to delete all threads for a specific email/domain
- UI: In contacts list or a cleanup tool
- API: `delete_threads_by_email` — finds all emails from that address, gets unique thread_ids, deletes all data

Files: api.php, QueryAdapter.php, app.js, index.php

### TASK 7: Chrome Extension Manual-Only Mode
- Add toggle in Chrome extension popup/options for "Auto-sync" vs "Manual sync only"
- In manual mode, show a "Sync this thread" button overlay in Gmail
- Store preference in chrome.storage.local
- Extension files are at /Users/dan/Documents/extension2/extension2v1/chrome-extension (local Mac) — we can only prepare the code changes

NOTE: Chrome extension is on user's local Mac, not this server. We should note what needs to change but can't edit those files directly.

### TASK 8: Two-Round AI D3.js Chart
- After Round 2 (or any AI response), add "Generate Chart" button
- AI generates structured JSON (entities, relationships, events)
- D3.js force-directed graph renders: nodes as balloons (color-coded by type), arrows showing relationships, labels
- Interactive: drag, zoom, pan, click for details

Files: thread_view.php (inline JS + D3.js CDN)

### TASK 9: Hide Products Tab
- Remove Products tab from navigation in index.php
- Keep product_search.php file intact

Files: index.php

### TASK 10: Update AI Model Versions
Update to latest models:
- Claude: Add `claude-opus-4-6`, `claude-sonnet-4-6` (current has claude-sonnet-4-5-20250929)
- Other providers: verify current versions

Files to update:
- /extension2v1/aiapi/api_opus/config/api_keys.php — provider models list + defaults
- /extension2v1/public/thread_view.php — MODEL_LIMITS constant
- /extension2v1/config/config.php — CLAUDE_MODEL constant
- Also check /extension2/aiapi/api_opus/config/api_keys.php

Current model config in api_keys.php uses arrays like:
```php
'claude' => [
    'default_model' => 'claude-sonnet-4-5-20250929',
    'models' => ['claude-sonnet-4-5-20250929', 'claude-3-5-sonnet-20241022', ...]
]
```

## Architecture Patterns to Follow
- Use `MongoDatabase::insertOrUpdate()` for upserts (NOT `upsert()`)
- Use `QueryAdapter` for all data access (NOT raw SQL)
- AI proxy models keyed by provider: `[$provider => $model]`
- MongoDB `delete()` method available on MongoDatabase class
- Node.js on server is v10.19 — can't use for JS syntax checks
- `ThreadAnalyzer::stripQuotedContent()` for email body processing

## Available MongoDB Methods (MongoDatabase.php)
- `insert($collection, $data)`
- `insertOrUpdate($collection, $filter, $data)`
- `update($collection, $filter, $data)`
- `delete($collection, $filter)`
- `findAll($collection, $filter, $options)`
- `findOne($collection, $filter)`
- `count($collection, $filter)`
- `aggregate($collection, $pipeline)`

## Existing API patterns
- JSON responses via `jsonResponse(['success' => true, ...])`
- Error handling via `jsonResponse(['success' => false, 'error' => '...'])`
- POST data via `$input = json_decode(file_get_contents('php://input'), true)`
- GET params via `$_GET['param']`

Please design a detailed, step-by-step plan with specific code changes needed for each task. Group related changes by file to minimize edits. Prioritize the tasks that are quickest wins first.