Skip to content

🗄️ feat: Archive All Chats From Data Controls - #14885

Open
berry-13 wants to merge 5 commits into
devfrom
feat/archive-all-chats-data-control
Open

🗄️ feat: Archive All Chats From Data Controls#14885
berry-13 wants to merge 5 commits into
devfrom
feat/archive-all-chats-data-control

Conversation

@berry-13

Copy link
Copy Markdown
Collaborator

Summary

Adds an Archive all chats option under Settings > Data controls > Your data, next to Shared links. It confirms first, then archives every conversation currently visible in the chat list in one pass and starts a new chat.

Backend: POST /api/convos/archive/all is backed by a new archiveAllConvos method in packages/data-schemas. It archives in a single updateMany and then refreshes the stats of every chat project the archived conversations belonged to, mirroring how deleteConvos handles project stats.

Two deliberate calls in that method:

  • Temporary and retention-expired conversations are skipped. They are already hidden from the chat list, so archiving them would only surface them in the archived view.
  • The update runs with timestamps: false, so each conversation keeps its own updatedAt and the Archived chats table stays sorted by real activity instead of collapsing every row onto the archive time.

This also fixes a pre-existing wart in the single-chat archive flow. A chat's first turn writes the same message array under both [messages, <conversationId>] and [messages, "new"], and the messages query returns the new-chat cache verbatim. Archiving never reset that alias, so the messages of a just-archived chat kept rendering on the new chat screen until a reload. Deleting already guarded against this with clearDeletedConversationMessagesCache; archiving now does too, via clearArchivedConversationMessagesCache, which drops the alias but keeps the conversation's own history cached because an archived chat can still be reopened.

Change Type

  • New feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue)

Testing

Six new tests for archiveAllConvos against a real in-memory MongoDB (per-user scoping, already-archived no-op, temporary and expired chats skipped, updatedAt preserved, project stats refreshed, empty case), two new route tests for POST /archive/all, and four new tests for clearArchivedConversationMessagesCache.

cd packages/data-schemas && npx jest src/methods/conversation.spec.ts      # 74 passed
cd api && npx jest server/routes/__tests__/convos.spec.js                  # 38 passed
cd client && npx jest src/utils/__tests__/messages.test.ts                 # 61 passed
cd client && npx jest src/utils src/hooks/Chat src/components/Nav/Settings src/data-provider
                                                                           # 48 suites, 462 passed
cd client && npx tsc --noEmit                                              # clean
npx eslint <changed files>                                                 # clean

Manual verification in the browser, light and dark mode: archived two chats from the settings row, confirmed the sidebar emptied, the view moved to a new chat with no leftover messages, and both chats appeared under Archived chats and still opened with their history. Also confirmed Cancel archives nothing and the single-chat archive from the sidebar menu clears the chat pane the same way.

Test Configuration:

Node 24.16.0, MongoDB via mongodb-memory-server for the data-schemas suite, Ollama (gemma4:12b-it-qat) for the manual browser pass.

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • I have commented in any complex areas of my code
  • My changes do not introduce new warnings
  • I have written tests demonstrating that my changes are effective or that my feature works
  • Local unit tests pass with my changes

Copilot AI lite review requested due to automatic review settings August 16, 2026 02:08

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c4bc35c6dc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/data-schemas/src/methods/conversation.ts Outdated
Comment thread client/src/data-provider/mutations.ts Outdated
Comment thread client/src/components/Nav/SettingsTabs/Data/ArchiveAllChats.tsx Outdated
Comment thread client/src/data-provider/mutations.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a bulk “Archive all chats” action to the Data Controls settings UI and wires it through the client data layer to a new backend route and data-schemas method that archives all visible conversations for the authenticated user in a single DB pass.

Changes:

  • Backend: add archiveAllConvos(user) and expose it via POST /api/convos/archive/all, archiving via updateMany({ timestamps: false }) and refreshing affected project stats.
  • Client: add a Settings entry + dialog UI to trigger the bulk archive and start a new chat, plus a cache fix for the single-chat archive flow to clear the new-chat message alias.
  • Data-provider: add endpoint/type/service/mutation plumbing for archiveAllConversations().

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/data-schemas/src/methods/conversation.ts Implements archiveAllConvos with retention visibility filtering, timestamps: false, and best-effort project stats refresh.
packages/data-schemas/src/methods/conversation.spec.ts Adds unit tests for archiveAllConvos (scope, no-op, retention/temporary skip, updatedAt preservation, project stats refresh, empty).
packages/data-provider/src/types/mutations.ts Adds mutation option typing for the new archive-all mutation.
packages/data-provider/src/types.ts Adds TArchiveAllConversationsResponse type.
packages/data-provider/src/data-service.ts Adds archiveAllConversations() data-service call.
packages/data-provider/src/api-endpoints.ts Adds /api/convos/archive/all endpoint helper.
client/src/utils/messages.ts Refactors alias detection and adds clearArchivedConversationMessagesCache to fix the “new chat still shows archived convo” issue.
client/src/utils/tests/messages.test.ts Adds tests for clearArchivedConversationMessagesCache.
client/src/locales/en/translation.json Adds i18n strings for the Archive All UI and messaging.
client/src/data-provider/mutations.ts Adds useArchiveAllConversationsMutation and updates single-archive flow to clear the archived message alias.
client/src/components/Nav/SettingsTabs/Data/ArchiveAllChats.tsx Adds the Settings UI row + confirmation dialog to trigger the bulk archive and start a new chat.
client/src/components/Nav/Settings/registry.tsx Registers the new Settings entry.
api/server/routes/convos.js Adds POST /archive/all route calling db.archiveAllConvos.
api/server/routes/tests/convos.spec.js Adds route tests for the new endpoint (success + 500).
api/server/routes/test-utils/convos-route-mocks.js Adds archiveAllConvos to route mocks.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread client/src/data-provider/mutations.ts
@berry-13

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: c4bc35c6dc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 61aeb23a03

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/data-schemas/src/methods/conversation.ts Outdated
Comment thread client/src/components/Nav/SettingsTabs/Data/ArchiveAllChats.tsx Outdated
Comment thread client/src/components/Nav/SettingsTabs/Data/ArchiveAllChats.tsx Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 27d93703bc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +990 to +994
await Promise.all(
[...projectIds].map((projectId) =>
refreshChatProjectStatsForUser(mongoose, user, projectId),
),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Prevent older project refreshes from overwriting newer stats

If another tab creates or assigns a visible conversation in one of these projects after refreshChatProjectStatsForUser reads its count/latest conversation but before that helper writes the result, this archive refresh can overwrite the newer operation's project update with the earlier count and lastConversationId, leaving the project stale indefinitely. Fresh evidence in this revision is the post-update refresh here: snapshot-scoping the archive prevents the concurrent chat from being archived, but does not make the subsequent read-then-write stats reconciliation safe against newer project changes.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a pre-existing property of refreshChatProjectStatsForUser, whose read-then-write implementation is also used by deleteConvos, save/import, and project assignment. Fixing it correctly belongs in that shared helper across all six callers, not as an archive-only workaround in this PR.

Comment thread packages/data-schemas/src/methods/conversation.ts Outdated
Adds an "Archive all chats" row under Data controls > Your data, next to
Shared links, with a confirmation dialog. It calls a new
POST /api/convos/archive/all endpoint backed by archiveAllConvos, which
archives every conversation currently visible to the user in a single
updateMany and refreshes the stats of every chat project the archived
conversations belonged to.

Temporary and retention-expired conversations are skipped: they are
already hidden from the chat list, so archiving them would only surface
them in the archived view. The update runs with timestamps disabled so
each conversation keeps its own updatedAt and the archived list stays
sorted by real activity.

Archiving a conversation now also drops the new-chat message cache alias
for it. A chat's first turn writes the same message array under both the
conversation key and the new-chat key, so without this the messages of a
just-archived chat kept rendering on the new chat screen until a reload.
Deleting already handled this; archiving did not.
@berry-13
berry-13 force-pushed the feat/archive-all-chats-data-control branch from 27d9370 to 94b3613 Compare August 16, 2026 05:22

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 94b3613de4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +223 to +225
router.post('/archive/all', async (req, res) => {
try {
const dbResponse = await db.archiveAllConvos(req.user.id);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Move the archive-all handler into packages/api

This adds the new endpoint implementation directly to the legacy /api workspace and calls the data-schema method there. Move the handler into the TypeScript /packages/api workspace and leave only the minimal JS route wrapper here; otherwise this new backend path bypasses the repository's required backend boundary and continues expanding the legacy server layer. CLAUDE.mdL20-L24

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The route is already thin transport glue: it only calls db.archiveAllConvos, returns the result, and maps errors, matching neighboring archive and pin handlers. The rule places database-specific shared logic in data-schemas, where this implementation already lives; a packages/api pass-through would add no policy or business logic.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 07217b4957

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/data-schemas/src/methods/conversation.ts
Comment thread packages/data-schemas/src/methods/conversation.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd2d6d92cb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +976 to +979
const idRange = lastConversationId
? { $gt: lastConversationId, $lte: snapshotBoundary._id }
: { $lte: snapshotBoundary._id };
const conversations = await Conversation.find({ ...filter, _id: idRange })

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Freeze archive membership instead of only its upper ID

When another tab unarchives an older conversation after snapshotBoundary is read but before its batch is queried, that conversation now satisfies the live filter and falls below the high-water mark, so this operation archives it even though it was absent from the initial visible set, reversing the concurrent user's action. The current high-water revision therefore still does not provide the fixed-snapshot semantics expected here; persist or otherwise identify membership at submission time rather than re-evaluating eligibility for every batch.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving this one open for maintainer judgement rather than acting on it, because the remedy conflicts with an earlier finding on the same code. The previous revision did materialise full membership up front, and the P2 at conversation.ts:942 asked for that to be replaced precisely because an unbounded hydrated read plus a large $in risks the BSON command size limit on big histories. Restoring fixed-snapshot membership reintroduces exactly that. The window here is also narrow: it needs a second tab to unarchive a conversation during the sweep, and the outcome is that one chat is archived again rather than any data loss. Happy to take either side, but it is a trade-off call rather than a defect to patch silently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants