Tổng › Cần sửa sớm

1. Cần sửa sớm

Commit c12a44b. Mục 1–4 ảnh hưởng trực tiếp người dùng hoặc chi phí khi có nhiều user. Mục 5 sửa nhỏ, nằm trên đường Run trả phí.

G1API + FEMở hoặc reload nhiều tab cùng lúc làm văng đăng nhập

Vấn đề
  • Mỗi tab tự gọi POST /api/auth/refresh, cả khi mount lẫn theo hẹn giờ.
  • Server xoay refresh token. Khi một token đã thu hồi bị dùng lại, server thu hồi toàn bộ family.
  • Hai tab gửi cùng cookie cũ thì request đến sau bị coi là dùng lại, và mọi tab mất phiên.
  • Ngoài ra, chỉ cần một lỗi mạng tạm thời trong lúc refresh là client cũng chuyển về anonymous.
Trường hợp hay gặp: trình duyệt khôi phục nhiều tab Forma, hoặc người dùng reload vài tab cùng lúc.
Vị trí
apps/api/src/auth/session.service.ts:74–80
apps/web/src/components/auth-provider.tsx:52 (hẹn giờ), :59–77 (refresh khi mount, lỗi nào cũng đăng xuất)
Thực hiện
  • Server: trong vài giây ngay sau khi xoay, token vừa thu hồi vì rotated vẫn được chấp nhận và trả về đúng phiên mới, thay vì thu hồi cả family.
  • Client: mỗi lúc chỉ một tab được refresh (Web Locks hoặc BroadcastChannel); các tab khác dùng chung kết quả.
  • Lỗi mạng hoặc 5xx thì thử lại. Chỉ 401 mới đăng xuất.
Kiểm
  • Gửi 2 request refresh song song bằng cùng một cookie: cả hai đều giữ được phiên.
  • Mở 3 tab rồi reload cùng lúc: vẫn đăng nhập.
  • Chặn mạng trong lúc refresh: không bị đăng xuất.
  • Token cũ dùng lại sau khoảng ân hạn: vẫn bị thu hồi family như hiện tại.

G2APIQuote không có giới hạn tần suất phía server

Vấn đề
  • quote() mở transaction DB và gọi Core compile tối đa 4 lần cho mỗi intent. Một group có thể tới 128 output.
  • create có rateLimit.hit, còn quote thì không.
  • Debounce 250 ms ở client không thay được giới hạn server. Mở nhiều tab, đổi settings liên tục hoặc gọi API trực tiếp đều dồn tải lên Core và DB mà không cần tạo job.
Vị trí
apps/api/src/jobs/jobs.service.ts:178 (quote), :147 (preflightMode), :210 (limiter mẫu ở create)
Thực hiện
  • Giới hạn quote theo user. Với group, đếm theo số intent.
  • Trả 429 kèm mã lỗi riêng. FE hiển thị lỗi này riêng, không gộp vào lỗi chung.
Kiểm
  • Test vượt ngưỡng phải trả 429.
  • Đếm số lần compile mỗi phút khi đổi settings liên tục ở 3 tab.

G3APILưu output: worker cũ và worker mới có thể cùng hoàn tất một job

Vấn đề
  • Job chuyển sang saving với hạn 180 s.
  • Hết hạn, reaper đưa job về processing, và một worker khác nhận lưu lại.
  • Worker cũ vẫn chạy tiếp. Câu UPDATE … succeeded cuối chỉ kiểm status = 'saving', không có token phân biệt lượt lưu.
  • safeFetch chỉ có timeout khi socket không hoạt động (30 s), không có hạn tổng. Stream chậm mà đều vẫn kéo quá 180 s.
Đây là rủi ro tìm thấy trong code, chưa tái hiện.
Vị trí
apps/api/src/jobs/job-lifecycle.service.ts:530 (vào saving), :633–637 (UPDATE cuối), :727 (reaper)
apps/api/src/common/http/safe-fetch.ts:73, :96
Thực hiện
  • Tạo token cho mỗi lượt lưu (ví dụ save_attempt) khi chuyển sang saving.
  • UPDATE cuối và các bước ghi asset chỉ chạy khi token còn khớp.
  • Thêm hạn tổng cho việc tải output, ngắn hơn hạn của lượt lưu.
Kiểm
  • Fault test: worker A dừng quá 180 s, worker B lưu xong, rồi A chạy tiếp. Kết quả: A không ghi được gì.
  • Số asset output đúng bằng số output của job.

G4APIHàng rào chi phí: trần guest chưa chạy, bộ đếm tăng trước khi job được nhận

Vấn đề
  • assertGuestSpendAllowed không có nơi nào gọi. Setting trần chi tiêu guest theo ngày vẫn tồn tại nên dễ bị hiểu là đang có hiệu lực.
  • assertSpendAllowed tăng bộ đếm Redis trước bước moderation và trước transaction tạo job. Request bị từ chối sau bước tăng (content_policy, quote hết hạn…) vẫn bị tính vào trần ngày.
  • Hậu quả: user có thể chạm user_daily_cap dù chưa chạy job nào.
Vị trí
apps/api/src/jobs/cost-guard.service.ts:61 (không có caller), :51 (tăng counter)
apps/api/src/jobs/jobs.service.ts:242–245
Thực hiện
  • Gọi trần guest trong đường Run của trial, hoặc bỏ setting nếu không dùng.
  • Chỉ tăng bộ đếm sau khi transaction tạo job commit; hoặc hoàn lại bộ đếm khi request bị từ chối sau bước tăng.
Kiểm
  • Request bị content_policy hoặc quote_expired không làm tăng bộ đếm.
  • Guest vượt trần bị chặn trước khi dispatch lên provider.

G5CoreDefault và VIP Sunburst ở 2K/4K gửi field background mà provider chỉ hỗ trợ ở 1K

Vấn đề
  • room.edit đặt mặc định background = 'auto' và luôn thêm field này vào payload Sunburst.
  • Khi chuyển sang Flare (mode Default), adapter chép nguyên input nên vẫn giữ field.
  • Schema KIE của Flare và Sunburst ghi rõ background chỉ hỗ trợ khi resolution = 1K, trong khi UI cho chọn 2K và 4K.
  • Ảnh hưởng cả 6 workflow phòng: Virtual Staging, Renovation, Furniture Removal, Sketch to Image, Floor Plan AI, Style Transfer.
Chưa thấy provider từ chối request. Nếu KIE bắt đầu kiểm điều kiện này, mọi lượt Run 2K/4K của hai mode sẽ lỗi.
Vị trí
services/core-engine/src/engine.mjs:714, :736
services/core-engine/src/model-adapters.mjs:49–56
Thực hiện
  • Chỉ thêm background khi resolution là 1K. Payload 1K giữ nguyên.
  • Không hạ 2K/4K xuống 1K, không đổi model.
  • Cập nhật compiler version/digest theo cơ chế hiện có.
Layer extract cũng gửi 2K + transparent, nhưng đó là đường riêng, xem K8 ở trang Không gấp.
Kiểm
  • Test payload: 1K có background; 2K và 4K không có, ở cả Default lẫn VIP Sunburst.
  • Digest lúc preflight trùng với digest lúc Run.
Schema và mã băm: xem trang provider.