Skip to main content

lighthouse_north_client 0.2.0 copy "lighthouse_north_client: ^0.2.0" to clipboard
lighthouse_north_client: ^0.2.0 copied to clipboard

SDK Flutter oficial para integrar o app do cliente à plataforma Lighthouse North de disparo push: registro de device token com evidência de consentimento (LGPD), heartbeat e opt-out fácil e gratuito. [...]

client-flutter — SDK Flutter da plataforma Lighthouse North (CODINOME) #

Codinome: o NOME DE PUBLICAÇÃO deste pacote (pub.dev) é PENDENTE de decisão do dono. client_flutter é o nome interno neutro do monorepo (ADR-13); renomear no futuro é uma operação mecânica. Enquanto isso, publish_to: none.

SDK Flutter que integra o app do cliente final à plataforma Lighthouse North de disparo push. A plataforma cuida do disparo e da segmentação; o SDK coleta o mínimo e oferece opt-out fácil e gratuito.

Compromissos deste SDK (contrato de produto — fatia 3.2) #

  1. Minimização LGPD por construção. O SDK coleta e envia EXATAMENTE platform, token, contactRef e consent — nada mais. Sem IP custom, sem User-Agent extra, sem identificadores de propaganda, sem qualquer dado do app hospedeiro. O User-Agent é fixo (lighthouse-north-client-flutter/0.1.0 (dart;os)) e identifica apenas o SDK.
  2. Plain-text por construção. O SDK NÃO renderiza conteúdo de push — a exibição é entregue ao sistema operacional. Não há WebView/HTML no caminho (deliberação do gate de segurança 3.1).
  3. Opt-out fácil e gratuito (requisito legal BLOQUEANTE): optOut() nunca lança exceção de rede, é best-effort com resultado explícito, e a UI do app DEVE oferecê-lo sempre (ver exemplo/).
  4. Cobrança honesta: se o usuário revogar a permissão de notificação nas Configurações do OS, o SDK remove o device da plataforma automaticamente (onPermissionRevoked).
  5. Zero segredos em log: token e app key só aparecem mascarados (fcm-...cdef).

Instalação #

Ainda não publicado no pub.dev (nome pendente). Use via path/git:

dependencies:
  client_flutter:
    path: ../packages/client-flutter   # ou git: https://github.com/SystemOverclock/MsgBoy

Requisitos: Flutter/Dart 3 (null-sound). Dependências do pacote: apenas http (+ Flutter SDK). O SDK não embute Firebase — ver abaixo.

Integração passo a passo #

1. Obtenha a app key no painel do tenant #

Painel Lighthouse North → Apps → Chaves. O material tem formato ak_… e é a credencial PÚBLICA do device flow (distinta das API keys pk_…). Ela é configuração do app cliente: nunca hardcoded no fonte — use --dart-define, config de ambiente ou o backend do seu app.

2. Inicialize #

import 'package:client_flutter/client_flutter.dart';

final client = await LighthouseNorthClient.init(
  appKey,                        // do painel — NUNCA hardcoded
  apiBaseUrl: 'https://api.seu-ambiente.lighthouse', // default: ver doc da API
);

Regras de apiBaseUrl: TLS-only — https:// sempre; http:// só é aceito em localhost/127.0.0.1/[::1] para dev/testes (erro tipado InsecureBaseUrlException caso contrário). Se um heartbeat estava ativo, o init retoma o timer e faz um refresh imediato (last_seen honesto).

3. Opt-in de push (permissão + token + consentimento) #

Chame a partir de uma ação explícita do usuário (botão/check de "quero receber notificações") — o consentimento precisa ser explícito (LGPD art. 7º):

try {
  final reg = await client.registerForPush(
    contactRef: 'id-do-contato-no-seu-sistema', // external_id — opcional
    policyVersion: '2026-09',                   // versão da política exibida
  );
  await client.startHeartbeat(); // 24h com jitter ±10% (sobrevive a restart)
} on PushPermissionDeniedException {
  // usuário negou no OS: device NÃO registrado — trate e siga (não é erro)
}

O que o fluxo faz: (1) pede a permissão de notificação do OS; (2) obtém o token push (Firebase do SEU app); (3) registra na plataforma com a evidência do consentimento (consent {granted: true, capturedAt, policyVersion} — a plataforma grava a trilha no contato quando há contactRef); (4) persiste localmente o mínimo (token/contactRef) para heartbeat e opt-out.

contactRef: se você quer push de MARKETING atrelado ao contato, passe o external_id dele. Sem contactRef, o device registra sem base legal de marketing (apto a transacional futuro).

4. Opt-out — OBRIGATÓRIO na UI do seu app #

final result = await client.optOut();
if (!result.fullyOptedOut) {
  // Falha de rede: em falha TOTAL (nada concluído) o SDK preservou o estado —
  // re-tentar optOut() conclui. Em falha PARCIAL do unregister (consent já
  // revogado) o estado foi limpo: re-tentar é noop; o device remanescente
  // segue no servidor apenas para transacional até o expurgo (90d sem
  // refresh). Nunca mostre "desativado" se não foi.
}

optOut() é best-effort em ordem deliberada: (1) revoga a base de marketing (consent granted=false + contactRef); (2) remove o device (unregister). Nunca lança exceção de rede — o resultado reporta cada passo (consentRevoked / unregistered / stateCleared / failures). Em falha TOTAL o SDK preserva o estado local mínimo para permitir a re-tentativa — descartar o token descartaria a capacidade de concluir o opt-out.

5. Revogação da permissão no OS (permission watcher) #

client.onPermissionRevoked.listen((event) {
  // O SDK JÁ removeu o device da plataforma (cobrança honesta).
  // Aqui você decide a UX: explicar, pedir reativação etc.
});

Token via firebase_messaging do hospedeiro (recomendado) #

O SDK não embute nem inicializa Firebase — ele lê o token do Firebase do seu app. No Android isso é automático (o handler nativo detecta o SDK do host). Se o seu app já usa o pacote firebase_messaging, o caminho mais simples em ambas as plataformas é fornecer o token via provider próprio:

class HostFirebaseTokenProvider implements PushTokenProvider {
  @override
  Future<bool> requestPermission() async {
    final settings = await FirebaseMessaging.instance.requestPermission();
    return settings.authorizationStatus == AuthorizationStatus.authorized;
  }

  @override
  Future<String> getToken() => FirebaseMessaging.instance.getToken()
      .then((t) => t ?? throw PushTokenUnavailableException('token nulo'));

  @override
  DevicePlatform resolvePlatform() => DevicePlatform.android; // ou ios
}

await LighthouseNorthClient.init(appKey, tokenProvider: HostFirebaseTokenProvider());

Sem Firebase no host: getToken lança FirebaseNotConfiguredException (erro claro e tipado). Em dev/testes, injete FakeTokenProvider().

Requisitos por plataforma (3.3 — nativos elevados) #

Plataforma Permissão Token Storage
Android ✅ POST_NOTIFICATIONS (13+; <13 concedida por padrão) ✅ FCM do host (sem Firebase no host → erro tipado) Android Keystore AES-256-GCM (3.3; migra o plaintext da 3.2 e o remove)
iOS ✅ UNUserNotificationCenter ✅ FCM do host detectado em runtime (3.3, sem dependência no pod); sem Firebase → erro tipado + provider Dart documentado Keychain (3.3; migra o UserDefaults plaintext e o remove)
Web — 3.4 (push VAPID) 3.4
Desktop (dev) — FakeTokenProvider InMemoryDeviceStateStore

A detecção de revogação de permissão acontece na volta ao primeiro plano (lifecycle) — ver docs/NATIVE_CONTRACT.md.

Rotação de token FCM (3.3 — onNewToken → refresh automático) #

O canal lighthouse_north_client agora recebe onNewToken do lado nativo e o SDK executa a rotação AUTOMATICAMENTE: registra o token NOVO (upsert, SEM consent — rotação não é ato de consentimento (@gate QA 3.3: reafirmar granted=true ressuscitaria consentimento revogado no intervalo do optOut parcial; a base vigente no servidor é a autoridade)) + unregister best-effort do antigo (evita push duplicado até o expurgo de 90d) + atualiza o estado local. O resultado chega na stream onTokenRotated (UX/logging); hosts com firebase_messaging próprio podem chamar handleTokenRotation(token) manualmente. No Android, um host com service nativo próprio encaminha com:

override fun onNewToken(token: String) {
    LighthouseNorthClientPlugin.dispatchNewToken(applicationContext, token)
}

Segurança e comportamento de rede #

  • TLS-only (exceção documentada: loopback para dev/testes);
  • timeout de 10s por tentativa;
  • retry com backoff exponencial (500ms → 1s → 2s) + jitter ±25%, máx. 3 tentativas, apenas em operações idempotentes (as 3 rotas de devices) e apenas em 408 | 429 | 5xx;
  • User-Agent próprio fixo; nenhum header do app hospedeiro;
  • token/app key NUNCA logados inteiros (máscara redactSecret);
  • log estruturado opcional (Lighthouse NorthLogger), silencioso por padrão.

Erros tipados (resumo) #

Todos os erros do SDK estendem Lighthouse NorthException (hierarquia sealed):

Erro Quando
PushPermissionDeniedException usuário negou a permissão (fluxo normal — não é falha)
FirebaseNotConfiguredException host sem Firebase (configure o host ou use provider/fake)
UnauthorizedAppKeyException app key rejeitada (401) — confira o painel
Lighthouse NorthApiException erro HTTP da API (statusCode/errorCode no contexto)
Lighthouse NorthNetworkException rede/timeout após as 3 tentativas
InsecureBaseUrlException / InvalidBaseUrlException base URL http fora de localhost / malformada
InvalidAppKeyException app key evidentemente inválida no init
Lighthouse NorthInvalidInputException contactRef 1..200 / token 16..4096 (validação local)
Lighthouse NorthUnsupportedPlatformException plataforma sem caminho nativo nesta versão
LighthouseNorthClientClosedException / Lighthouse NorthNotInitializedException ciclo de vida

Testes e fakeabilidade #

Toda dependência é injetável em LighthouseNorthClient.init: httpClient, tokenProvider (FakeTokenProvider), stateStore (InMemory…), logger, clock (FakeClock), scheduler (FakeScheduler — tempo virtual para heartbeat/backoff), random (Fixed… — jitter determinístico).

cd packages/client-flutter
flutter analyze   # No issues found
flutter test      # 87 testes verdes (76 da 3.2 + 11 da 3.3: rotação/version check)

O app example/ demonstra o fluxo legal completo (opt-in + opt-out obrigatório na UI) — rode com a API local (docker compose up -d pg redis api) e uma app key real do painel.

Contrato nativo e roadmap 3.3 #

  • docs/NATIVE_CONTRACT.md — spec canônica do canal lighthouse_north_client para os SDKs nativos Kotlin/Swift da fatia 3.3 (interface, fluxos, erros, storage).
  • 3.3 ENTREGUE nos nativos embutidos: 1ª compilação real (example APK no emulador — a pendência "nativos não compilados" da 3.2 está fechada), storage cifrado (Keystore/Keychain), rotação onNewToken → refresh automático, getToken iOS via Firebase do host detectado em runtime, correções de API do embedding (ActivityAware/lifecycle 2.7.0) que só a compilação real revelou.
  • Ainda 3.4+: Firebase/APNs do projeto Lighthouse North (ação do dono), web push VAPID, observação contínua de permissão. Build iOS pendente de macOS (sem Xcode nesta máquina — o Swift foi escrito e revisado, não compilado).

Licença #

MIT (ver LICENSE).

0
likes
0
points
0
downloads

Publisher

verified publisherlighthousenorth.com.br

Weekly Downloads

SDK Flutter oficial para integrar o app do cliente à plataforma Lighthouse North de disparo push: registro de device token com evidência de consentimento (LGPD), heartbeat e opt-out fácil e gratuito. Minimização por construção: coleta apenas platform/token/contactRef/consent.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, http, meta

More

Packages that depend on lighthouse_north_client

Packages that implement lighthouse_north_client