iGRPIGRP 3.0Documentation

Envio — SDKs e API

Passo a passo para uma aplicação iGRP enviar notificações — template, envio a partir do backend Spring Boot ou do frontend Next.js, inbox e sino da header.

Este guia liga uma aplicação iGRP ao Notification Service, do template ao sino da header. O exemplo envia por email a confirmação de um pedido; troca os nomes pelos da tua aplicação.

Os SDKs têm páginas de referência próprias: SDK TypeScript e SDK Java.

Quem enviaQuando usar
Backend (Spring Boot + SDK Java)O envio é consequência de uma regra de negócio do serviço (convites, alterações de estado).
Frontend (Server Action + SDK TypeScript)O envio parte de uma ação do utilizador na app (fechar um passo, emitir um recibo).

Nos dois casos o envio é M2M: um cliente OAuth2 client_credentials do Access Management. A inbox, essa, lê-se com o token do utilizador.

Processos já notificam

O runtime de processos avisa por IN_APP quem pode executar a tarefa seguinte, sem código na tua app — ver Notificações de tarefas.


1. Pré-requisitos

  • Um cliente M2M no Access Management (client ID + secret) cuja conta de serviço:
    • está associada à aplicação, para o token sair com o claim application_code;
    • tem a permissão igrp.notification.send (e igrp.notification.read para consultar envios; igrp.notification.admin se também listares templates).
  • O código da aplicação (IGRP_APP_CODE).
  • O canal que vais usar ligado no serviço (para EMAIL, o SMTP — ver Configurar os canais) e ativo nas definições da aplicação. Senão: 422 CHANNEL_NOT_ENABLED.

Conta de serviço sem aplicação

Se o token M2M não trouxer application_code, o serviço tenta validar o acesso à aplicação como se o chamador fosse um utilizador, e uma conta de serviço falha: 422 ACCESS_MANAGER_UNAVAILABLE (User not found). Sem permissões, a resposta é 403. Confirma os dois no Access Management antes de depurar o código.

2. Criar e publicar o template

Cria o template na Notifications UI (editor visual) ou pela API de templates e publica-o: só templates publicados são usados no envio.

CampoExemplo
Códigopedido-confirmacao
CanalEMAIL
Localept-CV
AssuntoPedido {{numeroPedido}} recebido
Variáveisnome, numeroPedido

As variáveis usam a sintaxe Handlebars ({{nome}}). O envio procura o template com o locale exato: se só publicaste pt-CV, um envio com pt falha com 422 TEMPLATE_ERROR. Detalhes em Templates.


Backend (Spring Boot)

3. Dependência e cliente

Adiciona cv.igrp.platform.notification:client e cria os beans ApiClient e NotificationsApi como em SDK Java › Configurar num serviço Spring Boot.

4. Serviço de envio

EMAIL precisa de SMTP configurado

Para enviar por EMAIL, o provider SMTP tem de estar configurado no Notification Service (NOTIFICATION_PROVIDERS_EMAILSMTP_*: servidor, porta, credenciais e remetente). Sem ele, o envio é recusado com 422 CHANNEL_NOT_ENABLED e nenhum email sai — ver Configurar os canais › EMAIL (SMTP). O canal também tem de estar ativo nas Definições da aplicação.

@Service
public class ConfirmacaoNotifier {

    private static final Logger LOG = LoggerFactory.getLogger(ConfirmacaoNotifier.class);
    private final Optional<NotificationsApi> notificationsApi;

    public ConfirmacaoNotifier(Optional<NotificationsApi> notificationsApi) {
        this.notificationsApi = notificationsApi;
    }

    public void enviar(String email, String nome, String numeroPedido) {
        if (notificationsApi.isEmpty()) {
            LOG.info("Notificações desativadas, confirmação {} não enviada", numeroPedido);
            return;
        }
        TemplateRefDto template = new TemplateRefDto();
        template.setCode("pedido-confirmacao");
        template.setLocale("pt-CV");

        RecipientDto recipient = new RecipientDto();
        recipient.setEmail(email);

        SendNotificationRequest request = new SendNotificationRequest();
        request.setChannelStrategy(ChannelStrategy.SPECIFIC);
        request.setChannels(List.of(Channel.EMAIL));
        request.setRecipients(List.of(recipient));
        request.setTemplate(template);
        request.setVariables(Map.of("nome", nome, "numeroPedido", numeroPedido));
        request.setBusinessKey(numeroPedido);
        request.setIdempotencyKey("pedido-confirmacao:" + numeroPedido);

        try {
            notificationsApi.get().send(request);
        } catch (ApiException e) {
            // o envio falhou; decide se isto deve falhar o comando de negócio
            LOG.warn("Confirmação {} não enviada: {} {}", numeroPedido, e.getErrorCode(), e.getErrorMessage());
        }
    }
}

idempotencyKey evita emails duplicados se o comando for repetido.


Frontend (Next.js)

3. Instalar o SDK

pnpm add @igrp/platform-notification-client-ts

4. Factories do cliente

Um cliente M2M (criado uma vez) para enviar, e um cliente por pedido com o token do utilizador para a inbox:

// src/lib/notification-client.ts
import 'server-only';
import { NotificationClient } from '@igrp/platform-notification-client-ts';
import { auth } from '@/lib/auth';

const baseUrl = process.env.NOTIFICATION_SERVICE_BASE_URL ?? '';

let m2mClient: NotificationClient | undefined;

/** Envio, anexos, templates — token client_credentials do Access Management. */
export function getNotificationM2MClient(): NotificationClient {
  m2mClient ??= NotificationClient.create(
    { baseUrl },
    {
      clientId: process.env.IGRP_M2M_CLIENT_ID!,
      clientSecret: process.env.IGRP_M2M_CLIENT_SECRET!,
      authBaseUrl: process.env.IGRP_ACCESS_MANAGEMENT_API || process.env.IGRP_AUTH_ISSUER!,
    },
  );
  return m2mClient;
}

/** Inbox do utilizador autenticado — o userId sai do token. */
export async function getNotificationUserClient(): Promise<NotificationClient> {
  const token = await auth.getAccessToken();
  if (!token?.accessToken) throw new Error('Sem sessão');
  return NotificationClient.create({
    baseUrl,
    timeout: 30000,
    headers: { Authorization: `Bearer ${token.accessToken}` },
  });
}

5. Server Action de envio

EMAIL precisa de SMTP configurado

Para enviar por EMAIL, o provider SMTP tem de estar configurado no Notification Service (NOTIFICATION_PROVIDERS_EMAILSMTP_*: servidor, porta, credenciais e remetente). Sem ele, o envio é recusado com 422 CHANNEL_NOT_ENABLED e nenhum email sai — ver Configurar os canais › EMAIL (SMTP). O canal também tem de estar ativo nas Definições da aplicação.

// src/app/(minha-app)/client/notification.ts
'use server';

import {
  ApiClientError,
  Channel,
  ChannelStrategy,
  IgrpNotificationErrorCode,
  type SendNotificationRequest,
} from '@igrp/platform-notification-client-ts';
import { getNotificationM2MClient } from '@/lib/notification-client';

export async function enviarConfirmacao(input: { email: string; nome: string; numeroPedido: string }) {
  const client = getNotificationM2MClient();
  const base: SendNotificationRequest = {
    applicationCode: process.env.IGRP_APP_CODE!,
    channelStrategy: ChannelStrategy.SPECIFIC,
    channels: [Channel.EMAIL],
    recipients: [{ email: input.email }],
    category: 'pedido-confirmacao',
    businessKey: input.numeroPedido,
    idempotencyKey: `pedido-confirmacao-${input.numeroPedido}`,
  };

  try {
    const { data } = await client.notifications.send({
      ...base,
      template: { code: 'pedido-confirmacao', locale: 'pt-CV' },
      variables: { nome: input.nome, numeroPedido: input.numeroPedido },
    });
    return data.id;
  } catch (error) {
    if (!(error instanceof ApiClientError)) throw error;
    const semTemplate =
      error.is(IgrpNotificationErrorCode.TEMPLATE_NOT_FOUND) || error.is(IgrpNotificationErrorCode.TEMPLATE_ERROR);
    if (!semTemplate) {
      // Server Actions só passam `message` ao browser
      throw new Error(`${error.serverMessage ?? error.message} [${error.errorCode ?? error.status}]`);
    }
    // template ainda não publicado: envia o mesmo texto inline
    const { data } = await client.notifications.send({
      ...base,
      inline: {
        subject: `Pedido ${input.numeroPedido} recebido`,
        title: 'Pedido recebido',
        body: `Olá ${input.nome}, recebemos o pedido ${input.numeroPedido}.`,
      },
    });
    return data.id;
  }
}

Para enviar um PDF, faz primeiro client.attachments.upload(blob, 'recibo.pdf', process.env.IGRP_APP_CODE) e junta attachments: [{ filename: 'recibo.pdf', contentRef }] — ver Anexos.

6. Sino de notificações na header

A header do framework mostra o array notifications devolvido por getHeaderData() em src/igrp.template.config.ts. Lê a inbox do utilizador e converte cada item com o mapInboxItem de SDK TypeScript › Sino da header:

// src/lib/header-notifications.ts
import 'server-only';
import type { IGRPNotificationArgs } from '@igrp/framework-next-types';
import { getNotificationUserClient } from '@/lib/notification-client';
import { mapInboxItem } from '@/lib/map-inbox-notification';

export async function getHeaderNotifications(): Promise<IGRPNotificationArgs[]> {
  try {
    const client = await getNotificationUserClient();
    const { data } = await client.inbox.list({ unreadOnly: false }, { page: 0, size: 10 });
    return (data.content ?? []).map(mapInboxItem);
  } catch {
    return []; // o sino nunca deve partir a página
  }
}
// src/igrp.template.config.ts (excerto)
getHeaderData: async () => {
  const user = bypass ? getMockUser().mockUser : undefined;
  return {
    user,
    notifications: bypass ? [] : await getHeaderNotifications(),
    notificationsUrl: process.env.NEXT_PUBLIC_IGRP_NOTIFICATION_URL || '',
    showNotifications: true,
    // ... restantes flags
  };
},

Para marcar como lida, chama inbox.markRead(deliveryId) (o id do item mapeado) numa Server Action.


Variáveis de ambiente

Backend

VariávelDescrição
NOTIFICATION_SERVICE_BASE_URLBase do Notification Service, sem /api/v1
IGRP_ACCESS_MANAGEMENT_APIBase do Access Management (/oauth2/token)
IGRP_M2M_CLIENT_ID, IGRP_M2M_CLIENT_SECRETCliente M2M

Frontend

VariávelDescrição
NOTIFICATION_SERVICE_BASE_URLBase do Notification Service, sem /api/v1
IGRP_APP_CODECódigo da aplicação (applicationCode)
IGRP_M2M_CLIENT_ID, IGRP_M2M_CLIENT_SECRETCliente M2M — só no servidor
IGRP_ACCESS_MANAGEMENT_API (ou IGRP_AUTH_ISSUER)authBaseUrl do token M2M
NEXT_PUBLIC_IGRP_NOTIFICATION_URLPágina "ver todas" do sino

No workspace do Studio o serviço fica em http://<slug>:<porta>/gateway-api/igrp-notification-service.

How is this guide?

Última atualização: