Dịch vụ DM đa-tenant dùng MySQL + Redis Stream + Express. Cung cấp API để:
tenantid)status cho dm_room và room_useruq_tenant_pair (tenant_id, user_a_id, user_b_id) và CHECK (user_a_id < user_b_id)CACHE_ROOM_SIZEroom_read_state lưu last_read_message_idstatus ở dm_room và room_user (0: khóa, 1: hoạt động)openapi.yaml để tích hợp nhanhsrc/server.js (Express)src/services/* (room, message, readstate)src/redis.jssrc/db.jssrc/worker/backupWorker.js (đọc stream, ghi DB)sql/*.sql (chạy bởi scripts/migrate.js)# 1) Cài dependencies
npm install
# 2) Tạo file .env và cấu hình (xem mục Cấu hình)
# Windows tạo nhanh file rỗng:
copy NUL .env
# 3) Tạo bảng/migrate
npm run migrate
Tham số và giá trị mặc định (tham chiếu src/config.js):
NODE_ENV=development
PORT=3000
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=root
DB_PASS=
DB_NAME=chatroom
REDIS_URL=redis://127.0.0.1:6379
STREAM_KEY=msg_stream
STREAM_GROUP=backup_group
BACKUP_INTERVAL_MS=3000
CACHE_ROOM_SIZE=200
Lưu ý:
CREATE DATABASE chatroom;CREATE/ALTER/INSERT/SELECT/UPDATE trên DB# Khởi động Redis (tùy môi trường)
redis-server
# API server
npm run dev
# Worker backup (nên chạy song song với server)
npm run worker
PORT (mặc định 3000)STREAM_KEY theo group STREAM_GROUP và ghi message vào MySQL001_dm_room.sql: bảng dm_room (duy nhất theo cặp trong cùng tenant)002_message.sql: bảng message (nội dung tin)003_room_read_state.sql: bảng room_read_state (trạng thái đọc)004_room_user.sql: bảng room_user (map user ngoại hệ thống + token)005_alter_users.sql: ví dụ thêm cột key cho bảng users (tuỳ hệ thống)006_alter_message_add_columns.sql: bổ sung cột nội dung007_alter_dm_room_add_status.sql: cột status cho dm_room008_alter_room_user_add_status.sql: cột status cho room_userChạy tất cả migrations:
npm run migrate
openapi.yaml)Health
curl -s http://localhost:3000/api/v1/health
Tạo/Lấy phòng DM (quyền admin)
curl -X POST "http://localhost:3000/api/v1/tenants/1/rooms" \
-H "x-tenant-id: 1" -H "x-private-key: <admin-key>" \
-H "Content-Type: application/json" \
-d '{"user_a_id":101,"user_b_id":202}'
Liệt kê phòng của 1 user
curl "http://localhost:3000/api/v1/tenants/1/rooms?user_id=101&limit=20"
Gửi tin nhắn vào phòng
curl -X POST "http://localhost:3000/api/v1/tenants/1/rooms/10/messages" \
-H "x-tenant-id: 1" -H "x-public-key: <public-key>" \
-H "x-room-user-token: <token-cua-user>" \
-H "Content-Type: application/json" \
-d '{"sender_id":101,"content_type":"text","content_text":"hello"}'
Đọc tin nhắn (prefer=db|cache)
curl "http://localhost:3000/api/v1/tenants/1/rooms/10/messages?limit=20&prefer=db" \
-H "x-tenant-id: 1" -H "x-public-key: <public-key>" \
-H "x-room-user-token: <token>"
Upsert read state
curl -X PUT "http://localhost:3000/api/v1/tenants/1/rooms/10/read-state" \
-H "x-tenant-id: 1" -H "x-public-key: <public-key>" \
-H "x-room-user-token: <token>" \
-H "Content-Type: application/json" \
-d '{"user_id":101,"last_read_message_id":12345}'
Đếm chưa đọc
curl "http://localhost:3000/api/v1/tenants/1/rooms/10/unread-count?user_id=101" \
-H "x-tenant-id: 1" -H "x-public-key: <public-key>" \
-H "x-room-user-token: <token>"
Quản trị status:
PUT /tenants/{tenantId}/rooms/{roomId}/status { "status": 0|1 }PUT /tenants/{tenantId}/room-users/{externalUserId}/status { "status": 0|1 }id DESCcursor là id cuối cùng của trang trước (WHERE id < cursor)room:msgs:${tenantId}:${roomId}, TTL 24h, tối đa CACHE_ROOM_SIZE phần tửdm_room(id, tenant_id, user_a_id, user_b_id, status, created_at)message(id, tenant_id, room_id, sender_id, content_type, content_text, content_json, ingest_id, created_at, ...)room_user(id, tenant_id, external_user_id, display_name, token, status, created_at)room_read_state(tenant_id, room_id, user_id, last_read_message_id, last_read_at)src/
server.js # khởi động HTTP server, mount routes, middlewares
config.js # đọc biến môi trường
db.js # MySQL pool
redis.js # Redis client + group init
routes/ # định tuyến REST
services/ # nghiệp vụ (room, message, readstate)
middlewares/ # error handler, auth (nếu cần mở rộng)
utils/ # pagination, validate
worker/backupWorker.js # backup tin nhắn từ Redis stream sang MySQL
sql/ # migrations
scripts/migrate.js # chạy migrations theo thứ tự
openapi.yaml # mô tả OpenAPI 3.1
x-tenant-id, với các API cần quyền còn có x-private-key hoặc x-public-key và x-room-user-tokenpublic/private key và tokenMIT (tuỳ chỉnh theo nhu cầu của bạn).