Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions docs/adr/0071-collapse-threads-in-email-query.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# 0071 - Enable collapseThreads in Email/query

Date: 2026-03-12

## Status

Proposed

## Context

JMAP `Email/query` supports `collapseThreads` (RFC 8621 §4.4). When `true`, server returns only the **latest email per thread**, avoiding duplicate rows in the mail list.

Currently, our app does **not** set `collapseThreads`. When thread is enabled, users see multiple emails from the same thread as separate rows.

### Two Query Paths (see ADR-0070)

| Path | `FORCE_EMAIL_QUERY` | Method | Cache |
|------|---------------------|--------|-------|
| Force query | `true` | `forceQueryAllEmailsForWeb()` | No local cache — server only |
| Cache-first | `false` | `getAllEmail()` | Local DB first, then sync |

### Problem: Cache Inconsistency on Toggle

On the cache-first path, the local DB reflects the `collapseThreads` mode it was built under. When thread mode changes:

- **OFF → ON**: Cache has individual emails (5 rows) but server now returns collapsed (3 rows) → stale first yield
- **ON → OFF**: Cache has collapsed emails (3 rows) but server now returns all individuals (5 rows) → missing emails in first yield

Force-query path has **no problem** — always queries server directly.

## Decision

### 1. Set `collapseThreads: true` in Email/query When Thread Is Enabled

In `MailAPIMixin.fetchAllEmail()` and `ThreadAPI.searchEmails()`, pass `collapseThreads: true` when thread is enabled.

### 2. Clear Email Cache on Thread Setting Toggle

Reuse the existing thread-enabled setting. **No new flag needed.** When thread is toggled (enable ↔ disable), clear email cache immediately in the toggle handler. Next `getAllEmail()` will rebuild cache under correct mode.

### 3. No Change for Force-Query Path

Already server-only. Just pass `collapseThreads: true` in the query.

## Consequences

**Positive**: Correct thread display, reduced data per page, spec-compliant.

**Negative**: One-time full reload on each toggle; toggle handler coupled with cache management.

## Implementation Steps

1. Add `collapseThreads` to `QueryEmailMethod` in `MailAPIMixin.fetchAllEmail()` and `ThreadAPI.searchEmails()`
2. Pass thread-enabled status from Settings to query builder
3. Clear email cache in thread setting toggle handler
4. Update `GetEmailsInMailboxInteractor` and related interactors to propagate thread status

## References

- [RFC 8621 §4.4](https://www.rfc-editor.org/rfc/rfc8621#section-4.4)
- [ADR-0070](./0070-sync-strategy-disappearing-emails.md)
- `lib/features/base/mixin/mail_api_mixin.dart` — `fetchAllEmail()`
- `lib/features/thread/data/repository/thread_repository_impl.dart` — `getAllEmail()`
- `lib/features/thread/domain/usecases/get_emails_in_mailbox_interactor.dart`
Loading
Loading