VP-Chat Performance & UI Architecture v4 (Zalo-Speed Engine)
Nâng cấp toàn diện kiến trúc Chat VinhPhatERP thành hệ thống Chat tốc độ cao (Zalo-Speed Performance), kết hợp tối ưu hóa 7 tầng: Database, API/RPC, Query Cache, Realtime, View Model & Virtualized Renderer, Scroll Engine, Assets & UI Polish.
1. Bảng Chỉ Số Hiệu Năng Mục Tiêu (Performance Acceptance Criteria)
| Metric | Hiện tại (Baseline) | Mục tiêu (Target v4) | Đo lường / Bằng chứng |
|---|---|---|---|
| Chat Shell Open | ~350ms | < 50ms | Modal/Drawer mở tức thì không giật |
| First Message Paint | ~480ms | < 150ms | Tải từ IndexedDB cache + latest 50 msgs |
| DOM Nodes in Tree | ~3.500 (khi tải nhiều tin) | < 300 nodes | TanStack Virtual chỉ render visible items |
| Message Query (DB) | ~180ms | < 60ms | Composite Index (room_id, created_at DESC, id DESC) |
| Realtime Append Latency | ~220ms (Do invalidate full) | < 50ms | Append-only & Local Cache Patching (0 refetch) |
| Reaction Update | ~350ms (Refetch all msgs) | < 16ms (Instant) | In-memory cache patch trực tiếp vào message.reactions |
| Scroll FPS | ~38-45 FPS | > 58-60 FPS | GPU accelerated, không layout reflow |
| Older Messages Load | Viewport giật/nhảy vị trí | 0px Viewport Jump | Scroll height differential anchoring |
2. Kiến Trúc Hệ Thống 7 Tầng (7-Layer Architecture Pipeline)
┌─────────────────────────┐
│ Supabase DB │
│ (Composite Index & RLS) │
└────────────┬────────────┘
│
Cursor Pagination (50 msgs)
│
▼
┌─────────────────────────┐
│ Normalized Cache Store │
│ (IndexedDB + TanStack) │
└────────────┬────────────┘
│
┌───────────────────┴───────────────────┐
▼ ▼
Realtime INSERT / RXN User Scroll Up
│ │
Append-only Cache Patch Cursor Fetch (older 50)
│ │
└───────────────────┬───────────────────┘
▼
┌─────────────────────────┐
│ View Model Engine │
│ ├── resolveSenderIdentity│
│ ├── Incremental Cluster │
│ └── Semantic Position │
└────────────┬────────────┘
▼
┌─────────────────────────┐
│ Virtualized Renderer │
│ (TanStack Virtual DOM) │
└────────────┬────────────┘
▼
┌─────────────────────────┐
│ Smart Scroll Engine │
│ ├── State A: Bottom Lock│
│ ├── State B: Read Lock │
│ └── State C: Send Lock │
└────────────┬────────────┘
▼
┌─────────────────────────┐
│ Semantic UI Bubbles │
│ ├── 2x4 Radius Matrix │
│ ├── Embedded Meta Time │
│ └── Lazy-Loaded Assets │
└─────────────────────────┘
3. Kế Hoạch Triển Khai Chi Tiết 7 Giai Đoạn
Phase 0: Baseline & Database Index Optimization
[NEW] 20260829000001_chat_performance_indexes.sql
- Tạo composite index tối ưu cho timeline chat.
- Đảm bảo query WHERE room_id = ? ORDER BY created_at DESC LIMIT 50 đạt Index Only Scan (< 10ms).
CREATE INDEX IF NOT EXISTS idx_chat_messages_room_timeline ON public.chat_messages (room_id, created_at DESC, id DESC) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS idx_chat_reactions_room_lookup ON public.chat_message_reactions (room_id, message_id);
Phase 1: Data Fetching & Parallel Bootstrap
[MODIFY] chat.api.ts, useChat.ts
- Chuẩn hóa cursor pagination dựa trên cặp (created_at, id).
- Giới hạn tải mặc định CHAT_MESSAGES_PAGE_SIZE = 40 (thay vì tải thừa).
- Tải song song (Parallel Promise): messages (latest 40) + room participants + unread counter cùng 1 lúc khi mở ChatDrawer.
- Hydrate ngay lập tức từ IndexedDB để Chat Shell mở trong < 50ms.
Phase 2: Realtime Engine Tối Ưu (Append-Only & Zero-Refetch)
[MODIFY] useChat.ts
- Khi nhận tin mới (INSERT): Gọi appendMessage() cục bộ và dedup qua client_id.
- Khi có reaction (chat_message_reactions): Cập nhật trực tiếp in-memory mảng message.reactions của đúng tin nhắn đó trong cache.
- Khi có cập nhật tin (UPDATE): Patch trực tiếp thuộc tính is_pinned hoặc deleted_at vào cache row tương ứng.
- BroadcastChannel Loop Guard: Gắn origin: window.crypto.randomUUID() để tab nhận tin qua BroadcastChannel không vô tình phát ngược lại.
Nguyên tắc cốt lõi: tuyệt đối không sử dụng invalidateQueries cho bất kỳ sự kiện realtime nào (INSERT, UPDATE, Reaction). Mọi cập nhật đều thực hiện bằng cách patch trực tiếp vào in-memory cache, đảm bảo latency < 16ms và 0 request SELECT thừa.
Phase 3: View Model & Incremental Grouping
[MODIFY] chat.types.ts, chat.utils.ts
- Định nghĩa MessagePosition = 'single' | 'first' | 'middle' | 'last'.
- Định nghĩa ChatMessageViewModel chứa dữ liệu đã chuẩn hóa (sender name, initials, avatar, formatted time, delivery status).
- Hàm resolveSenderIdentity(): Tập trung giải quyết tên viết tắt và avatar của người gửi (xóa bỏ hoàn toàn fallback 'U' bừa bãi).
- Hàm buildMessageGroups():
- Gom cluster: Cùng sender + Cùng phòng + Thời gian gần (threshold 5p) + Không có ranh giới ngày/system.
- Incremental Grouping: Khi có tin nhắn realtime đến, chỉ kiểm tra và nối vào cluster cuối cùng thay vì lặp lại toàn bộ 5.000 tin nhắn cũ.
Phase 4: Virtualized Renderer & Scroll Engine
[MODIFY] ChatMessageList.tsx
- Tích hợp TanStack Virtual quản lý hiển thị DOM nodes: chỉ kết xuất các cluster trong khung nhìn (Viewport) + overscan, giữ DOM dưới 300 nodes kể cả với phòng chat 50.000 tin nhắn.
- Scroll Engine 3 trạng thái:
- State A (Đang ở đáy): Nhận tin realtime, tự động cuộn xuống đáy.
- State B (Đang đọc tin cũ): Nhận tin realtime, giữ nguyên vị trí scroll, hiển thị FAB kèm badge số tin mới.
- State C (Gửi tin nhắn): Optimistic update, bắt buộc cuộn tức thì xuống đáy.
- Scroll Anchoring: Bù trừ scrollHeight khi tải trang tin nhắn cũ phía trên, đạt 0px viewport jump.
- FAB Layout: Đặt ngoài luồng danh sách tin, neo tuyệt đối (không đè lên dải gợi ý).
Phase 5: Semantic Bubble Rendering & Compact Geometry
[NEW] ChatMessageMeta.tsx | [MODIFY] ChatBubble.tsx, chat-bubble.css
- Component ChatMessageMeta hiển thị giờ gửi + tick trạng thái (○ đang gửi, ✓ đã gửi, ✓✓ đã nhận, ✓✓ xanh đã xem).
- Tự động chuyển đổi layout: Inline cho tin dài, Side-by-side cho tin ngắn, Chip overlay cho hình ảnh.
- Nhận viewModel chuẩn hóa từ Phase 3.
- 1 Avatar duy nhất ở cuối (hoặc đầu) mỗi incoming cluster, không lặp lại trên từng tin nhắn.
- Ma trận bo góc Semantic 2x4 (Incoming/Outgoing x Single/First/Middle/Last).
- Định hình min-width: 44px; min-height: 36px; để tin nhắn ngắn giữ trọn hình khối bong bóng chat sắc nét, không bị biến dạng.
Phase 6: Asset Optimization & UI Polish
[MODIFY] ChatImagePreview.tsx, Cross-Browser Styling
- Image/Attachment Optimization:
- Tải thumbnail nhẹ qua IntersectionObserver lazy load; chỉ tải ảnh gốc phân giải cao khi người dùng bấm mở Lightbox.
- Tệp đính kèm hiển thị metadata (tên file, đuôi mở rộng, kích thước) không tải file trước.
- Cross-Browser Styling:
- Tùy biến thanh cuộn mỏng mịn chuẩn W3C (scrollbar-width: thin; và ::-webkit-scrollbar 5px), tự ẩn khi không cuộn.
- Đảm bảo độ tương phản cao với Design Tokens ở cả Light và Dark mode.
Phase 7: Kiểm Thử Hiệu Năng & Architecture Guard Verification
Chạy toàn bộ quy trình kiểm tra tự động:
npm run rpc:check npm run typecheck npm run lint -- --max-warnings=0
Kiểm thử thực tế các kịch bản:
- Phòng chat 1.000+ tin nhắn mở trong < 150ms.
- Gửi tin nhắn số ngắn "22", "23": Hiển thị bong bóng chuẩn Zalo.
- Gửi reaction: Cập nhật tức thì 0ms, không có request SELECT toàn bộ tin nhắn.
- Cuộn lên tải tin cũ: Viewport đứng im, không bị giật.
4. User Review Required
Đây là bản nâng cấp toàn diện nhất từ trước đến nay cho Chat Engine của VinhPhatERP, kết hợp tối ưu cả hiệu năng Backend/Database và trải nghiệm Frontend/DOM. Toàn bộ code tuân thủ 100% Architecture Guard (no-emoji, Semantic Tokens, no-business-logic-in-ui).