> For the complete documentation index, see [llms.txt](https://datamob.gitbook.io/doc-locator/TQfkVhcPsZiXIvXxq8Bv/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://datamob.gitbook.io/doc-locator/TQfkVhcPsZiXIvXxq8Bv/english/service.md).

# Reference

[< Voltar](/doc-locator/TQfkVhcPsZiXIvXxq8Bv/english/en.md)

`LocatorService` é a **interface principal** do SDK Locator exposta para o APP e para bridges de WebView. Tudo que o APP precisa fazer com o SDK passa, direta ou indiretamente, por aqui.

***

## 4.1 Visão Geral

O `LocatorService` encapsula:

* Ciclo de vida do SDK (start, stop, destroy)
* Estado interno (modo, sessão, configuração atual)
* Sincronização com backend (config, grupos, features, cercas, scopes)
* Envio de dados (localizações e eventos)
* Execução de comandos (recebidos de APP, servidor, FCM, MQTT)
* Gerenciamento de permissões (o SDK sabe o que está pendente)

Fluxo macro esperado:

1. App cria/obtém uma instância concreta do SDK (`LocatorService`).
2. App registra uma implementação de `LocatorIntegration`.
3. App configura o SDK (license, URLs, etc) usando `setConfig`.
4. App chama `start()` para iniciar o SDK.
5. SDK sincroniza tudo (`syncAll` ou métodos de sync específicos).
6. SDK começa a coletar localizações, enviar dados e processar comandos.

***

## 4.2 Interface Completa

```ts
export interface LocatorService {
  // Integração
  registerIntegration(integration: LocatorIntegration): void;

  // Consultas (somente leitura)
  getConfig(): LocatorConfig;
  getGroups(): LocatorGroups;
  getFeatures(): LocatorFeatures;
  getGeofences(): LocatorGeofences;
  getState(): LocatorState;
  getSdkMode(): LocatorSdkMode;
  getSession(): LocatorSession;
  getVersion(): string;
  getJwtToken(): string;
  pendingPermissions(): LocatorPermission[];

  // Ciclo de vida
  start(correlation?: Record<string, string>): Promise<void>;
  stop(): Promise<void>;
  destroy(): Promise<void>;

  // Mutação de estado/configuração
  setConfig(config: LocatorConfig): void;
  setState(state: LocatorState, correlation?: Record<string, string>): void;
  setSdkMode(mode: LocatorSdkMode, correlation?: Record<string, string>): void;
  setGroups(groups: LocatorGroups): void;
  setFeatures(features: LocatorFeatures): void;
  setGeofences(geofences: LocatorGeofences, correlation?: Record<string, string>): void;

  // Sincronização com backend
  syncConfig(correlation?: Record<string, string>): Promise<void>;
  syncScopes(correlation?: Record<string, string>): Promise<void>;
  syncGroups(correlation?: Record<string, string>): Promise<void>;
  syncFeatures(correlation?: Record<string, string>): Promise<void>;
  syncGeofences(correlation?: Record<string, string>): Promise<void>;
  syncAll(correlation?: Record<string, string>): Promise<void>;

  // Envio de dados & comandos
  sendEvents(data: LocatorEventPackage, correlation?: Record<string, string>): Promise<void>;
  sendLocations(data: LocatorCollectPackage, correlation?: Record<string, string>): Promise<void>;
  execute(command: LocatorCommand, correlation?: Record<string, string>): Promise<LocatorCommandResult>;
}
```

#### 🟩 **Kotlin (Android)**

```kotlin
interface LocatorService {
    fun registerIntegration(integration: LocatorIntegration)
    
    fun getConfig(): LocatorConfig
    fun getGroup(): LocatorGroups
    fun getFeatures(): LocatorFeatures
    fun getGeofences(): LocatorGeofences
    fun getState(): LocatorState
    fun getSdkMode(): LocatorSdkMode
    fun getVersion(): String
    fun getSession(): LocatorSession
    fun getJwtToken(): String
    fun getJwtToken(correlation: Map<String, String>?): String
    fun pendingPermissions(): List<LocatorPermission>
    
    fun start()
    fun start(correlation: Map<String, String>?)
    fun stop()
    fun stop(correlation: Map<String, String>?)
    fun destroy()
    fun destroy(correlation: Map<String, String>?)
    
    fun setConfig(config: LocatorConfig)
    fun setConfig(config: LocatorConfig, correlation: Map<String, String>?)
    fun setState(state: LocatorState)
    fun setState(state: LocatorState, correlation: Map<String, String>?)
    fun setSdkMode(mode: LocatorSdkMode)
    fun setSdkMode(mode: LocatorSdkMode, correlation: Map<String, String>?)
    fun setGroup(groups: LocatorGroups)
    fun setGroup(groups: LocatorGroups, correlation: Map<String, String>?)
    fun setFeatures(features: LocatorFeatures)
    fun setGeofences(geofences: LocatorGeofences)
    fun setGeofences(geofences: LocatorGeofences, correlation: Map<String, String>?)
    
    fun syncConfig()
    fun syncConfig(correlation: Map<String, String>?)
    fun syncScopes()
    fun syncGroup()
    fun syncGroup(correlation: Map<String, String>?)
    fun syncFeatures()
    fun syncGeofences()
    fun syncGeofences(correlation: Map<String, String>?)
    fun syncAll()
    fun syncAll(correlation: Map<String, String>?)
    
    fun sendEvents(data: LocatorEventPackage)
    fun sendLocations(data: LocatorCollectPackage)
    fun execute(command: LocatorCommand): LocatorCommandResult
    
    fun setLogLevel(level: LocatorLogLevel, customTag: String? = null)
}
```

#### 🟧 **Swift (iOS)**

```swift
protocol LocatorService {
    // MARK: - Integração
    func registerIntegration(integration: LocatorIntegration)
    func registerBackgroundTasks()

    // MARK: - Consultas (somente leitura)
    func getConfig() -> LocatorConfig?
    func getGroups() -> LocatorGroups
    func getFeatures() -> LocatorFeatures
    func getState() -> LocatorState
    func getSdkMode() -> LocatorSdkMode
    func getVersion() -> String
    func getSession() -> LocatorSession
    func getJwtToken() -> String
    func getEnvironment() -> LocatorEnvironment
    func getDebugLocations() -> [LocatorDebugLocation]
    func pendingPermissions() async -> [LocatorPermission]

    // MARK: - Ciclo de vida
    func start(correlation: [String: String]?) async throws
    func stop() async throws
    func destroy() async throws

    // MARK: - Sincronização com backend
    func syncConfig(correlation: [String: String]?) async throws
    func syncScopes(correlation: [String: String]?) async throws
    func syncGroups(correlation: [String: String]?) async throws
    func syncFeatures(correlation: [String: String]?) async throws
    func syncGeofences(correlation: [String: String]?) async throws
    func syncAll(correlation: [String: String]?) async throws

    // MARK: - Mutação de estado/configuração
    func setConfig(_ config: LocatorConfig)
    func setState(_ state: LocatorState, correlation: [String: String]?)
    func setSdkMode(_ mode: LocatorSdkMode, correlation: [String: String]?)
    func setGroups(_ groups: LocatorGroups)
    func setFeatures(_ features: LocatorFeatures)
    func setLogLevel(level: LocatorLogLevel)
    func setEnvironment(environment: LocatorEnvironment)
    func clearDebugLocations()

    // MARK: - Envio de dados & comandos
    func sendEvents(_ data: LocatorEventPackage, correlation: [String: String]?) async throws
    func sendLocations(_ data: LocatorCollectPackage, correlation: [String: String]?) async throws
    func execute(_ command: LocatorCommand, correlation: [String: String]?) async throws -> LocatorCommandResult?
}
```

> ⚠️ **Diferenças do iOS em relação à interface genérica acima:** o `LocatorService` do iOS **não expõe** `getGeofences()` nem `setGeofences(...)` — as cercas chegam por `syncGeofences()` e pelo backend. `getConfig()` devolve `LocatorConfig?` (opcional) e `pendingPermissions()` é `async`. Em contrapartida, o iOS tem `registerBackgroundTasks()`, `setLogLevel(level:)`, `setEnvironment(environment:)`, `getEnvironment()`, `getDebugLocations()` e `clearDebugLocations()`, que não existem na interface genérica.

> 💡 **iOS:** every method that takes `correlation: [String: String]?` ships with a **default overload** without the parameter (which internally calls the variant with `correlation: nil`). Existing call sites keep compiling untouched — adopt the `correlation:` variant only when you want to propagate distributed correlation context.

***

## 4.2.1 Correlation (Distributed Tracing)

As of version **1.2.7 (iOS)**, `LocatorService` accepts an optional `correlation: [String: String]?` parameter (`Map<String, String>?` on Android, `Record<string, string>` on TS) on every method that triggers backend traffic.

`correlation` is an **arbitrary dictionary** defined by the host APP (`{ "traceId": "...", "spanId": "...", "userJourney": "sos-button-tap" }`) that the SDK propagates **without interpreting** it:

| Channel                       | How `correlation` travels                                                                                                                                                                       |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **HTTP (LocatorIntegration)** | Included on the `correlation` field of the `LocatorRequestApi<T>` payload sent to `/cert`, `/token`, `/scopes`, `/config`, `/features`, `/groups`, `/geofences`, `/audio`.                      |
| **MQTT publish**              | JSON-encoded and attached as MQTT v5 **`correlationData`** property on `locator/collect/...`, `locator/event/...` and `locator/command/response/...` topics.                                    |
| **MQTT receive**              | The SDK reads `correlationData` from the incoming MQTT message and propagates it through the command pipeline. The MQTT response published by the command result reuses the same `correlation`. |

**When to use:**

* End-to-end tracking of a user journey (e.g. SOS button tap → audio upload → command acknowledgement).
* Joining logs from the APP, SDK, HTTP backend and MQTT broker under a single `traceId`.
* Carrying tracing context (W3C Trace Context, OpenTelemetry, Datadog APM, etc).

**When NOT to use:**

* To identify the request itself — that is what `id` (request id) and `sessionId` inside `LocatorRequestApi` are for.
* To carry sensitive data (PII, tokens) — `correlation` is only propagated, and may show up in logs.

***

## 4.3 Ciclo de Vida do SDK

### 4.3.1 `registerIntegration(integration: LocatorIntegration): void`

Registra a implementação de `LocatorIntegration` usada pelo SDK para acessar o backend.

* **Quem chama:** APP na inicialização.
* **Quando chamar:** antes de qualquer `start()` ou `sync*()`.

**Comportamento esperado:**

* Substitui qualquer implementação anterior.
* Não dispara chamadas de rede por si só.
* Pode validar minimamente a instância (ex: não aceitar `undefined`).

***

### 4.3.2 `start(correlation?): Promise<void>`

Inicia o SDK, incluindo:

* inicialização de sessão (`LocatorSession`)
* validação de permissões mínimas
* configuração de timers/foreground service (Android)
* conexão inicial com MQTT/WSS (conforme config)
* opcionalmente, um `syncAll()` (dependendo da implementação)

**Parâmetros:**

* `correlation` *(opcional, iOS 1.2.7+)* — dicionário propagado em todas as chamadas HTTP de inicialização (`getCert`, `getApiToken`, `getMqttToken`, `getWssToken`, `getConfig`, `getGeofences`) e em quaisquer mudanças de `state`/`mode` disparadas internamente. Ver [§4.2.1 Correlation](#421-correlation-distributed-tracing).

**Pré-requisitos recomendados:**

* `registerIntegration()` chamado
* `setConfig()` já configurado com `license`, `api`, `mqtt`, etc
* Permissões mínimas resolvidas (ou o SDK retorna em `pendingPermissions()` o que falta)

**Eventos esperados:**

* Pode disparar `SDKSTATE_CHANGED`
* Pode disparar `SDKMODE_CHANGED` (se modo default definido)
* Pode disparar eventos de erro se algo bloqueante falhar (ex: `PERMISSION_ERROR`)

***

### 4.3.3 `stop(): Promise<void>`

Para a coleta ativa e operações de rede, mas **mantém cache e certificados**.

* Desconecta de MQTT/WSS.
* Cancela timers de coleta / flush.
* Mantém:
  * certificados mTLS
  * tokens (até expirar)
  * configurações / caches locais

***

### 4.3.4 `destroy(): Promise<void>`

Desativa completamente o SDK para a licença corrente:

* Chama internamente um `stop()`.
* Remove:
  * certificados
  * tokens
  * caches de config, grupos, features, cercas
  * sessão ativa
  * **iOS 1.2.14+:** the regions the SDK kept monitored on CoreLocation

Use quando:

* Usuário faz logout global
* Licença não é mais válida para aquele device
* APP precisa resetar estado

***

## 4.4 Leitura de Estado & Configurações

### 4.4.1 `getConfig(): LocatorConfig`

Retorna a última `LocatorConfig` conhecida pelo SDK.

* Fonte: `setConfig()` ou `syncConfig()`.
* Pode estar **desatualizada** se o app nunca sincronizou.

**Uso típico:**

* Mostre ao desenvolvedor / devtools.
* Para debug: inspecionar intervalos e política de coleta.

***

### 4.4.2 `getGroups(): LocatorGroups`

Retorna:

* `admin[]`: grupos com permissão elevada.
* `all[]`: todos os grupos que impactam visibilidade/coleta.

Fonte: `setGroups()` ou `syncGroups()`.

***

### 4.4.3 `getFeatures(): LocatorFeatures`

Lista de features habilitadas para a licença no dispositivo.

* Cada `LocatorFeature` pode conter `scopes`.
* O SDK **não deve ativar** features que exijam scopes não presentes.

***

### 4.4.4 `getGeofences(): LocatorGeofences`

Retorna todas as cercas conhecidas pelo SDK.

* Não significa que todas estão ativas — depende dos `groups`.
* Atualizado via `setGeofences()` ou `syncGeofences()`.

> 🟧 **iOS:** this method **does not exist** on the iOS `LocatorService`. Geofences come from the backend through `syncGeofences()` and live only in the SDK local database.

***

### 4.4.5 `getState(): LocatorState`

Estado atual do SDK:

* `DEFAULT`, `IDLE`, `COLLECTING`, `PAUSED`, `STOPPED`.

**Diferença chave:**

* `STOPPED`: pós-`stop()`, sem coleta.
* `PAUSED`: SDK ativo, mas coleção inibida temporariamente.
* `COLLECTING`: coleta ativa e agendada.

***

### 4.4.6 `getSdkMode(): LocatorSdkMode`

Modo de operação atual, ex:

* `DEFAULT`: modo normal
* `OBSERVED`: foco em rastreio, mais agressivo
* `SOS`: modo de emergência
* `ALERT`: modo de atenção

O modo afeta:

* Intervalo de coleta e envio
* Política de bateria
* Critérios de retenção offline

***

### 4.4.7 `getSession(): LocatorSession`

Sessão atual do SDK:

```ts
export interface LocatorSession {
  id: string;
  startAt: number;
  endAt?: number;
}
```

#### 🟩 **Kotlin (Android)**

```kotlin
data class LocatorSession(
    val id: String,
    val startAt: Long, // epoch ms
    val endAt: Long? = null // epoch ms
)
```

#### 🟧 **Swift (iOS)**

```swift
struct LocatorSession {
    let id: String
    let startAt: Int64
    let endAt: Int64?
}
```

* `id`: identificador único por ciclo de `start()`.
* `endAt`: preenchido em `stop()`/`destroy()`.

Pode ser usado para:

* Correlacionar eventos/locais no backend.
* Auditoria/telemetria.

***

### 4.4.8 `getVersion(): string`

Versão do SDK em execução.

* Ex: `"1.2.3"` ou `"1.2.3-android"`.

Ideal para:

* Logging no app
* Envio de metadata para ferramentas de crash

***

### 4.4.9 `getJwtToken(): string`

Retorna o **último JWT válido** conhecido pelo SDK.

* Normalmente JWT\_API.
* Pode ser usado por WebViews ou módulos externos que precisem do token gerenciado pelo SDK.

⚠️ Cuidados:

* Use apenas se o contrato do produto permitir o compartilhamento.
* Renove token via `LocatorIntegration.getToken()` quando necessário (SDK pode cuidar disso internamente).

***

### 4.4.10 `pendingPermissions(): LocatorPermission[]`

Retorna a lista de permissões **ainda não concedidas**, segundo os requisitos do SDK.

Possíveis valores (sob `LocatorPermission`):

* `location_fine`
* `location_coarse`
* `location_background`
* `activity_recognition`
* `body_sensors`
* `battery_optimization`

#### 🟩 **Kotlin (Android)**

```kotlin
  LOCATION_FINE = "location_fine",
  LOCATION_COARSE = "location_coarse",
  LOCATION_BACKGROUND = "location_background",
  ACTIVITY_RECOGNITION = "activity_recognition",
  BODY_SENSORS = "body_sensors",
  BATTERY_OPTIMIZATION = "battery_optimization",
  FOREGROUND_SERVICE = "foreground_service"
  FOREGROUND_SERVICE_LOCATION = "foreground_service_location"
  ACCESS_NETWORK_STATE = "access_network_state"
```

#### 🟧 **Swift (iOS)**

```swift
CRITICAL_ALERT = "critical_alert"
LOCATION = "location"
LOCATION_BACKGROUND = "location_background"
MICROPHONE_ACCESS = "microphone_access"
POST_NOTIFICATIONS = "post_notifications"
```

**Uso sugerido:**

* Antes de chamar `start()`, pergunte ao SDK.
* Se a lista **não estiver vazia**, o app deve abrir o fluxo de permissão.

***

### 4.4.11 `getEnvironment(): LocatorEnvironment` *(iOS 1.2.14+)*

Returns the environment the SDK is configured for — `PROD` (default) or `DEV`.

* Local-only read, no network traffic.
* The value lives **in memory**: it falls back to `PROD` on every process launch, including when iOS relaunches the app in the background.

**Typical usage:**

```swift
if LocatorServiceSdk.shared.getEnvironment() == .DEV {
  // show the diagnostics screen of the test app
}
```

***

### 4.4.12 `getDebugLocations(): [LocatorDebugLocation]` *(iOS 1.2.14+)*

Returns the history of collected locations recorded in the debug table, each one carrying the origin of the collection.

* Data only exists if the integrator called `setEnvironment(environment: .DEV)` — **writing** is gated by the environment, reading is not.
* This table is **not** the publish queue: it survives the MQTT publish, so the full history of what was collected stays visible.
* Data recorded during a `DEV` session remains readable after switching back to `PROD`, until someone calls `clearDebugLocations()` or `destroy()`.

```swift
for debugLocation in LocatorServiceSdk.shared.getDebugLocations() {
  print(debugLocation.origin.rawValue, debugLocation.location.latitude, debugLocation.location.longitude)
}
```

> See `LocatorDebugLocation` in [Types and Interfaces](/doc-locator/TQfkVhcPsZiXIvXxq8Bv/english/service/types-interfaces.md) and `LocatorCollectOrigin` in [Enums](/doc-locator/TQfkVhcPsZiXIvXxq8Bv/english/service/enums.md).

***

## 4.5 Mutação de Estado & Configuração

### 4.5.1 `setConfig(config: LocatorConfig): void`

Aplica a configuração do SDK para a licença nesta instância.

**Responsabilidades:**

* Salvar `config` em storage interno.
* Comparar `revision` (se existente) para identificar alteração.
* Reconfigurar:
  * MQTT (broker, clientId, username, etc)
  * Política de coleta (intervalos, batch size)
  * Política de retry

**Momento recomendado de uso:**

* Na ativação, após `getConfig()` via backend.
* Quando backend informar nova `revision`.

***

### 4.5.2 `setState(state, correlation?): void`

Força mudança de estado operacional do SDK.

**Parâmetros:**

* `state` — novo estado (`COLLECTING`, `PAUSED`, `STOPPED`, etc).
* `correlation` *(opcional, iOS 1.2.7+)* — propagado para os eventos MQTT disparados pela mudança de estado (ex.: quando o SDK ao entrar em `COLLECTING` aciona internamente `ModeManager.start`, que dispara um publish MQTT).

Exemplos de uso:

* `IDLE` quando usuário está logado mas sem coleta ativa.
* `PAUSED` quando usuário pausa temporariamente localização.
* `COLLECTING` quando app quer garantir coleta imediata.

***

### 4.5.3 `setSdkMode(mode, correlation?): void`

Altera o **modo lógico** do SDK (observed, SOS, alert, etc).

**Parâmetros:**

* `mode` — novo modo do SDK.
* `correlation` *(opcional, iOS 1.2.7+)* — propagado para todos os efeitos colaterais do modo (publishes MQTT, requests internas). Em modo `SOS`, é o `correlation` que viaja com o upload de áudio para `/audio` e com as respostas MQTT de comandos do fluxo de SOS.

Impactos típicos:

* `SOS`: coleta com intervalos menores, prioridade alta.
* `POWER_SAVER` (via `LocatorPowerMode`) pode combinar com certos modos.

**O SDK deve**:

* Ajustar timers de coleta/envio de acordo com o modo.
* Disparar `LocatorEventType.SDKMODE_CHANGED`.

***

### 4.5.4 `setGroups(groups: LocatorGroups): void`

Aplica a lista de grupos no SDK, impactando:

* Tópicos MQTT monitorados
* Geofences ativas (somente de grupos presentes)
* Regras de visibilidade

***

### 4.5.5 `setFeatures(features: LocatorFeatures): void`

Aplica features, considerando:

* `feature.feature` (identificador)
* `feature.scopes` (se presentes)

O SDK deve:

* Verificar se os scopes exigidos estão presentes (`getScopes()` / cache interno).
* Ativar/desativar internamente o código associado.

***

### 4.5.6 `setGeofences(geofences: LocatorGeofences): void`

Atualiza a lista de cercas conhecida pelo SDK.

* Deve registrar/desregistrar monitoramento de geofences nativas (OS).
* Considerar `groupId` + `LocatorGroups` para determinar quais cercas ativar.

> 🟧 **iOS:** this method **does not exist** on the iOS `LocatorService`. Use `syncGeofences()` to pull geofences from the backend.

***

### 4.5.7 `setLogLevel(level: LocatorLogLevel): void`

Configures the minimum log level emitted by the SDK at runtime. The SDK starts in `LocatorLogLevel.NONE` (silent) until the integrator opts in.

**Signatures:**

* **🟦 TypeScript:** `setLogLevel(level: LocatorLogLevel): void` *(if exposed on the bridge)*
* **🟩 Kotlin (Android):** `fun setLogLevel(level: LocatorLogLevel, customTag: String? = null)` — optional `customTag` overrides the default logcat tag.
* **🟧 Swift (iOS, 1.2.8+):** `func setLogLevel(level: LocatorLogLevel)`

**Behavior:**

* Inclusive filter: a call with `WARN` emits `WARN` and `ERROR` only; `INFO` and `DEBUG` are suppressed.
* `NONE` silences everything (default).
* Idempotent — safe to call multiple times across the SDK lifecycle (even before `start()`).
* Local-only configuration: nothing is sent to the backend, no MQTT publish, no correlation propagation.

> ⚠️ **iOS 1.2.14:** `LocatorLogLevel` cases are now uppercase (`DEBUG`, `INFO`, `WARN`, `ERROR`, `NONE`). Calls using the old names (`.debug`, `.none`, …) no longer compile. From this version on the log level also stopped enabling the debug collection table — that now depends on `setEnvironment(environment: .DEV)`.

**iOS specifics:**

* Levels are mapped to Apple Unified Logging (`os.log`) via the subsystem `br.com.vivo.locator`, with one `OSLog` category per level (`Debug`, `Info`, `Warn`, `Error`, `None`).
* The same level is forwarded to the embedded MQTT client (`MQTT.Logger.level`), so MQTT diagnostics follow the configured verbosity.
* Visible via Console.app, `log stream --subsystem br.com.vivo.locator`, or attached via Xcode debugger.

**Android specifics:**

* Defaults to logcat under the SDK tag, or to `customTag` when provided.
* `ERROR` callsites that pass a `Throwable` emit the stacktrace via `Log.e(tag, msg, t)`.

**Recommended usage:**

```swift
// iOS — enable verbose logging during development
locator.setLogLevel(level: .DEBUG)

// Silence everything in production (default, no-op call)
locator.setLogLevel(level: .NONE)
```

```kotlin
// Android — verbose with a custom tag during QA
locator.setLogLevel(level = LocatorLogLevel.DEBUG, customTag = "LocatorQA")
```

> ⚠️ Avoid leaving `DEBUG` enabled in release builds: payload/config dumps may include sensitive data (tokens, license, geofence coordinates).

***

### 4.5.8 `setEnvironment(environment: LocatorEnvironment): void` *(iOS 1.2.14+)*

Sets the environment the SDK operates in. `PROD` is the default; `DEV` enables writing the debug collection table read through `getDebugLocations()`.

* Local-only configuration: nothing is sent to the backend.
* Idempotent, and may be called before `start()`.
* The environment lives **in memory** and falls back to `PROD` on every process launch — including a background relaunch performed by iOS. To keep recording, call the method again on each launch.

```swift
// enable collection inspection on test builds
LocatorServiceSdk.shared.setEnvironment(environment: .DEV)
```

> ⚠️ As of 1.2.14 the log level no longer enables the debug table. Anyone who relied on `setLogLevel(level: .DEBUG)` for that must call `setEnvironment(environment: .DEV)` instead.

***

### 4.5.9 `clearDebugLocations(): void` *(iOS 1.2.14+)*

Clears the debug collection table.

* Does not affect the publish queue nor locations already sent.
* Independent of the configured environment: works in both `PROD` and `DEV`.

```swift
LocatorServiceSdk.shared.clearDebugLocations()
```

***

## 4.6 Sincronização com Backend

### 4.6.1 `syncConfig(correlation?): Promise<void>`

**Parâmetros:**

* `correlation` *(opcional, iOS 1.2.7+)* — propagado para a chamada `LocatorIntegration.getConfig` e para o payload HTTP correspondente.

Fluxo típico:

1. SDK monta `LocatorRequestApiConfig` com:
   * `license`
   * `sessionId`
   * `sdkVersion`
   * `osPlatform`
   * `timestamp`
2. Chama `LocatorIntegration.getConfig`.
3. Recebe `LocatorResponseApiConfig`.
4. Chama internamente `setConfig()`.

***

### 4.6.2 `syncScopes(): Promise<void>`

Assíncrono, mas fundamental para RBAC.

* SDK chama `LocatorIntegration.getScopes`.
* Atualiza cache de scopes.
* Revalida features ativas (`setFeatures` interno).

***

### 4.6.3 `syncGroups(): Promise<void>`

* Atualiza `LocatorGroups` via `getGroups()`.
* Ajusta tópicos MQTT e geofences ativas.

***

### 4.6.4 `syncFeatures(): Promise<void>`

* Chama `getFeatures()`.
* Aplica features novas.
* Desativa features removidas.

***

### 4.6.5 `syncGeofences(): Promise<void>`

* Chama `getGeofences()`.
* Atualiza monitoramento de geofences.

***

### 4.6.6 `syncAll(correlation?): Promise<void>`

**Parâmetros:**

* `correlation` *(opcional, iOS 1.2.7+)* — propagado para **todas** as chamadas HTTP encadeadas pelo sync completo. Útil para juntar a janela de sincronização inteira sob um único `traceId`.

Sincronização completa em ordem controlada, por exemplo:

1. `syncConfig()`
2. `syncScopes()`
3. `syncGroups()`
4. `syncFeatures()`
5. `syncGeofences()`

Deve:

* Tratar erro parcial.
* Aplicar backoff quando necessário.
* Disparar eventos `*_SYNCED`:
  * `CONFIGS_SYNCED`
  * `SCOPES_SYNCED`
  * `GROUPS_SYNCED`
  * `FEATURES_SYNCED`
  * `GEOFENCES_SYNCED`

***

## 4.7 Envio de Dados

### 4.7.1 `sendEvents(data, correlation?): Promise<void>`

Envia um pacote de eventos para o backend via MQTT (ou outro canal interno).

**Parâmetros:**

* `data` — `LocatorEventPackage` contendo os eventos.
* `correlation` *(opcional, iOS 1.2.7+)* — anexado ao publish MQTT como propriedade `correlationData` (MQTT v5). Ver [§4.2.1](#421-correlation-distributed-tracing).

`LocatorEventPackage`:

```ts
export interface LocatorEventPackage extends LocatorPackage<LocatorEvent> {}
```

#### 🟩 **Kotlin (Android)**

```kotlin
TODO
```

#### 🟧 **Swift (iOS)**

```swift
TODO
```

**Responsabilidades do SDK:**

* Garantir preenchimento de:
  * `id` (pacote)
  * `license`
  * `sessionId`
  * `connectivity`
  * `network`
  * `osPlatform`
  * `sdkVersion`
  * `timestamp`
* Enfileirar caso offline (respeitando `offlineRetentionDays`).
* Tratar `retryPolicy`.

***

### 4.7.2 `sendLocations(data, correlation?): Promise<void>`

Semelhante a `sendEvents`, mas para localizações (`LocatorCollect`).

**Parâmetros:**

* `data` — `LocatorCollectPackage`.
* `correlation` *(opcional, iOS 1.2.7+)* — anexado ao publish MQTT do tópico `locator/collect/...` como `correlationData`.

**Idealmente:**

* O APP não chama isso diretamente, é responsabilidade interna do SDK.
* Caso seja exposto, é para casos avançados de manual send / flush forçado.

***

## 4.8 Execução de Comandos

### 4.8.1 `execute(command, correlation?): Promise<LocatorCommandResult>`

Executa um comando enviado por:

* APP (chamada direta)
* FCM (payload interpretado pelo APP → SDK)
* MQTT (comandos recebidos de backend e repassados internamente)

**Parâmetros:**

* `command` — `LocatorCommand` a ser executado.
* `correlation` *(opcional, iOS 1.2.7+)* — propagado para todas as chamadas HTTP/MQTT geradas durante a execução do comando. Quando o comando chega via MQTT, o SDK extrai automaticamente o `correlationData` da mensagem recebida e usa esse valor no publish da `LocatorCommandResult`.

`LocatorCommand`:

* `type`: `LocatorCommandType`
* `requiresInternet`: se `true`, não executa offline
* `priority`: `LocatorPriority`
* `expiresAt`: command TTL (epoch **ms**); an expired command is not executed. On Android the legacy field `expireAt` is also accepted
* `timestamp`: generation time (epoch **ms**)

**Exemplos de tipos:**

* `SET_SDK_MODE`
* `SET_POWER_MODE`
* `START_SDK`
* `STOP_SDK`
* `SYNC_*`
* `KEEP_ALIVE`

**Responsabilidades do SDK:**

* Validar `expiresAt` (não executar comando expirado).
* Respeitar `requiresInternet`.
* Tratar idempotência se necessário (via `command.id`).
* Retornar `LocatorCommandResult` com:
  * `status`: `SUCCESS | FAILED | ERROR`
  * `errorCode` se aplicável
  * `attempts`, `startAt`, `endAt`, `timestamp`

**Exemplo: comportamento típico de alguns comandos**

* `SET_SDK_MODE` → chama internamente `setSdkMode()`.
* `SYNC_CONFIG` → chama `syncConfig()`.
* `SYNC_ALL` (se existir no futuro) → chama `syncAll()`.

***

## 4.9 Fluxo típico de uso (APP)

### 4.9.1 Ativação da licença

1. APP obtém `license` e JWT inicial.
2. APP cria `LocatorIntegrationImpl`.
3. APP chama `locatorService.registerIntegration(integration)`.
4. APP chama `locatorService.syncAll()` ou:
   * `syncConfig`
   * `syncGroups`
   * `syncFeatures`
   * `syncGeofences`
5. APP chama `locatorService.start()`.

***

## 4.10 Exemplos de Uso — TypeScript (React Native/Web)

```ts
import {
  LocatorService,
  LocatorIntegration,
  LocatorConfig,
  LocatorSdkMode,
} from "./locator-sdk";

const locatorService: LocatorService = createLocatorService(); // implementação concreta

class MyLocatorIntegration implements LocatorIntegration {
  async getCert(p) {
    /* ... */
  }
  async getToken(p) {
    /* ... */
  }
  async getScopes(p) {
    /* ... */
  }
  async getFeatures(p) {
    /* ... */
  }
  async getConfig(p) {
    /* ... */
  }
  async getGroups(p) {
    /* ... */
  }
  async getGeofences(p) {
    /* ... */
  }
}

export async function initLocator() {
  const integration = new MyLocatorIntegration();
  locatorService.registerIntegration(integration);

  // Sync inicial
  await locatorService.syncAll();

  // Start SDK
  await locatorService.start();

  // Verificar permissões
  const pending = locatorService.pendingPermissions();
  if (pending.length > 0) {
    // abrir telas de permissão no app
  }

  // Mudar modo para observado
  locatorService.setSdkMode(LocatorSdkMode.OBSERVED);
}
```

***

## 4.11 Exemplos de Uso — Kotlin (Android)

```kotlin
class AppLocatorManager(
    private val locator: LocatorService,
    private val integration: LocatorIntegration
) {

    suspend fun initialize() {
        locator.registerIntegration(integration)

        // Sincronização inicial
        locator.syncAll()

        val pending = locator.pendingPermissions()
        if (pending.isNotEmpty()) {
            // abrir UI pedindo permissões
        }

        // Start do SDK
        locator.start()
    }

    suspend fun enableSosMode() {
        locator.setSdkMode(LocatorSdkMode.SOS)
    }

    suspend fun pauseTracking() {
        locator.setState(LocatorState.PAUSED)
    }

    suspend fun fullStop() {
        locator.stop()
    }

    suspend fun logoutAndDestroy() {
        locator.destroy()
    }
}
```

***

## 4.12 Exemplos de Uso — Swift (iOS)

```swift
final class LocatorManager {

    private let locator: LocatorService
    private let integration: LocatorIntegration

    init(locator: LocatorService, integration: LocatorIntegration) {
        self.locator = locator
        self.integration = integration
    }

    func initialize() async throws {
        locator.registerIntegration(integration)

        try await locator.syncAll()
        try await locator.start()

        let pending = locator.pendingPermissions()
        if !pending.isEmpty {
            // apresentar telas de permissão
        }
    }

    func setObservedMode() {
        locator.setSdkMode(.OBSERVED)
    }

    func stopSdk() async throws {
        try await locator.stop()
    }

    func destroySdk() async throws {
        try await locator.destroy()
    }
}
```

***

## 4.13 Resumo da Parte 4

Nesta parte documentamos completamente:

* Todos os métodos do `LocatorService`
* Como cada método se relaciona com:
  * ciclo de vida
  * sincronização
  * envio de dados
  * execução de comandos
  * permissões
* Fluxos típicos de uso (ativação, modo SOS, pausa, logout)
* Exemplos em TypeScript, Kotlin e Swift

## Correlation (`correlation` parameter)

The 13 methods with remote side-effects accept `correlation: Map<String, String>? = null` (Kotlin) / `Record<string, string>?` (TypeScript) / `[String: String]?` (Swift) as an optional final parameter.

### Methods that accept correlation

`setConfig`, `setSdkMode`, `setGroup`, `setGeofences`, `setState`, `getJwtToken`, `start`, `stop`, `destroy`, `syncConfig`, `syncGroup`, `syncGeofences`, `syncAll`.

### Methods that do NOT accept correlation

* `registerIntegration`, `getConfig`, `getGroup`, `getFeatures`, `getGeofences`, `getState`, `getSdkMode`, `getVersion`, `getSession`, `pendingPermissions`, `setFeatures`, `setLogLevel` — local read or local config, no remote emit.
* `syncScopes`, `syncFeatures` — deprioritized in BTC-1938 matrix (do not emit to BE currently).
* `sendEvents`, `sendLocations`, `execute` — correlation travels via MQTT 5 `correlationData` (not in payload). No facade parameter.

### Semantics

* `correlation = null` (default): publish/request goes **without** correlation; field omitted from wire (MQTT 5 property omitted; HTTP `Data.correlation` absent).
* `correlation = emptyMap()` (`mapOf()`): publish/request goes with **empty object** (`{}` UTF-8 bytes in MQTT; `Data.correlation = {}` in HTTP). Distinguishable from `null`.
* `correlation = mapOf("k" to "v", ...)`: keys are sorted alphabetically during serialization (deterministic — same Map produces identical bytes).

### No ambient fallback (G5)

Correlation only travels when explicitly passed by the caller. **No snapshot** of "session" or "active operation". Internal workers always emit without correlation.

### Java legacy compatibility

Android SDK methods have explicit overloads without the `correlation` parameter to preserve Java ABI. Existing callers continue to compile unchanged.

Starting in **v2.2.0**, the non-`correlation` overloads of the 13 public methods (introduced in 2.1.2) were declared **explicitly on the `LocatorService` interface**. This ensures Java callers can call both `service.setSdkMode(LocatorSdkMode.SOS)` and `sdk.setSdkMode(LocatorSdkMode.SOS)` without casting and without any changes to pre-existing code.

Before v2.2.0, the non-`correlation` overload existed only as a shim on the concrete `LocatorSDK` class — Java callers holding a reference typed as `LocatorService` would need to cast to the concrete type or pass `null` explicitly. This ABI gap is now closed.

Kotlin callers are unaffected (Kotlin already resolved the default argument).

### `registerServiceErrorListener(listener: (Exception) -> Unit)`

> Available from **v2.2.0**. This method belongs to the `LocatorSDK` class (not the `LocatorService` interface) — invoke it via the concrete instance returned by `LocatorSDK.initialize(...)` or `LocatorSDK.getInstance()`.

Registers a listener for **asynchronous** errors during the SDK lifecycle. Useful for capturing failures that do not reach the caller via exception (because they happen inside the SDK's internal coroutines).

Covered cases:

* Failure to fetch the certificate during `start()` — when `LocatorSDKCertificateNotReadyException` (code `LOC_SDK_105`) is thrown inside `sdkScope.scopedLaunch`, the listener receives the exception.
* Failure to initialize `LocationForegroundService` (e.g., eligibility gate denied, Android 14+ FGS-BG-start restriction).
* Other asynchronous failures reported via `LocatorSDK.notifyServiceError(error)` internally.

#### Signature

```kotlin
fun registerServiceErrorListener(listener: (Exception) -> Unit)
```

#### Example

```kotlin
val sdk = LocatorSDK.initialize(context = applicationContext)
sdk.registerServiceErrorListener { error ->
    Log.e("App", "SDK async error: ${error.message}", error)
    // e.g., surface to crash reporter, retry start(), etc.
}
sdk.setConfig(config = config)
sdk.start()
```

### Exceptions

| Class                                        | Code              | When it is thrown                                                                                                                                                                                |
| -------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `LocatorSDKNotInitializedException`          | LOC\_SDK\_101     | `getInstance()` called before `initialize()`.                                                                                                                                                    |
| `LocatorSDKNoConfigSetException`             | LOC\_SDK\_102     | `start()` called without a prior `setConfig()` (blank license).                                                                                                                                  |
| `LocatorSDKMissingPermissionsException`      | LOC\_SDK\_103     | `start()` called without the main location permissions.                                                                                                                                          |
| `LocatorSDKMissingAudioPermissionsException` | LOC\_SDK\_104     | `setSdkMode(SOS)` when RECORD\_AUDIO (and/or FOREGROUND\_SERVICE\_MICROPHONE on API 34+) is not granted.                                                                                         |
| **`LocatorSDKCertificateNotReadyException`** | **LOC\_SDK\_105** | **(new in 2.2.0)** `start()` called, but the certificate is not available within the 15 s timeout. Also reported to `registerServiceErrorListener` when thrown inside the SDK's coroutine scope. |
| `LocatorSDKGetFeaturesException`             | —                 | `getFeatures()` fails when querying the integrator.                                                                                                                                              |
| `LocatorSDKGetGeofencesException`            | —                 | `getGeofences()` fails when querying the local repository.                                                                                                                                       |

[< Voltar](/doc-locator/TQfkVhcPsZiXIvXxq8Bv/english/en.md)
