DocumentaçãoDocumentationDocumentaciónOne Conecta
ÍndiceIndexÍndice
Baixar .mdDownload .mdBajar .md
Você está vendo esta documentação online. No topo você também pode baixar o PDF (mesmo conteúdo desta página, no idioma e modo atuais) e o Markdown (Funcional ou Técnica).You are viewing this documentation online. At the top you can also download the PDF (same content as this page, in the current language and mode) and the Markdown (Functional or Technical).Está viendo esta documentación en línea. Arriba también puede bajar el PDF (mismo contenido de esta página, en el idioma y modo actuales) y el Markdown (Funcional o Técnica).
Feature · HomeFeature · HomeFeature · Home

Home

A primeira tela depois do login: o painel do dia do representante de vendas. Reúne numa coluna rolável a saudação, o carrossel de comunicados, a grade de atalhos com contadores de pendência e os indicadores (KPIs) do dia — bulls eye, pilares comerciais, visitas, pedidos, volume, volume de entrega, cobertura e SOP. Cada bloco só existe se o mercado o declarar na End Market Configuration, então BR, CL e ZA têm Homes bem diferentes. A leitura abre do cache; o remoto entra no puxar-para-atualizar e no sweep por TTL. The first screen after login: the sales rep's dashboard of the day. On one scrollable column it gathers the greeting, the communications carousel, the grid of shortcuts with pending counters and the day's indicators (KPIs) — bulls eye, commercial pillars, visits, orders, volume, delivery volume, coverage and SOP. Each block only exists if the market declares it in the End Market Configuration, so BR, CL and ZA have quite different Homes. The read opens from cache; remote kicks in on pull-to-refresh and on the TTL sweep. La primera pantalla después del login: el panel del día del representante de ventas. Reúne en una columna desplazable el saludo, el carrusel de comunicados, la grilla de atajos con contadores de pendencias y los indicadores (KPIs) del día — bulls eye, pilares comerciales, visitas, pedidos, volumen, volumen de entrega, cobertura y SOP. Cada bloque solo existe si el mercado lo declara en la End Market Configuration, por eso BR, CL y ZA tienen Homes bastante distintas. La lectura abre del caché; el remoto entra en el deslizar-para-actualizar y en el sweep por TTL.

PúblicoAudiencePúblico
Representante · QA · Suporte · DevRep · QA · Support · DevRepresentante · QA · Soporte · Dev
Onde ficaWhereDónde
Primeira aba do menu inferior (tela inicial)First tab of the bottom nav (landing screen)Primera pestaña del menú inferior (pantalla inicial)
AtualizadoUpdatedActualizado
30/07/20262026-07-30
Disponível emAvailable inDisponible en BR CL ZA
01

O que é e para que serveWhat it is and what it's forQué es y para qué sirve

A Home é onde o app abre. Ela responde três perguntas em sequência: o que eu tenho pendente hoje? (a grade de atalhos, cada um com o número de itens em aberto), como eu estou indo? (os cartões de indicador — realizado × meta × diferença × percentual) e tem algum aviso da companhia? (o carrossel de comunicados). Não é uma tela de trabalho: nada é criado, editado ou enviado a partir dela — ela informa e encaminha. The Home is where the app opens. It answers three questions in order: what do I have pending today? (the shortcut grid, each with a count of open items), how am I doing? (the indicator cards — realized × target × difference × percentage) and is there any company notice? (the communications carousel). It is not a working screen: nothing is created, edited or uploaded from it — it informs and forwards. La Home es donde la app abre. Responde tres preguntas en orden: ¿qué tengo pendiente hoy? (la grilla de atajos, cada uno con el número de ítems abiertos), ¿cómo voy? (las tarjetas de indicador — realizado × meta × diferencia × porcentaje) y ¿hay algún aviso de la compañía? (el carrusel de comunicados). No es una pantalla de trabajo: nada se crea, edita ni envía desde ella — informa y encamina.

O que está pendente?What is pending?¿Qué está pendiente?

Grade de atalhos de 4 colunas com um contador por atalho (pedidos, entregas, casos, tarefas, Conecta Você).Four-column shortcut grid with a counter per shortcut (orders, deliveries, cases, tasks, Conecta Você).Grilla de atajos de 4 columnas con un contador por atajo (pedidos, entregas, casos, tareas, Conecta Você).

Como eu estou indo?How am I doing?¿Cómo voy?

Cartões de indicador: rosca, barra horizontal e carrossel por categoria — sempre realizado × meta × diferença × %.Indicator cards: donut, horizontal bar and per-category carousel — always realized × target × difference × %.Tarjetas de indicador: dona, barra horizontal y carrusel por categoría — siempre realizado × meta × diferencia × %.

Tem aviso novo?Any new notice?¿Hay aviso nuevo?

Carrossel de comunicados: banner de imagem; tocar abre um modal com nome, descrição e tipo.Communications carousel: image banner; tapping opens a modal with name, description and type.Carrusel de comunicados: banner de imagen; tocar abre un modal con nombre, descripción y tipo.

Escopo desta telaScope of this screenAlcance de esta pantalla Esta doc cobre o que vive na Home: saudação, faixa de última sincronização, carrossel de comunicados, grade de atalhos com contadores, e os oito módulos de indicador. Os destinos dos atalhos são telas próprias — Lista de pedidos, Visitas, Varejos, Casos, Tarefas, Conecta Você, Entregas do dia, Prime, Novo varejo — e cada uma tem sua própria doc. O carrossel de comunicados, por não ter tela própria, é documentado aqui. This doc covers what lives on the Home: greeting, last-sync strip, communications carousel, shortcut grid with counters, and the eight indicator modules. The shortcut destinations are their own screens — Order list, Visits, Retails, Cases, Tasks, Conecta Você, Deliveries of the day, Prime, New retail — each with its own doc. The communications carousel, having no screen of its own, is documented here. Esta doc cubre lo que vive en la Home: saludo, franja de última sincronización, carrusel de comunicados, grilla de atajos con contadores, y los ocho módulos de indicador. Los destinos de los atajos son pantallas propias — Lista de pedidos, Visitas, Puntos de venta, Casos, Tareas, Conecta Você, Entregas del día, Prime, Nuevo punto de venta — cada una con su propia doc. El carrusel de comunicados, al no tener pantalla propia, se documenta aquí.

02

Como acessarHow to openCómo acceder

  1. É a tela de entradaIt is the landing screenEs la pantalla de entradaDepois do login e da sincronização inicial, o app abre direto na Home — a primeira das três abas do menu inferior (Home · Visitas · Pedidos) e a aba padrão.After login and the initial sync, the app opens straight on the Home — the first of the three bottom-nav tabs (Home · Visits · Orders) and the default tab.Después del login y la sincronización inicial, la app abre directo en la Home — la primera de las tres pestañas del menú inferior (Home · Visitas · Pedidos) y la pestaña por defecto.
  2. Pelo menu inferiorFrom the bottom navDesde el menú inferiorToque no ícone de casa a qualquer momento. As três abas base ficam vivas em memória — voltar para a Home preserva a posição da rolagem. Tocar na aba já ativa rola a Home de volta ao topo.Tap the house icon at any time. The three base tabs stay alive in memory — coming back to the Home preserves the scroll position. Tapping the already active tab scrolls the Home back to the top.Toque el ícono de casa en cualquier momento. Las tres pestañas base quedan vivas en memoria — volver a la Home preserva la posición del desplazamiento. Tocar la pestaña ya activa desplaza la Home de vuelta arriba.
  3. Pelo menu lateralFrom the side menuDesde el menú lateralO botão de menu no topo abre a gaveta; o item "Home" volta para esta aba. A gaveta não empurra uma tela nova — ela troca a aba ativa.The menu button at the top opens the drawer; the "Home" item returns to this tab. The drawer doesn't push a new screen — it switches the active tab.El botón de menú arriba abre el cajón; el ítem "Home" vuelve a esta pestaña. El cajón no empuja una pantalla nueva — cambia la pestaña activa.
  4. O que aparece no topoWhat shows at the topQué aparece arribaBarra com o logo da marca, botão de menu, indicador de conexão e o sino de notificações (com selo de não-lidas). Abaixo dela, a faixa de conexão aparece sempre que a rede não está boa.Bar with the brand logo, menu button, connection indicator and the notifications bell (with an unread badge). Below it, the connection strip shows whenever the network isn't healthy.Barra con el logo de la marca, botón de menú, indicador de conexión y la campana de notificaciones (con sello de no leídas). Debajo, la franja de conexión aparece siempre que la red no está bien.
03

Estrutura da telaScreen structureEstructura de la pantalla

Uma coluna rolável, com puxar para atualizar. São doze blocos na ordem abaixo — a faixa de sincronização, a saudação e dez módulos. Cada módulo desaparece por conta própria quando o mercado não o declara ou quando não há dado, então a Home real de cada país é bem mais curta que esta lista (ver Mercados).A single scrollable column, with pull to refresh. There are twelve blocks in the order below — the sync strip, the greeting and ten modules. Each module hides itself when the market doesn't declare it or when there's no data, so each country's real Home is much shorter than this list (see Markets).Una columna desplazable, con deslizar para actualizar. Son doce bloques en el orden de abajo — la franja de sincronización, el saludo y diez módulos. Cada módulo se oculta solo cuando el mercado no lo declara o cuando no hay dato, por eso la Home real de cada país es mucho más corta que esta lista (ver Mercados).

1 · Última sincronização1 · Last sync1 · Última sincronización
Faixa centralizada, o primeiro item da rolagem: "Dados carregados em" + data e hora do último sync dos indicadores. Sem dado ainda, mostra "-".Centered strip, the first item in the scroll: "Data loaded on" + date and time of the last indicator sync. With no data yet, it shows "-".Franja centrada, el primer ítem del desplazamiento: "Datos cargados en" + fecha y hora del último sync de los indicadores. Sin dato aún, muestra "-".
2 · Saudação2 · Greeting2 · Saludo
"Olá" + o primeiro nome do representante de vendas. À direita, quando o mercado habilita, uma pílula Encerrar jornada que abre a tela de encerramento (ver Jornada). Este bloco nunca se esconde."Hello" + the sales rep's first name. On the right, when the market enables it, an End journey pill that opens the closing screen (see Journey). This block never hides."Hola" + el primer nombre del representante de ventas. A la derecha, cuando el mercado lo habilita, una píldora Cerrar jornada que abre la pantalla de cierre (ver Jornada). Este bloque nunca se oculta.
3 · Comunicados (carrossel)3 · Communications (carousel)3 · Comunicados (carrusel)
Banners deslizáveis, um por página, com pontinhos de posição embaixo (escondidos quando há só um). O banner é uma imagem pronta com o texto embutido; tocar abre o modal de detalhe. Só entram os comunicados dentro da janela de validade, ordenados por prioridade.Swipeable banners, one per page, with position dots underneath (hidden when there's only one). The banner is a ready-made image with the copy baked in; tapping opens the detail modal. Only communications inside their validity window show, ordered by priority.Banners deslizables, uno por página, con puntitos de posición abajo (ocultos cuando hay solo uno). El banner es una imagen ya lista con el texto incrustado; tocar abre el modal de detalle. Solo entran los comunicados dentro de la ventana de validez, ordenados por prioridad.
4 · Atalhos com pendências4 · Shortcuts with pending items4 · Atajos con pendencias
Grade de 4 colunas: ícone + rótulo + selo com o número de itens em aberto (o selo só aparece quando é maior que zero). Mostra 8 atalhos e, se o mercado declarar mais, um botão de seta expande o restante. Quais atalhos aparecem e em que ordem é 100% definido pelo mercado.A 4-column grid: icon + label + badge with the count of open items (the badge only shows when greater than zero). It shows 8 shortcuts and, if the market declares more, an arrow button expands the rest. Which shortcuts appear and in what order is 100% market-defined.Grilla de 4 columnas: ícono + rótulo + sello con el número de ítems abiertos (el sello solo aparece cuando es mayor que cero). Muestra 8 atajos y, si el mercado declara más, un botón de flecha expande el resto. Cuáles atajos aparecen y en qué orden es 100% definido por el mercado.
5 · Bulls eye5 · Bulls eye5 · Bulls eye
Cartão com uma barra horizontal por indicador (embarque FMC, embarque NC, meta FMC/SOQ, meta NC/SOQ, execução no cliente, engajamento B2B, crédito) e um semáforo: verde ≥ 80%, neutro ≥ 50%, vermelho abaixo. Só ZA.Card with one horizontal bar per indicator (FMC shipment, NC shipment, FMC/SOQ target, NC/SOQ target, customer execution, B2B engagement, credit) and a traffic light: green ≥ 80%, neutral ≥ 50%, red below. ZA only.Tarjeta con una barra horizontal por indicador (embarque FMC, embarque NC, meta FMC/SOQ, meta NC/SOQ, ejecución en el cliente, engagement B2B, crédito) y un semáforo: verde ≥ 80%, neutro ≥ 50%, rojo por debajo. Solo ZA.
6 · Pilares comerciais6 · Commercial pillars6 · Pilares comerciales
Mesmo formato do bulls eye, com os oito pilares (inadimplência, parceria FAT, efetividade, cobertura Prime, produtividade, capilaridade, positivação de parceria, boost plan). Só BR.Same layout as bulls eye, with the eight pillars (overdue, FAT partnership, effectiveness, Prime coverage, productivity, capillarity, partnership activation, boost plan). BR only.Mismo formato que bulls eye, con los ocho pilares (morosidad, alianza FAT, efectividad, cobertura Prime, productividad, capilaridad, activación de alianza, boost plan). Solo BR.
7 · Visitas do dia7 · Visits of the day7 · Visitas del día
Cartão de rosca com realizado, diferença e meta. Quando o mercado pede o formato detalhado, abre uma quebra por tipo de visita (vendedor presencial, televendas, digital).A donut card with realized, difference and target. When the market asks for the detailed layout, it adds a breakdown by visit type (field seller, telesales, digital).Tarjeta de dona con realizado, diferencia y meta. Cuando el mercado pide el formato detallado, abre un desglose por tipo de visita (vendedor presencial, televentas, digital).
8 · Pedidos do dia8 · Orders of the day8 · Pedidos del día
Mesmo cartão de rosca, para pedidos; a quebra detalhada é por categoria de venda (FMC, MODI, RYO, parceria…).Same donut card, for orders; the detailed breakdown is by sales category (FMC, MODI, RYO, partnership…).La misma tarjeta de dona, para pedidos; el desglose detallado es por categoría de venta (FMC, MODI, RYO, alianza…).
9 · Volume do dia9 · Volume of the day9 · Volumen del día
Um cartão por categoria, em carrossel quando há mais de uma: selo da categoria, barra de progresso e a linha meta / realizado / %. O ícone de informação abre um modal com o detalhamento por produto (desabilitado quando não há detalhe).One card per category, in a carousel when there's more than one: category badge, progress bar and the target / realized / % row. The info icon opens a modal with the per-product breakdown (disabled when there's no detail).Una tarjeta por categoría, en carrusel cuando hay más de una: sello de la categoría, barra de progreso y la línea meta / realizado / %. El ícono de información abre un modal con el desglose por producto (deshabilitado cuando no hay detalle).
10 · Volume de entrega do dia10 · Delivery volume of the day10 · Volumen de entrega del día
Cartão expansível: tocar abre a lista de detalhes com animação. Com mais de uma categoria, vira carrossel; sem carrossel, a categoria é escolhida por um seletor no cabeçalho. Só BR.An expandable card: tapping reveals the detail list with an animation. With more than one category it becomes a carousel; without the carousel, the category is picked from a selector in the header. BR only.Tarjeta expansible: tocar abre la lista de detalles con animación. Con más de una categoría se vuelve carrusel; sin carrusel, la categoría se elige con un selector en el encabezado. Solo BR.
11 · Cobertura11 · Coverage11 · Cobertura
Cartão de rosca da cobertura, com uma linha por produto (imagem opcional do produto, barra e a linha meta / realizado / %). Tocar no ícone de informação, ou em qualquer linha, abre o modal "varejos sem cobertura", com abas por produto. Só CL.Coverage donut card, with one row per product (optional product image, bar and the target / realized / % row). Tapping the info icon, or any row, opens the "retails without coverage" modal, with per-product tabs. CL only.Tarjeta de dona de la cobertura, con una fila por producto (imagen opcional del producto, barra y la línea meta / realizado / %). Tocar el ícono de información, o cualquier fila, abre el modal "puntos de venta sin cobertura", con pestañas por producto. Solo CL.
12 · SOP12 · SOP12 · SOP
Um cartão por categoria (em carrossel) com um filtro de tipo no cabeçalho (entregue / todos) e uma seção por período — "até hoje" e "mês" — cada uma com barra e a linha meta / realizado / %. BR e ZA.One card per category (in a carousel) with a type filter in the header (delivered / all) and one section per period — "month-to-date" and "month" — each with a bar and the target / realized / % row. BR and ZA.Una tarjeta por categoría (en carrusel) con un filtro de tipo en el encabezado (entregado / todos) y una sección por período — "hasta hoy" y "mes" — cada una con barra y la línea meta / realizado / %. BR y ZA.

Categorias sempre completasCategories always completeCategorías siempre completas Quando o mercado declara categorias (por exemplo FMC, parceria e OTP no volume) e o backend devolve só algumas, a Home completa as que faltam com zero em vez de sumir com elas. Assim o carrossel tem sempre o mesmo número de páginas e o representante de vendas percebe a categoria sem movimento. When the market declares categories (say FMC, partnership and OTP on volume) and the backend returns only some, the Home fills the missing ones with zero instead of dropping them. That way the carousel always has the same number of pages and the sales rep notices the category with no movement. Cuando el mercado declara categorías (por ejemplo FMC, alianza y OTP en volumen) y el backend devuelve solo algunas, la Home completa las que faltan con cero en vez de eliminarlas. Así el carrusel siempre tiene el mismo número de páginas y el representante de ventas percibe la categoría sin movimiento.

04

Status e estadosStatus & statesEstado y estados

Estados da tela inteiraWhole-screen statesEstados de la pantalla completa

Carregando → indicador com a marca no centroLoading → branded indicator in the centerCargando → indicador con la marca al centro Pronta → a coluna de blocosReady → the column of blocksLista → la columna de bloques Erro → tela de falha com "tentar de novo"Error → failure view with "try again"Error → pantalla de falla con "reintentar"

uma coisa derruba a Home inteira para o estado de erro: a configuração do mercado não carregar. Se os indicadores ou os comunicados falharem, a tela abre normalmente e os módulos daquele dado simplesmente não aparecem — falha parcial não bloqueia o resto.Only one thing drops the whole Home into the error state: the market configuration failing to load. If the indicators or the communications fail, the screen opens normally and the modules for that data simply don't show — a partial failure doesn't block the rest.Solo una cosa lleva la Home entera al estado de error: que la configuración del mercado no cargue. Si los indicadores o los comunicados fallan, la pantalla abre normalmente y los módulos de ese dato simplemente no aparecen — una falla parcial no bloquea el resto.

Por que um bloco não apareceuWhy a block didn't showPor qué un bloque no apareció

O mercado não declara o móduloThe market doesn't declare the moduleEl mercado no declara el módulo
Causa mais comum. A configuração do mercado lista, nome por nome, os módulos da Home; o que não está lá — ou está lá marcado como invisível — não é renderizado. Ver a matriz em Mercados.The most common cause. The market configuration lists the Home modules by name; whatever isn't there — or is there flagged invisible — is not rendered. See the matrix in Markets.La causa más común. La configuración del mercado lista, nombre por nombre, los módulos de la Home; lo que no está ahí — o está marcado como invisible — no se renderiza. Ver la matriz en Mercados.
O indicador daquele bloco veio vazioThat block's indicator came emptyEl indicador de ese bloque vino vacío
Visitas do dia, pedidos do dia e cobertura desaparecem quando o indicador correspondente não veio; volume, volume de entrega, SOP e bulls eye desaparecem quando a lista de categorias/indicadores fica vazia.Visits of the day, orders of the day and coverage disappear when the matching indicator is missing; volume, delivery volume, SOP and bulls eye disappear when the list of categories/indicators is empty.Visitas del día, pedidos del día y cobertura desaparecen cuando el indicador correspondiente no vino; volumen, volumen de entrega, SOP y bulls eye desaparecen cuando la lista de categorías/indicadores queda vacía.
Não há comunicado válido hojeNo valid communication todayNo hay comunicado válido hoy
O carrossel só aparece com pelo menos um comunicado cuja janela (início/fim) cobre o momento atual. Fora da janela, o bloco inteiro sai da tela.The carousel only shows with at least one communication whose window (start/end) covers the current moment. Outside the window, the whole block leaves the screen.El carrusel solo aparece con al menos un comunicado cuya ventana (inicio/fin) cubre el momento actual. Fuera de la ventana, el bloque entero sale de la pantalla.
Não há representante de vendas resolvidoNo resolved sales repNo hay representante de ventas resuelto
Sem o cadastro do representante em cache, a Home não busca indicadores, comunicados nem contadores: a saudação fica sem nome e todos os contadores ficam em zero.Without the rep record in cache, the Home doesn't fetch indicators, communications nor counters: the greeting has no name and every counter stays at zero.Sin el registro del representante en caché, la Home no busca indicadores, comunicados ni contadores: el saludo queda sin nombre y todos los contadores quedan en cero.

Os contadores dos atalhosThe shortcut countersLos contadores de los atajos

Os números nos selos não vêm do backend como contadores — a Home os calcula lendo o cache local de cada área. Cada leitura que falha degrada para zero em silêncio, então um selo em zero pode significar "nada pendente" ou "aquele cache ainda não sincronizou".The numbers on the badges don't come from the backend as counters — the Home computes them by reading each area's local cache. Every failed read silently degrades to zero, so a zero badge can mean "nothing pending" or "that cache hasn't synced yet".Los números de los sellos no vienen del backend como contadores — la Home los calcula leyendo el caché local de cada área. Cada lectura que falla degrada a cero en silencio, así que un sello en cero puede significar "nada pendiente" o "ese caché aún no sincronizó".

AtalhoShortcutAtajoO que o número contaWhat the number countsQué cuenta el número
Pedidos pendentesPending ordersPedidos pendientesPedidos do cache cujo status cai no grupo "pendente" — oito status, inclusive rascunho e aprovado (ver Lista de pedidos).Cached orders whose status falls in the "pending" group — eight statuses, including draft and approved (see Order list).Pedidos del caché cuyo estado cae en el grupo "pendiente" — ocho estados, incluso borrador y aprobado (ver Lista de pedidos).
Entregas do diaDeliveries of the dayEntregas del díaQuantidade de entregas do dia — a mesma regra da tela de Entregas do dia (pedidos já faturados/separados).Number of the day's deliveries — the same rule as the Deliveries of the day screen (orders already invoiced/pick-listed).Cantidad de entregas del día — la misma regla de la pantalla de Entregas del día (pedidos ya facturados/separados).
CasosCasesCasosCasos abertos: novo, em andamento, escalado e em espera. Fechados e desconhecidos ficam fora (ver Casos).Open cases: new, working, escalated and on hold. Closed and unknown are excluded (see Cases).Casos abiertos: nuevo, en curso, escalado y en espera. Cerrados y desconocidos quedan fuera (ver Casos).
Conecta VocêSoma das ações pendentes que o backend informa por varejo — é o único contador que não é calculado por filtro local (ver Conecta Você).Sum of the pending actions the backend reports per retail — the only counter not computed by a local filter (see Conecta Você).Suma de las acciones pendientes que el backend informa por punto de venta — el único contador que no se calcula por filtro local (ver Conecta Você).
TarefasTasksTareasSó as tarefas com status pendente — futuras, expiradas e concluídas não contam (ver Tarefas).Only tasks with pending status — future, expired and completed don't count (see Tasks).Solo las tareas con estado pendiente — futuras, expiradas y completadas no cuentan (ver Tareas).
Varejos · Prime · Novo varejo · Área de devoluções · Cobrança · PistasRetails · Prime · New retail · Returns area · Collections · CluesPuntos de venta · Prime · Nuevo punto de venta · Área de devoluciones · Cobranza · PistasSem contador — o selo nunca aparece nestes atalhos.No counter — the badge never shows on these shortcuts.Sin contador — el sello nunca aparece en estos atajos.

Semáforo dos indicadoresIndicator traffic lightSemáforo de los indicadores

≥ 80% do alvo → positivo≥ 80% of target → positive≥ 80% del objetivo → positivo ≥ 50% → neutro≥ 50% → neutral≥ 50% → neutro < 50% → negativo< 50% → negative< 50% → negativo

Vale para as barras do bulls eye e dos pilares comerciais. Nos cartões de rosca e de volume o progresso é a barra/anel em si, limitado entre 0 e 100%.Applies to the bulls eye and commercial pillar bars. On the donut and volume cards the progress is the bar/ring itself, clamped between 0 and 100%.Vale para las barras del bulls eye y de los pilares comerciales. En las tarjetas de dona y de volumen el progreso es la barra/anillo en sí, limitado entre 0 y 100%.

05

AçõesActionsAcciones

A Home não escreve nada: não há criação, edição nem envio de transação a partir dela. Todas as ações são de leitura, de navegação ou de ajuste da própria visualização.The Home writes nothing: there's no creation, editing nor transaction upload from it. Every action is a read, a navigation or a tweak of the view itself.La Home no escribe nada: no hay creación, edición ni envío de transacción desde ella. Todas las acciones son de lectura, de navegación o de ajuste de la propia visualización.

Puxar para atualizarPull to refreshDeslizar para actualizar
Rebusca indicadores e comunicados no servidor e recalcula os contadores. É o único gesto da tela que força rede. A tela não pisca no estado de carregando — o próprio gesto tem indicador.Re-fetches indicators and communications from the server and recomputes the counters. It's the only gesture on the screen that forces network. The screen doesn't flash the loading state — the gesture has its own indicator.Re-obtiene indicadores y comunicados del servidor y recalcula los contadores. Es el único gesto de la pantalla que fuerza red. La pantalla no parpadea en el estado de cargando — el propio gesto tiene indicador.
Tocar num atalhoTap a shortcutTocar un atajo
Navega para a tela do atalho. Dois deles trocam a aba em vez de empurrar uma tela: pedidos pendentes (que ainda pré-seleciona a aba "pendentes" da Lista de pedidos) e visitas do dia. Os demais empurram: entregas do dia, casos, Conecta Você, tarefas, varejos, simulador Prime, novo varejo, pistas e cobrança. Chat bot Voll e área de devoluções não navegam — mostram um aviso "em desenvolvimento".Navigates to the shortcut's screen. Two of them switch the tab instead of pushing a screen: pending orders (which also pre-selects the "pending" tab of the Order list) and visits of the day. The rest push: deliveries of the day, cases, Conecta Você, tasks, retails, Prime simulator, new retail, clues and collections. Voll chat bot and returns area don't navigate — they show an "under development" notice.Navega a la pantalla del atajo. Dos de ellos cambian la pestaña en vez de empujar una pantalla: pedidos pendientes (que además preselecciona la pestaña "pendientes" de la Lista de pedidos) y visitas del día. Los demás empujan: entregas del día, casos, Conecta Você, tareas, puntos de venta, simulador Prime, nuevo punto de venta, pistas y cobranza. Chat bot Voll y área de devoluciones no navegan — muestran un aviso "en desarrollo".
Expandir / recolher atalhosExpand / collapse shortcutsExpandir / contraer atajos
Quando o mercado declara mais de oito atalhos, uma seta dupla abaixo da grade abre a segunda parte com animação e gira 180°. Hoje nenhum mercado passa de oito, então a seta não aparece.When the market declares more than eight shortcuts, a double arrow below the grid reveals the second part with an animation and rotates 180°. Today no market goes past eight, so the arrow doesn't show.Cuando el mercado declara más de ocho atajos, una flecha doble bajo la grilla abre la segunda parte con animación y gira 180°. Hoy ningún mercado pasa de ocho, por lo que la flecha no aparece.
Abrir um comunicadoOpen a communicationAbrir un comunicado
Tocar no banner abre um modal com a imagem, a pílula do tipo (campanha, promoção, novidade, operacional), o nome e a descrição. O botão "Ver mais detalhes" no rodapé não navega — dispara um aviso "Em breve".Tapping the banner opens a modal with the image, the type pill (campaign, promotion, news, operational), the name and the description. The "See more details" button in the footer doesn't navigate — it fires a "Coming soon" notice.Tocar el banner abre un modal con la imagen, la píldora del tipo (campaña, promoción, novedad, operacional), el nombre y la descripción. El botón "Ver más detalles" del pie no navega — dispara un aviso "Próximamente".
Ver o detalhe de um volumeSee a volume's detailVer el detalle de un volumen
O ícone de informação no cartão de volume do dia abre um modal com a quebra por produto. Sem detalhe, o ícone fica inerte; o cartão de "sem detalhes" do modal existe, mas é inalcançável por este caminho — sem detalhe o ícone não recebe toque, então o modal nunca abre vazio.The info icon on the volume-of-the-day card opens a modal with the per-product breakdown. With no detail the icon is inert; the modal's "no details" card exists but is unreachable through this path — with no detail the icon gets no tap handler, so the modal never opens empty.El ícono de información en la tarjeta de volumen del día abre un modal con el desglose por producto. Sin detalle el ícono queda inerte; la tarjeta de "sin detalles" del modal existe, pero es inalcanzable por este camino — sin detalle el ícono no recibe toque, así que el modal nunca abre vacío.
Ver varejos sem coberturaSee retails without coverageVer puntos de venta sin cobertura
No cartão de cobertura, o ícone de informação abre o modal na primeira aba; tocar numa linha de produto abre já naquela aba. Cada aba mostra nome e código SAP dos varejos que faltam cobrir. É informativo — não dá para agir dali.On the coverage card, the info icon opens the modal on the first tab; tapping a product row opens right on that tab. Each tab lists name and SAP code of the retails still to cover. It's informational — you can't act from there.En la tarjeta de cobertura, el ícono de información abre el modal en la primera pestaña; tocar una fila de producto abre directo en esa pestaña. Cada pestaña muestra nombre y código SAP de los puntos de venta que faltan cubrir. Es informativo — no se puede actuar desde ahí.
Filtrar o SOPFilter the SOPFiltrar el SOP
O seletor no cabeçalho do cartão SOP alterna entre os tipos que o mercado declara (hoje "entregue" e "todos") e recarrega as seções de período na hora, sem sair da tela.The selector in the SOP card header toggles between the types the market declares (today "delivered" and "all") and reloads the period sections on the spot, without leaving the screen.El selector en el encabezado de la tarjeta SOP alterna entre los tipos que el mercado declara (hoy "entregado" y "todos") y recarga las secciones de período al instante, sin salir de la pantalla.
Trocar de categoriaSwitch categoryCambiar de categoría
Nos cartões em carrossel (volume, volume de entrega, SOP), deslize lateralmente — os pontinhos acompanham. No volume de entrega sem carrossel, a troca é por um seletor no cabeçalho.On carousel cards (volume, delivery volume, SOP), swipe sideways — the dots follow. On delivery volume without the carousel, switching is done from a header selector.En las tarjetas en carrusel (volumen, volumen de entrega, SOP), deslice lateralmente — los puntitos acompañan. En volumen de entrega sin carrusel, el cambio es por un selector en el encabezado.
Expandir o volume de entregaExpand the delivery volumeExpandir el volumen de entrega
Tocar em qualquer parte do cartão (ou na seta) abre a lista de detalhes com animação de altura e fade. Só quando o mercado pede o formato detalhado.Tapping anywhere on the card (or the arrow) opens the detail list with a height + fade animation. Only when the market asks for the detailed layout.Tocar cualquier parte de la tarjeta (o la flecha) abre la lista de detalles con animación de altura y fade. Solo cuando el mercado pide el formato detallado.
Encerrar a jornadaEnd the journeyCerrar la jornada
A pílula ao lado da saudação abre a tela de encerramento de jornada (ver Jornada). É a única ação da Home que sai de uma área que não é a grade de atalhos.The pill next to the greeting opens the end-of-journey screen (see Journey). It's the only Home action that leaves from somewhere other than the shortcut grid.La píldora al lado del saludo abre la pantalla de cierre de jornada (ver Jornada). Es la única acción de la Home que sale de un área distinta de la grilla de atajos.
Abrir notificações e o menuOpen notifications and the menuAbrir notificaciones y el menú
O sino abre Notificações (o selo mostra "9+" acima de nove). O botão de menu abre a gaveta, cujos itens vêm do menuConfig do mercado: Home, notificações, ajuda (FAQ), central de dados, ajustes e sair nos três mercados — mais relatórios em BR e CL, que a África do Sul não declara. Varejos, novo varejo, simulador Prime e pistas têm handler na gaveta, mas nenhum mercado os declara — não aparecem para ninguém (ver Pendências).The bell opens Notifications (the badge shows "9+" above nine). The menu button opens the drawer, whose items come from the market's menuConfig: Home, notifications, help (FAQ), data center, settings and logout in all three markets — plus reports in BR and CL, which South Africa doesn't declare. Retails, new retail, Prime simulator and clues do have a drawer handler, but no market declares them — they show up for nobody (see Pending items).La campana abre Notificaciones (el sello muestra "9+" por encima de nueve). El botón de menú abre el cajón, cuyos ítems vienen del menuConfig del mercado: Home, notificaciones, ayuda (FAQ), central de datos, ajustes y salir en los tres mercados — más reportes en BR y CL, que Sudáfrica no declara. Puntos de venta, nuevo punto de venta, simulador Prime y pistas tienen handler en el cajón, pero ningún mercado los declara — no aparecen para nadie (ver Pendientes).
06

Arquitetura e fluxo de dadosArchitecture & data flowArquitectura y flujo de datos

Clean Architecture + Riverpod + Freezed + ObjectBox. A Home é somente leitura — não há grafo de escrita, nenhuma transação sai desta tela. O que existe são dois caminhos: a abertura, que monta o State a partir do cache, e a sincronização remota, disparada pelo pull-to-refresh ou pelo sweep por TTL do DataSyncOrchestrator, que grava no cache e avisa a Home para reler.Clean Architecture + Riverpod + Freezed + ObjectBox. The Home is read-only — there's no write graph, no transaction leaves this screen. There are two paths: the open, which assembles the State from cache, and the remote sync, triggered by pull-to-refresh or by the DataSyncOrchestrator TTL sweep, which writes to cache and tells the Home to re-read.Clean Architecture + Riverpod + Freezed + ObjectBox. La Home es solo lectura — no hay grafo de escritura, ninguna transacción sale de esta pantalla. Existen dos caminos: la apertura, que arma el State desde el caché, y la sincronización remota, disparada por el pull-to-refresh o por el sweep por TTL del DataSyncOrchestrator, que graba en el caché y avisa a la Home para releer.

Leitura · abre do cacheRead · opens from cacheLectura · abre del caché

O build() chama _load() com source: local, então abrir a Home nunca vai à rede. O Notifier resolve a config de mercado e o representante de vendas primeiro e só então dispara, em paralelo, indicadores + comunicados + contadores:build() calls _load() with source: local, so opening the Home never hits the network. The Notifier resolves the market config and the sales rep first and only then fires, in parallel, indicators + communications + counters:El build() llama _load() con source: local, por lo que abrir la Home nunca va a la red. El Notifier resuelve la config de mercado y el representante de ventas primero y solo entonces dispara, en paralelo, indicadores + comunicados + contadores:

  • HomeKPIModelObjectBox · cache
    • getHomeKpis()HomeKPILocalDataSource
      • toDomainHomeKpiEntitydomain
        • getHomeKpis(source: local)HomeKPIRepositoryImpl
          • execute(source: local)GetHomeKPIUseCase
            • _load() + EMC + Communications + contadoresHomeNotifier + HomeState
              • → UIHomePage

Os contadores dos atalhos entram nesse mesmo _load(), por um caminho paralelo: o GetRepActionsPendingCountsUseCaseseis caches distintos (pedidos, entregas do dia, visitas, casos, Conecta Você, tarefas) e devolve um único objeto de contagens. Nenhuma dessas leituras vai à rede — detalhe em UseCases.The shortcut counters ride the same _load(), on a parallel path: GetRepActionsPendingCountsUseCase reads six distinct caches (orders, deliveries of the day, visits, cases, Conecta Você, tasks) and returns a single counts object. None of those reads hits the network — detail in UseCases.Los contadores de los atajos entran en ese mismo _load(), por un camino paralelo: el GetRepActionsPendingCountsUseCase lee seis cachés distintos (pedidos, entregas del día, visitas, casos, Conecta Você, tareas) y devuelve un único objeto de conteos. Ninguna de esas lecturas va a la red — detalle en UseCases.

Sincronização remota · pull-to-refresh e sweep por TTLRemote sync · pull-to-refresh and TTL sweepSincronización remota · pull-to-refresh y sweep por TTL

O remoto é write-through: o repository grava no cache antes de devolver, e cai no cache se a chamada falhar. O DataSyncOrchestrator roda um timer (intervalo do EMC, hoje 60 s) e, por tipo obsoleto, refaz o fetch e incrementa uma revisão; a Home escuta essas revisões e responde relendo o cache (nunca a rede):Remote is write-through: the repository saves to cache before returning, and falls back to cache if the call fails. The DataSyncOrchestrator runs a timer (EMC interval, today 60 s) and, per stale type, redoes the fetch and bumps a revision; the Home listens to those revisions and responds by re-reading the cache (never the network):El remoto es write-through: el repository graba en el caché antes de devolver, y cae al caché si la llamada falla. El DataSyncOrchestrator corre un timer (intervalo del EMC, hoy 60 s) y, por tipo obsoleto, rehace el fetch e incrementa una revisión; la Home escucha esas revisiones y responde releyendo el caché (nunca la red):

  • DataSyncOrchestratortimer · sweepInterval 60s
    • isStale(type, lastSyncAt, now)DataFreshnessConfigTTL por tipo · EMC
      • execute(source: remote)GetHomeKPIUseCase · GetCommunicationsUseCase
        • getHomeKpis(locationHierarchySfid)HomeKPIRemoteDataSourcegRPC · KpiConectaRepService
          • toDTO → toDomain → saveHomeKpisHomeKPIModelObjectBox · write-through
            • _bumpRevisions(types)listenDataRevision7 DataSyncType
              • refresh(source: local)HomeNotifierrelê o cache

Notas de implementaçãoImplementation notesNotas de implementación O HomeNotifier é @riverpod autoDispose (provider homeProvider) e usa o mixin AsyncGuard: build() devolve guardedBuild(body: _load) e refresh() usa runGuarded — sem AsyncValue.loading, sem invalidateSelf (§37). O locationHierarchySfid de todo request é resolvido no repository a partir de currentResourceProvider (resource.locationHierarchyId, não sfid) — o Notifier nunca o passa (§25). O lastSyncAt exibido vem de homeKpis.lastSyncAt, nunca do Resource (§23). O único gate de visibilidade é config.homeConfig.modules.where(isVisible), materializado em HomeState.visibleModules; cada widget consulta getModule(type) e faz early-return (§27) — a HomePage não tem um único if sobre estado. HomeNotifier is @riverpod autoDispose (provider homeProvider) and uses the AsyncGuard mixin: build() returns guardedBuild(body: _load) and refresh() uses runGuarded — no AsyncValue.loading, no invalidateSelf (§37). The locationHierarchySfid of every request is resolved in the repository from currentResourceProvider (resource.locationHierarchyId, not sfid) — the Notifier never passes it (§25). The displayed lastSyncAt comes from homeKpis.lastSyncAt, never from the Resource (§23). The only visibility gate is config.homeConfig.modules.where(isVisible), materialised into HomeState.visibleModules; each widget checks getModule(type) and early-returns (§27) — HomePage has not a single if on state. El HomeNotifier es @riverpod autoDispose (provider homeProvider) y usa el mixin AsyncGuard: build() devuelve guardedBuild(body: _load) y refresh() usa runGuarded — sin AsyncValue.loading, sin invalidateSelf (§37). El locationHierarchySfid de todo request se resuelve en el repository desde currentResourceProvider (resource.locationHierarchyId, no sfid) — el Notifier nunca lo pasa (§25). El lastSyncAt mostrado viene de homeKpis.lastSyncAt, nunca del Resource (§23). El único gate de visibilidad es config.homeConfig.modules.where(isVisible), materializado en HomeState.visibleModules; cada widget consulta getModule(type) y hace early-return (§27) — la HomePage no tiene un solo if sobre estado.

07

Modelo de dadosData modelModelo de datos

A Home tem dois agregados próprios, cada um com o seu proto, e ambos existem em quatro representaçõesProto (wire gRPC) → DTO (Freezed) → Model (ObjectBox) → Entity (domínio) — ligadas por mappers, com cache write-through. O terceiro insumo da tela, os contadores dos atalhos, não tem modelo próprio: é um objeto calculado em memória a partir dos caches de outras features.The Home has two aggregates of its own, each with its proto, and both exist in four representationsProto (gRPC wire) → DTO (Freezed) → Model (ObjectBox) → Entity (domain) — linked by mappers, with write-through cache. The screen's third input, the shortcut counters, has no model of its own: it's an in-memory object computed from other features' caches.La Home tiene dos agregados propios, cada uno con su proto, y ambos existen en cuatro representacionesProto (wire gRPC) → DTO (Freezed) → Model (ObjectBox) → Entity (dominio) — unidas por mappers, con caché write-through. El tercer insumo de la pantalla, los contadores de los atajos, no tiene modelo propio: es un objeto calculado en memoria desde los cachés de otras features.

O primeiro é HomeKpi (10 campos): um agregado raiz único por instalação, com o lastSyncAt e nove blocos de indicador, dos quais quatro são opcionais. Os blocos reusam três formas genéricas — BasicKpi (rosca), DetailKpi (linha de detalhe) e PillarKpi (barra) —, então a mesma estrutura serve visitas, pedidos, cobertura, volume, SOP e bulls eye. O segundo é Communications (2 campos): container com lastSyncAt + lista de comunicados. Enums e datas são tipados em camadas diferentes nos dois — vem primeiro o proto, depois as estruturas campo a campo, os mappers e a lista de deltas.The first is HomeKpi (10 fields): a single root aggregate per install, holding lastSyncAt and nine indicator blocks, four of them optional. The blocks reuse three generic shapes — BasicKpi (donut), DetailKpi (detail row) and PillarKpi (bar) — so the same structure serves visits, orders, coverage, volume, SOP and bulls eye. The second is Communications (2 fields): a container with lastSyncAt + the list of communications. Enums and dates are typed in different layers in each — first the proto, then the structures field by field, the mappers and the delta list.El primero es HomeKpi (10 campos): un agregado raíz único por instalación, con el lastSyncAt y nueve bloques de indicador, cuatro de ellos opcionales. Los bloques reutilizan tres formas genéricas — BasicKpi (dona), DetailKpi (fila de detalle) y PillarKpi (barra) —, así que la misma estructura sirve visitas, pedidos, cobertura, volumen, SOP y bulls eye. El segundo es Communications (2 campos): contenedor con lastSyncAt + la lista de comunicados. Los enums y las fechas se tipan en capas distintas en cada uno — primero el proto, luego las estructuras campo a campo, los mappers y la lista de deltas.

Proto

Dois arquivos, ambos proto3, package mn.bat.conectarep.streambridge: KpiConectaRep.proto e CommunicationsConectaRep.proto. Cada um tem um serviço com um único método unário:Two files, both proto3, package mn.bat.conectarep.streambridge: KpiConectaRep.proto and CommunicationsConectaRep.proto. Each has one service with a single unary method:Dos archivos, ambos proto3, package mn.bat.conectarep.streambridge: KpiConectaRep.proto y CommunicationsConectaRep.proto. Cada uno tiene un servicio con un único método unario:

getHomeKpisunary · KpiConectaRep.proto
MétodoMethodMétodo

rpc getHomeKpis(KpiRequest) returns (KpiReply)

path /mn.bat.conectarep.streambridge.KpiConectaRepService/getHomeKpis

Request · KpiRequest
locationHierarchySfid
string · #1 · hierarquia do representante de vendas (resolvida no repository)sales rep hierarchy (resolved in the repository)jerarquía del representante de ventas (resuelta en el repository)
dateReference
string · #2 · optional · aceito pelo datasource, nunca preenchido pelo repositoryoptional · accepted by the datasource, never filled by the repositoryoptional · aceptado por el datasource, nunca llenado por el repository
lastModifiedDate
string · #3 · optional · não plumbado em camada nenhumaoptional · not plumbed in any layeroptional · no plumbeado en ninguna capa
Reply · KpiReply

commercialPillars¹ · visitsOfTheDay · ordersOfTheDay · volumeOfTheDay · deliveryVolumeOfTheDay¹ · modiCoverage¹ · sop¹ · repeated bullsEye · endJourney9 campos; os blocos estão detalhados nas Estruturas de dados abaixo.9 fields; the blocks are detailed in Data structures below.9 campos; los bloques están detallados en Estructuras de datos abajo.

getCommunicationsunary · CommunicationsConectaRep.proto
MétodoMethodMétodo

rpc getCommunications(CommunicationsRequest) returns (CommunicationsReply)

path /mn.bat.conectarep.streambridge.CommunicationsConectaRepService/getCommunications

Request · CommunicationsRequest
locationHierarchySfid
string · #1 · idem — único campo realmente enviadosame — the only field actually sentídem — el único campo realmente enviado
dateReference
string · #2 · optional · parâmetro do datasource sem calleroptional · datasource parameter with no calleroptional · parámetro del datasource sin caller
lastModifiedDate
string · #3 · optional · parâmetro do datasource sem caller (delta-sync inerte)optional · datasource parameter with no caller (inert delta sync)optional · parámetro del datasource sin caller (delta-sync inerte)
Reply · CommunicationsReply

repeated Communication communicationsos 8 campos de Communication estão na segunda árvore abaixo.Communication's 8 fields are in the second tree below.los 8 campos de Communication están en el segundo árbol abajo.

Estruturas de dadosData structuresEstructuras de datos

Colunas Proto · DTO · Model · Entity, uma linha por campo. O delta (texto azul) marca onde o tipo primeiro muda lendo da esquerda para a direita. ¹ = optional no proto. Atenção ao sufixo: DTOs e Models usam KPI em maiúsculas (HomeKPIDTO, BasicKPIModel) e as Entities usam Kpi (HomeKpiEntity).Columns Proto · DTO · Model · Entity, one row per field. The delta (blue text) marks where the type first changes reading left to right. ¹ = optional in the proto. Mind the suffix: DTOs and Models use uppercase KPI (HomeKPIDTO, BasicKPIModel) while Entities use Kpi (HomeKpiEntity).Columnas Proto · DTO · Model · Entity, una fila por campo. El delta (texto azul) marca dónde primero cambia el tipo leyendo de izquierda a derecha. ¹ = optional en el proto. Atención al sufijo: los DTOs y Models usan KPI en mayúsculas (HomeKPIDTO, BasicKPIModel) y las Entities usan Kpi (HomeKpiEntity).

  • HomeKpi KpiReply 10 camposfieldscampos
    CampoProtoDTOModelEntity
    lastSyncAtDateTimeDateTime
    commercialPillarsCommercialPillars¹CommercialPillarsDTO?ToOne<CommercialPillarsModel>CommercialPillarsEntity?
    visitsOfTheDayBasicKpiBasicKPIDTOToOne<BasicKPIModel>BasicKpiEntity
    ordersOfTheDayBasicKpiBasicKPIDTOToOne<BasicKPIModel>BasicKpiEntity
    volumeOfTheDayVolumeKpiVolumeKPIDTOToOne<VolumeKPIModel>VolumeKpiEntity
    deliveryVolumeOfTheDayVolumeKpi¹VolumeKPIDTO?ToOne<VolumeKPIModel>VolumeKpiEntity?
    modiCoverageBasicKpi¹BasicKPIDTO?ToOne<BasicKPIModel>BasicKpiEntity?
    sopSopKpi¹SopKPIDTO?ToOne<SopKPIModel>SopKpiEntity?
    bullsEyerepeated PillarsKpiList<PillarKPIDTO>ToMany<PillarKPIModel>List<PillarKpiEntity>
    endJourneyJourneyKpiJourneyKPIDTOToOne<JourneyKPIModel>JourneyKpiEntity
    • CommercialPillars HomeKpi.commercialPillars¹ 3 camposfieldscampos
      CampoProtoDTOModelEntity
      totalTargetdoubledoubledoubledouble
      totalRealizeddoubledoubledoubledouble
      pillarsListrepeated PillarsKpiList<PillarKPIDTO>ToMany<PillarKPIModel>List<PillarKpiEntity>
      • PillarKpi CommercialPillars.pillarsList[] · HomeKpi.bullsEye[] 6 no proto · 5 no appin proto · 5 in appen el proto · 5 en la app
        CampoProtoDTOModelEntity
        kpiNamestringStringStringString
        targetdoubledoubledoubledouble
        realizeddoubledoubledoubledouble
        percentagedoubledoubledoubledouble
        isAchievedbool¹bool?bool?bool?
        differencedouble
    • BasicKpi visitsOfTheDay · ordersOfTheDay · modiCoverage · VolumeKpi.categories[] 7 campos + 1 só no Modelfields + 1 Model-onlycampos + 1 solo en el Model
      CampoProtoDTOModelEntity
      categorystring¹String?String?String?
      targetdoubledoubledoubledouble
      realizeddoubledoubledoubledouble
      differencedoubledoubledoubledouble
      percentagedoubledoubledoubledouble
      totaldouble¹double?double?double?
      detailsrepeated DetailKpiList<DetailKPIDTO>ToMany<DetailKPIModel>List<DetailKpiEntity>
      parentTypeString
      • DetailKpi BasicKpi.details[] · SopCategoryItem.periods[] 8 campos + getterfields + gettercampos + getter
        CampoProtoDTOModelEntity
        detailTypestring¹String?String?String?
        periodstring¹String?String?String?
        targetdoubledoubledoubledouble
        realizeddoubledoubledoubledouble
        differencedoubledoubledoubledouble
        percentagedoubledoubledoubledouble
        totaldouble¹double?double?double?
        visitsrepeated stringList<String>List<String>List<String>
        progress
        getter da Entity — (percentage / 100).clamp(0.0, 1.0), o valor que alimenta a barra.Entity getter — (percentage / 100).clamp(0.0, 1.0), the value feeding the bar.getter de la Entity — (percentage / 100).clamp(0.0, 1.0), el valor que alimenta la barra.
    • VolumeKpi volumeOfTheDay · deliveryVolumeOfTheDay¹ 1 campo + 1 só no Modelfield + 1 Model-onlycampo + 1 solo en el Model
      CampoProtoDTOModelEntity
      categoriesrepeated BasicKpiList<BasicKPIDTO>ToMany<BasicKPIModel>List<BasicKpiEntity>
      parentTypeString
    • SopKpi HomeKpi.sop¹ 1 campofieldcampo
      CampoProtoDTOModelEntity
      categoriesrepeated SopCategoryList<SopCategoryDTO>ToMany<SopCategoryModel>List<SopCategoryEntity>
      • SopCategory SopKpi.categories[] 2 camposfieldscampos
        CampoProtoDTOModelEntity
        categorystringStringStringString
        itemsrepeated SopCategoryItemList<SopCategoryItemDTO>ToMany<SopCategoryItemModel>List<SopCategoryItemEntity>
        • SopCategoryItem SopCategory.items[] 2 camposfieldscampos
          CampoProtoDTOModelEntity
          typestringStringStringString
          periodsrepeated DetailKpiList<DetailKPIDTO>ToMany<DetailKPIModel>List<DetailKpiEntity>
    • JourneyKpi HomeKpi.endJourney 1 campofieldcampo
      CampoProtoDTOModelEntity
      kpisrepeated KpiInfoList<ActionKPIDTO>ToMany<ActionKPIModel>List<ActionKpiEntity>
      • ActionKpi JourneyKpi.kpis[] · proto KpiInfo 2 camposfieldscampos
        CampoProtoDTOModelEntity
        kpiNamestringStringStringString
        valuedoubledoubledoubledouble
  • Communications CommunicationsReply 2 camposfieldscampos
    CampoProtoDTOModelEntity
    lastSyncAtDateTime?DateTimeDateTime?
    itemsrepeated CommunicationList<CommunicationDTO>ToMany<CommunicationModel>List<CommunicationEntity>
    • Communication Communications.items[] 8 camposfieldscampos
      CampoProtoDTOModelEntity
      sfidstringStringStringString
      typestringCommunicationTypeStringCommunicationType
      namestringStringStringString
      descriptionstringStringStringString
      imageUrlstringStringStringString
      priorityint32intintint
      startDatestringDateTime?DateTime?DateTime?
      endDatestringDateTime?DateTime?DateTime?

Mappers

Os dois agregados seguem as 5 direções canônicas. Todos os mappers da Home são extensions (não classes), e fromMap é sempre static na extension do DTO:Both aggregates follow the canonical 5 directions. Every Home mapper is an extension (not a class), and fromMap is always static on the DTO extension:Los dos agregados siguen las 5 direcciones canónicas. Todos los mappers de la Home son extensions (no clases), y fromMap es siempre static en la extension del DTO:

DireçãoDirectionDirecciónMétodoMethodMétodoOnde/quandoWhere/whenDónde/cuándo
JSON → DTOfromMapmock (dev); numéricos caem para 0.0, strings para "", listas para []mock (dev); numerics default to 0.0, strings to "", lists to []mock (dev); numéricos caen a 0.0, strings a "", listas a []
Proto → DTOtoDTO · toCommunicationsDTOremote; opcionais lidos por hasX(); é aqui que o comunicado já ganha enum e datas tipadasremote; optionals read via hasX(); this is where a communication already gets a typed enum and datesremote; opcionales leídos por hasX(); es aquí donde el comunicado ya recibe enum y fechas tipadas
DTO → EntitytoDomainé onde o HomeKpi.lastSyncAt é cunhado (DateTimeUtils.now())where HomeKpi.lastSyncAt is minted (DateTimeUtils.now())donde el HomeKpi.lastSyncAt es acuñado (DateTimeUtils.now())
Entity → ModeltoModelgrava relações ToOne/ToMany e injeta parentType; em Communications lança se lastSyncAt for nulowrites ToOne/ToMany relations and injects parentType; in Communications it throws if lastSyncAt is nullgraba relaciones ToOne/ToMany e inyecta parentType; en Communications lanza si lastSyncAt es nulo
Model → EntitytoDomainleitura do cache (a abertura da Home); usa .target! nos quatro blocos obrigatórioscache read (the Home open); uses .target! on the four required blockslectura del caché (la apertura de la Home); usa .target! en los cuatro bloques obligatorios

Os únicos deltasThe only deltasLos únicos deltas

  • Toda sub-mensagem opcional ou obrigatória vira ToOne no Model (os 8 blocos de HomeKpi) e toda repetida vira ToMany (bullsEye, pillarsList, details, categories, items, periods, kpis, Communications.items).Every optional or required sub-message becomes ToOne in the Model (HomeKpi's 8 blocks) and every repeated one becomes ToMany (bullsEye, pillarsList, details, categories, items, periods, kpis, Communications.items).Toda sub-mensaje opcional u obligatoria se vuelve ToOne en el Model (los 8 bloques de HomeKpi) y toda repetida se vuelve ToMany (bullsEye, pillarsList, details, categories, items, periods, kpis, Communications.items).
  • DetailKpi.visits é a exceção: repeated string continua List<String> no ObjectBox (lista escalar, não relação).DetailKpi.visits is the exception: repeated string stays List<String> in ObjectBox (scalar list, not a relation).DetailKpi.visits es la excepción: repeated string sigue siendo List<String> en ObjectBox (lista escalar, no relación).
  • HomeKpi.lastSyncAt não existe no proto nem no DTO — é cunhado no mapper DTO→Entity com DateTimeUtils.now() e daí persistido no Model. Em Communications ele existe já no DTO, e o delta é de nulidade: DateTime? na Entity contra DateTime não-nulo no Model — guardado por um StateError no toModel().HomeKpi.lastSyncAt exists neither in the proto nor in the DTO — it is minted in the DTO→Entity mapper with DateTimeUtils.now() and persisted into the Model from there. In Communications it already exists on the DTO, and the delta is one of nullability: DateTime? on the Entity against non-null DateTime on the Model — guarded by a StateError in toModel().HomeKpi.lastSyncAt no existe en el proto ni en el DTO — es acuñado en el mapper DTO→Entity con DateTimeUtils.now() y de ahí persistido en el Model. En Communications ya existe en el DTO, y el delta es de nulidad: DateTime? en la Entity contra DateTime no-nulo en el Model — resguardado por un StateError en el toModel().
  • Communications inverte a convenção do projeto: o enum (type) e as datas (startDate/endDate) são tipados já no DTO, não na Entity/Model. O type ainda volta a String no Model (guarda o value) e é reparseado na leitura.Communications inverts the project convention: the enum (type) and the dates (startDate/endDate) are typed already in the DTO, not in the Entity/Model. type then goes back to String in the Model (storing the value) and is re-parsed on read.Communications invierte la convención del proyecto: el enum (type) y las fechas (startDate/endDate) se tipan ya en el DTO, no en la Entity/Model. El type vuelve a String en el Model (guarda el value) y se reparsea en la lectura.
  • parentType (em BasicKpi e VolumeKpi) existe só no Model: é um discriminador de persistência preenchido com literais no toModel() ("visitsOfTheDay", "ordersOfTheDay", "volumeOfTheDay", "deliveryVolumeOfTheDay", "modiCoverage") e nunca lido de volta.parentType (on BasicKpi and VolumeKpi) exists only in the Model: a persistence discriminator filled with literals in toModel() ("visitsOfTheDay", "ordersOfTheDay", "volumeOfTheDay", "deliveryVolumeOfTheDay", "modiCoverage") and never read back.parentType (en BasicKpi y VolumeKpi) existe solo en el Model: es un discriminador de persistencia llenado con literales en el toModel() ("visitsOfTheDay", "ordersOfTheDay", "volumeOfTheDay", "deliveryVolumeOfTheDay", "modiCoverage") y nunca releído.
  • PillarsKpi.difference (campo 6 do proto) é o único campo descartado: não existe no DTO, no Model nem na Entity, e o mapper Proto→DTO não o lê (ver Pendências).PillarsKpi.difference (proto field 6) is the only dropped field: it exists neither in the DTO, the Model nor the Entity, and the Proto→DTO mapper never reads it (see Pending).PillarsKpi.difference (campo 6 del proto) es el único campo descartado: no existe en el DTO, el Model ni la Entity, y el mapper Proto→DTO no lo lee (ver Pendencias).
  • Renome de mensagem, não de campo: a mensagem KpiInfo do proto vira ActionKPIDTO / ActionKpiEntity / ActionKPIModel. O campo continua kpis.A message rename, not a field one: the proto's KpiInfo message becomes ActionKPIDTO / ActionKpiEntity / ActionKPIModel. The field stays kpis.Renombre de mensaje, no de campo: el mensaje KpiInfo del proto se vuelve ActionKPIDTO / ActionKpiEntity / ActionKPIModel. El campo sigue siendo kpis.
08

Repository

Dois repositories próprios, HomeKPIRepositoryImpl e CommunicationsRepositoryImpl, com a mesma forma: quatro métodos cada, três guard-clauses de roteamento no get… e write-through no caminho remoto. Nenhum dos dois tem lógica de TTL — obsolescência é decisão do DataSyncOrchestrator (ver Arquitetura). Os contadores não têm repository: leem os repositories de outras features, sempre pelos métodos cache-only.Two dedicated repositories, HomeKPIRepositoryImpl and CommunicationsRepositoryImpl, with the same shape: four methods each, three routing guard-clauses in get… and write-through on the remote path. Neither has TTL logic — staleness is the DataSyncOrchestrator's call (see Architecture). The counters have no repository: they read other features' repositories, always through the cache-only methods.Dos repositories propios, HomeKPIRepositoryImpl y CommunicationsRepositoryImpl, con la misma forma: cuatro métodos cada uno, tres guard-clauses de ruteo en el get… y write-through en el camino remoto. Ninguno tiene lógica de TTL — la obsolescencia la decide el DataSyncOrchestrator (ver Arquitectura). Los contadores no tienen repository: leen los repositories de otras features, siempre por los métodos cache-only.

getHomeKpis({source = local}) HomeKPIRepositoryImpl mock · cache · remotemock · cache · remotemock · caché · remote
Retorno
Future<Result<HomeKpiEntity, Failure>>
ComportamentoBehaviorComportamiento
Três guard-clauses, nesta ordem exata. O source default é local, então a abertura da tela cai no cache; refresh() passa remote.Three guard-clauses, in this exact order. The default source is local, so opening the screen lands in cache; refresh() passes remote.Tres guard-clauses, en este orden exacto. El source por defecto es local, así que abrir la pantalla cae en el caché; refresh() pasa remote.
  • 1 · _useMock || source == mock _fetchFromMock() — lê o asset do mercado, mapeia e devolve. Não persiste._fetchFromMock() — reads the market asset, maps and returns. Does not persist._fetchFromMock() — lee el asset del mercado, mapea y devuelve. No persiste.
  • 2 · source == local || !isConnected _fetchFromCacheOrFail() — cache não-nulo vence; cache vazio vira NetworkFailure._fetchFromCacheOrFail() — non-null cache wins; empty cache becomes NetworkFailure._fetchFromCacheOrFail() — caché no-nulo gana; caché vacío se vuelve NetworkFailure.
  • 3 · senãoelsesi no _fetchFromRemoteWithFallback() — resolve o representante de vendas; se for nulo cai no cache sem chamar a rede; senão chama o gRPC com resource.locationHierarchyId, mapeia, grava (saveHomeKpis) e devolve. Em exceção, loga e tenta o cache; cache vazio propaga a falha original._fetchFromRemoteWithFallback() — resolves the sales rep; if null it falls back to cache without calling the network; otherwise calls gRPC with resource.locationHierarchyId, maps, saves (saveHomeKpis) and returns. On exception it logs and tries cache; an empty cache propagates the original failure._fetchFromRemoteWithFallback() — resuelve el representante de ventas; si es nulo cae al caché sin llamar a la red; si no llama al gRPC con resource.locationHierarchyId, mapea, graba (saveHomeKpis) y devuelve. En excepción, loguea e intenta el caché; caché vacío propaga la falla original.
getCachedHomeKpis() HomeKPIRepositoryImpl local
Retorno
Future<Result<HomeKpiEntity?, Failure>>
ComportamentoBehaviorComportamiento
Lê a única linha do ObjectBox. Nunca vai à rede; cache vazio devolve Success(null) (não é falha).Reads ObjectBox's single row. Never hits the network; an empty cache returns Success(null) (not a failure).Lee la única fila del ObjectBox. Nunca va a la red; caché vacío devuelve Success(null) (no es falla).
getCachedHomeKpisLastSyncAt() HomeKPIRepositoryImpl hook do sweepsweep hookhook del sweep
Retorno
Future<DateTime?>
ComportamentoBehaviorComportamiento
Lê só o lastSyncAt da linha, sem mapear a árvore inteira. É o que o DataSyncOrchestrator consulta para decidir se o tipo homeKpi está obsoleto. Erro degrada para null — e null conta como obsoleto.Reads only the row's lastSyncAt, without mapping the whole tree. It is what the DataSyncOrchestrator checks to decide whether the homeKpi type is stale. An error degrades to null — and null counts as stale.Lee solo el lastSyncAt de la fila, sin mapear el árbol entero. Es lo que el DataSyncOrchestrator consulta para decidir si el tipo homeKpi está obsoleto. Un error degrada a null — y null cuenta como obsoleto.
saveHomeKpis({homeKpi}) HomeKPIRepositoryImpl write-through
Retorno
Future<Result<void, Failure>>
ComportamentoBehaviorComportamiento
Cache-writer chamado só após um fetch remoto bem-sucedido. Encaminha o lastSyncAt da Entity — o repository não lê o relógio (§21). O datasource limpa a árvore antiga antes de gravar.A cache-writer called only after a successful remote fetch. It forwards the Entity's lastSyncAt — the repository does not read the clock (§21). The datasource clears the old tree before writing.Cache-writer llamado solo tras un fetch remoto exitoso. Encamina el lastSyncAt de la Entity — el repository no lee el reloj (§21). El datasource limpia el árbol antiguo antes de grabar.
getCommunications({source = local}) CommunicationsRepositoryImpl mock · cache · remotemock · cache · remotemock · caché · remote
Retorno
Future<Result<CommunicationsEntity?, Failure>>
ComportamentoBehaviorComportamiento
Mesmas três guard-clauses do KPI, com duas diferenças: o retorno é nullable (cache vazio é Success(null), não falha) e o caminho de mock persiste no ObjectBox.The same three guard-clauses as the KPI one, with two differences: the return is nullable (empty cache is Success(null), not a failure) and the mock path does persist to ObjectBox.Las mismas tres guard-clauses del KPI, con dos diferencias: el retorno es nullable (caché vacío es Success(null), no falla) y el camino de mock sí persiste en ObjectBox.
  • 1 · _useMock || source == mock _fetchFromMock() → mapeia → grava → devolve._fetchFromMock() → maps → saves → returns._fetchFromMock() → mapea → graba → devuelve.
  • 2 · source == local || !isConnected getCachedCommunications().getCachedCommunications().getCachedCommunications().
  • 3 · senãoelsesi no _fetchFromRemoteWithFallback() — envia o locationHierarchySfid, grava e devolve; em falha, cache não-nulo vence, cache vazio propaga a falha._fetchFromRemoteWithFallback() — sends only the locationHierarchySfid, saves and returns; on failure, a non-null cache wins, an empty cache propagates the failure._fetchFromRemoteWithFallback() — envía solo el locationHierarchySfid, graba y devuelve; en falla, caché no-nulo gana, caché vacío propaga la falla.
getCachedCommunications() CommunicationsRepositoryImpl local
Retorno
Future<Result<CommunicationsEntity?, Failure>>
ComportamentoBehaviorComportamiento
Container do cache (lastSyncAt + itens). Nunca vai à rede; a filtragem por validade e a ordenação por prioridade acontecem depois, no State.The cache container (lastSyncAt + items). Never hits the network; validity filtering and priority ordering happen later, in the State.El contenedor del caché (lastSyncAt + ítems). Nunca va a la red; el filtrado por validez y el orden por prioridad ocurren después, en el State.
getCachedCommunicationsLastSyncAt() CommunicationsRepositoryImpl hook do sweepsweep hookhook del sweep
Retorno
Future<DateTime?>
ComportamentoBehaviorComportamiento
Idem ao do KPI; TTL do tipo communications é 3600 s (ver Mercados).Same as the KPI one; the communications type TTL is 3600 s (see Markets).Ídem al del KPI; el TTL del tipo communications es 3600 s (ver Mercados).
saveCommunications({entity}) CommunicationsRepositoryImpl write-through
Retorno
Future<Result<void, Failure>>
ComportamentoBehaviorComportamiento
Chamado nos dois caminhos de fetch (mock e remoto). O toModel() lança StateError se o lastSyncAt vier nulo — só entidades já estampadas por um fetch podem ser persistidas.Called on both fetch paths (mock and remote). toModel() throws a StateError if lastSyncAt is null — only entities already stamped by a fetch can be persisted.Llamado en los dos caminos de fetch (mock y remoto). El toModel() lanza StateError si el lastSyncAt viene nulo — solo entidades ya estampadas por un fetch pueden persistirse.

Os repositories emprestadosThe borrowed repositoriesLos repositories prestados Os contadores dos atalhos atravessam seis repositories de outras features, sempre por método cache-only: getCachedOrders() (pedidos), getOrders(source: local) via entregas do dia, getCachedVisits() (visitas), getCachedCases(), getCachedConectaVoceApprovals() e getTasks(source: local). Os contratos completos vivem nas docs dessas features. The shortcut counters cross six repositories from other features, always through a cache-only method: getCachedOrders() (orders), getOrders(source: local) via deliveries of the day, getCachedVisits() (visits), getCachedCases(), getCachedConectaVoceApprovals() and getTasks(source: local). Their full contracts live in those features' docs. Los contadores de los atajos atraviesan seis repositories de otras features, siempre por un método cache-only: getCachedOrders() (pedidos), getOrders(source: local) vía entregas del día, getCachedVisits() (visitas), getCachedCases(), getCachedConectaVoceApprovals() y getTasks(source: local). Los contratos completos viven en las docs de esas features.

09

Datasources

Seis datasources: os três clássicos (Remote / Local / Mock) para cada um dos dois agregados. Os locais são sincronos (não devolvem Future) e todos os erros de banco viram CacheException com log.Six datasources: the classic three (Remote / Local / Mock) for each of the two aggregates. The local ones are synchronous (they don't return a Future) and every DB error becomes a logged CacheException.Seis datasources: los tres clásicos (Remote / Local / Mock) para cada uno de los dos agregados. Los locales son sincrónicos (no devuelven Future) y todos los errores de base se vuelven CacheException con log.

Remote HomeKPIRemoteDataSource gRPC
EnvioSendEnvío
Monta um KpiRequest com locationHierarchySfid; dateReference só se não-nulo. lastModifiedDate nunca é setado.Builds a KpiRequest with locationHierarchySfid; dateReference only when non-null. lastModifiedDate is never set.Arma un KpiRequest con locationHierarchySfid; dateReference solo si no es nulo. lastModifiedDate nunca se setea.
Fluxo de usoUsage flowFlujo de uso
Chamado só pelo _fetchFromRemoteWithFallback do repository, que já resolveu a hierarquia. Canal streambridge, com os interceptores globais (inclusive o deadline de 15 s quando a conexão está instável).Called only by the repository's _fetchFromRemoteWithFallback, which already resolved the hierarchy. streambridge channel, with the global interceptors (including the 15 s deadline when the connection is unstable).Llamado solo por el _fetchFromRemoteWithFallback del repository, que ya resolvió la jerarquía. Canal streambridge, con los interceptores globales (incluido el deadline de 15 s cuando la conexión está inestable).
Tratamento de erroError handlingManejo de error
GrpcErrorGrpcExceptionHandler.handle; qualquer outro → ServerException("Failed to fetch HomeKPI from gRPC"), com log.GrpcErrorGrpcExceptionHandler.handle; anything else → ServerException("Failed to fetch HomeKPI from gRPC"), logged.GrpcErrorGrpcExceptionHandler.handle; cualquier otro → ServerException("Failed to fetch HomeKPI from gRPC"), con log.
getHomeKpis({locationHierarchySfid, dateReference?})
Retorno
Future<HomeKPIDTO>
UsoUseUso
Único método. Converte o KpiReply para DTO na saída (toDTO).The only method. Converts the KpiReply to a DTO on the way out (toDTO).Único método. Convierte el KpiReply a DTO en la salida (toDTO).
Local HomeKPILocalDataSource ObjectBox
EnvioSendEnvío
Nenhum — leitura/escrita direta na box. Uma única linha (a Home é agregado global, não por conta).None — direct box read/write. A single row (the Home is a global aggregate, not per account).Ninguno — lectura/escritura directa en la box. Una única fila (la Home es un agregado global, no por cuenta).
Tratamento de erroError handlingManejo de error
Todo método embrulha em CacheException com mensagem própria e shouldLog: true.Every method wraps into a CacheException with its own message and shouldLog: true.Todo método envuelve en CacheException con mensaje propio y shouldLog: true.
getHomeKpis()
Retorno
HomeKpiEntity?
UsoUseUso
Pega a primeira linha e mapeia a árvore inteira (toDomain); box vazia → null. É o caminho da abertura da tela.Takes the first row and maps the whole tree (toDomain); empty box → null. This is the screen-open path.Toma la primera fila y mapea el árbol entero (toDomain); box vacía → null. Es el camino de la apertura de la pantalla.
getHomeKpisLastSyncAt()
Retorno
DateTime?
UsoUseUso
Lê só o timestamp, sem toDomain — barato o bastante para o sweep rodar a cada minuto.Reads only the timestamp, no toDomain — cheap enough for the sweep to run every minute.Lee solo el timestamp, sin toDomain — barato para que el sweep corra cada minuto.
saveHomeKpis({entity})
Retorno
void
UsoUseUso
Chama clearHomeKpis() primeiro e depois grava o novo modelo — substituição total, nunca merge.Calls clearHomeKpis() first and then writes the new model — full replacement, never a merge.Llama clearHomeKpis() primero y luego graba el nuevo modelo — reemplazo total, nunca merge.
clearHomeKpis()
Retorno
void
UsoUseUso
Esvazia as dez boxes filhas em ordem (detalhes, básicos, ações, pilares, pilares comerciais, volume, itens de SOP, categorias de SOP, SOP, jornada) e só então a raiz — a árvore de relações não deixa órfãos.Empties the ten child boxes in order (details, basics, actions, pillars, commercial pillars, volume, SOP items, SOP categories, SOP, journey) and only then the root — the relation tree leaves no orphans.Vacía las diez boxes hijas en orden (detalles, básicos, acciones, pilares, pilares comerciales, volumen, ítems de SOP, categorías de SOP, SOP, jornada) y solo entonces la raíz — el árbol de relaciones no deja huérfanos.
Mock HomeKPIMockDataSource assets
EnvioSendEnvío
Nenhum. O arquivo é escolhido por mercado + modo: {mercado}_home_kpi.json ou {mercado}_real_home_kpi.json.None. The file is picked by market + mode: {market}_home_kpi.json or {market}_real_home_kpi.json.Ninguno. El archivo se elige por mercado + modo: {mercado}_home_kpi.json o {mercado}_real_home_kpi.json.
Tratamento de erroError handlingManejo de error
No modo real-mock, asset ausente devolve "{}" em silêncio (Home sem indicador nenhum); no modo sintético, asset ausente vira CacheException.In real-mock mode a missing asset returns "{}" silently (a Home with no indicators at all); in synthetic mode a missing asset becomes a CacheException.En modo real-mock, un asset ausente devuelve "{}" en silencio (Home sin ningún indicador); en modo sintético, un asset ausente se vuelve CacheException.
getHomeKpis()
Retorno
Future<HomeKPIDTO>
UsoUseUso
Lê o asset, jsonDecode, fromMap. Único método.Reads the asset, jsonDecode, fromMap. The only method.Lee el asset, jsonDecode, fromMap. Único método.
Remote CommunicationsRemoteDataSource gRPC
EnvioSendEnvío
CommunicationsRequest com locationHierarchySfid; dateReference se não-nulo e lastModifiedDate se não-nulo e não-vazio (guarda assimétrica). Nenhum caller preenche os dois últimos.CommunicationsRequest with locationHierarchySfid; dateReference when non-null and lastModifiedDate when non-null and non-empty (asymmetric guard). No caller fills the last two.CommunicationsRequest con locationHierarchySfid; dateReference si no es nulo y lastModifiedDate si no es nulo y no está vacío (guarda asimétrica). Ningún caller llena los dos últimos.
Fluxo de usoUsage flowFlujo de uso
Mesmo canal streambridge. Chamado no refresh() e no sweep, nunca na abertura.Same streambridge channel. Called on refresh() and on the sweep, never on open.Mismo canal streambridge. Llamado en el refresh() y en el sweep, nunca en la apertura.
Tratamento de erroError handlingManejo de error
GrpcErrorGrpcExceptionHandler.handle; outro → ServerException("Failed to fetch Communications from gRPC").GrpcErrorGrpcExceptionHandler.handle; other → ServerException("Failed to fetch Communications from gRPC").GrpcErrorGrpcExceptionHandler.handle; otro → ServerException("Failed to fetch Communications from gRPC").
getCommunications({locationHierarchySfid, dateReference?, lastModifiedDate?})
Retorno
Future<CommunicationsDTO>
UsoUseUso
Único método. O toCommunicationsDTO() já estampa lastSyncAt com o relógio.The only method. toCommunicationsDTO() already stamps lastSyncAt from the clock.Único método. El toCommunicationsDTO() ya estampa lastSyncAt con el reloj.
Local CommunicationsLocalDataSource ObjectBox
EnvioSendEnvío
Nenhum. Duas boxes: o container e os itens (sfid indexado).None. Two boxes: the container and the items (indexed sfid).Ninguno. Dos boxes: el contenedor y los ítems (sfid indexado).
Tratamento de erroError handlingManejo de error
CacheException por método, com log.A per-method CacheException, logged.CacheException por método, con log.
getCommunications()
Retorno
CommunicationsEntity?
UsoUseUso
Primeira linha → toDomain; box vazia → null.First row → toDomain; empty box → null.Primera fila → toDomain; box vacía → null.
getCommunicationsLastSyncAt()
Retorno
DateTime?
UsoUseUso
Hook do sweep, sem mapear os itens.Sweep hook, without mapping the items.Hook del sweep, sin mapear los ítems.
saveCommunications({entity})
Retorno
void
UsoUseUso
Limpa e regrava — substituição total.Clears and rewrites — full replacement.Limpia y regraba — reemplazo total.
clearCommunications()
Retorno
void
UsoUseUso
Esvazia a box de itens e depois a do container.Empties the items box and then the container one.Vacía la box de ítems y luego la del contenedor.
Mock CommunicationsMockDataSource assets
EnvioSendEnvío
Nenhum. {mercado}_communications.json ou {mercado}_real_communications.json; a chave lida é communications.None. {market}_communications.json or {market}_real_communications.json; the key read is communications.Ninguno. {mercado}_communications.json o {mercado}_real_communications.json; la clave leída es communications.
Tratamento de erroError handlingManejo de error
Igual ao mock de KPI: real-mock sem arquivo devolve "{}" em silêncio (lista vazia, carrossel oculto).Same as the KPI mock: real-mock with no file silently returns "{}" (empty list, carousel hidden).Igual al mock de KPI: real-mock sin archivo devuelve "{}" en silencio (lista vacía, carrusel oculto).
getCommunications()
Retorno
Future<CommunicationsDTO>
UsoUseUso
Único método; o fromMap do container estampa lastSyncAt com o relógio e ignora entradas que não sejam objeto.The only method; the container's fromMap stamps lastSyncAt from the clock and skips non-object entries.Único método; el fromMap del contenedor estampa lastSyncAt con el reloj e ignora entradas que no sean objeto.
10

Enums e labelsEnums & labelsEnums y labels

Os enums que dirigem a Home vêm de duas famílias: os compartilhados de configuração de mercado (ModuleType, ModuleDetailType, CardType) — abaixo só a fatia da Home — e os próprios de KPI e comunicado. Um valor por linha.The enums driving the Home come from two families: the shared market-config ones (ModuleType, ModuleDetailType, CardType) — only the Home slice below — and the dedicated KPI and communication ones. One value per line.Los enums que dirigen la Home vienen de dos familias: los compartidos de configuración de mercado (ModuleType, ModuleDetailType, CardType) — abajo solo la porción de la Home — y los propios de KPI y comunicado. Un valor por línea.

ModuleType fatia Home (74 no total)Home slice (74 overall)porción Home (74 en total) 13
casevalueMódulo da HomeHome moduleMódulo de la Home
endJourneyend_journeypílula "encerrar jornada" na saudação"end journey" pill in the greetingpíldora "cerrar jornada" en el saludo
communicationscommunicationscarrossel de comunicadoscommunications carouselcarrusel de comunicados
repActionsrep_actionsgrade de atalhos (usa details)shortcut grid (uses details)grilla de atajos (usa details)
bullsEyebulls_eyecartão bulls eye (usa details)bulls eye card (uses details)tarjeta bulls eye (usa details)
commercialPillarscommercial_pillarscartão de pilares comerciais (usa details)commercial pillars card (uses details)tarjeta de pilares comerciales (usa details)
visitsOfTheDayvisits_of_the_dayrosca de visitas do diavisits-of-the-day donutdona de visitas del día
ordersOfTheDayorders_of_the_dayrosca de pedidos do diaorders-of-the-day donutdona de pedidos del día
volumeOfTheDayvolume_of_the_daycartão/carrossel de volumevolume card/carouseltarjeta/carrusel de volumen
deliveryVolumeOfTheDaydelivery_volume_of_the_daycartão expansível de volume de entregaexpandable delivery-volume cardtarjeta expansible de volumen de entrega
vuseCoveragevuse_coveragecartão de cobertura (lê o KPI modiCoverage)coverage card (reads the modiCoverage KPI)tarjeta de cobertura (lee el KPI modiCoverage)
sopsopcartão SOP (usa filterOptions + periodOptions)SOP card (uses filterOptions + periodOptions)tarjeta SOP (usa filterOptions + periodOptions)
conectaVoceconecta_vocesem módulo — nenhum mercado o declara como módulo (só como detail de rep_actions)no module — no market declares it as a module (only as a rep_actions detail)sin módulo — ningún mercado lo declara como módulo (solo como detail de rep_actions)
dailyKpisdaily_kpissem presença em nenhum EMC (ver Pendências)no presence in any EMC (see Pending)sin presencia en ningún EMC (ver Pendencias)
ModuleDetailType atalhos + bulls eye + pilares (80 no total)shortcuts + bulls eye + pillars (80 overall)atajos + bulls eye + pilares (80 en total) 13 + 7 + 8
casevalueNavega paraNavigates toNavega a
homeModulePendingOrderspending_ordersaba Pedidos, pré-filtrada em "pendentes"Orders tab, pre-filtered to "pending"pestaña Pedidos, prefiltrada en "pendientes"
homeModuleDeliveriesOfTheDaydeliveries_of_the_dayDeliveriesOfTheDayPage
homeModuleVisitsOfTheDayvisits_of_the_dayaba VisitasVisits tabpestaña Visitas
homeModuleCasescasesCasesPage
homeModuleConectaVoceconecta_voceConectaVoceHubPage
homeModuleTaskstasksTasksPage
homeModuleRetailsretailsRetailsPage
homeModulePrimeSimulatorprime_simulatorPrimeSimulatorPage
homeModuleNewAccountnew_accountNewRetailTypeSelectionPage
homeModuleCluescluesClavePage (entrada geográfica)ClavePage (geographic entry)ClavePage (entrada geográfica)
homeModuleCollectionsManagementcollections_managementCollectionsPage
homeModuleReturnsAreareturns_area— aviso "em desenvolvimento"— "under development" notice— aviso "en desarrollo"
homeModuleChatBotVollchat_bot_voll— aviso "em desenvolvimento" (nenhum mercado declara)— "under development" notice (no market declares it)— aviso "en desarrollo" (ningún mercado lo declara)
bullsEyeShipmentFmcshipment_fmcbarra do bulls eyebulls eye barbarra del bulls eye
bullsEyeShipmentNcshipment_ncbarra do bulls eyebulls eye barbarra del bulls eye
bullsEyeTargetFmcSoqtarget_fmc_soqbarra do bulls eyebulls eye barbarra del bulls eye
bullsEyeTargetNcSoqtarget_nc_soqbarra do bulls eyebulls eye barbarra del bulls eye
bullsEyeCustomerExecutioncustomer_executionbarra do bulls eyebulls eye barbarra del bulls eye
bullsEyeB2bEngagementb2b_engagementbarra do bulls eyebulls eye barbarra del bulls eye
bullsEyeCreditcreditbarra do bulls eyebulls eye barbarra del bulls eye
commercialPillarsOverdueoverduebarra de pilar comercialcommercial pillar barbarra de pilar comercial
commercialPillarsFatPartnershipfat_partnershipbarra de pilar comercialcommercial pillar barbarra de pilar comercial
commercialPillarsEffectivenesseffectivenessbarra de pilar comercialcommercial pillar barbarra de pilar comercial
commercialPillarsPrimeCoverageprime_coveragebarra de pilar comercialcommercial pillar barbarra de pilar comercial
commercialPillarsProductivityproductivitybarra de pilar comercialcommercial pillar barbarra de pilar comercial
commercialPillarsCapilaritycapilaritybarra de pilar comercialcommercial pillar barbarra de pilar comercial
commercialPillarsPositivationPartnershippositivation_partnershipbarra de pilar comercialcommercial pillar barbarra de pilar comercial
commercialPillarsBoostPlanboost_planbarra de pilar comercialcommercial pillar barbarra de pilar comercial
CardType formato do cartão, por módulocard layout, per moduleformato de la tarjeta, por módulo 6
casevalueEfeito na HomeEffect on the HomeEfecto en la Home
simplesimplerosca sem quebra de detalhe (default do ModuleConfig)donut with no detail breakdown (the ModuleConfig default)dona sin desglose de detalle (default del ModuleConfig)
detaileddetailedabre a quebra por tipo/categoria; no volume de entrega, habilita expandiropens the breakdown by type/category; on delivery volume it enables expandingabre el desglose por tipo/categoría; en volumen de entrega habilita expandir
carouselcarouseluma página por categoria + pontinhos (só com mais de uma)one page per category + dots (only with more than one)una página por categoría + puntitos (solo con más de una)
productImagesproduct_imagesna cobertura, mostra a foto do produto em cada linhaon coverage, shows the product photo on each rowen cobertura, muestra la foto del producto en cada fila
listlistnão usado por nenhum módulo da Homenot used by any Home moduleno usado por ningún módulo de la Home
unknownunknownfallback com log de valor não mapeadofallback with an unmapped-value logfallback con log de valor no mapeado
BullsEyeKpiType rótulo da barrabar labelrótulo de la barra 8
casevaluechave de traduçãotranslation keyclave de traducción
shipmentFmcshipment_fmcbullsEyeShipmentFmc
shipmentNcshipment_ncbullsEyeShipmentNc
targetFmcSoqtarget_fmc_soqbullsEyeTargetFmcSoq
targetNcSoqtarget_nc_soqbullsEyeTargetNcSoq
customerExecutioncustomer_executionbullsEyeCustomerExecution
b2bEngagementb2b_engagementbullsEyeB2bEngagement
creditcreditbullsEyeCredit
unknownunknownnenhuma → cai no nome do KPI em Title Casenone → falls back to the KPI name in Title Caseninguna → cae al nombre del KPI en Title Case
CommercialPillarsKpiType rótulo da barrabar labelrótulo de la barra 9
casevaluechave de traduçãotranslation keyclave de traducción
overdueoverduecommercialPillarsOverdue
fatPartnershipfat_partnershipcommercialPillarsFatPartnership
effectivenesseffectivenesscommercialPillarsEffectiveness
primeCoverageprime_coveragecommercialPillarsPrimeCoverage
productivityproductivitycommercialPillarsProductivity
capilaritycapilaritycommercialPillarsCapilarity
positivationPartnershippositivation_partnershipcommercialPillarsPositivationPartnership
boostPlanboost_plancommercialPillarsBoostPlan
unknownunknownnenhuma → cai no nome do KPI em Title Casenone → falls back to the KPI name in Title Caseninguna → cae al nombre del KPI en Title Case
KpiTargetType filtro do cartão SOPSOP card filterfiltro de la tarjeta SOP 2
casevalueObservaçãoNoteObservación
allalltambém é o fallback de fromValue — este enum não tem unknownalso the fromValue fallback — this enum has no unknowntambién es el fallback de fromValue — este enum no tiene unknown
delivereddeliveredos dois valores declarados por BR e ZA em filterOptionsthe two values BR and ZA declare in filterOptionslos dos valores que BR y ZA declaran en filterOptions
KpiPeriod seções do cartão SOPSOP card sectionssecciones de la tarjeta SOP 3
casevalueRótulo na HomeLabel on the HomeRótulo en la Home
monthToDatemtd"até hoje""month-to-date""hasta hoy"
monthmonth"mês""month""mes"
unknown""fallback — a Home usa o valor cru do períodofallback — the Home shows the raw period valuefallback — la Home usa el valor crudo del período
CategoryForSale categorias esperadas (volume, volume de entrega, SOP)expected categories (volume, delivery volume, SOP)categorías esperadas (volumen, volumen de entrega, SOP) 17
casewireValuelabel
fmcfmcFMC
thpDevicesthp_devicesTHP Devices
thpSticksthp_sticksTHP Sticks
vapourDevicesvapour_devicesVapour Devices
vapourLiquidsvapour_liquidsVapour Liquids
oraloralOral
ryoryoRYO
myomyoMYO
otpotpOTP
otpAccessoriesotp_accessoriesOTP Accessories
otherEaother_eaOther EA
otherUnitother_unitOther UNIT
otherPceother_pceOther PCE
vusevuseVUSE
partnershippartnershipPartnership
ncncNC
unknown""""
fromValue({value})
Casa por wireValue ou por label, sem diferenciar maiúsculas, e ignora o próprio unknown no conjunto de comparação. Só as categorias de volume, volume de entrega e SOP passam por este enum; as de visitas do dia e pedidos do dia são comparadas como string crua (por isso valores fora do enum, como o modi de CL, funcionam ali).Matches by wireValue or by label, case-insensitively, and excludes unknown itself from the comparison set. Only volume, delivery volume and SOP categories go through this enum; visits of the day and orders of the day compare raw strings (which is why values outside the enum, like CL's modi, work there).Casa por wireValue o por label, sin distinguir mayúsculas, e ignora el propio unknown en el conjunto de comparación. Solo las categorías de volumen, volumen de entrega y SOP pasan por este enum; las de visitas del día y pedidos del día se comparan como string cruda (por eso valores fuera del enum, como el modi de CL, funcionan ahí).
CommunicationType pílula do modal de comunicadocommunication modal pillpíldora del modal de comunicado 5
casevalueRótulo da pílulaPill labelRótulo de la píldora
campaigncampaignCampanhaCampaignCampaña
promotionpromotionPromoçãoPromotionPromoción
newsnewsNovidadeNewsNovedad
operationaloperationalOperacionalOperationalOperacional
unknownunknownfallback de fromString (com log) — a pílula reusa o rótulo NovidadefromString fallback (logged) — the pill reuses the News labelfallback de fromString (con log) — la píldora reutiliza el rótulo Novedad
CommunicationTypeUx
A cor da pílula não varia por tipo: tagColor é sempre info e tagBackgroundColor sempre brandAccent. O tipo muda apenas o texto.The pill colour doesn't vary by type: tagColor is always info and tagBackgroundColor always brandAccent. The type only changes the text.El color de la píldora no varía por tipo: tagColor es siempre info y tagBackgroundColor siempre brandAccent. El tipo solo cambia el texto.
DataSourceType origem do fetchfetch originorigen del fetch 3
caseQuem usa na HomeWho uses it on the HomeQuién lo usa en la Home
mocksessão de mock (o repository também cai aqui quando o flag global está ligado)mock session (the repository also lands here when the global flag is on)sesión de mock (el repository también cae aquí cuando el flag global está encendido)
localbuild() e o refresh(source: local) disparado pelo live-updatebuild() and the refresh(source: local) fired by the live updatebuild() y el refresh(source: local) disparado por el live-update
remotedefault do refresh() — o pull-to-refreshthe refresh() default — pull-to-refreshdefault del refresh() — el pull-to-refresh
DataSyncType os 7 tipos que a Home escuta (26 no total)the 7 types the Home listens to (26 overall)los 7 tipos que la Home escucha (26 en total) 7
casekeyenabledMarketsTTL
homeKpihomeKpiBR · CL · ZA300 s
communicationscommunicationsBR · CL · ZA3600 s
ordersordersBR · CL · ZA600 s
visitsvisitsBR · CL · ZA600 s
taskstasksBR · CL · ZA600 s
casescasesBR— (cai no default 300 s)— (falls to the 300 s default)— (cae al default de 300 s)
conectaVoceconectaVoceBR— (cai no default 300 s)— (falls to the 300 s default)— (cae al default de 300 s)
Por que estes 7Why these 7Por qué estos 7
São exatamente os tipos que alimentam a Home: os dois agregados próprios + os cinco caches dos contadores. Quando o sweep atualiza qualquer um deles com sucesso, a revisão sobe e a Home relê o cache uma única vez por lote (as revisões são incrementadas num só copyWith, então não há flicker).They are exactly the types feeding the Home: the two own aggregates + the five counter caches. When the sweep successfully refreshes any of them the revision goes up and the Home re-reads the cache exactly once per batch (revisions are bumped in a single copyWith, so there's no flicker).Son exactamente los tipos que alimentan la Home: los dos agregados propios + los cinco cachés de los contadores. Cuando el sweep actualiza cualquiera de ellos con éxito, la revisión sube y la Home relee el caché una sola vez por lote (las revisiones se incrementan en un solo copyWith, así que no hay flicker).

Enums emprestados dos contadoresEnums borrowed by the countersEnums prestados por los contadores As regras de pendência usam enums de outras features — OrderStatus/OrderStatusGroup (Lista de pedidos), CaseStatus (Casos), TaskStatus (Tarefas) e VisitType (Visitas, usado no rótulo da quebra de visitas do dia). Os valores completos vivem naquelas docs; aqui só interessa o subconjunto que conta como pendente (ver Status). The pending rules use enums from other features — OrderStatus/OrderStatusGroup (Order list), CaseStatus (Cases), TaskStatus (Tasks) and VisitType (Visits, used to label the visits-of-the-day breakdown). Their full value sets live in those docs; what matters here is only the subset that counts as pending (see Status). Las reglas de pendencia usan enums de otras features — OrderStatus/OrderStatusGroup (Lista de pedidos), CaseStatus (Casos), TaskStatus (Tareas) y VisitType (Visitas, usado en el rótulo del desglose de visitas del día). Los valores completos viven en esas docs; aquí solo importa el subconjunto que cuenta como pendiente (ver Estado).

11

UseCases

Quatro UseCases entram no _load(). Os dois primeiros são pass-through finos sobre os repositories da Home; o terceiro é o único com regra de negócio própria (as contagens); o quarto resolve a configuração do mercado, que decide o que a tela renderiza.Four UseCases feed _load(). The first two are thin pass-throughs over the Home repositories; the third is the only one with business logic of its own (the counts); the fourth resolves the market configuration, which decides what the screen renders.Cuatro UseCases entran en el _load(). Los dos primeros son pass-through finos sobre los repositories de la Home; el tercero es el único con regla de negocio propia (los conteos); el cuarto resuelve la configuración del mercado, que decide qué renderiza la pantalla.

GetHomeKPIUseCase os indicadoresthe indicatorslos indicadores
MétodoMethodMétodoRetornaReturnsRetornaUsoUseUso
execute({source = local})Result<HomeKpiEntity, Failure>chamado no _load(); local na abertura, remote no pull-to-refresh e no sweepcalled in _load(); local on open, remote on pull-to-refresh and on the sweepllamado en el _load(); local en la apertura, remote en el pull-to-refresh y en el sweep
getCached()Result<HomeKpiEntity?, Failure>exposto, sem consumidor na Homeexposed, no Home consumerexpuesto, sin consumidor en la Home
getCachedLastSyncAt()DateTime?hook do DataSyncOrchestrator para decidir obsolescência do tipo homeKpiDataSyncOrchestrator hook to decide staleness of the homeKpi typehook del DataSyncOrchestrator para decidir obsolescencia del tipo homeKpi
GetCommunicationsUseCase os comunicadosthe communicationslos comunicados
MétodoMethodMétodoRetornaReturnsRetornaUsoUseUso
execute({source = local})Result<CommunicationsEntity?, Failure>chamado no _load(), em paralelo com os indicadorescalled in _load(), in parallel with the indicatorsllamado en el _load(), en paralelo con los indicadores
getCached()Result<CommunicationsEntity?, Failure>exposto, sem consumidor na Homeexposed, no Home consumerexpuesto, sin consumidor en la Home
getCachedLastSyncAt()DateTime?hook do sweep para o tipo communicationssweep hook for the communications typehook del sweep para el tipo communications
Onde a filtragem aconteceWhere filtering happensDónde ocurre el filtrado
O UseCase devolve o container inteiro. Janela de validade e ordenação por prioridade são getter do State (visibleCommunications), não do UseCase — §27.The UseCase returns the whole container. Validity window and priority ordering are a State getter (visibleCommunications), not the UseCase — §27.El UseCase devuelve el contenedor entero. La ventana de validez y el orden por prioridad son getter del State (visibleCommunications), no del UseCase — §27.
GetRepActionsPendingCountsUseCase os contadores · 6 cachesthe counters · 6 cacheslos contadores · 6 cachés
MétodoMethodMétodoRetornaReturnsRetornaUsoUseUso
execute()RepActionsPendingCountsEntityúnico método público. Note que não devolve Result: toda falha de leitura é engolida e o contador daquele eixo fica em 0the only public method. Note it does not return a Result: every read failure is swallowed and that axis's counter stays at 0único método público. Note que no devuelve Result: toda falla de lectura se engulle y el contador de ese eje queda en 0
CampoFieldCampoFonte (cache-only)Source (cache-only)Fuente (cache-only)PredicadoPredicatePredicado
pendingOrdersOrderRepository.getCachedOrders()order.isPendingo grupo pending inteiro (8 status)the whole pending group (8 statuses)el grupo pending entero (8 estados)
deliveriesGetDeliveriesOfTheDayUseCase.execute(source: local).deliveries.length — sem filtro extra; o critério (pedido separado/faturado) está dentro daquele UseCase.deliveries.length — no extra filter; the criterion (pick-listed/invoiced order) lives inside that UseCase.deliveries.length — sin filtro extra; el criterio (pedido separado/facturado) está dentro de ese UseCase
visitsOfTheDayGetVisitsUseCase.getCached().visits.length cru — sem filtro de data nem de statusraw .visits.length — no date nor status filter.visits.length crudo — sin filtro de fecha ni de estado
casesCaseManagementRepository.getCachedCases()status ∈ {newCase, working, escalated, onHold}status ∈ {newCase, working, escalated, onHold}estado ∈ {newCase, working, escalated, onHold}
conectaVoceActionsConectaVoceApprovalsRepository.getCachedConectaVoceApprovals()soma de account.totalOfPendingActions — campo do servidor, não filtro localsum of account.totalOfPendingActions — a server field, not a local filtersuma de account.totalOfPendingActions — campo del servidor, no filtro local
tasksGetTasksUseCase.execute(source: local)task.status == TaskStatus.pending
Cache-only, comprovadoCache-only, provenCache-only, comprobado
Nenhuma das seis leituras pode ir à rede: quatro usam métodos getCached* explícitos, e as duas que passam por source: local caem na primeira guard-clause do repository, que devolve o cache sem tocar no remoto.None of the six reads can hit the network: four use explicit getCached* methods, and the two going through source: local land on the repository's first guard-clause, which returns cache without touching remote.Ninguna de las seis lecturas puede ir a la red: cuatro usan métodos getCached* explícitos, y las dos que pasan por source: local caen en la primera guard-clause del repository, que devuelve el caché sin tocar el remoto.
RepActionsPendingCountsEntity
Seis campos int, todos com default 0, sem getters. Não tem modelo, DTO nem proto — é objeto de memória.Six int fields, all defaulting to 0, no getters. It has no model, DTO nor proto — it's an in-memory object.Seis campos int, todos con default 0, sin getters. No tiene modelo, DTO ni proto — es objeto de memoria.
GetEndMarketConfigurationUseCase o que a tela mostrawhat the screen showsqué muestra la pantalla
MétodoMethodMétodoRetornaReturnsRetornaUsoUseUso
execute()Result<MarketConfiguration, Failure>seleciona o mercado ativo pela chave minúscula (br/cl/za…); homeConfig.modules visíveis alimenta HomeState.visibleModules. É a única falha que derruba a tela (getOrThrow). Mercado ausente do JSON vira BusinessFailure.picks the active market by its lowercase key (br/cl/za…); the visible homeConfig.modules feed HomeState.visibleModules. It is the only failure that takes the screen down (getOrThrow). A market missing from the JSON becomes a BusinessFailure.selecciona el mercado activo por su clave minúscula (br/cl/za…); los homeConfig.modules visibles alimentan HomeState.visibleModules. Es la única falla que tumba la pantalla (getOrThrow). Un mercado ausente del JSON se vuelve BusinessFailure.
12

Notifier & State

Um único provider — homeProvider, gerado do HomeNotifier (@riverpod, autoDispose, com o mixin AsyncGuard). O HomeState Freezed é a fonte única de verdade da tela: guarda os módulos visíveis, os dois agregados, os contadores e o cadastro do representante de vendas, e expõe por getters todo o trabalho de composição (completar categorias com zero, filtrar comunicados por validade). Os widgets nunca calculam nada.A single provider — homeProvider, generated from HomeNotifier (@riverpod, autoDispose, with the AsyncGuard mixin). The Freezed HomeState is the screen's single source of truth: it holds the visible modules, the two aggregates, the counters and the sales rep record, and exposes all composition work through getters (zero-filling categories, filtering communications by validity). Widgets never compute anything.Un único provider — homeProvider, generado del HomeNotifier (@riverpod, autoDispose, con el mixin AsyncGuard). El HomeState Freezed es la fuente única de verdad de la pantalla: guarda los módulos visibles, los dos agregados, los contadores y el registro del representante de ventas, y expone por getters todo el trabajo de composición (completar categorías con cero, filtrar comunicados por validez). Los widgets nunca calculan nada.

MétodosMethodsMétodos

build() FutureOr<HomeState>

Magro (§37): resolve os três UseCases da Home, observa o de configuração de mercado, e observa três providers ambientais (mercado ativo, ambiente, cadastro do representante) — qualquer mudança neles reconstrói. Registra o listenDataRevision para os 7 DataSyncType com onChanged: refresh(source: local). Termina em return guardedBuild(body: () => _load()).Thin (§37): resolves the three Home UseCases, watches the market-config one, and watches three ambient providers (active market, environment, rep record) — a change in any of them rebuilds. It registers listenDataRevision for the 7 DataSyncTypes with onChanged: refresh(source: local). It ends with return guardedBuild(body: () => _load()).Magro (§37): resuelve los tres UseCases de la Home, observa el de configuración de mercado, y observa tres providers ambientales (mercado activo, ambiente, registro del representante) — cualquier cambio en ellos reconstruye. Registra el listenDataRevision para los 7 DataSyncType con onChanged: refresh(source: local). Termina en return guardedBuild(body: () => _load()).

_load({source = local}) private · Future<HomeState>

Dono único da montagem do State, sempre por ref.read (para o refresh não forçar re-build). Dispara a configuração e o cadastro do representante em paralelo, aguarda a configuração com getOrThrow() (é o único ponto que pode lançar) e filtra homeConfig.modules por isVisible. Só então, e apenas se o representante não for nulo, dispara os três futures restantes (indicadores, comunicados, contadores) e os aguarda: indicadores e comunicados entram por .valueOrNull, então a falha deles é silenciosa.The single owner of State assembly, always via ref.read (so the refresh doesn't force a re-build). It fires the config and the rep record in parallel, awaits the config with getOrThrow() (the only point that can throw) and filters homeConfig.modules by isVisible. Only then, and only if the rep is non-null, does it fire the three remaining futures (indicators, communications, counters) and await them: indicators and communications come in via .valueOrNull, so their failure is silent.Dueño único del armado del State, siempre por ref.read (para que el refresh no fuerce re-build). Dispara la configuración y el registro del representante en paralelo, aguarda la configuración con getOrThrow() (el único punto que puede lanzar) y filtra homeConfig.modules por isVisible. Solo entonces, y solo si el representante no es nulo, dispara los tres futures restantes (indicadores, comunicados, contadores) y los aguarda: indicadores y comunicados entran por .valueOrNull, así que su falla es silenciosa.

refresh({source = remote}) pull-to-refresh + live-updatepull-to-refresh + live updatepull-to-refresh + live-update

Dois null-guards: sai se o State atual for nulo e se o representante de vendas do State atual for nulo. Depois runGuarded(body: () => _load(source: source)). Nunca seta AsyncValue.loading. O default remote é o pull-to-refresh; o live-update chama com local, porque o sweep já trouxe o dado do servidor para o cache. Não há refreshHome — o nome é refresh, sem sufixo (§37).Two null-guards: it returns if the current State is null and if the current State's sales rep is null. Then runGuarded(body: () => _load(source: source)). It never sets AsyncValue.loading. The remote default is pull-to-refresh; the live update calls it with local, because the sweep already pulled the server data into cache. There is no refreshHome — the name is refresh, unsuffixed (§37).Dos null-guards: sale si el State actual es nulo y si el representante de ventas del State actual es nulo. Luego runGuarded(body: () => _load(source: source)). Nunca setea AsyncValue.loading. El default remote es el pull-to-refresh; el live-update lo llama con local, porque el sweep ya trajo el dato del servidor al caché. No hay refreshHome — el nombre es refresh, sin sufijo (§37).

getModuleNameKey({moduleType}) TranslationConstants

Mapeia repActions e dailyKpis para chaves de tradução, com fallback genérico. Sem nenhum call site no app — código morto (ver Pendências).Maps repActions and dailyKpis to translation keys, with a generic fallback. No call site at all in the app — dead code (see Pending).Mapea repActions y dailyKpis a claves de traducción, con fallback genérico. Sin ningún call site en la app — código muerto (ver Pendencias).

State disponível para a PageState available to the PageState disponible para la Page

HomeState 7 campos + 1 lookup + 10 gettersfields + 1 lookup + 10 getterscampos + 1 lookup + 10 getters
Campo / getterField / getterCampo / getterTipoTypeTipoPara quêWhat forPara qué
visibleModulesList<ModuleConfig>módulos com isVisible do EMC — o gate de tudoEMC modules with isVisible — the gate for everythingmódulos con isVisible del EMC — el gate de todo
marketNameStringnome do mercado ativo (não renderizado hoje)active market name (not rendered today)nombre del mercado activo (no renderizado hoy)
environmentNameStringnome do ambiente (não renderizado hoje)environment name (not rendered today)nombre del ambiente (no renderizado hoy)
resourceResourceEntity?saudação (firstName) e o guard de carregamento; nunca a fonte do lastSyncAtgreeting (firstName) and the load guard; never the source of lastSyncAtsaludo (firstName) y el guard de carga; nunca la fuente del lastSyncAt
homeKpisHomeKpiEntity?o agregado de indicadores inteirothe whole indicator aggregateel agregado de indicadores entero
communicationsCommunicationsEntity?o container de comunicados (não filtrado)the communications container (unfiltered)el contenedor de comunicados (no filtrado)
repActionsCountsRepActionsPendingCountsEntityos 6 contadores; default é o objeto todo-zerothe 6 counters; the default is the all-zero objectlos 6 contadores; el default es el objeto todo-cero
getModule(type)ModuleConfig?o lookup que cada widget usa para decidir se aparecethe lookup each widget uses to decide whether to showel lookup que cada widget usa para decidir si aparece
lastSyncAtDateTime?homeKpis?.lastSyncAt — a faixa do topo (§23)homeKpis?.lastSyncAt — the top strip (§23)homeKpis?.lastSyncAt — la franja superior (§23)
endJourneyKpisList<ActionKpiEntity>KPIs da jornada — sem consumidor na Homejourney KPIs — no consumer on the HomeKPIs de la jornada — sin consumidor en la Home
displayBullsEyeList<PillarKpiEntity>percorre os details declarados e casa por kpiName; o que falta entra zeradowalks the declared details and matches by kpiName; what's missing comes in zeroedrecorre los details declarados y casa por kpiName; lo que falta entra en cero
displayCommercialPillarsList<PillarKpiEntity>idem, sobre commercialPillars.pillarsListsame, over commercialPillars.pillarsListídem, sobre commercialPillars.pillarsList
displaySopCategoriesList<SopCategoryEntity>completa as categorias declaradas em categoryOptions (via CategoryForSale)fills the categories declared in categoryOptions (via CategoryForSale)completa las categorías declaradas en categoryOptions (vía CategoryForSale)
displayVolumeOfTheDayCategoriesList<BasicKpiEntity>idem, zerando o que faltarsame, zeroing what's missingídem, poniendo en cero lo que falte
displayDeliveryVolumeCategoriesList<BasicKpiEntity>idem, para o volume de entregasame, for delivery volumeídem, para el volumen de entrega
displayVisitsOfTheDayDetailsList<DetailKpiEntity>compara detailType com as strings cruas de categoryOptions; lista vazia devolve o dado do backend intactocompares detailType against the raw strings of categoryOptions; an empty list returns the backend data untouchedcompara detailType con las strings crudas de categoryOptions; una lista vacía devuelve el dato del backend intacto
displayOrdersOfTheDayDetailsList<DetailKpiEntity>idem, para pedidos do diasame, for orders of the dayídem, para pedidos del día
visibleCommunicationsList<CommunicationEntity>filtra pela janela (início/fim vs DateTimeUtils.now(); nulo = sem limite) e ordena por priority ascendentefilters by the window (start/end vs DateTimeUtils.now(); null = no bound) and sorts by ascending priorityfiltra por la ventana (inicio/fin vs DateTimeUtils.now(); nulo = sin límite) y ordena por priority ascendente
13

Page e widgetsPage & widgetsPage y widgets

A HomePage recebe apenas um ScrollController opcional (a RootPage o injeta para o "tocar na aba ativa rola ao topo") e observa o homeProvider. É o exemplo canônico de page magra do projeto: um Column listando doze filhos, sem um único if sobre estado — cada módulo se auto-esconde. Os modais aparecem aninhados sob o widget que os abre.The HomePage receives only an optional ScrollController (RootPage injects it for "tap the active tab to scroll to top") and watches homeProvider. It is the project's canonical thin page: a Column listing twelve children, with not a single if on state — each module hides itself. Modals appear nested under the widget that opens them.La HomePage recibe solo un ScrollController opcional (la RootPage lo inyecta para el "tocar la pestaña activa desplaza arriba") y observa el homeProvider. Es el ejemplo canónico de page magra del proyecto: un Column listando doce hijos, sin un solo if sobre estado — cada módulo se auto-oculta. Los modales aparecen anidados bajo el widget que los abre.

  • HomePage ConsumerWidget · AppPageShell
    • CustomLoadingIndicator estado loadingloading stateestado loading
    • FailureStateView estado error · retry via ref.invalidate(homeProvider)error state · retry via ref.invalidate(homeProvider)estado error · retry vía ref.invalidate(homeProvider)
    • CustomPullToRefresh estado data · refresh()data state · refresh()estado data · refresh()
      • DataLoadInfo state.lastSyncAt
      • GreetingModule saudação · sem gategreeting · no gatesaludo · sin gate
        • EndJourneyPill gate end_journey → goToEndJourneygate end_journey → goToEndJourneygate end_journey → goToEndJourney
      • CommunicationsCarouselModule gate communications + lista vaziagate communications + empty listgate communications + lista vacía
        • CommunicationsCarouselWidget PageView · sem auto-avançono auto-advancesin auto-avance
          • CommunicationBannerWidget banner tocáveltappable bannerbanner tocable
            • CommunicationImage asset ou Image.network + fallbackasset or Image.network + fallbackasset o Image.network + fallback
            • CommunicationDetailModalContent modal · imagem + tipo + nome + descrição; rodapé dispara aviso "Em breve"modal · image + type + name + description; footer fires a "Coming soon" noticemodal · imagen + tipo + nombre + descripción; el pie dispara aviso "Próximamente"
          • CommunicationsCarouselIndicatorsWidget pontinhos · oculto com 1 itemdots · hidden with 1 itempuntitos · oculto con 1 ítem
      • RepActionsModule ConsumerStatefulWidget · gate rep_actions + details vaziosgate rep_actions + empty detailsgate rep_actions + details vacíos
        • CustomToolTile um por atalho visível · ícone + rótulo + selo de contagemone per visible shortcut · icon + label + count badgeuno por atajo visible · ícono + rótulo + sello de conteo
        • AnimatedSwitcher 2ª parte da grade + seta de expandir (só acima de 8 atalhos)2nd part of the grid + expand arrow (only above 8 shortcuts)2ª parte de la grilla + flecha de expandir (solo arriba de 8 atajos)
      • BullsEyeModule gate bulls_eye + lista vaziagate bulls_eye + empty listgate bulls_eye + lista vacía
        • KpiHorizontalProgressRow uma por indicador declaradoone per declared indicatoruna por indicador declarado
      • CommercialPillarsModule ConsumerWidget · gate commercial_pillarsgate commercial_pillarsgate commercial_pillars
        • KpiHorizontalProgressRow uma por pilar · valores por KpiValueFormatterone per pillar · values via KpiValueFormatteruna por pilar · valores por KpiValueFormatter
      • VisitsOfTheDayModule ConsumerWidget · gate visits_of_the_day + KPI nulogate visits_of_the_day + null KPIgate visits_of_the_day + KPI nulo
        • KpiDonutCard detalhes só com detailed · rótulo por VisitTypedetails only with detailed · label via VisitTypedetalles solo con detailed · rótulo por VisitType
      • OrdersOfTheDayModule ConsumerWidget · gate orders_of_the_day + KPI nulogate orders_of_the_day + null KPIgate orders_of_the_day + KPI nulo
        • KpiDonutCard rótulo por CategoryLabelResolver.shortlabel via CategoryLabelResolver.shortrótulo por CategoryLabelResolver.short
      • VolumeOfTheDayModule StatefulWidget · gate volume_of_the_day + categorias vaziasgate volume_of_the_day + empty categoriesgate volume_of_the_day + categorías vacías
        • ExpandablePageView + KpiCarouselIndicator só com carousel e mais de 1 categoriaonly with carousel and more than 1 categorysolo con carousel y más de 1 categoría
        • KpiCategoryBadge · KpiLinearProgressBar · KpiSummaryRow o corpo do cartãothe card bodyel cuerpo de la tarjeta
        • VolumeDetailsModalContent modal do ícone de informação · KpiModuleDetailList ou CustomEmptyStateinfo-icon modal · KpiModuleDetailList or CustomEmptyStatemodal del ícono de información · KpiModuleDetailList o CustomEmptyState
      • DeliveryVolumeOfTheDayModule StatefulWidget · gate delivery_volume_of_the_day + categorias vaziasgate delivery_volume_of_the_day + empty categoriesgate delivery_volume_of_the_day + categorías vacías
        • KpiModuleCard + KpiModuleHeader com seta de expandir quando detailedwith expand arrow when detailedcon flecha de expandir cuando detailed
        • CustomDropdown<int> seletor de categoria (caminho sem carrossel)category selector (non-carousel path)selector de categoría (camino sin carrusel)
        • KpiModuleDetailList dentro de SizeTransition + FadeTransitioninside SizeTransition + FadeTransitiondentro de SizeTransition + FadeTransition
      • CoverageModule ConsumerWidget · gate vuse_coverage + modiCoverage nulogate vuse_coverage + null modiCoveragegate vuse_coverage + modiCoverage nulo
        • KpiDonutCard com expansionContent das linhas de produtowith the product rows as expansionContentcon expansionContent de las filas de producto
        • CoverageMissingRetailsModalContent ConsumerStatefulWidget · modal com abas por produto; observa cachedRetailsBySfidProvidermodal with per-product tabs; watches cachedRetailsBySfidProvidermodal con pestañas por producto; observa cachedRetailsBySfidProvider
      • SopModule StatefulWidget · gate sop + categorias vaziasgate sop + empty categoriesgate sop + categorías vacías
        • CustomDropdown<KpiTargetType> filtro de tipo, das filterOptionstype filter, from filterOptionsfiltro de tipo, de las filterOptions
        • KpiLinearProgressBar · KpiSummaryRow uma seção por período das periodOptionsone section per period from periodOptionsuna sección por período de las periodOptions
        • ExpandablePageView + KpiCarouselIndicator só com carousel e mais de 1 categoriaonly with carousel and more than 1 categorysolo con carousel y más de 1 categoría

Fora da coluna, mas parte da tela: o AppPageShell monta a CustomAppBar (botão de menu abrindo o CustomDrawer, BrandLogo, ConnectivityIndicator e AppBarBellButton) e sempre insere o ConnectivityBanner; o menu inferior e a gaveta pertencem à RootPage, não à Home. O espaçamento entre módulos vive dentro de cada widget (§32) — a page não insere nenhum SizedBox.Outside the column, but part of the screen: AppPageShell assembles the CustomAppBar (menu button opening the CustomDrawer, BrandLogo, ConnectivityIndicator and AppBarBellButton) and always inserts the ConnectivityBanner; the bottom nav and the drawer belong to RootPage, not to the Home. Spacing between modules lives inside each widget (§32) — the page inserts no SizedBox.Fuera de la columna, pero parte de la pantalla: el AppPageShell arma la CustomAppBar (botón de menú que abre el CustomDrawer, BrandLogo, ConnectivityIndicator y AppBarBellButton) y siempre inserta el ConnectivityBanner; el menú inferior y el cajón pertenecen a la RootPage, no a la Home. El espaciado entre módulos vive dentro de cada widget (§32) — la page no inserta ningún SizedBox.

Notas por mercadoMarket notesNotas por mercado

A Home é inteiramente dirigida pelo End Market Configuration: a presença do bloco homeConfig habilita a tela, e cada módulo, cada atalho, cada indicador e cada formato de cartão é declarado por mercado. Três mercados têm homeConfig; os outros três não têm o bloco, e caem numa Home sem nenhum módulo. As contagens declaradas: BR 9 módulos, ZA 8, CL 7 (dos quais o carrossel de comunicados está desligado em BR e CL, então o número renderizável é 8, 8 e 6).The Home is entirely driven by the End Market Configuration: the presence of the homeConfig block enables the screen, and every module, every shortcut, every indicator and every card layout is declared per market. Three markets have homeConfig; the other three don't have the block at all, and land on a Home with no modules. Declared counts: BR 9 modules, ZA 8, CL 7 (of which the communications carousel is off in BR and CL, so the renderable number is 8, 8 and 6).La Home es enteramente dirigida por el End Market Configuration: la presencia del bloque homeConfig habilita la pantalla, y cada módulo, cada atajo, cada indicador y cada formato de tarjeta se declara por mercado. Tres mercados tienen homeConfig; los otros tres no tienen el bloque, y caen en una Home sin ningún módulo. Los conteos declarados: BR 9 módulos, ZA 8, CL 7 (de los cuales el carrusel de comunicados está apagado en BR y CL, así que el número renderizable es 8, 8 y 6).

BRx CLx ZAx AR PY PE
habilitadoenabledhabilitado presente, desligadopresent, offpresente, apagado ausenteabsentausente

Módulos da Home por mercadoHome modules by marketMódulos de la Home por mercado

MóduloModuleMóduloBRCLZA
end_journeyxxx
communicationsfalsefalsex
rep_actionsxxx
bulls_eyex
commercial_pillarsx
visits_of_the_dayxxx
orders_of_the_dayxxx
volume_of_the_dayxxx
delivery_volume_of_the_dayx
vuse_coveragex
sopxx

Atalhos (rep_actions.details) por mercadoShortcuts (rep_actions.details) by marketAtajos (rep_actions.details) por mercado

AtalhoShortcutAtajoBRCLZA
pending_ordersx
deliveries_of_the_dayxx
casesx
tasksxx
conecta_vocex
retailsxxx
prime_simulatorx
new_accountxxx
returns_areax
collections_managementx
cluesx
chat_bot_voll
visits_of_the_day

As duas últimas linhas existem no enum ModuleDetailType e no código do módulo, mas nenhum mercado as declara — inclusive visits_of_the_day, que só existe como módulo, nunca como atalho (ver Pendências). Nenhum detail declarado hoje está desligado: todos os presentes têm isVisible: true.The last two rows exist in the ModuleDetailType enum and in the module's code, but no market declares them — including visits_of_the_day, which only exists as a module, never as a shortcut (see Pending). No declared detail is off today: every present one has isVisible: true.Las dos últimas filas existen en el enum ModuleDetailType y en el código del módulo, pero ningún mercado las declara — incluido visits_of_the_day, que solo existe como módulo, nunca como atajo (ver Pendencias). Ningún detail declarado hoy está apagado: todos los presentes tienen isVisible: true.

Indicadores declarados por mercadoDeclared indicators by marketIndicadores declarados por mercado

IndicadorIndicatorIndicadorFamíliaFamilyFamiliaBRCLZA
shipment_fmcbulls_eyex
shipment_ncbulls_eyex
target_fmc_soqbulls_eyex
target_nc_soqbulls_eyex
customer_executionbulls_eyex
b2b_engagementbulls_eyex
creditbulls_eyex
overduecommercial_pillarsx
fat_partnershipcommercial_pillarsx
effectivenesscommercial_pillarsx
prime_coveragecommercial_pillarsx
productivitycommercial_pillarsx
capilaritycommercial_pillarsx
positivation_partnershipcommercial_pillarsx
boost_plancommercial_pillarsx

Formato dos cartões e opções por mercadoCard layouts and options by marketFormato de las tarjetas y opciones por mercado

MóduloModuleMóduloBRCLZA
communicationscarouselcarouselcarousel
visits_of_the_daysimpledetailed · physical_seller, physical_telesales, digitaldetailed
orders_of_the_daysimpledetailed · fmc, modi, ryo, partnershipdetailed
volume_of_the_daycarousel · fmc, partnership, otpdetailed, carousel · fmc, vuse, ryo, partnershipdetailed, carousel · fmc, nc
delivery_volume_of_the_daycarousel · fmc, partnership, otp
vuse_coverageproduct_images
sopcarousel · fmc, partnership, otp · filtro delivered, all · períodos mtd, monthcarousel · fmc, nc · filtro delivered, all · períodos mtd, month
end_journey · rep_actions · bulls_eye · commercial_pillarssem cardType nem opções — só isVisible (e details nos dois últimos e em rep_actions)no cardType nor options — only isVisible (plus details on the last two and on rep_actions)sin cardType ni opciones — solo isVisible (más details en los dos últimos y en rep_actions)

TTL das estruturas que a Home consomeTTL of the structures the Home consumesTTL de las estructuras que la Home consume

O bloco dataFreshnessConfig existe em BR, CL e ZA com valores idênticos nos três (e nos três ambientes), e está ausente em AR/PY/PE. Fora do bloco, tudo cai em defaultTtlSeconds: 300; a cadência do sweep é sweepIntervalSeconds: 60.The dataFreshnessConfig block exists in BR, CL and ZA with identical values across the three (and across the three environments), and is absent in AR/PY/PE. Outside the block, everything falls to defaultTtlSeconds: 300; the sweep cadence is sweepIntervalSeconds: 60.El bloque dataFreshnessConfig existe en BR, CL y ZA con valores idénticos en los tres (y en los tres ambientes), y está ausente en AR/PY/PE. Fuera del bloque, todo cae a defaultTtlSeconds: 300; la cadencia del sweep es sweepIntervalSeconds: 60.

ChaveKeyClaveTTLPara que serve na HomeWhat it's for on the HomePara qué sirve en la Home
homeKpi300 stodos os cartões de indicador + a faixa de última sincronizaçãoevery indicator card + the last-sync striptodas las tarjetas de indicador + la franja de última sincronización
communications3600 scarrossel de comunicadoscommunications carouselcarrusel de comunicados
orders600 scontadores de pedidos pendentes e de entregas do diapending-orders and deliveries-of-the-day counterscontadores de pedidos pendientes y de entregas del día
visits600 scontador de visitas (calculado, não exibido) e a regra de entregas do diavisits counter (computed, not shown) and the deliveries-of-the-day rulecontador de visitas (calculado, no mostrado) y la regla de entregas del día
tasks600 scontador de tarefas pendentespending-tasks countercontador de tareas pendientes
casesnão declarado → 300 sundeclared → 300 sno declarado → 300 scontador de casos abertos (só BR)open-cases counter (BR only)contador de casos abiertos (solo BR)
conectaVocenão declarado → 300 sundeclared → 300 sno declarado → 300 scontador de ações Conecta Você (só BR)Conecta Você actions counter (BR only)contador de acciones Conecta Você (solo BR)
retails1800 snomes dos varejos no modal de cobertura (CL)retail names in the coverage modal (CL)nombres de los puntos de venta en el modal de cobertura (CL)
notifications300 sselo de não-lidas no sino da barraunread badge on the app-bar bellsello de no leídas en la campana de la barra
resource3600 so cadastro do representante — sem ele a Home não busca nadathe rep record — without it the Home fetches nothingel registro del representante — sin él la Home no busca nada
BR

A Home mais densaThe densest HomeLa Home más densa BR é o único com pilares comerciais e volume de entrega, e o único cuja grade de atalhos tem os oito itens (pedidos pendentes, entregas, casos, tarefas, Conecta Você, varejos, simulador Prime, novo varejo) — exatamente o limite antes de a seta de expandir aparecer. Também é o único com contadores em quatro atalhos ao mesmo tempo. As roscas de visitas e pedidos são simple, sem quebra de detalhe. BR is the only one with commercial pillars and delivery volume, and the only one whose shortcut grid holds all eight items (pending orders, deliveries, cases, tasks, Conecta Você, retails, Prime simulator, new retail) — exactly the threshold before the expand arrow appears. It's also the only one with counters on four shortcuts at once. The visits and orders donuts are simple, with no detail breakdown. BR es el único con pilares comerciales y volumen de entrega, y el único cuya grilla de atajos tiene los ocho ítems (pedidos pendientes, entregas, casos, tareas, Conecta Você, puntos de venta, simulador Prime, nuevo punto de venta) — exactamente el límite antes de que aparezca la flecha de expandir. También es el único con contadores en cuatro atajos a la vez. Las donas de visitas y pedidos son simple, sin desglose de detalle.

CL

Cobertura e atalhos própriosCoverage and its own shortcutsCobertura y atajos propios CL é o único com o cartão de cobertura (com foto de produto) e o único sem SOP e sem bulls eye/pilares — ou seja, nenhum cartão de barra horizontal. Também é o único com os atalhos área de devoluções, cobrança e pistas, e é o único que declara categorias na quebra de visitas do dia (vendedor presencial / televendas / digital) e em pedidos do dia (inclusive modi, valor que não existe no enum de categorias e só funciona porque essa quebra compara strings cruas). Dos seis atalhos declarados, só um tem contador (entregas do dia). CL is the only one with the coverage card (with product photos) and the only one without SOP and without bulls eye/pillars — that is, no horizontal-bar card at all. It's also the only one with the returns area, collections and clues shortcuts, and the only one declaring categories on the visits-of-the-day breakdown (field seller / telesales / digital) and on orders of the day (including modi, a value absent from the category enum that only works because this breakdown compares raw strings). Of the six declared shortcuts, only one has a counter (deliveries of the day). CL es el único con la tarjeta de cobertura (con foto de producto) y el único sin SOP y sin bulls eye/pilares — o sea, ninguna tarjeta de barra horizontal. También es el único con los atajos área de devoluciones, cobranza y pistas, y el único que declara categorías en el desglose de visitas del día (vendedor presencial / televentas / digital) y en pedidos del día (incluido modi, valor que no existe en el enum de categorías y solo funciona porque ese desglose compara strings crudas). De los seis atajos declarados, solo uno tiene contador (entregas del día).

ZA

Bulls eye e o único carrossel de comunicadosBulls eye and the only communications carouselBulls eye y el único carrusel de comunicados ZA é o único com bulls eye (sete indicadores) e o único mercado em que o carrossel de comunicados está ligado. É também a grade de atalhos mais enxuta — três itens (tarefas, varejos, novo varejo), dos quais só tarefas tem contador. Visitas e pedidos do dia são detailed mas sem categoryOptions, então a quebra mostra o que o backend mandar, sem completar categorias com zero. ZA is the only one with bulls eye (seven indicators) and the only market where the communications carousel is on. It also has the leanest shortcut grid — three items (tasks, retails, new retail), of which only tasks has a counter. Visits and orders of the day are detailed but without categoryOptions, so the breakdown shows whatever the backend sends, with no zero-filled categories. ZA es el único con bulls eye (siete indicadores) y el único mercado donde el carrusel de comunicados está encendido. También tiene la grilla de atajos más reducida — tres ítems (tareas, puntos de venta, nuevo punto de venta), de los cuales solo tareas tiene contador. Visitas y pedidos del día son detailed pero sin categoryOptions, así que el desglose muestra lo que el backend envíe, sin completar categorías con cero.

ARPYPE

Sem homeConfigNo homeConfigSin homeConfig Existem como mercados do app, mas o bloco homeConfig está integralmente ausente na configuração dos três — eles só têm quatro blocos de topo (version, updateConfig, newRetailConfig, visitsConfig). O mapper resolve a ausência para uma lista de módulos vazia, então a Home abre sem erro e sem nenhum bloco: só a barra, a faixa de sincronização (em "-") e a saudação. Também não têm dataFreshnessConfig, então todo TTL cai no default de 300 s. Os mocks de indicador e de comunicado desses três mercados são arquivos vazios de conteúdo — {} no de indicadores e uma lista vazia no de comunicados —, coerentes com a configuração. They exist as app markets, but the homeConfig block is entirely absent from all three configurations — they only carry four top-level blocks (version, updateConfig, newRetailConfig, visitsConfig). The mapper resolves the absence into an empty module list, so the Home opens without error and without a single block: just the bar, the sync strip (showing "-") and the greeting. They also have no dataFreshnessConfig, so every TTL falls to the 300 s default. The indicator and communication mocks for these three markets are files empty of content — {} in the KPI one and an empty list in the communications one — consistent with the configuration. Existen como mercados de la app, pero el bloque homeConfig está integralmente ausente en la configuración de los tres — solo tienen cuatro bloques de tope (version, updateConfig, newRetailConfig, visitsConfig). El mapper resuelve la ausencia a una lista de módulos vacía, así que la Home abre sin error y sin ningún bloque: solo la barra, la franja de sincronización (en "-") y el saludo. Tampoco tienen dataFreshnessConfig, por lo que todo TTL cae al default de 300 s. Los mocks de indicador y de comunicado de esos tres mercados son archivos vacíos de contenido — {} en el de indicadores y una lista vacía en el de comunicados —, coherentes con la configuración.

Pendências / roadmapPending / roadmapPendencias / roadmap

  • O carrossel de comunicados está desligado em BR e CL (isVisible: false) — é o único módulo com false em todo o homeConfig, e ZA é o único mercado que o renderiza. Somando: não existem mocks br_real_/cl_real_ de comunicados (no modo real-mock esses mercados recebem {}), o za_real_communications.json é byte-idêntico ao sintético, e todas as janelas de validade dos mocks são de junho de 2026 com data sem hora — logo já expiradas, o que deixa o carrossel vazio até nas fixtures de ZA.The communications carousel is off in BR and CL (isVisible: false) — the only module with false anywhere in homeConfig, and ZA is the only market rendering it. On top of that: there are no br_real_/cl_real_ communication mocks (in real-mock mode those markets get {}), za_real_communications.json is byte-identical to the synthetic one, and every mock validity window is June 2026 with date-only values — hence already expired, which leaves the carousel empty even on ZA's fixtures.El carrusel de comunicados está apagado en BR y CL (isVisible: false) — es el único módulo con false en todo el homeConfig, y ZA es el único mercado que lo renderiza. Sumando: no existen mocks br_real_/cl_real_ de comunicados (en modo real-mock esos mercados reciben {}), el za_real_communications.json es byte-idéntico al sintético, y todas las ventanas de validez de los mocks son de junio de 2026 con fecha sin hora — o sea ya expiradas, lo que deja el carrusel vacío incluso en las fixtures de ZA.
  • O contador de visitas é calculado e nunca exibido. RepActionsPendingCountsEntity.visitsOfTheDay é preenchido a cada _load(), mas nenhum mercado declara visits_of_the_day como detail de rep_actions (o valor existe no enum só como módulo). E se declarasse, a contagem é o tamanho cru da lista de visitas em cache — sem filtro de dia nem de status —, então não corresponde a "visitas de hoje".The visits counter is computed and never displayed. RepActionsPendingCountsEntity.visitsOfTheDay is filled on every _load(), but no market declares visits_of_the_day as a rep_actions detail (the value exists in the enum only as a module). And were it declared, the count is the raw length of the cached visits list — no day nor status filter — so it wouldn't mean "today's visits".El contador de visitas se calcula y nunca se muestra. RepActionsPendingCountsEntity.visitsOfTheDay se llena en cada _load(), pero ningún mercado declara visits_of_the_day como detail de rep_actions (el valor existe en el enum solo como módulo). Y si se declarara, el conteo es el tamaño crudo de la lista de visitas en caché — sin filtro de día ni de estado —, así que no correspondería a "visitas de hoy".
  • O selo de "pedidos pendentes" conta o grupo pending inteiro — os oito status do grupo, inclusive draft, approved e approvedNotSync. Um pedido já aprovado, portanto, continua contando como pendência no atalho. Isso divergiu da decisão registrada para a feature, que restringe a contagem a pendingRepApproval — o único status que exige ação do representante. O doc descreve o comportamento real; a regra combinada não está implementada.The "pending orders" badge counts the whole pending group — all eight statuses of the group, including draft, approved and approvedNotSync. An already-approved order therefore keeps counting as pending on the shortcut. This diverges from the decision on record for the feature, which restricts the count to pendingRepApproval — the only status that actually requires rep action. The doc describes the real behaviour; the agreed rule is not implemented.El sello de "pedidos pendientes" cuenta el grupo pending entero — los ocho estados del grupo, incluidos draft, approved y approvedNotSync. Un pedido ya aprobado, por lo tanto, sigue contando como pendencia en el atajo. Esto divergió de la decisión registrada para la feature, que restringe el conteo a pendingRepApproval — el único estado que realmente exige acción del representante. El doc describe el comportamiento real; la regla acordada no está implementada.
  • O modo mock não popula o lastSyncAt dos indicadores. O caminho de mock do repository de KPI é o único dos dois que não chama o save… — o de comunicados persiste. Consequência: em sessão mock o cache de homeKpi fica vazio, a faixa do topo mostra o timestamp cunhado em memória mas o sweep vê lastSyncAt == null e trata o tipo como obsoleto em todo ciclo.Mock mode doesn't populate the indicators' lastSyncAt. The KPI repository's mock path is the only one of the two that doesn't call save… — the communications one persists. Consequence: in a mock session the homeKpi cache stays empty, the top strip shows the in-memory minted timestamp but the sweep sees lastSyncAt == null and treats the type as stale on every cycle.El modo mock no puebla el lastSyncAt de los indicadores. El camino de mock del repository de KPI es el único de los dos que no llama al save… — el de comunicados persiste. Consecuencia: en sesión mock el caché de homeKpi queda vacío, la franja superior muestra el timestamp acuñado en memoria pero el sweep ve lastSyncAt == null y trata el tipo como obsoleto en cada ciclo.
  • O mock real de BR não bate com a configuração de BR. O br_real_home_kpi.json traz um bloco bullsEye — que BR não declara, logo é payload morto — e omite o deliveryVolumeOfTheDay, que BR declara: no modo real-mock o cartão de volume de entrega aparece com todas as categorias zeradas.BR's real mock doesn't match BR's configuration. br_real_home_kpi.json carries a bullsEye block — which BR doesn't declare, hence dead payload — and omits deliveryVolumeOfTheDay, which BR does declare: in real-mock mode the delivery-volume card shows every category zeroed.El mock real de BR no coincide con la configuración de BR. El br_real_home_kpi.json trae un bloque bullsEye — que BR no declara, o sea payload muerto — y omite el deliveryVolumeOfTheDay, que BR sí declara: en modo real-mock la tarjeta de volumen de entrega aparece con todas las categorías en cero.
  • cases e conectaVoce não têm TTL declarado em ttlSecondsByType (são 2 dos 8 tipos de sincronização sem entrada), embora sejam justamente dois dos sete que a Home escuta — ficam no default de 300 s. E o registro de alvos do orquestrador não é filtrado por enabledMarkets, então esses dois tipos, declarados como BR-only, são varridos também em CL e ZA.cases and conectaVoce have no declared TTL in ttlSecondsByType (2 of the 8 sync types without an entry), even though they're precisely two of the seven the Home listens to — they stay on the 300 s default. And the orchestrator's target registry is not filtered by enabledMarkets, so those two types, declared BR-only, are swept in CL and ZA too.cases y conectaVoce no tienen TTL declarado en ttlSecondsByType (2 de los 8 tipos de sincronización sin entrada), aunque son justamente dos de los siete que la Home escucha — quedan en el default de 300 s. Y el registro de objetivos del orquestador no se filtra por enabledMarkets, así que esos dos tipos, declarados como BR-only, se barren también en CL y ZA.
  • O cartão de pilares comerciais pode aparecer vazio. Ao contrário do bulls eye, o módulo de pilares só verifica se o módulo está declarado — não verifica se a lista de pilares está vazia. Com o módulo declarado e nenhum pilar, o cartão renderiza com cabeçalho e nenhuma linha.The commercial-pillars card can render empty. Unlike bulls eye, the pillars module only checks whether the module is declared — it does not check whether the pillar list is empty. With the module declared and no pillars, the card renders with a header and no rows.La tarjeta de pilares comerciales puede aparecer vacía. A diferencia del bulls eye, el módulo de pilares solo verifica si el módulo está declarado — no verifica si la lista de pilares está vacía. Con el módulo declarado y ningún pilar, la tarjeta renderiza con encabezado y ninguna fila.
  • O bulls eye não formata os valores por mercado. A linha de bulls eye usa arredondamento cru (toStringAsFixed(0)) enquanto a linha de pilar comercial — visualmente idêntica — usa o formatador de KPI com o mercado ativo. Em mercado com separador diferente, as duas barras exibem números com formatação divergente na mesma tela.Bulls eye doesn't format values per market. The bulls eye row uses raw rounding (toStringAsFixed(0)) while the commercial-pillar row — visually identical — uses the KPI formatter with the active market. In a market with a different separator, the two bars show differently formatted numbers on the same screen.El bulls eye no formatea los valores por mercado. La fila de bulls eye usa redondeo crudo (toStringAsFixed(0)) mientras la fila de pilar comercial — visualmente idéntica — usa el formateador de KPI con el mercado activo. En un mercado con separador distinto, las dos barras muestran números con formato divergente en la misma pantalla.
  • O volume de entrega tem dois títulos. O caminho de cartão único usa a chave deliveryVolumeOfTheDay e o caminho de carrossel usa deliveryVolumeTitle — o mesmo módulo muda de título conforme o formato declarado pelo mercado.Delivery volume has two titles. The single-card path uses the deliveryVolumeOfTheDay key and the carousel path uses deliveryVolumeTitle — the same module changes title depending on the layout the market declares.El volumen de entrega tiene dos títulos. El camino de tarjeta única usa la clave deliveryVolumeOfTheDay y el camino de carrusel usa deliveryVolumeTitle — el mismo módulo cambia de título según el formato declarado por el mercado.
  • O SOP muta estado dentro do build(). Quando o tipo selecionado não está entre as filterOptions do mercado, o módulo reatribui _selectedType dentro do build, sem setState — funciona por acidente do ciclo de render, mas é a classe de código que quebra em rebuild fora de ordem.SOP mutates state inside build(). When the selected type isn't among the market's filterOptions, the module reassigns _selectedType inside build, with no setState — it works by accident of the render cycle, but it's the class of code that breaks on out-of-order rebuilds.El SOP muta estado dentro del build(). Cuando el tipo seleccionado no está entre las filterOptions del mercado, el módulo reasigna _selectedType dentro del build, sin setState — funciona por accidente del ciclo de render, pero es la clase de código que se rompe en rebuilds fuera de orden.
  • Quatro itens da gaveta têm handler e nenhuma declaração. O drawer sabe navegar para varejos, novo varejo, simulador Prime e pistas, mas nenhum mercado declara esses tipos no menuConfig — e o casamento é por igualdade exata de string, então os quatro são caminhos inalcançáveis. O de novo varejo já estava registrado como código morto; os outros três são da mesma família.Four drawer items have a handler and no declaration. The drawer knows how to navigate to retails, new retail, Prime simulator and clues, but no market declares those types in menuConfig — and the match is exact string equality, so all four are unreachable paths. The new-retail one was already on record as dead code; the other three are the same family.Cuatro ítems del cajón tienen handler y ninguna declaración. El drawer sabe navegar a puntos de venta, nuevo punto de venta, simulador Prime y pistas, pero ningún mercado declara esos tipos en menuConfig — y el casamiento es por igualdad exacta de string, así que los cuatro son caminos inalcanzables. El de nuevo punto de venta ya estaba registrado como código muerto; los otros tres son de la misma familia.
  • A Home pede um botão de busca que não existe. A page passa displaySearchButton: true, o shell repassa ao CustomAppBar, e a barra nunca lê o parâmetro — nenhum botão de busca é renderizado em mercado nenhum. É parâmetro morto ponta a ponta — e não só na Home: nove pages o passam, e os irmãos displayChatButton e displayChangeLocationButton são igualmente ignorados pela barra.The Home asks for a search button that doesn't exist. The page passes displaySearchButton: true, the shell forwards it to CustomAppBar, and the bar never reads the parameter — no search button is rendered in any market. It's a dead parameter end to end — and not only on the Home: nine pages pass it, and its siblings displayChatButton and displayChangeLocationButton are equally ignored by the bar.La Home pide un botón de búsqueda que no existe. La page pasa displaySearchButton: true, el shell lo reenvía al CustomAppBar, y la barra nunca lee el parámetro — ningún botón de búsqueda se renderiza en ningún mercado. Es parámetro muerto de punta a punta — y no solo en la Home: nueve pages lo pasan, y sus hermanos displayChatButton y displayChangeLocationButton son igualmente ignorados por la barra.
  • Campos de contrato inertes. PillarsKpi.difference (campo 6) é recebido e descartado — a diferença dos pilares e do bulls eye seria dado de tela e não existe no app. E os dois protos declaram dateReference e lastModifiedDate como optional: o datasource de KPI aceita o primeiro, o de comunicados aceita os dois, e nenhum caller preenche nenhum — o delta-sync existe no contrato e está inerte nas duas pernas.Inert contract fields. PillarsKpi.difference (field 6) is received and dropped — the pillar and bulls eye difference would be screen data and doesn't exist in the app. And both protos declare dateReference and lastModifiedDate as optional: the KPI datasource accepts the first, the communications one accepts both, and no caller fills any — delta sync exists in the contract and is inert on both legs.Campos de contrato inertes. PillarsKpi.difference (campo 6) se recibe y se descarta — la diferencia de los pilares y del bulls eye sería dato de pantalla y no existe en la app. Y los dos protos declaran dateReference y lastModifiedDate como optional: el datasource de KPI acepta el primero, el de comunicados acepta los dos, y ningún caller llena ninguno — el delta-sync existe en el contrato y está inerte en las dos piernas.
  • Membros sem consumidor. ModuleType.dailyKpis não aparece em nenhum EMC e o único método que ramifica nele — HomeNotifier.getModuleNameKey — não tem call site; ModuleDetailType.homeModuleChatBotVoll também não é declarado por mercado nenhum, então o ramo de aviso "em desenvolvimento" é inalcançável para ele (só returns_area, declarado em CL, chega lá); e o getter HomeState.endJourneyKpis não tem leitor — a pílula de jornada só checa a presença do módulo, nunca os KPIs.Members with no consumer. ModuleType.dailyKpis appears in no EMC and the only method branching on it — HomeNotifier.getModuleNameKey — has no call site; ModuleDetailType.homeModuleChatBotVoll isn't declared by any market either, so the "under development" notice branch is unreachable for it (only returns_area, declared in CL, gets there); and the HomeState.endJourneyKpis getter has no reader — the journey pill only checks module presence, never the KPIs.Miembros sin consumidor. ModuleType.dailyKpis no aparece en ningún EMC y el único método que ramifica en él — HomeNotifier.getModuleNameKey — no tiene call site; ModuleDetailType.homeModuleChatBotVoll tampoco lo declara ningún mercado, así que el ramo de aviso "en desarrollo" es inalcanzable para él (solo returns_area, declarado en CL, llega ahí); y el getter HomeState.endJourneyKpis no tiene lector — la píldora de jornada solo verifica la presencia del módulo, nunca los KPIs.
  • Divergência de nome entre configuração e dado. O módulo de cobertura é declarado como vuse_coverage mas o indicador que ele lê chama-se modiCoverage — o cruzamento é deliberado e está no código do widget, mas obriga quem lê a configuração a saber do apelido.Name divergence between config and data. The coverage module is declared as vuse_coverage but the indicator it reads is named modiCoverage — the cross-wiring is deliberate and lives in the widget's code, but it forces anyone reading the configuration to know about the alias.Divergencia de nombre entre configuración y dato. El módulo de cobertura se declara como vuse_coverage pero el indicador que lee se llama modiCoverage — el cruce es deliberado y vive en el código del widget, pero obliga a quien lee la configuración a conocer el alias.