Skip to content

feat: add unified email/messaging management system#80

Merged
atomantic merged 26 commits intomainfrom
feat/messages-system
Mar 6, 2026
Merged

feat: add unified email/messaging management system#80
atomantic merged 26 commits intomainfrom
feat/messages-system

Conversation

@atomantic
Copy link
Owner

Summary

  • Adds a new Messages page (/messages/:tab) with unified email/messaging management across Gmail, Outlook, and Teams
  • Server: Account CRUD, sync coordinator with per-account JSON caching, draft queue with status machine, send dispatcher, and Playwright selector management
  • Client: Inbox with search/filter, account configuration, draft review/approve/send workflow, sync controls with Socket.IO events, and editable DOM selector config
  • Gmail uses MCP integration (stub), Outlook/Teams use Playwright CDP browser automation (stub) — both ready for implementation

New Files (18)

Server (7): routes/messages.js, services/messageAccounts.js, messageDrafts.js, messageSync.js, messageGmailSync.js, messagePlaywrightSync.js, messageSender.js

Client (6): pages/Messages.jsx, components/messages/InboxTab.jsx, AccountsTab.jsx, DraftsTab.jsx, SyncTab.jsx, MessageDetail.jsx

Modified Files (5)

  • server/index.js — register /api/messages routes
  • server/lib/fileUtils.js — add messages path to PATHS
  • client/src/App.jsx — add /messages/:tab route (lazy loaded)
  • client/src/components/Layout.jsx — add Messages nav item, full-width layout
  • client/src/services/api.js — add 18 message API functions

Test plan

  • Verify Messages nav item appears between MeatSpace and Security in sidebar
  • Navigate to /messages/inbox — empty state shows correctly
  • Switch between Inbox, Accounts, Drafts, Sync tabs via URL
  • Create a Gmail account in Accounts tab — verify it appears in list
  • Toggle account enabled/disabled
  • Delete account
  • Trigger sync from Sync tab — verify progress events
  • Verify DOM selector editor shows/hides and saves
  • Client builds without errors
  • Server imports without errors

Adds Messages page with Gmail, Outlook, and Teams account management,
sync coordination with per-account caching, draft queue with AI generation
stub, and Playwright selector configuration for DOM scraping.
Copilot AI review requested due to automatic review settings March 6, 2026 04:19
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Introduces a new Messages feature that unifies email/messaging management (Gmail/Outlook/Teams) with a new UI page and a server-side API for accounts, inbox caching, drafts, sync, and selector configuration.

Changes:

  • Adds /api/messages routes + JSON-file-backed services for message accounts, cached inbox, drafts, sync dispatching, and selector storage.
  • Adds a new client /messages/:tab page with Inbox/Accounts/Drafts/Sync tabs and Socket.IO-driven sync status UI.
  • Registers Messages navigation + routing, and extends shared PATHS/data locations for messages storage.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
server/services/messageSync.js Implements JSON cache load/save, inbox aggregation/search, and per-account sync dispatch.
server/services/messageSender.js Draft sending dispatcher that updates draft status and emits socket events.
server/services/messagePlaywrightSync.js Selector CRUD + Playwright sync/send/test stubs.
server/services/messageGmailSync.js Gmail MCP sync/send stubs.
server/services/messageDrafts.js JSON-file draft CRUD + basic status updates.
server/services/messageAccounts.js JSON-file account CRUD + sync metadata.
server/routes/messages.js Express API endpoints with Zod validation for accounts/inbox/drafts/sync/selectors.
server/lib/fileUtils.js Adds PATHS.messages data directory path.
server/index.js Registers /api/messages route mount.
client/src/services/api.js Adds message API helpers (accounts, inbox, drafts, sync, selectors).
client/src/pages/Messages.jsx New Messages page with tab routing and account prefetch.
client/src/components/messages/InboxTab.jsx Inbox list + search/filter + detail view.
client/src/components/messages/MessageDetail.jsx Message view + draft generation/saving actions.
client/src/components/messages/AccountsTab.jsx Account create/toggle/delete UI.
client/src/components/messages/DraftsTab.jsx Draft review/approve/send/delete UI.
client/src/components/messages/SyncTab.jsx Sync triggers + selector editor + socket listeners for sync status.
client/src/components/Layout.jsx Adds Messages nav item + full-width layout for messages routes.
client/src/App.jsx Adds /messages/:tab routes and lazy-loads Messages page.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

…t validation

- AccountsTab: handle API errors with .catch() to reset UI state
- Rename getSyncStatus to getMessageSyncStatus for consistency
- Determine sendVia from account provider in draft generation
- Validate/clamp limit and offset query params in inbox route
- Guard deduplication against undefined externalId
- Annotate messages with accountId when aggregating across accounts
- Coerce invalid tab params to inbox in Messages page
- Wrap provider sync in error handler with status update and event
- Wrap send dispatch in error handler to prevent stuck draft status
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

- Validate accountId as UUID in inbox and message detail routes
- Add UUID guard in loadCache/saveCache to prevent path traversal
- Fix delete handler: 204 returns null, use .then(() => true) pattern
- Add fallback branch in sender for !result.success without error field
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

…pollution

- Fix empty query string appended to inbox/drafts API URLs
- Allow empty string in email field (fix Zod .email() vs default '')
- Move /:accountId/:messageId after draft routes to prevent collision
- Validate UUID on account PUT/DELETE params
- Restrict selector provider to allowed values (outlook, teams)
- Derive sendVia from account when not specified in draft creation
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

…elete

- Add 300ms debounce to inbox search to avoid per-keystroke fetches
- Validate accountId exists before creating drafts in POST /drafts
- Delete message cache and drafts when account is deleted
- Add deleteCache() and deleteDraftsByAccountId() helpers
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Adds real CDP WebSocket integration for scraping messages from Outlook
and Teams via the portos-browser instance. Includes Launch Browser button
for Playwright accounts, auth detection (Okta/Microsoft login pages),
DOM evaluation via Runtime.evaluate, and selector testing against live pages.
…ener, tests, quality fixes

- Allow empty string in updateAccountSchema email field for parity with create
- Add UUID validation to sync endpoints for consistent 400 responses
- Add messages:sync:failed socket listener in SyncTab to clear spinner
- Create messages.test.js with 49 tests covering routes/validation/errors
- Extract duplicated search filter in messageSync, consolidate sender error handling
- Add UUID validation to draft and launch param routes
- Add error guards to client async handlers
Copilot AI review requested due to automatic review settings March 6, 2026 06:25
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

… validation errors

- Skip non-UUID cache filenames in inbox aggregation to prevent stray files breaking /inbox
- Use JSON.stringify for selector interpolation in CDP Runtime.evaluate to prevent JS injection
- Close WebSocket in evaluateOnPage error handler to prevent resource leaks
- Switch from schema.parse() to validateRequest() for proper 400 responses on invalid input
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

- Add in-memory per-account lock to prevent concurrent syncs (returns 409)
- Move cache read inside lock scope to prevent interleaved read-write
- Support structured provider result { messages, status } for accurate sync status
- Only mark sync as 'success' when provider truly succeeds
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

- Always emit messages:sync:completed with status so client clears syncing state
- Replace onRefresh() with reactive setAccounts() in AccountsTab for local state updates
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

When selectors.json doesn't exist (fresh install), the SyncTab rendered
no selector editor cards because it only mapped Object.entries of an
empty object. Define DEFAULT_SELECTORS for outlook/teams and merge them
with fetched data so the editor cards always appear.

Addresses review thread PRRT_kwDOQx8jQ85ym5Zk
…messageSync tests

- Return { error, status: 502 } instead of throwing in syncAccount for consistent error handling
- Remove duplicate error toasts in AccountsTab and DraftsTab (shared request helper already handles)
- Add 42 unit tests for messageSync covering cache IO, dedup, trimming, lock behavior, and error paths
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

…t refactor, VITE_PORT comment

- Update CLAUDE.md to acknowledge simple re-entrancy guards are acceptable
- Remove unused onRefresh prop from AccountsTab
- Fix deleteCache to only log success on actual unlink, differentiate ENOENT
- Replace inline test copies with tests through real exported functions
- Add clarifying comment for VITE_PORT in pm2Standardizer template
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

…onal sync toast

- Detect Vite processes by VITE_PORT env var in addition to script name regex
- Rename PORTS.WEB to PORTS.UI in pm2Standardizer template for consistency
- Only show sync success toast when status is actually 'success'
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

… duplicate field, deterministic test

- Update pm2Standardizer guidance to accept PORTS.UI for Vite dev ports
- Fix streamingDetect config-file heuristics to set devUiPort instead of uiPort for Vite
- Remove redundant isViteProcess field (identical to usesVite)
- Replace setTimeout with setImmediate in sync lock test for determinism
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@atomantic atomantic merged commit cf69c69 into main Mar 6, 2026
6 checks passed
@atomantic atomantic deleted the feat/messages-system branch March 6, 2026 15:45
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