Appearance
Type Deep Dive — Provider Token And Conference Runtime
1. Token actions của Stringee và Twilio không cùng contract
Stringee
stringeeToken:
- guard
ctx.Stringee == nil -> errUnsupported(action/stringee.go:20), - luôn tạo user token theo
ctx.Access.UserID, - nếu có
room, tạo thêmroom_tokenvới quyềnPublish/Subscribe/ControlRoom/Record(action/stringee.go:42).
Twilio
twilioToken:
- guard
ctx.Twilio == nil -> errUnsupported(action/twilio.go:18), - tạo identity dạng
userID:random8(action/twilio.go:33), - nếu có
room, addVideoGrant(room)rồi trảtoken(action/twilio.go:36).
Điều này có nghĩa Twilio token mang identity per session/call, còn Stringee token gắn trực tiếp user identity.
2. FE wrappers
Stringee
| Surface | Vai trò |
|---|---|
StringeeProviderWrapper | query GetStringeeToken rồi mount provider (StringeeProviderWrapper.tsx:20) |
StringeeProvider | connect client khi lazy = false, reconnect trên requestnewtoken, emit chat events (StringeeProvider.ts:48) |
StringeeConferenceDialog | request room_token theo roomId, map participants từ useUser() (StringeeConferenceDialog.tsx:86) |
StringeeConference | preview mặc định trước khi join, sau đó mới mount room runtime (StringeeConference/index.tsx:255) |
Twilio
| Surface | Vai trò |
|---|---|
TwilioVideoPreview | preview media local trước khi join |
TwilioVideo | gọi getTwilioToken(room), rồi Video.connect(token, { name: room }) |
TwilioVideo/index.tsx | bật overlay khi currentConversation.video_room_id có giá trị |
3. Twilio preview payload mismatch
Parent TwilioVideo/index.tsx chờ:
ts
{ videoEnabled, microphoneEnabled }ở handleAccept() (TwilioVideo/index.tsx:27)
Nhưng TwilioVideoPreview lại emit:
ts
{ videoEnabled, audioEnabled }(TwilioVideoPreview.tsx:69)
Kết quả là values.microphoneEnabled ở parent có thể luôn là undefined, khiến preview mic state không truyền đúng sang room runtime.
4. createConference có contract drift mạnh
Logic hiện tại
- parse
type = meet | stringee(action/type.go:28), meet-> tạo Google Calendar event và Hangout link (conference.go:88),stringee-> tạo room Stringee bằngconversation_idhoặc UUID mới (conference.go:143),- nếu
conversation_id != nil-> mutate conversation_set: { external_call_id: conference_url }(conference.go:60).
Drift 1: update sai field contract
FE overlay Twilio đọc conversation.video_room_id (TwilioVideo/index.tsx:14) và metadata permission cũng chỉ expose video_room_id / video_room_provider (public_conversation.yaml:62, public_conversation_admin.yaml:43).
Nhưng backend lại update external_call_id, field không nằm trong permission columns đã thấy ở metadata search hiện tại. Đây là lệch contract rõ giữa action layer và runtime FE/read model.
Drift 2: mutate conversation có thể fail ngầm
createConference dùng ctx.Controller, tức access client theo session user (action/action.go:39), không phải admin client. Nếu field _set.external_call_id bị role schema hoặc permission chặn, Mutate() sẽ lỗi. Nhưng code chỉ log:
ctx.Logger.Err(err).Msgf("failed to update conversation: %s", err)
và vẫn return success output (conference.go:79).
Drift 3: Stringee create path không guard nil provider
Trong khi stringeeToken có guard ctx.Stringee == nil, nhánh createConference -> createStringeeRoom gọi thẳng:
ctx.Stringee.Room.Create(...)
(conference.go:149)
Nếu env thiếu config Stringee và env.NewConfig() để Stringee = nil, nhánh này sẽ là điểm rủi ro runtime.
5. Findings kỹ thuật
| ID | Mức độ | Mô tả |
|---|---|---|
| PR-F01 | Cao | Twilio preview emit audioEnabled nhưng parent đọc microphoneEnabled, làm lệch media state transfer (TwilioVideoPreview.tsx:69, TwilioVideo/index.tsx:27). |
| PR-F02 | Rất cao | createConference update external_call_id thay vì video_room_id/video_room_provider, trái với contract FE/read model (conference.go:60, public_conversation_current.yaml:23). |
| PR-F03 | Cao | createConference swallow lỗi mutate conversation và vẫn trả output success, tạo trạng thái “conference created nhưng conversation chưa link” (conference.go:79). |
| PR-F04 | Cao | Nhánh createConference -> stringee không check ctx.Stringee == nil, khác chuẩn guard của stringeeToken (action/stringee.go:20, conference.go:149). |