Pular para conteúdo

Rune Courier

Servico de chat em tempo real para a plataforma HAUS — conversas user-to-user com isolamento multi-tenant e multi-aplicacao.

Visao Geral

O Rune Courier e o servico centralizado de chat da plataforma HAUS. Cada aplicacao (Hotel, Chronicle, Chronos) utiliza o mesmo servico com isolamento duplo: por aplicacao e por tenant.

Funcionalidades Principais

Modulo Descricao
Conversas Diretas (1:1) e em grupo com participantes
Mensagens Texto, imagem, arquivo e sistema com cursor pagination
WebSocket Atualizacoes em tempo real (mensagens, typing, presenca)
Presenca Status online/offline por tenant via Redis
Typing Indicador de digitacao com TTL de 5 segundos
Read Receipts Marcacao de leitura e contagem de nao-lidos
Multi-tenant Isolamento duplo (application_id, tenant_id)

Stack

Camada Tecnologia
Backend Quarkus 3.17 + Java 21 + PostgreSQL 16
Real-time Quarkus WebSockets Next
Cache Redis 7 (presenca, typing, unread)
Auth JWT via OATH + BaseAuthFilter (SDK)
Permissoes Guild (roles PARLEY_ADMIN, PARLEY_USER)
SDK ChatClientService no haus-quarkus-sdk

Multi-Tenancy

Isolamento duplo via (application_id, tenant_id):

graph TB
    subgraph "application_id = HOTEL-BACKEND"
        H1["tenant_id = hotel-A<br/>Staff + Hospedes"]
        H2["tenant_id = hotel-B<br/>Staff + Hospedes"]
    end

    subgraph "application_id = CHRONICLE"
        C1["tenant_id = org-X<br/>Membros"]
        C2["tenant_id = org-Y<br/>Membros"]
    end

    subgraph "application_id = CHRONOS"
        T1["tenant_id = clinica-1<br/>Profissionais + Clientes"]
    end

Como funciona

  1. Frontend envia JWT + headers X-Application-Id e X-Tenant-Id
  2. AuthFilter valida token via OATH introspection
  3. ParleyContext extrai (applicationId, tenantId, userId) do request
  4. Toda query no banco inclui WHERE application_id = ? AND tenant_id = ?
  5. WebSocket recebe app e tenant como query params na conexao

Uso por projeto

Projeto application_id tenant_id Quem conversa
Hotel HOTEL-BACKEND hotel_id Staff interno + hospede-recepcao
Chronicle CHRONICLE organization_id Membros da organizacao
Chronos CHRONOS tenant_id Profissionais + clientes

Tipos de Conversa

DIRECT (1:1)

Conversa entre dois usuarios. O sistema previne duplicatas — se ja existe uma conversa direta entre os dois usuarios no mesmo tenant, ela e reutilizada.

GROUP

Conversa com multiplos participantes. Possui nome e o criador recebe role ADMIN.

Canais no Hotel

No Hotel, as conversas sao separadas por canal via metadata JSONB:

  • INTERNAL — Apenas staff (HOTEL_ADMIN, HOTEL_GERENTE). Chat entre funcionarios.
  • SUPPORT — Hospede conversa com recepcao/staff. Canal de atendimento.
{ "channel": "INTERNAL" }

Tipos de Mensagem

Tipo Descricao
TEXT Mensagem de texto
IMAGE Imagem (URL do Vault)
FILE Arquivo (URL do Vault)
SYSTEM Notificacao automatica do sistema

WebSocket

Conexao em tempo real para receber eventos:

ws://host/ws/chat?token={jwt}&app={appId}&tenant={tenantId}

Eventos Server → Client

Evento Descricao
MESSAGE_RECEIVED Nova mensagem
MESSAGE_UPDATED Mensagem editada
MESSAGE_DELETED Mensagem removida
TYPING_START Usuario comecou a digitar
TYPING_STOP Usuario parou de digitar
READ_RECEIPT Conversa marcada como lida
PRESENCE_CHANGED Status online/offline
CONVERSATION_CREATED Nova conversa criada

Eventos Client → Server

{ "type": "TYPING", "conversationId": "uuid" }
{ "type": "TYPING_STOP", "conversationId": "uuid" }
{ "type": "MARK_READ", "conversationId": "uuid", "messageId": "uuid" }

SDK — ChatClientService

O haus-quarkus-sdk inclui o ChatClientService para integracao server-to-server:

@Inject ChatClientService chatClient;

// Enviar mensagem de sistema
chatClient.sendSystemMessage(tenantId, conversationId, "Reserva confirmada!");

// Criar conversa direta
chatClient.findOrCreateDirect(tenantId, userId, email, name);

// Criar grupo
chatClient.createGroup(tenantId, "Equipe Recepcao", participants);

Configuracao (application.properties)

quarkus.rest-client.chat-api.url=http://parley:8080
haus.chat.enabled=true
haus.chat.application-id=hotel-backend
haus.chat.auth.email=hotel-backend
haus.chat.auth.password=HOTEL-BACKEND987!@#

Integracoes

Servico Uso
OATH Autenticacao JWT + introspection
Guild Registro de roles e permissoes no startup
Herald Notificacoes offline (quando usuario sem WebSocket ativo)
Scrolls Audit log de eventos (criacao de conversa, delete de msg)
Vault Anexos — frontend faz upload para Vault, URL vai no metadata da mensagem