9f7c9099bc
Synchronous translation on read (Stage D) blocks the HTTP handler on translator I/O. Stage E switches to "send moments-fast, deliver when translated": recipients whose preferred_language differs from the detected body_lang are inserted with available_at=NULL, and an async worker turns them on once a LibreTranslate call materialises the cache row (or fails terminally after 5 retries). Schema delta on diplomail_recipients: available_at, translation_attempts, next_translation_attempt_at, plus a snapshot recipient_preferred_language so the worker queries do not need a join. Read paths (ListInbox, GetMessage, UnreadCount) filter on available_at IS NOT NULL. Push fan-out is moved from Service to the worker so the recipient only sees the toast when the inbox row is actually visible. Translator backend is now a configurable choice: empty BACKEND_DIPLOMAIL_TRANSLATOR_URL → noop (deliver original); populated → LibreTranslate HTTP client. Per-attempt timeout, max attempts, and worker interval all live in DiplomailConfig. The HTTP client itself is unit-tested via httptest (happy path, BCP47 normalisation, unsupported pair, 5xx, identical src/dst, missing URL); worker delivery + fallback paths are covered by the testcontainers-backed e2e tests in diplomail_e2e_test.go. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
31 lines
803 B
Go
31 lines
803 B
Go
//
|
|
// Code generated by go-jet DO NOT EDIT.
|
|
//
|
|
// WARNING: Changes to this file may cause incorrect behavior
|
|
// and will be lost if the code is regenerated
|
|
//
|
|
|
|
package model
|
|
|
|
import (
|
|
"github.com/google/uuid"
|
|
"time"
|
|
)
|
|
|
|
type DiplomailRecipients struct {
|
|
RecipientID uuid.UUID `sql:"primary_key"`
|
|
MessageID uuid.UUID
|
|
GameID uuid.UUID
|
|
UserID uuid.UUID
|
|
RecipientUserName string
|
|
RecipientRaceName *string
|
|
RecipientPreferredLanguage string
|
|
AvailableAt *time.Time
|
|
TranslationAttempts int32
|
|
NextTranslationAttemptAt *time.Time
|
|
DeliveredAt *time.Time
|
|
ReadAt *time.Time
|
|
DeletedAt *time.Time
|
|
NotifiedAt *time.Time
|
|
}
|