Skip to content

Conversation

@pierre-lehnen-rc
Copy link
Contributor

@pierre-lehnen-rc pierre-lehnen-rc commented Nov 4, 2025

Proposed changes (including videos or screenshots)

Issue(s)

Feature Branch
VGA-1

Steps to test or reproduce

Further comments

Summary by CodeRabbit

  • New Features

    • Persistent media-call history with automatic in-chat summary messages for call outcomes and formatted durations.
  • Models & Typings

    • Public types and model surface expanded to expose call-history items and model access.
  • Tests

    • New unit tests validating history message payloads, state-to-text/icon mappings, and duration formatting.
  • Localization

    • Added bold translation variants for call status messages.

✏️ Tip: You can customize this high-level summary in your review settings.

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Nov 4, 2025

Looks like this PR is ready to merge! 🎉
If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Nov 4, 2025

🦋 Changeset detected

Latest commit: f2eb01b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 42 packages
Name Type
@rocket.chat/meteor Minor
@rocket.chat/core-typings Minor
@rocket.chat/i18n Minor
@rocket.chat/model-typings Minor
@rocket.chat/models Minor
@rocket.chat/media-calls Minor
@rocket.chat/uikit-playground Patch
@rocket.chat/api-client Patch
@rocket.chat/apps Patch
@rocket.chat/core-services Patch
@rocket.chat/cron Patch
@rocket.chat/ddp-client Patch
@rocket.chat/freeswitch Patch
@rocket.chat/fuselage-ui-kit Major
@rocket.chat/gazzodown Major
@rocket.chat/http-router Patch
@rocket.chat/livechat Patch
@rocket.chat/rest-typings Minor
@rocket.chat/ui-avatar Major
@rocket.chat/ui-client Major
@rocket.chat/ui-contexts Major
@rocket.chat/web-ui-registration Major
@rocket.chat/account-service Patch
@rocket.chat/authorization-service Patch
@rocket.chat/ddp-streamer Patch
@rocket.chat/omnichannel-transcript Patch
@rocket.chat/presence-service Patch
@rocket.chat/queue-worker Patch
@rocket.chat/stream-hub-service Patch
@rocket.chat/federation-matrix Patch
@rocket.chat/license Patch
@rocket.chat/omnichannel-services Patch
@rocket.chat/pdf-worker Patch
@rocket.chat/presence Patch
rocketchat-services Patch
@rocket.chat/mock-providers Patch
@rocket.chat/instance-status Patch
@rocket.chat/omni-core Patch
@rocket.chat/omni-core-ee Patch
@rocket.chat/network-broker Patch
@rocket.chat/ui-video-conf Major
@rocket.chat/ui-voip Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 4, 2025

Walkthrough

Adds call history data structures, persistence, and in-chat history messages: new CallHistory types and model, model registration, MediaCallServer API/event and CallDirector trigger, MediaCallService logic to persist history and post formatted Info Card messages to DMs, i18n entries, and unit tests for payload formatting.

Changes

Cohort / File(s) Summary
Test config
apps/meteor/jest.config.ts
Added <rootDir>/server/services/media-call/**.spec.ts to server testMatch.
Meteor model registration
apps/meteor/server/models.ts
Registered CallHistoryRaw as ICallHistoryModel in Meteor model registry.
History message payload utilities & tests
apps/meteor/server/services/media-call/getHistoryMessagePayload.ts, apps/meteor/server/services/media-call/getHistoryMessagePayload.spec.ts
New helpers mapping call states to i18n keys/icons, duration formatter, and builder for Info Card message payload; comprehensive unit tests covering states and durations.
Media call service (history logic)
apps/meteor/server/services/media-call/service.ts
Added historyUpdate listener and private methods (saveCallToHistory, saveInternalCallToHistory, sendHistoryMessage, getCallDuration, getCallHistoryItemState, getRoomIdForInternalCall); implements persistence of CallHistory entries, DM creation/resolution, message sending and linking, and duration/state computation.
MediaCall server API & director trigger
ee/packages/media-calls/src/definition/IMediaCallServer.ts, ee/packages/media-calls/src/server/MediaCallServer.ts, ee/packages/media-calls/src/server/CallDirector.ts
Added historyUpdate event and updateCallHistory({ callId }) API; CallDirector.hangupCallById invokes updateCallHistory after hangup.
Call history typings
packages/core-typings/src/ICallHistoryItem.ts, packages/core-typings/src/index.ts
New types: CallHistoryItemState and interfaces ICallHistoryItem, IMediaCallHistoryItem, IInternalMediaCallHistoryItem; re-exported from core-typings index.
Model typings & barrel
packages/model-typings/src/models/ICallHistoryModel.ts, packages/model-typings/src/index.ts
New type alias ICallHistoryModel = IBaseModel<CallHistoryItem> and exported from model-typings index.
CallHistory model implementation & exports
packages/models/src/models/CallHistory.ts, packages/models/src/index.ts, packages/models/src/modelClasses.ts
New CallHistoryRaw (extends BaseRaw<CallHistoryItem>) with indexes ({ uid, callId } unique and { uid, ts } desc), proxified export and added to modelClasses barrel.
Internationalization
packages/i18n/src/locales/en.i18n.json
Added bold translation keys: Call_ended_bold, Call_not_answered_bold, Call_failed_bold, Call_transferred_bold.
Changeset
.changeset/five-frogs-kneel.md
New changeset noting minor version bumps and describing in-chat voice call end messages.

Sequence Diagram(s)

sequenceDiagram
    participant CallDirector as Call Director
    participant MediaCallServer as Media Call Server
    participant MediaCallService as Media Call Service
    participant CallHistoryDB as CallHistory DB
    participant Rooms as Rooms Service
    participant MessageSvc as Message Service

    CallDirector->>MediaCallServer: hangupCallById(callId)
    MediaCallServer->>MediaCallServer: updateCallHistory({ callId })
    MediaCallServer->>MediaCallService: emit historyUpdate(callId)

    rect `#E8F4FF`
        note over MediaCallService: validate call ended & participants\ncompute duration & state
        MediaCallService->>MediaCallService: getCallDuration / getCallHistoryItemState
        MediaCallService->>Rooms: getRoomIdForInternalCall(call)
    end

    rect `#E9FBEF`
        note over MediaCallService,CallHistoryDB: persist outbound & inbound history items
        MediaCallService->>CallHistoryDB: insert outbound record
        MediaCallService->>CallHistoryDB: insert inbound record
    end

    rect `#FFF8E6`
        note over MediaCallService,MessageSvc: build Info Card and send DM, then link messageId
        MediaCallService->>MessageSvc: getHistoryMessagePayload + sendMessage
        MessageSvc-->>MediaCallService: messageId
        MediaCallService->>CallHistoryDB: update records with messageId
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing extra attention:
    • apps/meteor/server/services/media-call/service.ts — DB inserts, uniqueness, DM creation, error handling, and message linking.
    • apps/meteor/server/services/media-call/getHistoryMessagePayload.ts — payload schema, i18n keys, duration formatting and edge cases.
    • packages/models/src/models/CallHistory.ts — index definitions and uniqueness constraint correctness.

Possibly related PRs

Suggested reviewers

  • tassoevan
  • rodrigok

Poem

🐰
I hopped through code and counted rings,
Saved tiny tales of ending things.
A DM blooms when calls conclude,
Carrot crumbs of every mood. 🥕📞

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: In-Chat Messages for Voice Calls' is clear, specific, and directly summarizes the main feature being added—automatic in-chat messages for voice calls.
Linked Issues check ✅ Passed The implementation comprehensively addresses all functional requirements from VGA-1: call history persistence with proper state tracking (ended, not-answered, failed, error, transferred), post-call message triggers, duration display, and call history linkage.
Out of Scope Changes check ✅ Passed All changes directly support the voice call history feature: new data models, history persistence logic, message payload generation, and supporting infrastructure (typings, i18n, indexes). No unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/voip-room-messages

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 90d79af and f2eb01b.

📒 Files selected for processing (1)
  • packages/i18n/src/locales/en.i18n.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/i18n/src/locales/en.i18n.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Nov 4, 2025

Codecov Report

❌ Patch coverage is 7.61905% with 97 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.91%. Comparing base (035e0c7) to head (f2eb01b).
⚠️ Report is 3 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #37378      +/-   ##
===========================================
- Coverage    68.97%   68.91%   -0.07%     
===========================================
  Files         3359     3360       +1     
  Lines       114214   114282      +68     
  Branches     20535    20562      +27     
===========================================
- Hits         78784    78760      -24     
- Misses       33335    33430      +95     
+ Partials      2095     2092       -3     
Flag Coverage Δ
e2e 57.42% <ø> (-0.03%) ⬇️
e2e-api 42.54% <7.61%> (-0.32%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pierre-lehnen-rc pierre-lehnen-rc added this to the 7.13.0 milestone Nov 5, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Nov 19, 2025

📦 Docker Image Size Report

📈 Changes

Service Current Baseline Change Percent
sum of all images 1.2GiB 1.2GiB +12MiB
rocketchat 367MiB 355MiB +12MiB
omnichannel-transcript-service 141MiB 141MiB +2.0KiB
queue-worker-service 141MiB 141MiB +1.8KiB
ddp-streamer-service 127MiB 127MiB +1.0KiB
account-service 114MiB 114MiB +3.0KiB
stream-hub-service 111MiB 111MiB +1.2KiB
authorization-service 111MiB 111MiB +993B
presence-service 111MiB 111MiB +1.1KiB

📊 Historical Trend

---
config:
  theme: "dark"
  xyChart:
    width: 900
    height: 400
---
xychart
  title "Image Size Evolution by Service (Last 30 Days + This PR)"
  x-axis ["11/15 22:28", "11/16 01:28", "11/17 23:50", "11/18 22:53", "11/19 21:05", "11/19 22:19 (PR)"]
  y-axis "Size (GB)" 0 --> 0.5
  line "account-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "authorization-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "ddp-streamer-service" [0.12, 0.12, 0.12, 0.12, 0.12, 0.12]
  line "omnichannel-transcript-service" [0.14, 0.14, 0.14, 0.14, 0.14, 0.14]
  line "presence-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "queue-worker-service" [0.14, 0.14, 0.14, 0.14, 0.14, 0.14]
  line "rocketchat" [0.36, 0.36, 0.35, 0.35, 0.35, 0.36]
  line "stream-hub-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
Loading

Statistics (last 5 days):

  • 📊 Average: 1.4GiB
  • ⬇️ Minimum: 1.2GiB
  • ⬆️ Maximum: 1.6GiB
  • 🎯 Current PR: 1.2GiB
ℹ️ About this report

This report compares Docker image sizes from this build against the develop baseline.

  • Tag: pr-37378
  • Baseline: develop
  • Timestamp: 2025-11-19 22:19:51 UTC
  • Historical data points: 5

Updated: Wed, 19 Nov 2025 22:19:52 GMT

Co-authored-by: gabriellsh <henriques.gabriell@gmail.com>
Co-authored-by: gabriellsh <40830821+gabriellsh@users.noreply.github.com>
@gabriellsh gabriellsh marked this pull request as ready for review November 19, 2025 18:21
@gabriellsh gabriellsh requested review from a team as code owners November 19, 2025 18:21
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (6)
apps/meteor/server/services/media-call/getHistoryMessagePayload.spec.ts (2)

1-3: Avoid duplicating APP_ID literal in tests

Hardcoding const appId = 'media-call-core'; couples the spec to the exact string value. If APP_ID changes in getHistoryMessagePayload.ts, all these tests will break even though the rest of the shape is still valid.

Consider either:

  • Exporting APP_ID from getHistoryMessagePayload.ts and importing it here, or
  • Asserting result.blocks[0].appId against the literal in a single focused test, and using expect.objectContaining for other payload shape checks.

105-278: Comprehensive payload shape tests; consider slightly loosening deep equals

The payload tests thoroughly check:

  • Per-state icon/translation rows, and
  • Presence/absence and styling of the duration row across states.

Because you're using full toEqual on the entire object, any small structural change (e.g., adding a new optional field to InfoCardBlock) will force wide test updates. You might want to use expect.objectContaining for inner objects, while still asserting the critical fields (icon, i18n key, duration text, row backgrounds).

apps/meteor/server/services/media-call/getHistoryMessagePayload.ts (2)

7-20: *Clean up TODO and rely on _bold i18n keys for emphasis

callStateToTranslationKey is already using the Call_*_bold keys, which are expected to carry the emphasis (single-asterisk formatting) in the translation itself. The // TODO bold the text comment is now misleading and could encourage adding extra markup on top of the i18n formatting.

I’d suggest removing or updating that TODO to avoid double‑bolding via manual asterisks.

Also, since CallHistoryItemState is a union, you might consider adding a default case that throws or returns a safe fallback to catch any future state additions at runtime.

Based on learnings


58-91: History payload shape looks correct; TODO about “proper translation keys” is stale

getHistoryMessagePayload cleanly composes:

  • An info_card block scoped under APP_ID,
  • A first row with the state icon and translated text, and
  • An optional secondary row for the formatted duration.

Two minor points:

  1. The // TODO proper translation keys comment seems outdated now that callStateToTranslationKey already returns the finalized i18n keys; consider removing or clarifying it.
  2. This payload currently carries no explicit identifiers (e.g., callId) in the block itself; instead, you rely on associating the message _id back to CallHistory. If the client UX for “click to open Call History entry” depends on the block shape alone, confirm that the front end is indeed using appId: 'media-call-core' + messageId to resolve the history entry.
apps/meteor/server/services/media-call/service.ts (2)

70-89: Internal-only history guard is sensible; consider clarifying external/group behavior

saveCallToHistory:

  • Validates the call exists and is ended.
  • Skips calls where uids.length !== 2, effectively limiting history + summary messaging to 1:1 internal calls for now.

This matches the current “internal DM call” scope, but it also means:

  • Group calls or external calls will not produce history entries or summary messages yet.

Given the // TODO: save external media calls to history, it may be worth expanding that comment to explicitly mention group calls or additional scenarios, so the behavior is clear to future readers.


91-133: History record insertion looks correct; Promise usage could be simplified

saveInternalCallToHistory:

  • Correctly asserts both sides are user contacts.
  • Resolves/creates a DM room (if possible) and uses its rid for both history entries.
  • Computes state and duration once and fans them out into symmetric outbound/inbound CallHistory records for caller and callee.

Two minor observations:

  1. You’re wrapping each CallHistory.insertOne in its own .catch and then passing those promises into Promise.allSettled. Because errors are already caught and logged, allSettled doesn’t add much over a plain Promise.all here. You could either:
    • Drop .catch and actually inspect the allSettled results, or
    • Keep the .catch and replace Promise.allSettled with Promise.all (or even void Promise.all([...])) for simplicity.
  2. If getRoomIdForInternalCall fails, you still persist history (without rid) but skip the summary message. That’s a reasonable degradation; you might want to mention this in a comment if that fallback is intentional.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 035e0c7 and 4afa403.

📒 Files selected for processing (16)
  • apps/meteor/jest.config.ts (1 hunks)
  • apps/meteor/server/models.ts (2 hunks)
  • apps/meteor/server/services/media-call/getHistoryMessagePayload.spec.ts (1 hunks)
  • apps/meteor/server/services/media-call/getHistoryMessagePayload.ts (1 hunks)
  • apps/meteor/server/services/media-call/service.ts (3 hunks)
  • ee/packages/media-calls/src/definition/IMediaCallServer.ts (2 hunks)
  • ee/packages/media-calls/src/server/CallDirector.ts (2 hunks)
  • ee/packages/media-calls/src/server/MediaCallServer.ts (1 hunks)
  • packages/core-typings/src/ICallHistoryItem.ts (1 hunks)
  • packages/core-typings/src/index.ts (1 hunks)
  • packages/i18n/src/locales/en.i18n.json (1 hunks)
  • packages/model-typings/src/index.ts (1 hunks)
  • packages/model-typings/src/models/ICallHistoryModel.ts (1 hunks)
  • packages/models/src/index.ts (2 hunks)
  • packages/models/src/modelClasses.ts (1 hunks)
  • packages/models/src/models/CallHistory.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: packages/i18n/src/locales/en.i18n.json:918-921
Timestamp: 2025-11-19T18:20:07.683Z
Learning: Repo: RocketChat/Rocket.Chat — i18n/formatting
Learning: This repository uses a custom message formatting parser in UI blocks/messages; do not assume standard Markdown rules. For keys like Call_ended_bold, Call_not_answered_bold, Call_failed_bold, and Call_transferred_bold in packages/i18n/src/locales/en.i18n.json, retain the existing single-asterisk emphasis unless maintainers request otherwise.
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: apps/meteor/server/services/media-call/service.ts:141-141
Timestamp: 2025-11-19T18:20:37.096Z
Learning: In apps/meteor/server/services/media-call/service.ts, the sendHistoryMessage method should use call.caller.id or call.createdBy?.id as the message author, not call.transferredBy?.id. Even for transferred calls, the message should appear in the DM between the two users who are calling each other, not sent by the person who transferred the call.
📚 Learning: 2025-11-19T18:20:37.096Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: apps/meteor/server/services/media-call/service.ts:141-141
Timestamp: 2025-11-19T18:20:37.096Z
Learning: In apps/meteor/server/services/media-call/service.ts, the sendHistoryMessage method should use call.caller.id or call.createdBy?.id as the message author, not call.transferredBy?.id. Even for transferred calls, the message should appear in the DM between the two users who are calling each other, not sent by the person who transferred the call.

Applied to files:

  • ee/packages/media-calls/src/server/MediaCallServer.ts
  • apps/meteor/server/models.ts
  • ee/packages/media-calls/src/definition/IMediaCallServer.ts
  • apps/meteor/server/services/media-call/getHistoryMessagePayload.spec.ts
  • apps/meteor/server/services/media-call/getHistoryMessagePayload.ts
  • packages/core-typings/src/ICallHistoryItem.ts
  • ee/packages/media-calls/src/server/CallDirector.ts
  • apps/meteor/server/services/media-call/service.ts
📚 Learning: 2025-11-19T18:20:07.683Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: packages/i18n/src/locales/en.i18n.json:918-921
Timestamp: 2025-11-19T18:20:07.683Z
Learning: Repo: RocketChat/Rocket.Chat — i18n/formatting
Learning: This repository uses a custom message formatting parser in UI blocks/messages; do not assume standard Markdown rules. For keys like Call_ended_bold, Call_not_answered_bold, Call_failed_bold, and Call_transferred_bold in packages/i18n/src/locales/en.i18n.json, retain the existing single-asterisk emphasis unless maintainers request otherwise.

Applied to files:

  • apps/meteor/server/services/media-call/getHistoryMessagePayload.ts
  • packages/i18n/src/locales/en.i18n.json
📚 Learning: 2025-11-17T22:38:48.631Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37505
File: packages/i18n/src/locales/en.i18n.json:3765-3765
Timestamp: 2025-11-17T22:38:48.631Z
Learning: Rocket.Chat i18n copy: Keep sentence case for the value of "Notification_Desktop_show_voice_calls" in packages/i18n/src/locales/en.i18n.json (“Show desktop notifications for voice calls”) per design directive; do not change to Title Case even if nearby labels differ.

Applied to files:

  • packages/i18n/src/locales/en.i18n.json
📚 Learning: 2025-11-19T12:32:29.673Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37547
File: packages/i18n/src/locales/en.i18n.json:634-634
Timestamp: 2025-11-19T12:32:29.673Z
Learning: Repo: RocketChat/Rocket.Chat
Context: i18n workflow
Learning: In this repository, new translation keys should be added to packages/i18n/src/locales/en.i18n.json only; other locale files are populated via the external translation pipeline and/or fall back to English. Do not request adding the same key to all locale files in future reviews.

Applied to files:

  • packages/i18n/src/locales/en.i18n.json
🧬 Code graph analysis (10)
ee/packages/media-calls/src/server/MediaCallServer.ts (1)
ee/packages/media-calls/src/logger.ts (1)
  • logger (3-3)
apps/meteor/server/models.ts (2)
packages/models/src/index.ts (1)
  • registerModel (138-138)
packages/models/src/models/CallHistory.ts (1)
  • CallHistoryRaw (7-18)
packages/model-typings/src/models/ICallHistoryModel.ts (1)
packages/core-typings/src/ICallHistoryItem.ts (1)
  • CallHistoryItem (48-48)
apps/meteor/server/services/media-call/getHistoryMessagePayload.spec.ts (1)
apps/meteor/server/services/media-call/getHistoryMessagePayload.ts (4)
  • callStateToTranslationKey (8-20)
  • callStateToIcon (22-34)
  • getFormattedCallDuration (40-56)
  • getHistoryMessagePayload (59-91)
apps/meteor/server/services/media-call/getHistoryMessagePayload.ts (3)
packages/core-typings/src/ICallHistoryItem.ts (1)
  • CallHistoryItemState (6-16)
packages/core-typings/src/IMessage/IMessage.ts (1)
  • IMessage (162-260)
packages/fuselage-ui-kit/src/surfaces/FuselageSurfaceRenderer.tsx (1)
  • icon (361-367)
packages/core-typings/src/ICallHistoryItem.ts (3)
packages/core-typings/src/IUser.ts (1)
  • IUser (186-255)
packages/core-typings/src/IRoom.ts (1)
  • IRoom (21-95)
packages/core-typings/src/IMessage/IMessage.ts (1)
  • IMessage (162-260)
packages/models/src/index.ts (2)
packages/core-services/src/index.ts (1)
  • proxify (134-134)
packages/model-typings/src/models/ICallHistoryModel.ts (1)
  • ICallHistoryModel (5-5)
ee/packages/media-calls/src/server/CallDirector.ts (1)
ee/packages/media-calls/src/server/injection.ts (1)
  • getMediaCallServer (25-32)
apps/meteor/server/services/media-call/service.ts (4)
packages/core-typings/src/mediaCalls/IMediaCall.ts (1)
  • IMediaCall (35-68)
packages/models/src/index.ts (4)
  • MediaCalls (186-186)
  • CallHistory (149-149)
  • Rooms (204-204)
  • Users (213-213)
packages/core-typings/src/ICallHistoryItem.ts (2)
  • IInternalMediaCallHistoryItem (37-43)
  • CallHistoryItemState (6-16)
apps/meteor/server/services/media-call/getHistoryMessagePayload.ts (1)
  • getHistoryMessagePayload (59-91)
packages/models/src/models/CallHistory.ts (2)
packages/core-typings/src/ICallHistoryItem.ts (1)
  • CallHistoryItem (48-48)
packages/model-typings/src/models/ICallHistoryModel.ts (1)
  • ICallHistoryModel (5-5)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (25)
apps/meteor/jest.config.ts (1)

46-46: LGTM!

The testMatch pattern correctly includes the new media-call test suite.

apps/meteor/server/models.ts (2)

12-12: LGTM!

The import follows the existing pattern in the file.


99-99: LGTM!

The model registration is correct and follows the established pattern for other models in this file.

ee/packages/media-calls/src/server/MediaCallServer.ts (1)

68-72: LGTM!

The updateCallHistory method follows the same pattern as reportCallUpdate and correctly emits the historyUpdate event.

packages/model-typings/src/index.ts (1)

89-89: LGTM!

The export follows the established pattern for model type definitions.

packages/models/src/modelClasses.ts (1)

81-81: LGTM!

The export follows the established pattern for model classes.

ee/packages/media-calls/src/server/CallDirector.ts (2)

6-6: LGTM!

The import is necessary for the new history update functionality.


371-377: Verification complete: all callers of hangupCallById properly handle the return value.

All four call sites check the boolean return value:

  • Line 28: if (modified)
  • Line 361: extracts result.modifiedCount and checks if (ended)
  • Line 385: if (!modified || !agents?.length)
  • Line 402: if (!modified)

The implementation correctly triggers updateCallHistory only after successful hangup, consistent with AC1.

packages/model-typings/src/models/ICallHistoryModel.ts (1)

1-5: LGTM!

The type alias follows the standard pattern for model type definitions and correctly bridges the core typings to the model layer.

packages/core-typings/src/ICallHistoryItem.ts (1)

1-48: Verification confirms safe handling of optional fields.

The downstream logic properly manages optional messageId and rid:

  • rid is conditionally included using spread operator (...(rid && { rid })) during history creation
  • messageId is intentionally omitted at creation and safely assigned later via CallHistory.updateMany after message creation succeeds (line 157)
  • No unsafe direct property access patterns found in the codebase
  • Author field logic at line 141 correctly uses call.caller.id || call.createdBy?.id for transferred calls
packages/core-typings/src/index.ts (1)

149-151: Expose ICallHistoryItem via core typings barrel

The new export is consistent with the existing barrel pattern and correctly surfaces call-history typings to consumers.

packages/models/src/index.ts (2)

88-96: ICallHistoryModel import looks consistent with existing model-typings usage

Adding ICallHistoryModel to the existing model-typings import block matches the established pattern for other models. Just ensure the type alias in @rocket.chat/model-typings is exported under exactly this name.

If you want, you can double-check with a quick grep that ICallHistoryModel is exported from packages/model-typings/src/index.ts and defined in models/ICallHistoryModel.ts.


141-151: New CallHistory proxified model is wired like other models

CallHistory = proxify<ICallHistoryModel>('ICallHistoryModel') follows the same pattern as the other model proxies and gives services a typed façade over the raw model.

Please confirm that:

  • apps/meteor/server/models.ts registers 'ICallHistoryModel' with CallHistoryRaw, and
  • the string key 'ICallHistoryModel' matches the one used in packages/model-typings/src/models/ICallHistoryModel.ts.
ee/packages/media-calls/src/definition/IMediaCallServer.ts (1)

7-11: historyUpdate event and updateCallHistory trigger are coherent with existing IMediaCallServer shape

The new historyUpdate: { callId: string } event and the updateCallHistory(params: { callId: string }): void method fit cleanly into the existing event/trigger pattern (similar to callUpdated / reportCallUpdate), and keeping the payload to callId lets listeners look up full state as needed.

Please verify that:

  • MediaCallServer’s implementation of updateCallHistory actually emits the historyUpdate event on emitter, and
  • the media-call service (or other consumer) subscribes to historyUpdate to perform the call-history persistence and message posting, so the new interface is fully exercised.

Also applies to: 37-44

packages/models/src/models/CallHistory.ts (1)

1-18: CallHistoryRaw model and indexes align with expected access patterns

The new CallHistoryRaw model cleanly follows the existing BaseRaw pattern, and the chosen indexes make sense for per-user call history:

  • { uid: 1, callId: 1 } unique: enforces at most one history entry per user per call.
  • { uid: 1, ts: -1 }: supports efficient “recent calls for user” queries sorted by time.

Implementation looks correct and matches how other models are structured.

packages/i18n/src/locales/en.i18n.json (1)

918-921: Keys verified and correctly mapped; code ready

Verification confirms all four bold i18n keys are properly defined and mapped through the implementation and test suite. Single-asterisk emphasis is correct per the repository's custom message formatter.

apps/meteor/server/services/media-call/getHistoryMessagePayload.spec.ts (2)

4-56: State-to-translation/icon mapping tests look solid

These specs exercise all defined CallHistoryItemState values and verify both the translation keys and icon variants, including the shared mapping for failed/error. This gives good protection against regressions in the mapping helpers.


58-103: Nice edge coverage for duration formatting

The getFormattedCallDuration tests cover undefined/zero, short calls, exact minute, multi-hour, and large durations, including zero-padding. This should make future refactors to the underlying time logic much safer.

apps/meteor/server/services/media-call/getHistoryMessagePayload.ts (2)

22-34: Icon mapping is clear and consistent

The icon and variant choices for each call state (phone-off, clock, phone-issue, arrow-forward) are self-explanatory and align well with the state semantics, including sharing the same treatment for failed and error.


36-56: Duration formatting behavior is reasonable; zero/undefined handled well

getFormattedCallDuration:

  • Ignores undefined and zero (no duration row),
  • Uses intervalToDuration for robust hour/minute/second extraction, and
  • Produces either MM:SS or HH:MM:SS with zero-padding, wrapped in single asterisks.

Given that getCallDuration returns 0 for non‑activated calls, this nicely avoids showing a duration for ringing/not‑answered/failed cases while still formatting active calls correctly.

apps/meteor/server/services/media-call/service.ts (5)

23-24: historyUpdate wiring and ended-call guard align with “post-only-after-end” requirement

Subscribing to callServer.emitter.on('historyUpdate', …) and then guarding on call.ended in saveCallToHistory ensures that summary/history work is only attempted for concluded calls, satisfying the “no summary during ringing/active call” constraint, as long as historyUpdate is emitted at or after call completion.


135-165: History message author selection matches product guidance

sendHistoryMessage:

  • Finds the DM room and message author as const userId = call.caller.id || call.createdBy?.id;, which ensures the history message comes from one of the two call participants, not from a transfer agent.
  • Builds state and duration, uses getHistoryMessagePayload, and sends via sendMessage.
  • Backfills messageId into all CallHistory entries for the call when a message is successfully created, with robust error logging if sending fails.

This aligns with the retrieved guidance about not using transferredBy as the author. The only edge case to watch is any scenario where call.caller.id might be missing; in such a case the fallback to createdBy?.id would emit the message as a non-participant, but that should not happen for the internal-user-only calls you gate earlier.

Based on learnings


167-175: Duration computation matches formatter expectations

getCallDuration:

  • Returns 0 when activatedAt is missing, which naturally suppresses the duration row in getFormattedCallDuration.
  • Otherwise computes (endedAt - activatedAt) in seconds with floor, which is appropriate for user-facing call duration.

This pairs cleanly with the formatter logic and state mapping (non-activated calls are “not-answered” or “failed” and show no duration).


177-199: State derivation logic covers all defined outcomes

getCallHistoryItemState implements:

  • transferred when transferredBy is set (even if there’s also an error reason),
  • failed vs error split based on presence of activatedAt for error-like hangups,
  • not-answered when acceptedAt is never set, and
  • failed vs ended for accepted calls that never activate vs fully active calls.

This mapping is consistent with the CallHistoryItemState documentation and supports the required outcomes: Ended, Not Answered, and technical failures.


201-224: DM room resolution is robust; small behavior notes

getRoomIdForInternalCall:

  • Reuses an existing direct room when available.
  • Otherwise:
    • Picks a DM creator (createdBy.idcaller.iduids[0]),
    • Resolves usernames for the two participants, enforcing exactly two,
    • Uses createDirectMessage(usernames, dmCreatorId, !dmCreatorIsPartOfTheCall) to optionally exclude a non-participant creator from the DM membership.

Behavior notes:

  • If usernames cannot be resolved, this throws and is caught upstream, leading to history entries without rid and no summary message, which seems like a reasonable fallback.
  • Because you derive usernames from Users.findByIds(call.uids), you rely on those user records staying consistent with uids. If that invariant ever breaks, you’ll hit the “Invalid usernames for DM.” error; logging here is important (and already present upstream).

Overall, the room resolution logic looks sound for 1:1 internal calls.

tassoevan
tassoevan previously approved these changes Nov 19, 2025
tassoevan
tassoevan previously approved these changes Nov 19, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/meteor/server/services/media-call/service.ts (1)

140-140: Clarify or remove the inline comment.

The comment is informal and might confuse future maintainers. Either expand it to explain why caller.id is preferred for transferred calls or remove it entirely since the learning already documents this decision.

Apply this diff to clarify:

-		const userId = call.caller.id || call.createdBy?.id; // I think this should always be the caller, since during a transfer the createdBy contact is the one that transferred the call
+		// Use caller.id as message author; for transferred calls, message should appear in DM between original participants
+		const userId = call.caller.id || call.createdBy?.id;

Or simply remove the comment if the logic is self-evident.

Based on learnings

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4afa403 and f04e9e6.

📒 Files selected for processing (2)
  • apps/meteor/server/services/media-call/getHistoryMessagePayload.ts (1 hunks)
  • apps/meteor/server/services/media-call/service.ts (3 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: packages/i18n/src/locales/en.i18n.json:918-921
Timestamp: 2025-11-19T18:20:07.683Z
Learning: Repo: RocketChat/Rocket.Chat — i18n/formatting
Learning: This repository uses a custom message formatting parser in UI blocks/messages; do not assume standard Markdown rules. For keys like Call_ended_bold, Call_not_answered_bold, Call_failed_bold, and Call_transferred_bold in packages/i18n/src/locales/en.i18n.json, retain the existing single-asterisk emphasis unless maintainers request otherwise.
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: apps/meteor/server/services/media-call/service.ts:141-141
Timestamp: 2025-11-19T18:20:37.096Z
Learning: In apps/meteor/server/services/media-call/service.ts, the sendHistoryMessage method should use call.caller.id or call.createdBy?.id as the message author, not call.transferredBy?.id. Even for transferred calls, the message should appear in the DM between the two users who are calling each other, not sent by the person who transferred the call.
📚 Learning: 2025-11-19T18:20:37.096Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: apps/meteor/server/services/media-call/service.ts:141-141
Timestamp: 2025-11-19T18:20:37.096Z
Learning: In apps/meteor/server/services/media-call/service.ts, the sendHistoryMessage method should use call.caller.id or call.createdBy?.id as the message author, not call.transferredBy?.id. Even for transferred calls, the message should appear in the DM between the two users who are calling each other, not sent by the person who transferred the call.

Applied to files:

  • apps/meteor/server/services/media-call/getHistoryMessagePayload.ts
  • apps/meteor/server/services/media-call/service.ts
📚 Learning: 2025-11-19T18:20:07.683Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: packages/i18n/src/locales/en.i18n.json:918-921
Timestamp: 2025-11-19T18:20:07.683Z
Learning: Repo: RocketChat/Rocket.Chat — i18n/formatting
Learning: This repository uses a custom message formatting parser in UI blocks/messages; do not assume standard Markdown rules. For keys like Call_ended_bold, Call_not_answered_bold, Call_failed_bold, and Call_transferred_bold in packages/i18n/src/locales/en.i18n.json, retain the existing single-asterisk emphasis unless maintainers request otherwise.

Applied to files:

  • apps/meteor/server/services/media-call/getHistoryMessagePayload.ts
🧬 Code graph analysis (2)
apps/meteor/server/services/media-call/getHistoryMessagePayload.ts (2)
packages/core-typings/src/ICallHistoryItem.ts (1)
  • CallHistoryItemState (6-16)
packages/core-typings/src/IMessage/IMessage.ts (1)
  • IMessage (162-260)
apps/meteor/server/services/media-call/service.ts (4)
packages/core-typings/src/mediaCalls/IMediaCall.ts (1)
  • IMediaCall (35-68)
packages/models/src/index.ts (4)
  • MediaCalls (186-186)
  • CallHistory (149-149)
  • Rooms (204-204)
  • Users (213-213)
packages/core-typings/src/ICallHistoryItem.ts (2)
  • IInternalMediaCallHistoryItem (37-43)
  • CallHistoryItemState (6-16)
apps/meteor/server/services/media-call/getHistoryMessagePayload.ts (1)
  • getHistoryMessagePayload (57-89)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (10)
apps/meteor/server/services/media-call/getHistoryMessagePayload.ts (4)

7-19: LGTM!

The state-to-translation mapping correctly handles all CallHistoryItemState values. Grouping 'failed' and 'error' under the same i18n key is appropriate for user-facing messages.


21-33: LGTM!

Icon and variant selections are semantically appropriate for each call state. The visual distinction between successful outcomes (secondary) and failures (danger) will aid user comprehension.


39-55: LGTM!

Duration formatting correctly handles hours conditionally, provides sensible defaults, and guards against invalid inputs. The zero-duration edge case (e.g., instant hangup) is handled gracefully as "00:00".


57-89: LGTM!

The payload structure correctly implements a block-based message with InfoCard. The empty msg string (line 66) is appropriate—blocks provide the content. Setting groupable: false ensures call history messages remain distinct rather than being collapsed together.

apps/meteor/server/services/media-call/service.ts (6)

1-12: LGTM!

Import additions properly support the new history persistence feature. All imported types, models, and utilities are used in the methods below.


23-23: LGTM!

Using setImmediate to defer history persistence is appropriate—it prevents blocking the event emitter while ensuring the save happens after the current call stack completes. This pattern is consistent with line 28.


90-132: LGTM!

Robust implementation using Promise.allSettled to ensure both caller and callee history records are attempted. Error handling at each step and conditional message sending based on room availability are well thought out.


166-174: LGTM!

Duration calculation correctly uses activatedAt (when media started flowing) rather than createdAt, and returns 0 for calls that never activated. This aligns with user expectations for call duration.


200-223: LGTM!

The DM room resolution and creation logic correctly handles the transfer scenario where the DM creator (transferrer) is not part of the actual call. The fallback chain for dmCreatorId and the conditional exclusion logic ensure the DM is created between the actual call participants.


181-181: The hangupReason matching strategy is correct; no changes needed.

The .includes('error') check is safe. Analysis of the CallHangupReason type definition shows all error-related values end with '-error' (signaling-error, service-error, media-error, input-error), and none of the non-error values (normal, remote, rejected, unavailable, transfer, timeout) contain this substring. The concern about false positives is unfounded given the actual defined values in the codebase.

tassoevan
tassoevan previously approved these changes Nov 19, 2025
@gabriellsh gabriellsh added the stat: QA assured Means it has been tested and approved by a company insider label Nov 19, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Nov 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider stat: ready to merge PR tested and approved waiting for merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants