v beta-2.0.1 Released

Integração Frontend: API & Performance

05 de janeiro de 2026
beta-2.0.1
Time Técnico NexarSystems

Este documento descreve como a aplicação frontend se comunica com os microsserviços backend e as estratégias empregadas para garantir uma experiência de usuário responsiva.

# Padrões de Integração de API

Utilizamos o Repository Pattern para abstrair chamadas de API dos componentes de UI. Isso permite testes e mocking mais fáceis.

# Camada de Serviço (src/services/)

Cada domínio do backend possui um arquivo de serviço correspondente:

  • AuthService.ts: Login, refresh token, redefinição de senha.
  • GridService.ts: Busca de dados do grid, salvamento de alterações.
  • RosteredService.ts: Gerenciamento de perfis profissionais.

Exemplo: GridService.ts

import api from '@/boot/axios';
import { ShiftPack } from '@/types';

export default {
  async getByUnitAndMonth(unitId: string, month: string): Promise<ShiftPack[]> {
    const response = await api.get(`/api/shiftPack/list`, {
      params: { unitId, month }
    });
    return response.data;
  },

  async createShift(payload: CreateShiftPayload): Promise<ShiftItem> {
    const response = await api.post('/api/shiftItem/create', payload);
    return response.data;
  },

  async formatBulkSlots(payload: BulkSlotPayload): Promise<ApiResponse> {
    // Usado para criação de turnos customizados (repetidor)
    // payload.purgeBeforeInsert = true garante atomicidade
    const response = await api.post('/api/shiftPack/formatBulkSlots', payload);
    return response.data;
  }
};

# Persistência de Turnos Customizados (applyCustomShiftItems)

Quando usuários definem turnos customizados via SlotSchedullerContainer, o frontend deve garantir que essas alterações sejam aplicadas atomicamente. Usamos o endpoint formatBulkSlots com a flag purgeBeforeInsert.

Action da Store (gridStore.js):

async applyCustomShiftItems({ slotId, shiftPackId, customTurnos }) {
  // 1. Transforma objetos da UI em Modelos de Domínio
  const newShiftItems = customTurnos.map((turno, index) => {
    const duration = calculateDurationMinutes(turno.startTime, turno.endTime);
    return new ShiftItemModel({
      startTime: turno.startTime,
      endTime: turno.endTime,
      duration: duration,
      position: index,
      isShort: duration <= 60, // Calculado para UI, não persistido
      // ...
    });
  });

  // 2. Constrói o Payload
  const payload = {
    items: [{ shiftPackId, slotId, shiftItems: newShiftItems }],
    purgeBeforeInsert: true // CRÍTICO: Remove itens antigos antes de inserir novos
  };

  // 3. Envia para o BFF
  await SurrealService.formatBulkSlots(payload);
  
  // 4. Recarrega o Grid para sincronizar estado
  await this.loadShiftPacks(this.selectedGrid.id);
}

# Tratamento Global de Erros

Um interceptador Axios captura todos os erros de API e os despacha para o sistema de notificação:

  1. 401 Unauthorized: Redireciona para login (ou tenta refresh).
  2. 403 Forbidden: Mostra toast de “Acesso Negado”.
  3. 422 Validation Error: Destaca campos do formulário com mensagens do servidor.
  4. 500 Server Error: Mostra uma mensagem genérica de “Erro no Sistema” e loga o trace ID.

# Atualizações em Tempo Real (WebSockets)

Para suportar edição colaborativa, o frontend mantém uma conexão WebSocket (via cliente Socket.io) com o backend.

  • Evento: grid.updated
  • Payload: { unitId, month, modifiedBy }
  • Ação: Se o usuário estiver visualizando o grid afetado, um toast “Novos dados disponíveis” aparece, ou o grid se auto-atualiza (configurável).

# Otimização de Performance

# 1. Atualizações de UI Otimistas

Quando um usuário move um turno, a UI atualiza imediatamente, antes que a resposta da API seja recebida.

  • Sucesso: O spinner de carregamento desaparece.
  • Falha: O turno volta para sua posição original, e um toast de erro é mostrado.

# 2. Cache e Enriquecimento de Dados

Implementamos uma estratégia de cache para minimizar requisições de rede e enriquecer dados brutos com propriedades específicas de UI.

  • Stale-While-Revalidate: Dados de grid em cache são mostrados instantaneamente enquanto uma busca em segundo plano verifica atualizações.
  • Enriquecimento de Dados: Como o backend não armazena flags específicas de UI (como isShort), estas são calculadas em tempo de execução durante o processo de carregamento de dados.
// gridStore.js
_enrichShiftPacks(shiftPacks) {
  return shiftPacks.map(shiftPack => ({
    ...shiftPack,
    shiftItems: (shiftPack.shiftItems || []).map(shiftItem => ({
      ...shiftItem,
      // Recalcula flags de UI que não são persistidas
      isShort: shiftItem.duration <= 60 
    }))
  }));
}

# 3. Otimização de Bundle

  • Tree Shaking: Componentes Quasar não utilizados são excluídos do build.
  • Gzip/Brotli: Assets são comprimidos durante o processo de build.
  • Otimização de Imagem: Avatares de usuários e assets estáticos são servidos via CDN com capacidades de redimensionamento.

# Estratégia de Testes

  • Testes Unitários (Vitest): Foco em funções utilitárias, lógica de store e propriedades computadas complexas.
  • Testes de Componente (Vue Test Utils): Verificam se componentes renderizam corretamente e emitem os eventos esperados.
  • Testes E2E (Cypress): Simulam fluxos críticos do usuário: Login -> Abrir Grid -> Criar Turno -> Publicar.