Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions docs/guides/telemetry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
[comment]: # (@label Telemetria)
[comment]: # (@link guides/telemetry)

## Telemetria do PO UI

O PO UI oferece um serviço de telemetria **opt-in** que permite coletar dados anônimos sobre o uso dos componentes da biblioteca. Esses dados ajudam a equipe de desenvolvimento a entender quais componentes são mais utilizados, priorizar melhorias e corrigir problemas.

### O que é coletado

Os eventos de telemetria contêm apenas as seguintes informações:

| Campo | Descrição |
|---|---|
| `componentName` | Nome do componente utilizado (ex: `po-button`, `po-table`) |
| `libraryVersion` | Versão da biblioteca `@po-ui/ng-components` |
Comment on lines +12 to +15

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As linhas de tabela estão começando com || (ex.: || Campo | ...), o que geralmente impede a renderização correta em Markdown. Trocar para a sintaxe padrão | Campo | ... | melhora a leitura no portal e no GitHub.

Copilot uses AI. Check for mistakes.
| `angularVersion` | Versão do Angular utilizada na aplicação |
| `timestamp` | Data e hora do evento em formato ISO 8601 |
| `sessionId` | Identificador aleatório da sessão do navegador |

> **Nenhum dado pessoal, de negócio ou sensível é coletado.** Não são rastreados dados de formulário, interações do usuário ou informações de identificação pessoal.

### Como habilitar

A telemetria está **desabilitada por padrão**. Para habilitá-la, utilize o `PoTelemetryModule.forRoot()` na configuração do seu módulo ou aplicação:

**Abordagem com NgModule:**

```typescript
import { PoTelemetryModule } from '@po-ui/ng-components';

@NgModule({
imports: [
PoModule,
PoTelemetryModule.forRoot({
enabled: true,
endpointUrl: 'https://my-telemetry-api.example.com/events',
showConsentDialog: true
})
]
})
export class AppModule {}
```

**Abordagem Standalone:**

```typescript
import { importProvidersFrom } from '@angular/core';
import { PoTelemetryModule } from '@po-ui/ng-components';

bootstrapApplication(AppComponent, {
providers: [
importProvidersFrom(PoTelemetryModule.forRoot({
enabled: true,
endpointUrl: 'https://my-telemetry-api.example.com/events',
showConsentDialog: true
}))
]
});
```

### Configurações disponíveis

| Propriedade | Tipo | Padrão | Descrição |
|---|---|---|---|
| `enabled` | `boolean` | `false` | Habilita ou desabilita a coleta de telemetria |
| `endpointUrl` | `string` | — | URL do endpoint que receberá os eventos |
Comment on lines +63 to +66

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A tabela de "Configurações disponíveis" também está usando || no início das linhas, o que costuma quebrar a renderização em Markdown. Ajustar para a sintaxe padrão com | garante que a tabela seja exibida corretamente.

Copilot uses AI. Check for mistakes.
| `consentStorageKey` | `string` | `po-telemetry-consent` | Chave no `localStorage` para armazenar o consentimento |
| `batchIntervalMs` | `number` | `30000` | Intervalo em milissegundos para envio em batch |
| `showConsentDialog` | `boolean` | `true` | Exibe diálogo de consentimento na primeira vez |
| `consentDialogLiterals` | `object` | — | Literais customizadas para o diálogo de consentimento |

### Como o consentimento funciona

O serviço de telemetria implementa um mecanismo de consentimento em duas camadas:

1. **Configuração do desenvolvedor**: A telemetria só é ativada quando `enabled: true` é definido na configuração.
2. **Consentimento do usuário final**: Mesmo com a telemetria habilitada, os dados só são coletados após o consentimento explícito do usuário.

O fluxo de consentimento funciona da seguinte forma:

- Ao inicializar, o serviço verifica o `localStorage` pela chave configurada (`po-telemetry-consent` por padrão).
- Se não houver valor armazenado e `showConsentDialog` estiver habilitado, um diálogo de confirmação é exibido ao usuário utilizando o `PoDialogService`.
- Se o usuário **aceitar**, o valor `granted` é salvo no `localStorage` e a coleta de dados é iniciada.
- Se o usuário **recusar**, o valor `denied` é salvo e nenhum dado é coletado.

### Controle programático

O `PoTelemetryService` expõe métodos para controle programático do consentimento:

```typescript
import { PoTelemetryService } from '@po-ui/ng-components';

@Component({ ... })
export class SettingsComponent {
constructor(private telemetryService: PoTelemetryService) {}

enableTelemetry() {
this.telemetryService.grantConsent();
}

disableTelemetry() {
this.telemetryService.revokeConsent();
}
}
```

### Como desabilitar

Para desabilitar completamente a telemetria, basta:

- **Não importar** o `PoTelemetryModule.forRoot()` na aplicação, ou
- Definir `enabled: false` na configuração

Comment on lines +112 to +113

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A doc indica que é possível desabilitar definindo apenas enabled: false, mas pela tipagem atual endpointUrl é obrigatório em PoTelemetryConfig. Ajustar a doc ou o tipo evita confusão para quem quer alternar telemetria via environment/config.

Suggested change
- Definir `enabled: false` na configuração
- Definir `enabled: false` na configuração, mantendo um `endpointUrl` válido conforme a tipagem de `PoTelemetryConfig`:
```typescript
PoTelemetryModule.forRoot({
enabled: false,
endpointUrl: 'https://my-telemetry-api.example.com/events'
});

Copilot uses AI. Check for mistakes.
Para revogar o consentimento de um usuário que já havia consentido:

```typescript
this.telemetryService.revokeConsent();
```

### Customização do diálogo de consentimento

As literais do diálogo de consentimento podem ser customizadas:

```typescript
PoTelemetryModule.forRoot({
enabled: true,
endpointUrl: 'https://my-telemetry-api.example.com/events',
consentDialogLiterals: {
title: 'Coleta de dados de uso',
message: 'Gostaríamos de coletar dados anônimos sobre o uso dos componentes para melhorar a experiência. Nenhum dado pessoal é coletado. Deseja permitir?',
confirm: 'Sim, permitir',
cancel: 'Não, obrigado'
}
})
```

### Política de privacidade recomendada

Se a sua aplicação utiliza a telemetria do PO UI, é recomendado incluir na sua política de privacidade uma seção informando:

- Que dados anônimos de uso de componentes de interface são coletados
- Que nenhum dado pessoal ou de negócio é transmitido
- Que o usuário pode revogar o consentimento a qualquer momento
- O endpoint para o qual os dados são enviados

### Formato do payload

Os eventos são enviados em batch via `POST` para o endpoint configurado. O corpo da requisição é um array de objetos:

```json
[
{
"componentName": "po-table",
"libraryVersion": "21.4.0",
"angularVersion": "21.0.3",
"timestamp": "2026-03-05T12:00:00.000Z",
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
]
```

Em caso de falha no envio, os eventos são mantidos em buffer e reenviados na próxima tentativa.
2 changes: 2 additions & 0 deletions projects/portal/src/app/guide/guide-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { GuideReleasesComponent } from './guides/guide-releases/guide-releases.c
import { GuideSchematicsComponent } from './guides/guide-schematics/guide-schematics.component';
import { GuideSyncFundamentalsComponent } from './guides/guide-sync-fundamentals/guide-sync-fundamentals.component';
import { GuideSyncGetStartedComponent } from './guides/guide-sync-get-started/guide-sync-get-started.component';
import { GuideTelemetryComponent } from './guides/guide-telemetry/guide-telemetry.component';
import { GuideThemeServiceComponent } from './guides/guide-theme-service/guide-theme-service.component';
import { GuideCreateThemeCustomizationComponent } from './guides/guide-create-theme-customization/guide-create-theme-customization.component';
import { GuideGridSystemComponent } from './guides/guide-grid-system/guide-grid-system.component';
Expand Down Expand Up @@ -43,6 +44,7 @@ export const guidesRoutes: Routes = [
{ path: 'schematics', component: GuideSchematicsComponent },
{ path: 'sync-fundamentals', component: GuideSyncFundamentalsComponent },
{ path: 'sync-get-started', component: GuideSyncGetStartedComponent },
{ path: 'telemetry', component: GuideTelemetryComponent },
{ path: 'theme-service', component: GuideThemeServiceComponent },
{ path: 'create-theme-customization', component: GuideCreateThemeCustomizationComponent },
{ path: 'grid-system', component: GuideGridSystemComponent },
Expand Down
2 changes: 2 additions & 0 deletions projects/portal/src/app/guide/guide.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { GuideReleasesComponent } from './guides/guide-releases/guide-releases.c
import { GuideSchematicsComponent } from './guides/guide-schematics/guide-schematics.component';
import { GuideSyncFundamentalsComponent } from './guides/guide-sync-fundamentals/guide-sync-fundamentals.component';
import { GuideSyncGetStartedComponent } from './guides/guide-sync-get-started/guide-sync-get-started.component';
import { GuideTelemetryComponent } from './guides/guide-telemetry/guide-telemetry.component';
import { GuideThemeServiceComponent } from './guides/guide-theme-service/guide-theme-service.component';
import { GuideCreateThemeCustomizationComponent } from './guides/guide-create-theme-customization/guide-create-theme-customization.component';
import { GuideGridSystemComponent } from './guides/guide-grid-system/guide-grid-system.component';
Expand All @@ -44,6 +45,7 @@ import { GuideTypographyComponent } from './guides/guide-typography/guide-typogr
GuideSchematicsComponent,
GuideSyncFundamentalsComponent,
GuideSyncGetStartedComponent,
GuideTelemetryComponent,
GuideThemeServiceComponent,
GuideCreateThemeCustomizationComponent,
GuideGridSystemComponent,
Expand Down
1 change: 1 addition & 0 deletions projects/portal/src/app/guide/menu-guides.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class MenuGuidesService {
{ label: 'Schematics', link: 'guides/schematics' },
{ label: 'Fundamentos do PO Sync', link: 'guides/sync-fundamentals' },
{ label: 'Começando com o PO Sync', link: 'guides/sync-get-started' },
{ label: 'Telemetria', link: 'guides/telemetry' },
{ label: 'Customização de Temas usando o serviço PO-UI', link: 'guides/theme-service' },
{ label: 'Criando um tema para o PO UI', link: 'guides/create-theme-customization' },
{ label: 'Grid System', link: 'guides/grid-system' },
Expand Down
1 change: 1 addition & 0 deletions projects/ui/src/lib/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export * from './po-language/index';
export * from './po-i18n/index';
export * from './po-media-query/index';
export * from './po-notification/index';
export * from './po-telemetry/index';
export * from './po-theme/index';
4 changes: 4 additions & 0 deletions projects/ui/src/lib/services/po-telemetry/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './po-telemetry-config.interface';
export * from './po-telemetry.injection-token';
export * from './po-telemetry.module';
export * from './po-telemetry.service';
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* @usedBy PoTelemetryModule, PoTelemetryService
*
* @description
*
* Interface de configuração do serviço de telemetria.
*/
export interface PoTelemetryConfig {
/** Se a telemetria está habilitada (default: false — opt-in). */
enabled: boolean;

/** URL do endpoint que receberá os eventos. */
endpointUrl: string;
Comment on lines +9 to +13

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Como enabled e endpointUrl são obrigatórios, não dá para usar PoTelemetryModule.forRoot({ enabled: false }) sem fornecer uma URL “dummy”. Para suportar desabilitar por config/env sem URL, considere tornar endpointUrl opcional quando enabled for false (union type) ou validar em runtime apenas quando enabled for true.

Copilot uses AI. Check for mistakes.

/**
* Chave no `localStorage` para armazenar consentimento do usuário.
*
* @default `po-telemetry-consent`
*/
consentStorageKey?: string;

/**
* Intervalo em milissegundos para envio em batch.
*
* @default `30000`
*/
batchIntervalMs?: number;

/**
* Exibir diálogo de consentimento ao usuário na primeira vez.
*
* @default `true`
*/
showConsentDialog?: boolean;

/** Literais customizadas para o diálogo de consentimento. */
consentDialogLiterals?: {
title?: string;
message?: string;
confirm?: string;
cancel?: string;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { InjectionToken } from '@angular/core';

import { PoTelemetryConfig } from './po-telemetry-config.interface';

export const PO_TELEMETRY_CONFIG = new InjectionToken<PoTelemetryConfig>('PO_TELEMETRY_CONFIG');
43 changes: 43 additions & 0 deletions projects/ui/src/lib/services/po-telemetry/po-telemetry.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { ModuleWithProviders, NgModule } from '@angular/core';

import { PO_TELEMETRY_CONFIG } from './po-telemetry.injection-token';
import { PoTelemetryConfig } from './po-telemetry-config.interface';
import { PoTelemetryService } from './po-telemetry.service';

/**
* @description
*
* Módulo do serviço de telemetria do PO UI.
*
* Para utilização do serviço de telemetria, deve-se importar este módulo e invocar o método `forRoot`,
* informando um objeto que implementa a interface `PoTelemetryConfig`.
*
* A telemetria é **opt-in** e requer consentimento do usuário.
*
* **Exemplo de configuração:**
*
* ```
* import { PoTelemetryModule } from '@po-ui/ng-components';
*
* @NgModule({
* imports: [
* PoModule,
* PoTelemetryModule.forRoot({
* enabled: true,
* endpointUrl: 'https://my-telemetry-api.example.com/events',
* showConsentDialog: true
* })
* ]
* })
* export class AppModule {}
* ```
*/
@NgModule({})
export class PoTelemetryModule {
static forRoot(config: PoTelemetryConfig): ModuleWithProviders<PoTelemetryModule> {
return {
ngModule: PoTelemetryModule,
providers: [{ provide: PO_TELEMETRY_CONFIG, useValue: config }, PoTelemetryService]
};
}
}
Loading
Loading